Проект | Четвертый SoC, написанный на VHDL |
---|---|
Автор | Ричард Джеймс Хоу |
Авторское право | 2013-2019 Ричард Хоу |
Лицензия | Массачусетский технологический институт/LGPL |
Электронная почта | [email protected] |
В этом проекте реализован небольшой компьютер с стеком, предназначенный для выполнения Forth на базе процессора J1. Процессор был переписан на VHDL от Verilog и немного расширен.
Цели проекта заключаются в следующем:
Все три из них завершены.
Процессор H2, как и J1, представляет собой процессор на основе стека, выполняющий набор команд, специально подходящий для FORTH.
Текущая цель — плата Nexys3 с FPGA Xilinx Spartan-6 XC6LX16-CS324. В будущем будут нацелены на новые платы, поскольку срок службы этой платы подходит к концу. VHDL написан в общем виде, при этом аппаратные компоненты выводятся, а не создаются явным образом. Это должно сделать код достаточно переносимым, хотя интерфейсы к компонентам платы Nexys3 специфичны для периферийных устройств на этой плате.
Видео проекта в действии на оборудовании можно посмотреть здесь:
SoC также можно смоделировать с помощью симулятора, написанного на C, как показано ниже:
Архитектура системы следующая:
Лицензии, используемые в проекте, смешанные и предоставляются по каждому файлу. Для своего кода я использую лицензию MIT — так что не стесняйтесь использовать ее по своему усмотрению. Другие используемые лицензии — это LGPL и лицензия Apache 2.0. Они ограничены отдельными модулями, поэтому их можно удалить, если у вас есть неприятие кода LGPL.
Единственная целевая плата, доступная на данный момент, — это Nexys3, в будущем ситуация должна измениться, поскольку срок службы платы в настоящее время подходит к концу. Следующие платы, которые я планирую поддерживать, — это их преемник Nexys 4 и myStorm BlackIce (https://mystorm.uk/). Плата myStorm использует набор инструментов с полностью открытым исходным кодом для синтеза, размещения и маршрутизации, а также создания битовых файлов.
Сборка была протестирована под Debian Linux версии 8.
Вам потребуется:
Аппаратное обеспечение:
Xilinx ISE можно (или можно) загрузить бесплатно, но требуется регистрация. ISE должен быть на вашем пути:
PATH=$PATH:/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64;
PATH=$PATH:/opt/Xilinx/14.7/ISE_DS/ISE/lib/lin64;
Чтобы создать набор инструментов на основе C:
make embed.hex
Чтобы создать битовый файл, который можно будет записать на целевую плату:
make simulation synthesis implementation bitfile
Чтобы загрузить битовый файл на целевую плату:
make upload
Чтобы просмотреть форму волны, созданную с помощью «make Simulation»:
make viewer
Симулятор CLI на основе C можно вызвать с помощью:
make run
Который соберет исходный файл H2 Forth embed.fth и запустит собранный объектный файл в симуляторе H2 с активированным отладчиком. Графический симулятор можно запустить с помощью:
make gui-run
Для этого требуется freeglut, а также компилятор C.
Исходный проект J1 доступен по адресу:
Этот проект ориентирован на исходное ядро J1 и предоставляет реализацию eForth (написанную с использованием Gforth для мета-компиляции/кросс-компиляции в ядро J1). Он также предоставляет симулятор системы, написанной на C.
Интерпретатор eForth, на котором построен метакомпилятор, можно найти по адресу:
Процессор H2 и связанные с ним периферийные устройства теперь достаточно стабильны, однако источник всегда является исчерпывающим руководством относительно того, как ведут себя инструкции и периферийные устройства, а также карта регистров.
Есть несколько модификаций процессора J1, в том числе:
ЦП H2 ведет себя очень похоже на ЦП J1, и можно прочитать PDF-файл J1, чтобы лучше понять этот процессор. Процессор 16-битный, инструкции выполняются за один такт. Большинство примитивных слов Форта также могут быть выполнены за один цикл, за одним заметным исключением является store ("!"), которое разделено на две инструкции.
Внутри процессора находится следующее состояние:
Загрузка и сохранение в блоке ОЗУ, в котором хранится программа H2, отбрасывает младший бит, каждая другая операция с памятью использует младший бит (например, переходы, загрузка и сохранение на периферийных устройствах ввода/вывода). Это сделано для того, чтобы приложения могли использовать младший бит для символьных операций при доступе к оперативной памяти программы.
Набор команд декодируется следующим образом:
+---------------------------------------------------------------+
| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------------+
| 1 | LITERAL VALUE |
+---------------------------------------------------------------+
| 0 | 0 | 0 | BRANCH TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 0 | 1 | CONDITIONAL BRANCH TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 1 | 0 | CALL TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 1 | 1 | ALU OPERATION |T2N|T2R|N2A|R2P| RSTACK| DSTACK|
+---------------------------------------------------------------+
| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------------+
T : Top of data stack
N : Next on data stack
PC : Program Counter
LITERAL VALUES : push a value onto the data stack
CONDITIONAL : BRANCHS pop and test the T
CALLS : PC+1 onto the return stack
T2N : Move T to N
T2R : Move T to top of return stack
N2A : STORE T to memory location addressed by N
R2P : Move top of return stack to PC
RSTACK and DSTACK are signed values (twos compliment) that are
the stack delta (the amount to increment or decrement the stack
by for their respective stacks: return and data)
Все операции ALU заменяют T:
Ценить | Операция | Описание |
---|---|---|
0 | Т | Вершина стека |
1 | Н | Скопировать Т в Н |
2 | Т + Н | Добавление |
3 | Т и Н | Побитовое И |
4 | Разорванный | Побитовое ИЛИ |
5 | Т ^ Н | Побитовое исключающее ИЛИ |
6 | ~Т | Побитовая инверсия |
7 | Т = Н | Тест на равенство |
8 | Н < Т | Знаковое сравнение |
9 | Н >> Т | Логический сдвиг вправо |
10 | Т - 1 | Декремент |
11 | Р | Верхняя часть стопки возврата |
12 | [Т] | Загрузить с адреса |
13 | Н << Т | Логический сдвиг влево |
14 | глубина | Глубина стека |
15 | N u< Т | Беззнаковое сравнение |
16 | Установить состояние процессора | Включить прерывания |
17 | Получить состояние процессора | Прерывания включены? |
18 | глубина | Глубина возврата стк |
19 | 0= | Т == 0? |
20 | Идентификатор процессора | Идентификатор ЦП |
21 | БУКВАЛЬНЫЙ | Внутренняя инструкция |
Регистры, помеченные префиксом «o», являются выходными регистрами, а регистры с префиксом «i» — входными регистрами. Регистры разделены на входную и выходную часть регистров и адреса входных и выходных регистров не во всех случаях соответствуют друг другу.
Следующие периферийные устройства были реализованы в SoC VHDL для взаимодействия с устройствами на плате Nexys3:
SoC также имеет ограниченный набор прерываний, которые можно включить или отключить.
Карта выходного регистра:
Зарегистрироваться | Адрес | Описание |
---|---|---|
УАРТ | 0x4000 | Регистр UART |
оВТ100 | 0x4002 | Терминал VT100, запись |
oСветодиоды | 0x4004 | Светодиодные выходы |
oTimerCtrl | 0x4006 | Управление таймером |
oMemDout | 0x4008 | Вывод данных из памяти |
oMemControl | 0x400A | Управление памятью / Привет адрес |
oMemAddrLow | 0x400C | Адрес памяти Lo |
o7SegLED | 0x400E | 4 светодиодных 7-сегментного дисплея |
oIrcMask | 0x4010 | Маска прерывания ЦП |
oUartBaudTx | 0x4012 | Настройка частоты передачи UART Tx |
oUartBaudRx | 0x4014 | Настройка частоты передачи данных UART Rx |
Входные регистры:
Зарегистрироваться | Адрес | Описание |
---|---|---|
iUart | 0x4000 | Регистр UART |
iVT100 | 0x4002 | Статус терминала и клавиатура PS/2 |
iSwitches | 0x4004 | Кнопки и переключатели |
iTimerDin | 0x4006 | Текущее значение таймера |
iMemDin | 0x4008 | Ввод данных в память |
Следующее описание регистров следует читать по порядку, а также описывать работу периферийных устройств.
В SoC присутствует UART с фиксированной скоростью передачи данных и форматом (115200, 8 бит, 1 стоповый бит). UART имеет FIFO глубины 8 как на каналах RX, так и на каналах TX. Управление UART разделено между oUart и iUart.
Чтобы записать значение в UART, активируйте TXWE вместе с помещением данных в TXDO. Состояние FIFO можно проанализировать, просмотрев регистр iUart.
Чтобы прочитать значение из UART: можно проверить iUart, чтобы увидеть, присутствуют ли данные в FIFO; если в регистре oUart установлено значение RXRE, в следующем такте данные будут присутствовать в регистре iUart.
Скорость передачи UART можно изменить путем перестройки проекта VHDL, длину в битах, биты четности и стоповые биты можно изменить только путем внесения изменений в uart.vhd.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X |TXWE| X | X |RXRE| X | X | TXDO |
+-------------------------------------------------------------------------------+
TXWE: UART TX Write Enable
RXRE: UART RX Read Enable
TXDO: UART TX Data Output
Устройство VGA Text эмулирует терминал, с которым пользователь может общаться, записывая в регистр oVT100. Он поддерживает часть функций терминала VT100. Интерфейс ведет себя так же, как запись в UART с теми же сигналами занятости и управления. Ввод осуществляется с клавиатуры PS/2, имеющейся на плате, она ведет себя как механизм RX UART.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X |TXWE| X | X |RXRE| X | X | TXDO |
+-------------------------------------------------------------------------------+
TXWE: VT100 TX Write Enable
RXRE: UART RX Read Enable
TXDO: UART TX Data Output
На плате Nexys3 имеется группа светодиодов, расположенных рядом с переключателями, эти светодиоды можно включать (1) или выключать (0) путем записи в LEDO. Каждый светодиод здесь соответствует переключателю, рядом с которым он находится.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X | X | X | X | X | X | LEDO |
+-------------------------------------------------------------------------------+
LEDO: LED Output
Таймер управляется регистром oTimerCtrl, это 13-битный таймер, работающий на частоте 100 МГц, он может дополнительно генерировать прерывания, а текущий внутренний счетчик таймера может быть считан обратно с помощью регистра iTimerDin.
Таймер отсчитывает время, когда установлен бит TE, как только таймер достигает значения TCMP, он перерабатывается и может дополнительно генерировать прерывание, установив INTE. Это также переключает линии Q и NQ, которые выходят из таймера и направляются на контакты на плате (контакты см. в файле ограничений top.ucf).
Таймер можно сбросить, записав в RST.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| TE | RST|INTE| TCMP |
+-------------------------------------------------------------------------------+
TE: Timer Enable
RST: Timer Reset
INTE: Interrupt Enable
TCMP: Timer Compare Value
Ядро H2 имеет механизм прерываний, прерывания необходимо включать или отключать с помощью инструкции. Каждое прерывание можно замаскировать с помощью бита в IMSK, чтобы разрешить это конкретное прерывание. «1» в бите IMSK разрешает это конкретное прерывание, которое будет доставлено в ЦП, если внутри него разрешены прерывания.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X | X | X | X | X | X | IMSK |
+-------------------------------------------------------------------------------+
IMSK: Interrupt Mask
Этот регистр используется для установки скорости передачи данных и тактовой частоты выборки только для передачи.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| BTXC |
+-------------------------------------------------------------------------------+
BTXC: Baud Clock Settings
Этот регистр используется для установки скорости передачи данных и тактовой частоты выборки только для приема.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| BRXC |
+-------------------------------------------------------------------------------+
BRXC: Baud Clock Settings
Данные, которые будут выводиться на выбранный адрес, когда разрешение записи (WE) выдается в oMemControl.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| Data Ouput |
+-------------------------------------------------------------------------------+
Этот регистр содержит регистры управления встроенной памятью платы Nexys3. Плата содержит три устройства памяти, два устройства энергонезависимой памяти и энергозависимое устройство на базе оперативной памяти. Оба устройства, доступные через простой интерфейс SRAM (одно энергозависимое M45W8MW16, одно энергонезависимое - NP8P128A13T1760E), оба доступны, третье - это устройство памяти на основе SPI, NP5Q128A13ESFC0E) и в настоящее время недоступно.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| OE | WE | RST|WAIT| RCS| FCS| Address Hi |
+-------------------------------------------------------------------------------+
OE: Output Enable - enable reading from current address into iMemDin
WE: Write Enable - enable writing oMemDout into ram at current address
RST: Reset the Flash memory controller
RCS: RAM Chip Select, Enable Volatile Memory
FCS: Flash Chip Select, Enable Non-Volatile Memory
Address Hi: High Bits of RAM address
OE и WE являются взаимоисключающими, если установлены оба, эффекта нет.
Контроллер памяти находится в активной разработке, и интерфейс к нему может измениться.
Это младшие биты адреса ОЗУ.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| Address Lo |
+-------------------------------------------------------------------------------+
На плате Nexys3 имеется блок 7-сегментных дисплеев с десятичной точкой (на самом деле 8-сегментный), которые можно использовать для числового вывода. Сегменты светодиодов не могут быть адресованы напрямую. Вместо этого значение, хранящееся в L8SD, сопоставляется с шестнадцатеричным отображаемым значением (или значением BCD, но для этого требуется регенерация SoC и модификация универсального значения в VHDL).
Значение «0» соответствует нулю, отображаемому на сегменте светодиода, «15» — «F» и т. д.
Есть 4 дисплея подряд.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| L7SD0 | L7SD1 | L7SD2 | L7SD3 |
+-------------------------------------------------------------------------------+
L7SD0: LED 7 Segment Display (leftmost display)
L7SD1: LED 7 Segment Display
L7SD2: LED 7 Segment Display
L7SD3: LED 7 Segment Display (right most display)
Регистр iUart работает совместно с регистром oUart. Статус FIFO, который буферизует как передачу, так и прием байтов, доступен в регистре iUart, а также любых полученных байтах.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X |TFFL|TFEM| X |RFFL|RFEM| RXDI |
+-------------------------------------------------------------------------------+
TFFL: UART TX FIFO Full
TFEM: UART TX FIFO Empty
RFFL: UART RX FIFO Full
RFEM: UART RX FIFO Empty
RXDI: UART RX Data Input
Регистр iVT100 работает совместно с регистром oVT100. Состояние FIFO, который буферизует как передачу, так и прием байтов, доступно в регистре iVT100, а также любых полученных байтах. Он работает так же, как регистры iUart/oUart.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X |TFFL|TFEM| X |RFFL|RFEM| 0 | ACHR |
+-------------------------------------------------------------------------------+
TFFL: VGA VT100 TX FIFO Full
TFEM: VGA VT100 TX FIFO Empty
RFFL: PS2 VT100 RX FIFO Full
RFEM: PS2 VT100 RX FIFO Empty
ACHR: New character available on PS2 Keyboard
Этот регистр содержит текущее значение счетчика таймеров.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X | TCNT |
+-------------------------------------------------------------------------------+
TCNT: Timer Counter Value
iSwitches содержит входные строки из нескольких источников. Кнопки (BUP, BDWN, BLFT, BRGH и BCNT) соответствуют D-Pad на плате Nexys3. Переключатели (TSWI) — это те, которые упомянуты в oLeds, рядом с каждым из них есть светодиод.
Переключатели и кнопки уже аппаратно устранены, поэтому их не нужно обрабатывать после чтения из этих регистров.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| X | X | X | BUP|BDWN|BLFT|BRGH|BCNT| TSWI |
+-------------------------------------------------------------------------------+
BUP: Button Up
BDWN: Button Down
BLFT: Button Left
BRGH: Button Right
BCNT: Button Center
TSWI: Two Position Switches
Входные данные памяти, либо из SRAM, либо из флэш-памяти, индексируются oMemControl и oMemAddrLow. При чтении из флэш-памяти это может быть информация о состоянии или информация из таблицы запросов.
+-------------------------------------------------------------------------------+
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-------------------------------------------------------------------------------+
| Data Input |
+-------------------------------------------------------------------------------+
Определены следующие процедуры обслуживания прерываний:
Имя | Число | Описание |
---|---|---|
isrNone | 0 | Не используется |
isrRxFifoNotEmpty | 1 | FIFO UART RX не пуст |
isrRxFifoFull | 2 | UART RX FIFI заполнен |
isrTxFifoNotEmpty | 3 | FIFO UART TX не пуст |
isrTxFifoFull | 4 | FIFO UART TX заполнен |
isrKbdНовый | 5 | Новый клавиатурный персонаж PS/2 |
isrTimer | 6 | Таймер Счетчик |
isrDPadButton | 7 | Изменение состояния любой кнопки D-Pad |
Когда происходит прерывание и внутри процессора разрешены прерывания, то выполняется вызов ячейки памяти — это место совпадает с номером ISR. Например, ISR с номером «4» выполнит вызов (а не переход) к ячейке «4» в памяти.
Прерывания имеют задержку не менее 4-5 циклов, прежде чем они будут обработаны, в обработчике запроса на прерывание существует задержка в два-три цикла, затем необходимо выполнить вызов местоположения ISR в памяти, затем вызов слово, которое реализует сам ISR.
Если одновременно происходят два прерывания, они обрабатываются от наименьшего номера прерывания к наибольшему.
Прерывания теряются, когда происходит прерывание с тем же номером, которое не было обработано.
Симулятор на основе дизассемблера и C для H2 находится в одной программе (см. h2.c). Этот симулятор дополняет испытательный стенд VHDL tb.vhd и не является его заменой. Метакомпилятор работает поверх интерпретатора eForth и содержится в файлах embed.c и embed.blk. Метакомпилятор (на языке Форта кросс-компилятор) — это программа на Форте, которая используется для создания образа eForth, который запускается на целевой системе.
Инструментальная цепочка в настоящее время находится в процессе изменения, и в дальнейшем возможно усиление интеграции между h2.c и embed.c, а также изменение виртуальной машины для встраивания на ту, которая больше похожа на процессор H2, с долгосрочной целью создания самостоятельного хостинга. система.
Для сборки обоих необходим компилятор C, цель сборки «h2» будет собирать исполняемый файл, h2, а «embed» — метакомпилятор:
make h2 embed
И его можно запустить в исходном файле embed.fth с помощью цели make:
make run
Файл make не нужен:
Linux:
cc -std=c99 h2.c -o h2 # To build the h2 executable
cc -std=c99 embed.c -o embed # To build the embed VM executable
./embed embed.blk embed.hex embed.fth # Create the target eForth image
./h2 -h # For a list of options
./h2 -r embed.hex # Run the assembled file
Windows:
gcc -std=c99 h2.c -o h2.exe # Builds the h2.exe executable
gcc -std=c99 embed.c -o embed.exe # Builds the embed.exe executable
embed.exe embed.blk embed.hex embed.fth # Create the target eForth iamge
h2.exe -h # For a list of options
h2.exe -r embed.hex # Run the assembled file
Список доступных параметров командной строки:
- stop processing options, following arguments are files
-h print a help message and exit
-v increase logging level
-d disassemble input files (default)
-D full disassembly of input files
-T Enter debug mode when running simulation
-r run hex file
-L # load symbol file
-s # number of steps to run simulation (0 = forever)
-n # specify NVRAM block file (default is nvram.blk)
file* file to process
Эта программа выпущена под лицензией MIT, не стесняйтесь использовать ее и модифицировать по своему усмотрению. С минимальными изменениями он сможет собирать программы для исходного ядра J1.
Метакомпилятор работает поверх встроенной виртуальной машины. Это 16-разрядная виртуальная машина, которая изначально произошла от процессора H2. Проект включает в себя схему метакомпиляции, которая позволяет образу eForth генерировать новый образ eForth с изменениями. Эта система была адаптирована для использования с H2, который заменил кросс-компилятор, написанный на C, что позволило создать первый образ для H2.
Метакомпилятор — это обычная Forth-программа, она содержится в embed.fth. Затем программа метакомпилятора Forth используется для создания образа eForth, способного работать на цели H2.
Для получения дополнительной информации о метакомпиляции в Форте см.:
Дизассемблер принимает текстовый файл, содержащий собранную программу, состоящий из 16-битных шестнадцатеричных чисел. Затем он пытается дизассемблировать инструкции. Ему также можно передать файл символов, который может быть сгенерирован ассемблером, и попытаться найти местоположения, на которые указывают переходы и вызовы.
Дизассемблер используется сценарием tcl, называемым GTKwave, он превращает трассировку инструкций H2 из ряда чисел в инструкции и места назначения ветвления, которые они представляют. Это значительно упрощает отладку VHDL.
Фиолетовый след показывает дизассемблированные инструкции.
Симулятор на C реализует ядро H2 и большую часть SoC. Ввод-вывод для симулятора не является точным по циклам, но может использоваться для запуска и отладки программ с результатами, очень похожими на поведение оборудования. Это намного быстрее, чем восстановление битового файла, используемого для прошивки FPGA.
Симулятор также включает в себя отладчик, аналогичный программе DEBUG.COM, доступной в DOS. Отладчик можно использовать для разборки разделов памяти, проверки состояния периферии и вывода разделов памяти на экран. Его также можно использовать для установки точек останова, одношагового выполнения и выполнения кода до тех пор, пока не будет достигнута точка останова.
Для запуска отладчика необходимо указать шестнадцатеричный файл или исходный файл:
# -T turns debugging mode on
./h2 -T -r file.hex # Run simulator
Оба режима работы могут быть дополнены файлом символов, в котором указано, где расположены переменные, метки и функции собранного ядра.
Если указана опция «-T», режим отладки будет введен до выполнения моделирования. Должно появиться приглашение, и командная строка должна выглядеть следующим образом:
$ ./h2 -T -R h2.fth
Debugger running, type 'h' for a list of command
debug>
Точки останова могут быть установлены либо символически, либо по местоположению программы, для установки точек останова используется команда «b»:
Числа можно вводить в восьмеричном формате (префикс «0»), шестнадцатеричном (префикс «0x») или десятичном. Например, следующие три команды отладки устанавливают точку останова в одном и том же месте:
debug> b 16
debug> b 0x10
debug> b 020
'k' можно использовать для вывода списка текущих установленных точек останова:
debug> k
0x0010
Это устанавливает точку останова, когда функция «key?» называется:
debug> b key?
Функции и метки могут быть остановлены, для этого необходимо либо указать файл символов в командной строке, либо выполнить ассемблирование и запуск для использования в исходном файле, а не в шестнадцатеричном файле. Файлы символов можно использовать в исходных или шестнадцатеричных файлах.
Для одного шага можно ввести команду «s», хотя ничего особенного не произойдет, если трассировка отключена (отслеживание отключено по умолчанию). Трассировку можно включить или выключить с помощью команды «t»:
debug> s
debug> s
debug> t
trace on
debug> s
0001: pc(089a) inst(4889) sp(0) rp(0) tos(0000) r(0000) call 889 init
debug> s
0002: pc(0889) inst(807a) sp(0) rp(1) tos(0000) r(089b) 7a
debug> s
0003: pc(088a) inst(e004) sp(1) rp(1) tos(007a) r(089b) 6004
Рекомендуется отключить трассировку при запуске команды «c» или продолжения.
'.' Команда может использоваться для отображения внутреннего состояния ядер H2:
debug> .
Return Stack:
0000: 0000 08aa 0883 017b 0000 031b 0000 ffb0 0000 02eb ffb5 0210 0167 0167
0167 0167
0010: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000
Variable Stack:
tos: 0000
0001: 0000 0000 0000 0001 0004 0005 0000 ffb0 0000 0000 0000 0000 0000 0000
0000 0000
0011: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000
pc: 0538
rp: 0001
dp: 0000
ie: false
А команду «p» можно использовать для отображения состояния моделируемой периферии:
debug> p
LEDS: 00
VGA Cursor: 0005
VGA Control: 007a
Timer Control: 8032
Timer: 001b
IRC Mask: 0000
UART Input: 6c
LED 7seg: 0005
Switches: 00
LFSR: 40ba
Waiting: false
Для получения полного списка команд используйте команду «h».
Другие способы войти в режим отладки включают в себя вставку директивы ассемблера «.break» в исходный код (это работает только в том случае, если команда сборки и запуска используется в исходных файлах, а не в шестнадцатеричных файлах) и нажатие escape-символа при запуске симулятора. попытка чтения данных через имитируемую клавиатуру UART или PS/2 (экранирование все равно будет передано в симулятор, но при этом также активируется режим отладки).
Можно скомпилировать отдельную программу, протестировать под Linux и Windows. Это имитирует периферийные устройства платы Nexys3, с которыми взаимодействует SoC, но обеспечивает графическую среду, в отличие от утилиты командной строки. С устройством проще взаимодействовать и видеть, что оно делает, но сеансы отладки менее контролируемы. Это требует свободного перенасыщения.
Ниже приведено изображение работающего сеанса в симуляторе с графическим интерфейсом:
Строительство может быть выполнено с помощью
make gui
И работает:
make gui-run
Или:
./gui h2.hex (on Linux)
gui.exe h2.hex (on Windows)
Сборка Linux должна работать, когда в вашей системе установлен пакет разработки для свободного перенасыщения, сборка Windows может потребовать изменений в системе сборки и/или ручной установки компилятора, библиотек и заголовков.
Текущая карта ключей:
Up Activate Up D-Pad Button, Release turns off
Down Activate Down D-Pad Button, Release turns off
Left Activate Left D-Pad Button, Release turns off
Right Activate Right D-Pad Button, Release turns off
F1 - F8 Toggle Switch On/Off, F1 is left most, F8 Right Most
F11 Toggle UART/PS2 Keyboard Input
F12 Toggle Debugging Information
Escape Quit simulator
Все остальные клавиши клавиатуры перенаправляются на вход клавиатуры UART или PS/2.
Кнопки переключателей и D-Pad можно включать, нажимая на них, переключатели включаются при щелчке левой кнопкой мыши и выключаются при щелчке правой кнопкой мыши. Кнопки D-Pad включаются при нажатии на них и выключаются при отпускании клавиши в любом месте экрана.
Компоненты VHDL, используемые в этой системе, предназначены для многократного использования и переноса между различными инструментальными цепочками и поставщиками. Аппаратные компоненты, такие как блочная ОЗУ, подразумеваются, а не создаются явным образом. Компоненты также сделаны максимально универсальными, причем большинство из них имеют выбираемую ширину. Это было бы доведено до крайности, но, к сожалению, многие поставщики до сих пор не поддерживают стандарт VHDL-2008.
Файл | Лицензия | Автор | Описание |
---|---|---|---|
util.vhd | Массачусетский технологический институт | Ричард Джей Хау | Коллекция универсальных компонентов |
h2.vhd | Массачусетский технологический институт | Ричард Джей Хау | H2 Форт-ядро ЦП |
uart.vhd | Массачусетский технологический институт | Ричард Джей Хау | UART TX/RX (настраиваемое время выполнения) |
vga.vhd | LGPL 3.0 | Хавьер V Гарсия | Текстовый режим Дисплей VGA 80x40 |
Ричард Джей Хау | (и эмулятор терминала VT100) | ||
kbd.vhd | ??? | Скотт Ларсон | Клавиатура PS/2 |
Псевдо-Форт-подобный язык, используемый в качестве ассемблера, описан выше, приложение, которое фактически работает на ядре Форта, само по себе является интерпретатором Форта. В этом разделе описывается интерпретатор Forth, работающий на H2 Core. Он содержится в embed.fth.
ЗАДАЧА:
В этом проекте используется несколько языков, каждый из которых радикально отличается друг от друга и требует собственного набора стандартов кодирования и руководств по стилю.
Общие названия сигналов:
clk - The system clock
rst - A reset signal for the module
we - Write Enable
re - Read Enable
di - Data In
din - Data In
do - Data Out
dout - Data Out
control - Generally an input to a register, the documentation
for the module will need to be consulted to find out
what each bit means
signal_we - The write enable for 'signal'
signal_i - This is an input signal
signal_o - This is an output signal
Обычно суффиксы «_i» и «_o» не используются, модули делаются короткими, а имена выбираются так, чтобы их значение было очевидным. К этому правилу можно будет вернуться, когда проект вырастет.
Компоненты должны:
constant N: positive := 4;
signal a: std_logic_vector(N - 1 downto 0) := (others => '1');
Вместо:
signal a: std_logic_vector(3 downto 0) := x"F";
Правила стиля следующие:
Пример рекомендаций по форматированию. Здесь описывается простой регистр произвольной ширины:
-- Lots of comments about what the unit does should go
-- here. Describe the waveforms, states and use ASCII
-- art where possible.
library ieee, work;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- numeric_std not std_logic_arith
entity reg is -- generic and port indented one tab, their parameters two
generic (
N: positive); -- Generic parameters make for a generic component
port (
clk: in std_logic; -- standard signal names
rst: in std_logic; --
we: in std_logic;
di: in std_logic_vector(N - 1 downto 0);
do: out std_logic_vector(N - 1 downto 0)); -- note the position of ");
end entity; -- "end entity", not "end reg"
architecture rtl of reg is
signal r_c, r_n: std_logic_vector(N - 1 downto 0) := (others => '0');
begin
do <= r_c;
process(rst, clk)
begin
if rst = '1' then -- asynchronous reset
r_c <= (others => '0');
elsif rising_edge(clk) then -- rising edge, not "clk'event and clk = '1'"
r_c <= r_n;
end if;
end process;
process(r_c, di, we)
begin
r_n <= r_c;
if we = '1' then
r_n <= di;
end if;
end process;
end; -- "end" or "end architecture"
В этом проекте используется довольно много кода C, используемого для создания цепочки инструментов для ядра H2 и моделирования системы.
В приведенном здесь коде C нет ничего удивительного, поэтому с некоторыми исключениями следует разобраться.
static const char *alu_op_to_string(uint16_t instruction) {
/* notice also that the 'case' clauses are inline with the
* switch selector */
switch (ALU_OP(instruction)) {
case ALU_OP_T: return "T";
case ALU_OP_N: return "N";
case ALU_OP_T_PLUS_N: return "T+N";
case ALU_OP_T_AND_N: return "T&N";
case ALU_OP_T_OR_N: return "T|N";
case ALU_OP_T_XOR_N: return "T^N";
case ALU_OP_T_INVERT: return "~T";
case ALU_OP_T_EQUAL_N: return "N=T";
case ALU_OP_N_LESS_T: return "T>N";
case ALU_OP_N_RSHIFT_T: return "N>>T";
case ALU_OP_T_DECREMENT: return "T-1";
case ALU_OP_R: return "R";
case ALU_OP_T_LOAD: return "[T]";
case ALU_OP_N_LSHIFT_T: return "N<N";
case ALU_OP_ENABLE_INTERRUPTS: return "seti";
case ALU_OP_INTERRUPTS_ENABLED: return "iset?";
case ALU_OP_RDEPTH: return "rdepth";
case ALU_OP_T_EQUAL_0: return "0=";
case ALU_OP_CPU_ID: return "cpu-id";
default: return "unknown";
}
}
if (foo)
bar();
else
baz();
picocom --omap delbs -b 115200 -e b /dev/ttyUSB1