Эмулятор БК-0010 на FPGA — часть 2

в 18:10, , рубрики: fpga, Verilog, xilinx, Анализ и проектирование систем, Программирование

Ссылка на первую часть

Если вы уже успели поработать с блочным дизайном в Vivado, то могли увидеть, что внешний вид многих стандартных IP изменяется в зависимости от настраиваемых параметров. Например, модуль AXI-GPIO может быть одноканальным или двухканальным в зависимости от параметра «Enable dual channel»:

Эмулятор БК-0010 на FPGA — часть 2 - 1 Эмулятор БК-0010 на FPGA — часть 2 - 2

Для проекта БК-0010 нам тоже будет удобно воспользоваться этой технологией и сегодня мы узнаем, как это сделать.

Также в этой части мы:
– Рассмотрим общие сведения об архитектуре БК-0010
– Поговорим об интерфейсах, о том, как их создавать и как с ними работать.
– Создадим несколько вспомогательных IP, внешний вид и характеристики которых меняются в зависимости от параметров.

Общие сведения об архитектуре

Все элементы БК-0010 (CPU, RAM, ROM, порты) связаны между собой через шину МПИ. МПИ – это упрощённый вариант Q-bus от DEC, представляет собой 16-ти разрядную совмещённую (адрес и данные передаются по одним и тем же проводникам) двунаправленную шину.

Оригинальная шина МПИ была асинхронная, те или иные сигналы выставлялись на ней с некоторыми задержками, нормированными в наносекундах.

В том случае, если в процессе обмена по шине МПИ, Slave устройство не отвечало слишком долго, происходило прерывание по ошибке шины (в отличие, например, от Z80, где ничего подобного не было). Данная архитектурная особенность используется в БК-0010, поэтому её нужно эмулировать.

В проекте БК-0010 будет использоваться похожая внутренняя шина. Разумеется, нет никакого смысла делать совмещенную двунаправленную шину адреса и данных внутри FPGA, поэтому шин будет три – ADDR, DATAIN, DATAOUT (все по 16 бит). Шина будет полностью синхронной, никаких задержек в наносекундах.

В БК-0010 на шине МПИ было только одно Master устройство – CPU, поэтому процедуры захвата шины, прямого доступа к памяти и тому подобного я не реализовывал.

Остальные сигналы я оставил максимально соответствующими оригинальным:
SYNC – Сигнал, сообщающий о том, что Master выставил адрес на шину ADDR. Память адресуется байтами, но по шине данных байт с четным адресом передаётся всегда в младших 8 битах, байт с нечетным в старших.
DIN – Сигнал, сообщающий о том, что Master запросил чтение по ранее выставленному адресу. Чтение осуществляется всегда двухбайтовыми словами, если Master-у нужен только один байт, то второй игнорируется.
DOUT – Сигнал, сообщающий о том, что Master выставил данные на шину DATAOUT и требует, чтобы данные были записаны по ранее выставленному адресу.
WTBT – Сигнал, указывающий на то, что осуществляется байтовая операция. Выставляется только в цикле записи. Master обязан выставить записываемый байт либо в младшие 8 бит шины DATAOUT (в случае чётного адреса) либо в старшие (в случае нечётного). Оставшийся байт игнорируется Slave-устройством.
RPLY – Сигнал, с помощью которого Slave сообщает Master-у о том, что он закончил цикл шины (выставил данные в цикле чтения либо принял их в цикле записи). Если сигнал не приходит в течение 64 циклов, происходит прерывание по ошибке шины.
VIRQ – Сигнал требования прерывания.
IAKO – Сигнал подтверждения/запроса адреса прерывания. Данный сигнал проходил последовательно через все устройства, которые могли потребовать прерывание. Если устройству в данный момент прерывание не требовалось, то оно передавало сигнал дальше по цепочке. Если устройство в данный момент требовало прерывание, то оно не передавало сигнал дальше и начинало цикл передачи адреса прерывания. Позицией устройства в цепочке передачи сигнала IAKO определялся относительный его приоритет.

Прерывания от внешних устройств в БК-0010 используются, поэтому эти сигналы нужны.

Эмулятор БК-0010 на FPGA — часть 2 - 3

Эмулятор БК-0010 на FPGA — часть 2 - 4

Шины и интерфейсы

С шинами и интерфейсами есть некоторая терминологическая путаница, на которую нужно обратить внимание. В Verilog/VHDL шиной (bus) называется связанный набор однотипных цифровых сигналов, предназначенный для передачи многоразрядных чисел. Например шина данных, состоящая из восьми бит.
Кроме того, шиной так же принято называть совокупность разнородных сигналов (сигналы для данных, адреса, управления). Например шина PCI, шина AXI4, в нашем случае шина МПИ. Такая конструкция в терминологии Xilinx Vivado называется интерфейс (interface).

Нам придётся работать с шиной МПИ в нескольких местах. Этот интерфейс будут иметь как минимум CPU, RAM, ROM, порты внешних устройств. Для удобства работы мы сделаем его описание как единой сущности, чтобы не пришлось каждый раз вручную соединять каждый сигнал.

Для этого в Vivado вызываем инструмент Tools->Create interface:
Эмулятор БК-0010 на FPGA — часть 2 - 5
Добавляем сюда все необходимые сигналы, указываем их направление (для Slave направление будет автоматически инвертировано по сравнению с Master), обозначаем, какие сигналы должны присутствовать обязательно, а какие могут отсутствовать. Отдельно отмечаем синхросигналы и сигналы сброса.

Описание интерфейса сохраняется в формате xml. Для того, чтобы мы в проекте могли с ним работать, необходимо в свойствах проекта добавить путь к папке с этим файлом.
Эмулятор БК-0010 на FPGA — часть 2 - 6

IP-модуль с настраиваемыми характеристиками

Рассмотрим как создавать такие модули на примере интерконнекта. Интерконнект — это модуль, который соединяет между собой Master и Slave порты. Поскольку количество портов заранее не известно, этот параметр должен быть настраиваемым. Сам модуль интерконнекта в нашем случае весьма прост, поскольку нам не требуется ни преобразования ширины шины, ни буферизации. Его можно реализовать на комбинационной логике.

В нашем случае у нас будет только один процессор, соответственно интерконнекту достаточно иметь только один Slave порт. Количество Master портов будет задаваться параметром MASTER_INTERFACES:
Эмулятор БК-0010 на FPGA — часть 2 - 7
Текущая ревизия модуля поддерживает до 11 Master портов, естественно это количество можно сделать любым.

Итак, создадим наш модуль

  1. Создаём головной файл модуля, в котором описываем все сигналы, которые могут в этот модуль прийти. Их будет очень много — нам надо описать все сигналы для всех возможных портов MPI (1 Slave + 11 Master) + сигналы clk и rst. Пока что сигналы clk и rst в модуле не используются, поскольку он целиком сделан на комбинационной логике, но я оставил их для единообразия, вдруг в будущем потребуется буферизация или что-то подобное.
    module MPI_Interconnect
    (
        input       [15:0]  S00_ADDR,
        input       [15:0]  S00_DATA_W,
        output      [15:0]  S00_DATA_R,
        input               S00_SYNC,
        output              S00_RPLY,
        input               S00_DIN,
        input               S00_DOUT,
        input               S00_WTBT,
        input               S00_IAKO,
        output  reg         S00_VIRQ,
    
        output      [15:0]  M00_ADDR,
        output      [15:0]  M00_DATA_W,
        input       [15:0]  M00_DATA_R,
        output              M00_SYNC,
        input               M00_RPLY,
        output              M00_DIN,
        output              M00_DOUT,
        output              M00_WTBT,
        output              M00_IAKO,
        input   reg         M00_VIRQ,
    ...
    

  2. Преобразуем наш модуль в IP (Tools->Create and Package new IP). После этого у нас в Project Manager появляется новый пункт Package IP, где можно настраивать параметры проекта.
  3. На вкладке Interfaces создаём 12 интерфейсов MPI, используя описание интерфейса, созданное на предыдущем этапе.
  4. Настраиваем маппинг между созданными интерфейсами MPI и сигналами модуля. Если сигналы модуля названы так же, как порты в интерфейсе, то Vivado сделает этот маппинг сама, но в данном случае она не сможет догадаться, что сигналы M00_ADDR и M00_DIN относятся к нулевому Master порту, а M02_DOUT ко второму, так что придётся кое-что подправить руками.
    Эмулятор БК-0010 на FPGA — часть 2 - 8

  5. Задаём список возможных значений для параметра MASTER_INTERFACES. Кроме списка можно использовать также значения в шестнадцатеричном либо десятичном виде, checkbox, radio button.
    Эмулятор БК-0010 на FPGA — часть 2 - 9

  6. Настраиваем условия видимости портов. Порты S00_MPI и M00_MPI у нас видны всегда, порт M01_MPI помечаем как optional и то, что он должен быть виден лишь при условии $MASTER_INTERFACES > 1. Аналогично поступаем с остальными портами Master.
    Эмулятор БК-0010 на FPGA — часть 2 - 10

  7. Используя опции условной компиляции в Verilog, создаём необходимую логику работы нашего модуля, в зависимости от значения параметра MASTER_INTERFACES:
        if (MASTER_INTERFACES > 1) begin
            assign M01_ADDR     = S00_ADDR;
            assign M01_DATA_W   = S00_DATA_W;
            assign M01_SYNC     = S00_SYNC;
            assign M01_DIN      = S00_DIN;
            assign M01_DOUT     = S00_DOUT;
            assign M01_WTBT     = S00_WTBT;
            assign M01_IAKO     = (M00_VIRQ == 1) ? S00_IAKO : 1;
        end
    ...
    

Теперь вместо полутора сотен сигналов у нас есть аккуратный список из 12 интерфейсов, которые мы можем использовать в блочном дизайне:
Эмулятор БК-0010 на FPGA — часть 2 - 11

На этом этапе мы также создаём несколько модулей с интерфейсом MPI, это модули RAM и ROM. Их реализация довольно тривиальна, в основе лежит конечный автомат, реализующий логику работы шины MPI, а конкретно циклов чтения (ROM) либо чтения и записи (RAM). Модулей ROM у нас три — один для системного монитора, другой для интерпретатора языка Фокал и третий для модуля тестов. Размер каждого модуля по 8 КБ, все они создаются на основе блочной памяти FPGA. Размер модуля RAM 32КБ.

Важный момент — пространства имён не поддерживаются, поэтому массивы для инициализации разных ROM необходимо называть по-разному. Одинаковое название (даже в разных IP) приводит к труднодиагностируемой ситуации, когда один ROM инициализируется содержимым другого, при этом никаких warning-ов об этом не выдаётся.

Начинаем собирать наш проект. Пока у нас есть немного — модуль интерконнекта и модули RAM и ROM:
Эмулятор БК-0010 на FPGA — часть 2 - 12

Сигналы clk и rst пока никуда не подключены, мы их подключим как только разберёмся с clock domains. У модуля RAM осталось много неподключенных сигналов — туда будет подключаться контроллер дисплея. Слева у интерконнекта остался интерфейс MPI Slave. Сюда будет подключен модуль CPU.

Продолжение следует.

Ссылки

описание интерфейса МПИ
модуль интерконнекта МПИ
модуль RAM
модуль ROM системного монитора
модуль ROM интерпретатора языка Фокал
модуль ROM тестовой подсистемы

Автор: Andrey Baldin

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js