![](https://habrastorage.org/files/a36/f50/0e9/a36f500e94974df38078f91fe5cee6c6.jpg)
Большинство любительских проектов FPGA, опубликованных на Хабре, сделаны на оборудовании фирмы Altera (теперь Intel). Давайте для разнообразия посмотрим, что можно сделать на продукции его основного конкурента – Xilinx. Мы возьмём и сделаем достаточно большой и сложный проект, в процессе реализации которого нам понадобится:
- Выбрать Development board и необходимые PMOD к ней
- Определиться с дизайном проекта, выбрать clock domains и правила перехода между ними
- Освоить основные функции Xilinx Vivado – создание проекта, работу с блочными схемами, компиляцию, симуляцию, отладку
- Сделать несколько IP с интерфейсом AXI4
- Поработать с внешними устройствами
- Сделать с нуля собственный процессор с контроллером шины и обработкой прерываний
- Написать модуль для верификации
- Наконец собрать всё вместе и получить реализацию на FPGA легендарного (как минимум для тех, кто тогда жил) компьютера середины 80-х – БК-0010
Планируется цикл статей, в которых всё это будет подробно описано, сегодня первая из них. Проект написан на System Verilog с небольшими вставками Verilog и VHDL в тех местах, где это необходимо. От читателя требуется понимание базовых принципов языков Verilog/VHDL на уровне книжки Харрис&Харрис.
Пара слов о БК-0010
БК-0010 появился в 1986 году и представлял собой одноплатный компьютер на базе процессора КР1801ВМ1 (система команд DEC PDP-11). По мере повествования нам придётся рассмотреть кое-какие его архитектурные особенности, пока же ограничимся теми характеристиками компьютера, которые нам будут важны для выбора платы и другого оборудования:
Характеристика | Значение |
---|---|
CPU | 3 MHz, количество транзисторов около 18000 (n-МОП) |
RAM | 32 KB |
ROM | 8-32 KB |
Устройства вывода
- Бытовой телевизор, 512x256 в черно-белом режиме либо 256x256 в цветном (каждая точка могла иметь 4 цвета независимо от других)
- Звуковая пищалка (вывод 1 бит), совмещенная с выводом на магнитофон
Устройства ввода
- Клавиатура с расположением клавиш ЙЦУКЕН (JCUKEN)
![](https://habrastorage.org/files/1a2/ec5/1ef/1a2ec51efecf4ae39e1d5d5e2177ea0f.jpg)
Выбор платы
Какую плату и на каком кристалле взять для проекта? В случае с кристаллом под наши требования можно выбирать из Artix-7 и Zynq-7000, в обоих случаях будет достаточно самого маленького кристалла. Платы для разработки — кое-что делает сама Xilinx, это платы с весьма богатой начинкой, но с четырехзначным ценником. Есть европейская компания Trenz Electronic GmbH, но я бы сказал, что их продукция больше ориентирована на создание готовых устройств. На мой взгляд, наиболее подходящие платы с чипами Xilinx для любительского использования делает компания Digilent. На Artix-7 это Basys-3, Nexus 4 DDR и Nexus Video, на Zynq-7000 это Zybo и ZedBoard.
Для себя я остановился на Zybo. Эта плата одна из самых дешевых ($189, а если вы убедите Digilent, что удовлетворяете требованиям Academic Discount Program, то $125), у неё есть выходы как VGA так и HDMI, много портов PMOD, 512MB RAM. Да, эта плата основана на SoC, а возможности процессорного ядра я в этом проекте использовать не планирую. Но никто не мешает использовать эту плату просто как FPGA. У платы отсутствуют отладочные семисегментные индикаторы и нет возможности подключения PS2 либо USB клавиатуры к FPGA-части (в отличие от более дорогой Nexus 4 DDR), но разница в цене между этими двумя платами существенно больше, чем стоимость модулей PMOD, на которых эту функциональность можно получить.
Итак, в сухом остатке, для проекта нам понадобятся следующее оборудование:
Zybo
![Zybo](http://cdn6.bigcommerce.com/s-7gavg/products/98/images/4462/Zybo-obl4-academic-600__71953.1491605756.1280.1280.png)
PMOD-SSD – два семисегментных индикатора для отладки
![PMOD-SSD](http://cdn6.bigcommerce.com/s-7gavg/products/212/images/3880/Pmod_SSD__99365.1456867364.1280.1280.png)
PMOD-PS2 — для подключения PS/2 клавиатуры. Я такой готовый купить забыл, так что пришлось сделать его самому. Заодно поставил туда DC-DC преобразователь 3.3->5В так как имеющаяся у меня клавиатура от 3.3В не заработала.
![PMOD-PS2](http://cdn6.bigcommerce.com/s-7gavg/products/202/images/3870/Pmod_PS2__63402.1456867133.1280.1280.png)
Я не хочу использовать устаревший PS/2, а хочу подключить клавиатуру по USB.
Можно и так, но есть некоторые сложности.
На Zybo есть USB Host, но он подключен к PS-части. Если планируется PL-проект, то потребуется подключить к плате отдельный USB host.
Полная спецификация протокола USB (с поддержкой HOST и всех типов устройств) очень сложна для реализации на FPGA, к тому же интерфейс USB довольно высокочастотен. Разумным компромиссом является подключение внешнего конвертера физического уровня например по интерфейсу ULPI, для работы с ULPI можно найти готовый IP-модуль на Verilog/VHDL. Можно также подобрать другую плату, на которой уже есть USB host для работы с клавиатурами и мышками (у Digilent это, например, Nexus 4 DDR).
На Zybo есть USB Host, но он подключен к PS-части. Если планируется PL-проект, то потребуется подключить к плате отдельный USB host.
Полная спецификация протокола USB (с поддержкой HOST и всех типов устройств) очень сложна для реализации на FPGA, к тому же интерфейс USB довольно высокочастотен. Разумным компромиссом является подключение внешнего конвертера физического уровня например по интерфейсу ULPI, для работы с ULPI можно найти готовый IP-модуль на Verilog/VHDL. Можно также подобрать другую плату, на которой уже есть USB host для работы с клавиатурами и мышками (у Digilent это, например, Nexus 4 DDR).
Начало работы с Xilinx Vivado
Проекты для Xilinx (в данном случае речь о 7-й серии чипов) создаются в Xilinx Vivado. Поскольку мы не планируем использовать High-end чипы (UltraSCALE/UltraSCALE+), для наших целей подойдёт бесплатная Xilinx Vivado WebPACK edition. Регистрируемся на xilinx.com, скачиваем её и устанавливаем.
Системные требования
В основном это RAM. Для Zybo с трудом, но хватает 8GB, для более мощных чипов надо больше.
Для работы с Zybo нам потребуется скачать и добавить в Vivado пакет Vivado Board Files, содержащий описание интерфейсов, имеющихся на плате, частотные характеристики чипа и тому подобное. Скачиваем его с сайта Digilent (а точнее с GitHub) и добавляем в Vivado.
Также понадобится файл ресурсов, в котором описано соответствие контактов чипа номерам выводов разъёмов платы. Находим нашу плату, в данном случае Zybo на GitHub/Digilent и скачиваем.
И напоследок сделаем первый проект на Verilog. Этот проект нам в дальнейшем потребуется для создания контроллера клавиатуры БК-0010.
У меня есть вот такая раритетная клавиатура Mitsumi с интерфейсом PS/2:
![](https://habrastorage.org/files/cce/fed/6b5/ccefed6b5355464cb98f26c749fb53ae.jpg)
ishevchuk в своём проекте использовал вот этот контроллер для работы с PS/2 клавиатурой.
Возьмём его и мы и слегка переделаем. Контроллер всем хорош кроме того, что в нём жестко зашита тактовая частота 50 MHz. Такой частоты у нас в проекте БК-0010 не будет, кроме того, хардкодить такие вещи нехорошо. Создаём новый проект в Vivado, скачиваем файлы контроллера и задаём тактовую частоту в виде параметра:
Заголовок модуля с формулами
module Altera_UP_PS2_Command_Out #
(
parameter CLOCK = 100,
// Timing info for initiating Host-to-Device communication
// when using a 50MHz system clock
parameter CLOCK_CYCLES_FOR_101US = (CLOCK * 101), // 5050;
parameter NUMBER_OF_BITS_FOR_101US = $clog2(CLOCK_CYCLES_FOR_101US),
parameter COUNTER_INCREMENT_FOR_101US = 1,
// Timing info for start of transmission error
// when using a 50MHz system clock
parameter CLOCK_CYCLES_FOR_15MS = (CLOCK * 15000), // 750000;
parameter NUMBER_OF_BITS_FOR_15MS = $clog2(CLOCK_CYCLES_FOR_15MS),
parameter COUNTER_INCREMENT_FOR_15MS = 1,
// Timing info for sending data error
// when using a 50MHz system clock
parameter CLOCK_CYCLES_FOR_2MS = (CLOCK * 2000), // 100000;
parameter NUMBER_OF_BITS_FOR_2MS = $clog2(CLOCK_CYCLES_FOR_2MS),
parameter COUNTER_INCREMENT_FOR_2MS = 1
)
Некоторые модули в составе проекта в своём названии имеют слово Altera. На Xilinx это им работать не мешает, из уважения к разработчику я переименовывать их не стал.
Кроме того, изменим полярность сигнала RESET, у стандартных IP Xilinx сброс происходит при подаче 0 на вход RESET.
Для удобства работы оформим проект в виде IP. В Vivado есть встроенный инструмент, который это делает, он вызывается через Tools->Create and Package new IP. Входы и выходы головного файла проекта станут входами и выходами нашего нового IP. Vivado пытается сама определить тип портов, анализируя их название. В данном случае нам придётся вмешаться в этот процесс и исключить порт PS2_CLK из числа Clock and Reset Signals, чтобы уменьшить число Warnings при дальнейшей сборке проекта. PS2_CLK нельзя назвать полноценным синхросигналом, поскольку его частота лишь несколько десятков килогерц.
Инструмент весьма гибкий, мы можем не только задавать тип портов, но и управлять различными параметрами, задавать опции условной компиляции, менять внешний вид IP в зависимости от параметров. В данном проекте у нас есть два параметра — Initialize Mouse (выбор устройства — клавиатура или мышь) и Clock (тактовая частота в мегагерцах). Вопросы условной компиляции мы рассмотрим позже, когда будем писать модуль для работы с шиной MPI.
![](https://habrastorage.org/files/241/e8c/d58/241e8cd581d844ef9a3942207fedf713.png)
Подключаем Git к Vivado
Напоследок (а вообще это конечно нужно делать сразу после создания нового проекта) прикрутим к Vivado Git. Исходные тексты на Verilog/VHDL, constraints, описания компонент, описания интерфейсов IP-модулей, сам проект и прочее представляют собой текстовые файлы, с ними всё просто. Но есть одна сложность — в файле проекта (он в формате XML) имеются абсолютные пути к исходным текстам, это может вызвать некоторые проблемы при переносе проекта между машинами. Одно из решений — воспользоваться готовым инструментом (написанным инженерами Xilinx), этот инструмент на основе проекта Vivado создаёт переносимый tcl-скрипт, который при запуске на целевой машине создаёт там проект, идентичный оригинальному. К этому инструменту был дописан враппер, автоматизирующий создание tcl-скрипта, заполняющий файл .gitignore, осуществляющий обработку ошибок ввода и тому подобное. После установки этого враппера появляется возможность работать с Git прямо из tcl-консоли Vivado.
Заливаем проект в железо
Проверим теперь, как это всё работает. Закроем проект PS2 контроллера и создадим тестовый проект, принимающий скан-коды с клавиатуры и выдающий их на семисегментный индикатор. В этом проекте мы не напишем ни строчки Verilog-кода, а будем собирать схему из готовых IP-модулей.
В IP Integrator создаём новый блочный дизайн, добавляем в него IP и соединяем их, пока не получится вот такая схема:
![](https://habrastorage.org/files/1ce/7bb/b96/1ce7bbb9628047cca31aea2ac791ed09.png)
Здесь были использованы следующие IP:
Clocking wizard Модуль создания синхросигналов. Предназначен для создания синхросигналов (до 6 штук) с различной частотой и скважностью (в данном случае одного меандра 100MHz). На вход ему подаётся системный клок (125 MHz). Использует ресурс PLL, выходные синхросигналы распространяются через соответствующие ресурсы кристалла. Стандартный модуль Xilinx.
Binary Counter. Настраиваемый делитель, в данном случае 8-битный. Стандартный модуль Xilinx.
Slice. Делитель шины, в данном случае вытаскивает старший бит из Binary Counter, образуя таким образом делитель на 256. Стандартный модуль Xilinx.
Вообще с синхросигналом такие вещи делать нельзя, нужно брать ещё один выход из Clocking Wizard и корректно настраивать Clock Domain Crossing. Но в данном случае для работы SSD_pmod годится любая частота от сотни герц до сотен килогерц, не синхронизированная вообще ни с чем.
SSD_pmod. Модуль, выводящий байт в шестнадцатеричном виде на двухзначный семисегментный индикатор Digilent PMOD-SSD. Байт поступает на вход модуля. Исходный текст модуль выложен на GitHub.
PMOD_GPIO. Модуль, описывающий работу с сигналами в разъёмах PMOD. В зависимости от типа модуля, подключенного к разъёму, используются различные протоколы — GPIO, SPI, I2C, UART. Я взял за основу модуль написанный Digilent для поддержки своих PMOD, и слегка изменил его. Исходный текст модуль выложен на GitHub.
Модуль Constant. Это просто константа 0 или 1. Мы не используем в данном случае передачу в сторону клавиатуры, так что на входы send_command и the_command подан 0, а на вход reset подана 1 (в окончательном проекте у нас будет полноценная схема сброса).
Наконец PS2_controller, модуль, который мы создали на предыдущем шаге. Не забудьте указать путь к нему в свойствах проекта, чтобы его возможно было добавить.
У нас используются следующие внешние соединения:
sys_clock Синхросигнал 125MHz от внешнего генератора на плате (пин L16). Используется для запуска PLL.
PMOD_C К порту C подключена клавиатура, используются биты JC2 (W15) и JC4 (T10)
PMOD_D К порту D подключен семисегментный индикатор, используются все 8 бит.
Сохраняем блочный дизайн, генерируем враппер на Verilog (Generate HDL Wrapper...), компилируем проект (Generate Bitstream), заливаем его через JTAG в плату (Open Hardware Manager, Open Target, Program Device). Теперь при нажатии кнопок на клавиатуре их скан-коды будут выводиться на семисегментном индикаторе:
![](https://habrastorage.org/files/3f4/9dc/af9/3f49dcaf964e4416b024a87a3e896356.jpg)
8'h4E — это '-'
Ссылки
Для желающих попробовать всё это на железе, все исходники выложены на Github:
→ Враппер для работы с Git из Vivado
Кроме этого потребуется установить:
→ Описание интерфейсов и плат Digilent, в том числе Zybo
→ Раз и два — вспомогательные модули для вывода шестнадцатеричных чисел на семисегментный индикатор
→ Контроллер PS2-клавиатуры
→ Модуль в котором всё это соединяется вместе
Для установки модуля необходимо скачать его с Github и запустить .tcl файл, лежащий в корне, из под Vivado