Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: адресация pci
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Интерфейсы
sergey sva
Цитата
Шина PCI использует 32-разрядную адресацию портов ввода-вывода. В фазе адреса задатчик указывает точный адрес младшего из байтов, к которому осуществляется обращение. Для передачи значащих байтов будут использоваться те линии AD, которые соответствуют положению этих байтов в двойном слове. Например, если выполняется чтение байта из порта 00001012h, то в фазе адреса будет задан именно этот адрес, а сам байт будет находиться на линиях AD[23:16], чему соответствует комбинация 1011 на линиях C/BE[3:0]#.

Линии разрешения байтов C/BE# должны соответствовать двум младшим разрядам адреса порта.

Немного не понятно подскажите,
Например мастеру нужно прочитать ввод вывод, мастер устанавливает frame, на C/BE команда 0010 на AD адрес и фронт такта, в следующих тактах C/BE указывает где расположен байт на линиях AD. Но если C/Be 0000 то байт будет на ad0-ad7 . тут написано
Цитата
Линии разрешения байтов C/BE# должны соответствовать двум младшим разрядам адреса порта
?
XVR
Цитата(sergey sva @ Aug 30 2011, 09:17) *
Но если C/Be 0000 то байт будет на ad0-ad7 .
Он будет на ad0-ad31, и не байт, а двойное слово (32 бита)
2 младших бита адреса просто игнорируются, а требуемый размер и положение внутри двойного слова задается именно битами на C/BE. Логически весь обмен на PCI производится двойными словами, выровненными на границу двойного слова. Биты на C/BE могут выбрать от 1 до 4 байтов внутри этого двойного слова, с которыми в реальности и производится обмен

sergey sva
Цитата
Биты на C/BE могут выбрать от 1 до 4 байтов
Выбираем например C/BE 0001 младший байт младшего слова target должен вывести на шины ad0-ad7 ? на остальных что будет?
XVR
Цитата(sergey sva @ Aug 30 2011, 18:27) *
Выбираем например C/BE 0001 младший байт младшего слова target должен вывести на шины ad0-ad7 ? на остальных что будет?

Что угодно.

vitan
Цитата(sergey sva @ Aug 30 2011, 18:27) *
Выбираем например C/BE 0001 младший байт младшего слова target должен вывести на шины ad0-ad7 ? на остальных что будет?

CBE инверсные, младший байт надо по 1110 выдавать. Остальные отключены от шины, скорее всего будет 1, но не факт. Если 64-разрядная шина, то точно будет 1, ибо там должны быть предусмотрены подтяжки на AD63:32.
XVR
Цитата(vitan @ Aug 30 2011, 22:54) *
CBE инверсные, младший байт надо по 1110 выдавать.
Это да.
Цитата
Остальные отключены от шины, скорее всего будет 1, но не факт.
Не отключены. Активное устройство обязанно драйвить все исходящие шины. Данные с этих разрядов AD использоваться не будут, но какие то данные там присуствовать должны.
vitan
Цитата(XVR @ Aug 31 2011, 10:41) *
Не отключены.

Да, пардон, запамятовал (п.3.2.4, второй абзац).
sergey sva
Еще вопрос , На моем ПК 5разъемов PCI, как устройство узнает в каком оно слоте если на ad0-1 всегда 0 оно же должно ответить сигналом adsel если адрес совпал?
vitan
Цитата(sergey sva @ Sep 4 2011, 15:52) *
Еще вопрос , На моем ПК 5разъемов PCI, как устройство узнает в каком оно слоте если на ad0-1 всегда 0 оно же должно ответить сигналом adsel если адрес совпал?

Не, ну нельзя же так мучить общественность... Ну почитайте же стандарт, он в открытом доступе.
1. Сигнал называеnся IDSEL, а не adsel
2. Ответить этим сигналом устройство не может, ибо это для него вход.
3. Метод генерации IDSEL может быть любым, но обычно реализуют предложенный в стандарте.
Фактически устройство может знать только логический номер слота. Физическое его расположение оно никогда не узнает. В стандарте CompactPCI, например, для этого предусмотрены пины т.н. географического адреса (для общего развития).
sergey sva
Цитата
Не, ну нельзя же так мучить общественность

Ну я не специально разбираюсь с vhdl и PCI всего неделю.
Цитата
Сигнал называеnся IDSEL, а не adsel

Отпечатка вышла. хотел написать devsel
Сейчас бы хоть один пример запустить что бы можно было дальше разбираться, три примера прикрутил все собираются без ошибок заливаются,
но комп не запускается после перезагрузки вентиляторы работают стартовый экран не появляется. Буду дальше разбираться.
XVR
Цитата(sergey sva @ Sep 4 2011, 15:52) *
Еще вопрос , На моем ПК 5разъемов PCI, как устройство узнает в каком оно слоте
Устройство не должно интересовать в каком оно слоте. Равно как и сколько этих слотов вообще. Ваше устройство должно реагировать на адреса, прописанные в BARx ОС при инициализации PCI. ОС в процессе инициализации перебирает все устройства, какие найдет. Перебирает оно их по конфигурационному пространству, доступ к которому как раз и производится по географическому признаку (т.е. по номеру разъема, в вашем случае). Занимается этой адресацией PCI хаб, и если вы не пытаетесь разработать именно хаб, то способ как он это делает вас интересовать не должен

sergey sva
Ясно немного. При транзакции записи в конфигурационное пространство на шинах ad будет
номеров шины (разряды 23–16), устройства (15–11), функции (10–8) и регистра (7–2)
Номер шины это имеется ввиду через мосты ,если устройство включено через мост то 1 если через два то 2? номер устройства,что то я уже перепутался здесь написано про конфигурацию со стороны драйвера ?ссылка
XVR
Цитата(sergey sva @ Sep 4 2011, 23:32) *
Номер шины это имеется ввиду через мосты ,
Ну если грубо, то да.
Цитата
если устройство включено через мост то 1 если через два то 2?
Нет. Каждый мост в системе представляется шиной. Когда система сканирует конфигурацию PCI, она находит все мосты и присваивает им последовательные номера. Эти номера и будут номером шины.
Цитата
здесь написано про конфигурацию со стороны драйвера ?
Про доступ к Config Space там написано со стороны ядра ОС. Драйвер обычно на такой уровень не спускается. ОС (точнее даже BIOS) самостоятельно находит все устройства на PCI шине, самостоятельно их настраивает и отдает драйверу каждого конкретного устройства уже в готовом к работе виде. Драйвер в регистры из Configuration Space уже обычно не обращается.

sergey sva
понятно спасибо буду дальше разбираться.
sergey sva
В процессе конфигурации на шинах ad0-1 мастером устанавливается формат конфигурации (0-1), а что будет на остальных ad3-31?
Один формат краткий номер функции и номер регистра, в другом номер шины ... для чего два формата?
XVR
Цитата(sergey sva @ Sep 6 2011, 12:52) *
Один формат краткий номер функции и номер регистра, в другом номер шины ... для чего два формата?
Давно это было, но если мне не изменяет память, то один формат предназначен для записи конфиг. регистров самого моста (или устройства), в 2й формат для передачи запроса на доступ к конфиг. пространству через мост (к устройствам, подключенным за ним)

vitan
Цитата(XVR @ Sep 6 2011, 13:02) *
если мне не изменяет память

Не изменяет, так и есть.
sergey sva
Вычитал из книги Петрова вывод m66en должен соединяться с clk + резистор нагрузочный, его к земле присоединять, не совсем понимаю что здесь написано.
Цитата
Сегмент системной платы предназначенный для работы на частоте 66 ,должен обеспечить один нагрузочный резистор на вываоде m66 шинно соединена со всеми разъемами и компонентами предназначенными для использования только на системной плате которые содержад вывод m66 цепь синхронизации 66 должна соединяться с выводом m66что бы генерировать такты соответсвующей частоты для сигмента (от33до66) если выставлен сигнал m66 и от 0до33 если m66 снят.
vitan
Цитата(sergey sva @ Sep 7 2011, 08:46) *
Вычитал из книги Петрова вывод m66en должен соединяться с clk + резистор нагрузочный, его к земле присоединять, не совсем понимаю что здесь написано.

lol.gif
Ух! Ржунимагупаццталом.
Это в книжках нынче так пишут? Да еще и в таком олбанском стиле? Да, спасти этот мир тяжело...

Для сегмента с поддержкой 66 МГц M66EN равен 1. Для сегмента 33 МГц- нулю. Сегмент - это несколько слотов, на которых пины M66EN соединены между собой.

Читайте стандарт, не надо больше книжек..
sergey sva
)) книга с интернета в текстовом формате кто то наверно её переписал. в отсканированном не очень удобно читать.
Там еще для target, написано должна быть развязка земли от M66EN конденсатором.
Немного не понял как адресуется бар например для памяти? младшие байты 1-2указывают разрешение 64 или 32 ,
а как адрес указать к примеру: в устройстве 16 регистров 32бита нужно что бы доступ к ним был с адреса 0xf0 и по 0xff.
Что устройство должно записать BAR ?
XVR
Цитата
Немного не понял как адресуется бар например для памяти? младшие байты 1-2указывают разрешение 64 или 32 ,
Биты, а не байты. Ставьте 32х битный BAR.
Цитата
а как адрес указать к примеру: в устройстве 16 регистров 32бита нужно что бы доступ к ним был с адреса 0xf0 и по 0xff.
Не выйдет. Адреса будут всегда с 0 (относительно BAR'а)
Если вам надо 16 регистров, то биты в BAR0 должны быть такими -
0,1 - RO - 01 (Насколько помню, т.е. memory/32bit)
2-6 - RO - 0
7-31 - RW
В дешифраторе на вашем устройстве должны сравниваться биты адреса 7-31 с такими же битами BAR0
Цитата
Что устройство должно записать BAR ?
Устройство - ничего. Писать будет ОС (с PC)
sergey sva
Цитата
Писать будет ОС (с PC)

Система будет перебирать все адреса, например нужно прочитать 15й регистр? В устройстве дешифраторе должен ждать когда система запишет 15 в BAR (7-31)?
Прочитал еще: система вначале сохраняет значение BAR после записывает туда FFFFFFFF после читает отбрасывает биты 0-3 и вычисляет адрес.
Что то не пойму как это происходит.
XVR
Цитата
Система будет перебирать все адреса, например нужно прочитать 15й регистр?
Нет конечно
Цитата
В устройстве дешифраторе должен ждать когда система запишет 15 в BAR (7-31)?
Тоже нет
Цитата
Что то не пойму как это происходит.

Пример:
Код
Есть начало окна адресов для PCI. Пусть это будет 0xC0000000 (TOP)
ОС находит ваше устройство, пишет 0xFFFFFFFF в ваш BAR0, читает, что получилось - 0xFFFFFF81
ОС получает размер окна, для регистров вашего устройства (число нулей в BAR0) - 128 байтов
ОС выравнивает TOP на 128 байтов (ваш TOP уже выровнен) и записывает его в BAR0. Там теперь 0xC0000001
TOP смещается на 128 байтов - 0xC0000080

Теперь запись в 15 регистр (смещение регистра в BAR0 - 15*4 = 0x3C)
Код
ОС (драйвер) берет базу из образа вашего BAR0 (0xC0000000), который запомнен во внутренних структурах ОС, прибавляет смещение (результат 0xC000003C) и пишет по этому адресу 4х байтовое значение.
В вашем устройстве ловится запись по адресу 0xC000003C, старшие биты адреса (32-7=25 битов) сравниваются с содержимым BAR0. Т.к. они совпадают, то устройство производит запись в регистр 15 (биты адреса 2-6).
sergey sva
Понятно, не то что в книгах пишут))
Цитата
Пусть это будет 0xC0000000 (TOP)

Любой может быть ?
Цитата
что получилось - 0xFFFFFF81

Как посчитали ?
XVR
Цитата(sergey sva @ Sep 8 2011, 09:02) *
Любой может быть ?
Это определит система
Цитата
Как посчитали ?
Все разряды BAR0, которые RO намертво привязаны к константам и запись в них 1 игнорируется. Все разряды RW запишут 1, которая впоследствии и прочтется


sergey sva
Цитата
RO намертво привязаны к константам и запись в них 1 игнорируется.

Понятно, бит 0 1 2 служебные, а 3456 бит это количество доступных регистров. Остальные прочитаются как 1.
немного не уловил, 0xFFFFFF81 это нужно сдвинуть на 128 байт? откуда 128получилось?
Вот из книги, не пойму "а затем все значения увеличиваются на 1"
Нажмите для просмотра прикрепленного файла
XVR
Цитата
0xFFFFFF81 это нужно сдвинуть на 128 байт?
Нет, это просто адрес (за исключением 3х младших битов, их нужно считать нулями). Считаем количество нулей справа, получаем 7 нулей. Размер - 2**7+1 (128)
sergey sva
Набросал функцию которая должна из прочитанного бара определять диапазон ,размер и тип. но пока не работает Помогите разобраться.
Код
TBarReg GetPciBar(uint8_t bus, uint8_t dev, uint8_t func,uint8_t barnum)
{
    TBarReg  barstr;
    uint32_t bartemp = PciReadConfigDWord(bus, dev, func, barnum);
    uint32_t baradrran = 0;

    if(bartemp !=0){

               if(bartemp&0x00000001){
                   baradrran = 7;
                   for(uint32_t bari = 2; bari < 16; bari++ ){
                   if((bartemp>>bari)&0x00000001)break;
                   baradrran =  baradrran | (0x00000001<<bari);

                   }//end for
                barstr.Value = bartemp;
                barstr.RangeStart =  ((bartemp>>2)<<2)&0x0000ffff;
                barstr.RangeEnd   =  baradrran | barstr.RangeStart;
                barstr.Size       =  barstr.RangeEnd - barstr.RangeStart;
                memcpy(barstr.TypeB,"P  I/O",6);

               }else{

                   baradrran = 0x0f;
                   for(dword bari = 3; bari < 32; bari++ ){
                   if((bartemp>>bari)&0x00000001)break;
                   baradrran =  baradrran | (0x00000001<<bari);

                   }//end for
                barstr.Value = bartemp;
                barstr.RangeStart = (bartemp>>3)<<3;
                barstr.RangeEnd   =  baradrran | barstr.RangeStart;
                barstr.Size       =  barstr.RangeEnd-barstr.RangeStart;
                memcpy(barstr.TypeB,"MEMORY",6);

               }//end else
        
        
        
    }else{
        barstr.Value      = 0;
        barstr.RangeStart = 0;
        barstr.RangeEnd   = 0;
        barstr.Size       = 0;
        memcpy(barstr.TypeB,"No BAR",6);
    }//end else bartemp != 0


return barstr;
}//end GetPciBar
//-------------------------------------------------------------------------------------------------//
XVR
Вы забыли записать в BAR FFFFFFF.
sergey sva
ок сейчас попробую, а правильно делаю?
Вот к примеру в баре записано 0x00009401 эта функция дает такой результат диапазон P I/O 0x00009400-0x000097ff размер 0x3ff
это правильно?

Попробовал еще одной програмкой PCIsniffer она дает такой результат bar 0x00009401 P I/O 0x00009400-0x0000940F размер 0x10.

Попробовал в линуксе он дает такой результат P I/O 0x9000-0x900F размер 0x10.

Как правильно вычислить размер начальный и конечный диапазон, размер? Думал что нужно посчитать нули и 2 в этой степени (количества нулей) будет концом диапазона, 0x00009400 это 1001010000000000 10 нулей 2 в 10 степени будет 3ff.
sergey sva
Вот в спецификации написано, в чем ошибся не соображу?
Код
Число  старших  битов,  которые  устройство  фактически  устанавливает,  зависит  от  того,  сколько
адресного пространства устройство может адресовать. Устройство, которое хочет адресное пространство
памяти 1 МБ (использующее 32-разрядный регистр базового  адреса) должно  сформировать  старшие 12
битов адресного регистра, аппаратно другие биты установлены в 0.
Программное  обеспечение  Включения  питания  может  определять  количество  адресного  пространства
требуемое  устройству  для  записи   всех  единиц  в  регистр  и  для  чтения  значений   обратно. Устройство
должно  возвращать 0  во  все  незадействованные  биты  адреса ,  точно  определяя  требуемое  адресное
пространство.
Эта  конструкция  предполагает,  что  все  задействованное  адресное  пространство  питается  от  двух
источников  и  располагается  линейно. Устройства  могут  задействовать  больше  адресного  пространства
чем  требуется,  но  декодирование  для  4КБ  пространства  Памяти  и  для 256-байтового  ввода/вывода
предложено  для  устройств,  которые  нуждаются  в  меньшем   их  количестве.  Устройства,  которые
потребляют  больше  адресного  пространства  чем  они  используют,  не  требуются,  чтобы  ответить  на
неиспользуемую часть того адресного пространства.
XVR
Цитата
в чем ошибся не соображу?
Для того, что бы обнаружить биты в BAR регистре, которые можно установить, в них необходимо записать 1, а не надеяться на то, что она там будет сама по себе. Вы туда ничего не писали, соответственно все младшие нулевые биты адреса, которые туда записала ОС вы посчитали немодифицируемыми, а это не так



Вот, что должно быть:
Код
uint32_t barorg = PciReadConfigDWord(bus, dev, func, barnum);
PciWriteConfigDWord(bus, dev, func, barnum,-1);
uint32_t bartemp = PciReadConfigDWord(bus, dev, func, barnum);
PciWriteConfigDWord(bus, dev, func, barnum, barorg);

barstr.Value = barorg;
barstr.RangeStart =  barorg&~7;
barstr.Size       = -(bartemp&~7);
barstr.RangeEnd   =  barstr.RangeStart+barstr.Size;

sergey sva
Спасибо. переделал вроде правильно работает, Может еще что посоветуете?
Код
TBarReg GetPciBar(uint8_t bus, uint8_t dev, uint8_t func,uint8_t barnum)
{
    TBarReg  barstr;
    uint32_t BarReg1 = 0,  BarReg2 = 0;

    BarReg1 = PciReadConfigDWord(bus, dev, func, barnum);
     PciWriteConfigDWord(bus, dev, func, barnum,0xffffffff);
    BarReg2 = PciReadConfigDWord(bus, dev, func, barnum);
     PciWriteConfigDWord(bus, dev, func, barnum,BarReg1);

    
    if(BarReg1!=0){

               if(BarReg1&0x00000001){
                BarReg2&=0x0000ffff;
                barstr.Value      = BarReg1;
                barstr.RangeStart = BarReg2&~0x07;              
                barstr.Size       = 0x0000ffff-(BarReg2&~0x07);
                barstr.RangeEnd   = barstr.RangeStart+barstr.Size;
                memcpy(barstr.TypeB,"P  I/O",6);

               }else{
                barstr.Value      = BarReg1;
                barstr.RangeStart = BarReg2&~0x0f;              
                barstr.Size       = 0xffffffff-(BarReg2&~0x07);
                barstr.RangeEnd   = barstr.RangeStart+barstr.Size;
                memcpy(barstr.TypeB,"MEMORY",6);

               }//end else
        
        
        
    }else{
        barstr.Value      = 0;
        barstr.RangeStart = 0;
        barstr.RangeEnd   = 0;
        barstr.Size       = 0;
        memcpy(barstr.TypeB,"No BAR",6);
    }//end else bartemp != 0


return barstr;
}//end GetPciBar
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.