Выполнение транзакций на шине PCI. Реализация на VHDL
Не так давно я спрашивал о механизме опроса PCI-устройств. После я устроился на работу, доделал тестовое задание, а спрашивал я именно о нем, и благополучно забыл о нем. Но недавно выдали новый проект и пришлось все вспомнить, заодно и решил написать сюда.
- Конфигурационные транзакции
- Транзакции ввода/вывода
- Транзакции обращения к памяти
- Когда ведущим устройством является южный мост
- Когда ведущим устройством является устройство, подключенное к шине PCI
И так, для работы с шиной, нам понадобятся следующие сигналы:
clk (Clock) — обеспечивает синхронизацию всех транзакций на PCI, а также является входным для каждого PCI — устройства. AD (Address and Data) — мультиплексирования шина адреса и данных. IDSEL (Initialization Device Select) — выбор устройства инициализации, используется для выбора кристалла при транзакциях чтения конфигурации и записи. CBE (Bus Command and Byte Enables) — команды шины и разрешение байта. FRAME (Frame) — сигнал выдаётся мастером в начале транзакции и определяет её длительность. Для однофазных транзакций FRAME всегда длится один такт. При многофазных транзакциях FRAME снимается за один такт до завершения транзакции. IRDY (Initiator Ready) — сигнал готовности мастера. Он свидетельствует о готовности мастера завершить текущую фазу данных. TRDY (Target Ready) — сигнал готовности таргета, свидетельствующий о готовности таргета завершить текущую фазу данных. STOP (Stop) — этот сигнал выдаётся таргетом, если он хочет остановить текущую транзакцию. PAR (Parity) — контроль четности по линиям AD и CBE. RST(Reset) — cигнал сброса. Является асинхронным. DEVSEL (Device Select) — сигнал выбора устройства.
Перед началом работы с любым устройством его нужно инициализировать. Поэтому рассмотрим особенности выполнения конфигурационных транзакций.
Конфигурационные транзакции. Общие сведения.Для генерации конфигурационных транзакций PCI на ПК используются обращения к двум портам ввода-вывода, носящим имена CONFIG_ADDRESS и CONFIG_DATA, имеющим адреса 0CF8h и 0CFCh соответственно и входящим в состав моста Host–PCI, через который шина PCI прямо или косвенно соединяется с процессором. Порт CONFIG_ADDRESS имеет размер двойное слово и доступен только как единое целое. Обращения меньшего размера по принадлежащим ему адресам передаются на шину PCI как обычные транзакции ввода-вывода. Этот порт доступен для чтения и записи и имеет следующий формат:
Когда необходимо выполнить конфигурационную транзакцию, в этот порт записывается адрес регистра конфигурационного пространства PCI, состоящий из номеров шины (разряды 23–16), устройства (15–11), функции (10–8) и собственно регистра (7–2). Биты 1 и 0 должны всегда содержать нули, а старший бит должен содержать единицу, разрешая тем самым выполнение конфигурационной транзакции. Разряды 30–24 зарезервированы и должны содержать нули.
Собственно генерация конфигурационной транзакции происходит при чтении или записи порта CONFIG_DATA, когда в CONFIG_ADDRESS был записан адрес с установленным старшим битом и номером шины, соответствующим шине, подключенной к мосту Host–PCI, или любой шине PCI, лежащей ниже этой шины и соединённой с ней через один или несколько мостов PCI–PCI (допустимый диапазон номеров шин задаётся мосту Host–PCI в процессе его настройки). Доступ к порту CONFIG_DATA должен иметь размер, равный размеру считываемого или записываемого конфигурационного регистра, адрес которого находится в CONFIG_ADDRESS. Если номер шины, заданный в CONFIG_ADDRESS, совпадает с номером шины, подключённой непосредственно к мосту Host–PCI, генерируется конфигурационная транзакция с адресом типа 0, причём номер устройства, находящийхся в разрядах 15–11 порта CONFIG_ADDRESS, используется для выдачи одного из сигналов IDSEL, которые и служат для выбора конкретного устройства. Кроме того, декодированный номер устройства (один единичный и остальные нулевые биты) в фазе адреса конфигурационной транзакции передаётся в разрядах 31–11 адреса. Если адрес в CONFIG_ADDRESS указывает не ту шину, которая непосредственно подключена к мосту Host–PCI, последний генерирует конфигурационную транзакцию с адресом типа 1. Она будет обработана мостом PCI–PCI, который опознает содержащийся в адресе номер шины. Этот мост либо выполнит конфигурационную транзакцию с адресом типа 0 (если адресуемое устройство подключено к шине, прямо подсоединённой к этому мосту), либо сгенерирует транзакцию с адресом типа 1, обеспечив тем самым её прохождение через следующий мост. Длина этой цепочки теоретически ограничена только разрядностью поля, отведённого под номер шины (8 бит).
Если при выполнении транзакции выяснится, что адресуемого конфигурационного регистра не существует (указан номер несуществующей шины, устройства, функции или регистра), то операция записи не возымеет никаких действий, а операция чтения вернёт процессору значение, содержащее единицы в каждом разряде
Формат адреса для транзакции типа 1.
Формат адреса для транзакции типа 0.
Формат регистра конфигурации:
- Vendor ID — поле идентифицирует изготовителя устройства. Запрещено использовать значение 0xFFFF.
- Device ID — поле идентифицирует конкретный вид устройства. Запрещено использовать значение 0xFFFF.
- Revision ID — дополнение к идентификатору устройства. Может быть равно нулю.
- Header Type — Для многофункциональных устройств. Если 7ой бит равен 0, то устройство является однофункциональным, иначе — многофункциональное.
- Class Code — доступен только для чтения. Используется для идентификации общего функционального назначения устройства. Старший байт (адрес 0Bh) определяет базовый класс, средний — подкласс, младший — программный интерфейс (если он стандартизован).
- Subsystem ID, Subsystem Vendor ID — задаются производителем. Только для чтения. Хранят идентификаторы, позволяющие точно идентифицировать карты и устройства (в системе могут быть установлены несколько карт с совпадающими идентификаторами устройства и производителя (Device ID и Vendor ID).
- BAR0 — BAR5 — описывают области памяти и портов ввода-вывода.
- Бит 0 = 0 — признак памяти. Размером не более 2 Гбайт
- Бит 0 = 1 — признак области портов. Размером до 256 байт.
Мастер выставляет на шине AD адрес устройства, на шине CBE выполняемую команду, устанавливает сигнал FRAME в 0 и сигнал IRDY в 0. Далее, мастер ждет от таргета — выставления им сигналов TRDY и DEVSEL. Так же, таргет выставляет на шину AD запрашиваемые данные. Данные считаются валидными, когда IRDY, TRDY и DEVSEL равны уровню логического нуля.
РеализацияДля обращения к выводам ПЛИС потребуются специальные компоненты: буферы ввода/вывода для работы с Z — состоянием. Так, для шины AD подключение будет выглядеть следующим образом:
- O — выход буфера.
- IO — вход/выход буфера, непосредственно подключается к выводу ПЛИС.
- I — выход буфера.
- T — управление входом, уровень единицы — вход, уровень нуля — выход.
Как я уже писал выше, при начале транзакции, когда на шине AD выставлен адрес, всегда сигнал FRAME равен нулю. Ниже приведен код, который формирует сигнал AdrPhASE, во время действия которого нужно защелкнуть шину адреса и шину команд для последующей работы. Фактически сигнал AdrPhASE есть ни что иное, как выделение спадающего фронта сигнала FRAME, что однозначно идентифицирует начало транзакции.
Далее, работу всего устройства можно описать с помощью автомата.
- 0010 I/O Read
- 0011 I/O Write
- 0110 Memory Read
- 0111 Memory Write
- 1010 Configuration Read
- 1011 Configuration Write
Так выглядит чтение конфигурации в симуляторе:
Запись конфигурации Запись в портНа шине AD мастером выставляется номер регистра для записи, в следующем такте выставляются данные, которые нужно записать. Приведем пример только для записи одного регистра, остальные записываются аналогично.
Чтение портаТак выглядит запись и чтение порта ввода-вывода:
Запись и чтение памятиТак выглядит запись и чтение памяти в симуляторе:
Данные на шину AD выводятся следующим образом. В зависимости от состояния автомата, к выходному буферу подключается соответствующий регистр.
Сигнал разрешения выдачи данных на шину AD формируется следующим образом:
Отдельно хотелось бы добавить про компонент STS на примере выработки сигнала DEVSEL
Так как, активные уровни управляющих сигналов равны нулю, то для перехода в Z — состояние и отпускания линии нужно предварительно выдать уровень логической единицы и только потом перевести в Z — состояние.
ЗаключениеВ заключение хочу сказать, что выполнение транзакций на шине PCI не так сложно как кажется. Разработанная прошивка была залита в ПЛИС. Плата с ПЛИС вставлена в PCI слот и был включен компьютер. Система нашла плату и запросила драйвера на нее. Работает! :)