Введение
Основным инструментом “Школы дизайна цифровых схем” является недорогая отладочная плата OMDAZZ c ПЛИС CycloneIV EP4CE6E22C8N. Эта ПЛИС содержит всего 6000 логических элементов и 270 КБит RAM. Такая ограниченность в ресурсах и сформировала требования к параметрам проекта: 16 КБайт ОЗУ и текстовый графический адаптер. Идея проекта навеяна похожими параметрами радиолюбительского компьютера “Радио-86РК” опубликованного в начале 80-х годов прошлого века в журнале “Радио”. Этот компьютер был достаточно распространен, а по ресурсам как-раз соответствует возможностям нашей версии платы, что позволило предполагать, что в результате можно будет запустить нечто более сложное чем “Hello world”. Используемая отладочная плата была уже представлена в статьях Юрия Панчула. Информация и примеры использования платы доступны на GitHub.
Для работы с проектом необходим установленный Intel Quartus последней версии. Заливка проекта происходит при помощи скриптов Plus/boards/omdazz.
$ ./01_clean.bash - Очиста проекта
$ ./05_synthesize_for_fpga.bash - Синтез в Quartus и заливка проекта в FPGA
$ ./06_configure_fpga.bash - Заливка проекта в FPGA
$ ./07_upload_soft_to_fpga.bash - Загрузка программы через последовательный порт
Аппаратное обеспечение
Центральный процессор
Основой проекта является RISC-V процессор YRV опубликованный в книге одного из разработчиков процессоров семейства Z80 Монте Далримпла “Inside an Open-Source Processor” и адаптированный для ПЛИС Altera Юрием Панчулом. YRV - это ядро микроконтроллерного класса, в нем отсутствует кэш, виртуальная память, внеочередное выполнения инструкций, но есть статический конвейер с шестью стадиями и байпасами. В тоже время ядро поддерживает не только стандарт RV32I, но и двухбайтовые команды стандарта RV32C, и стандарт на атомарные операции. Особенностью процессора является возможность использования узкой шины данных (16 бит), что позволяет эффективно использовать процессор с реальными микросхемами памяти. Все это делает данное ядро интересным с точки зрения получения реального опыта применения микроконтроллерных RISC-V ядер. Адаптированная Юрием Панчулом версия YRV-Plus для ПЛИС Cyclone IV находится в репозитории . Эта версия ядра поддерживает тактовую частоту 50МГц.
Шина данных и порты
В качестве внешней шины использует подмножество шины AHB-Lite, основное различие заключается в том, что AHB-Lite поддерживает пакетную передачу и передачу более 32 бит, что в данном проекте не используется. Процессор использует сильно связанный интерфейс шины, так как это гарантирует предсказуемое время выполнения инструкций, что является важным фактором для микроконтроллеров, а также упрощает дизайн. Жесткая связь означает, что когда на внешней шине появляется состояние ожидания, то весь конвейер останавливается. И хотя в RISC-V Instruction Set Manual утверждается, что для embedded приложений необходим меньший регистровый файл, ширина шины данных часто является гораздо более определяющим фактором. Проект включает в себя опцию для 16-битной шины данных.
Проект поддерживает 7 memory-mapped 16-битных портов, один из которых используются для работы с модулем последовательного порта.
Видеоадаптер
Первоначально планировалось использовать QVGA адаптер подобно VGA mode 13h для IBM PC. Этот вариант хорошо работает на плате DE0-CV (любезно предоставленной FPGA-Systems), но из-за небольшого количества ресурсов в проекте пришлось ограничится монохромным текстовым видеоадаптером в режиме 640х480 с размером знака 8x8. Управление лучом производится модулем из состава лабораторных работ DDVCA проходивших в Бишкеке в 2022 году. За основу шрифта взят шрифт ZX-Spectrum. Создание шрифта производилось в программе 8x8 Pixel ROM Font Editor.
Char_065 db 0x7C, 0x82, 0x82, 0xFE, 0x82, 0x82, 0x82, 0x00 ; (A)
Char_066 db 0xFC, 0x82, 0x82, 0xFC, 0x82, 0x82, 0xFC, 0x00 ; (B)
Программа позволяет экспортировать шрифт в ассемблерный файл с операторами db, представляющими символы в шестнадцатеричном виде, который затем конвертируется при помощи любого текстового редактора в HEX файл для дальнейшей загрузки в ПЛИС при помощи функции $readmemh.
reg [7:0] char[0:2047];
initial $readmemh("char.mem8", char);
Это позволяет создавать любые свои символы в случае необходимости. Так как плата OMDAZZ не содержит ЦАП для VGA, то используется черно-белый режим, который может быть без труда доработан для любой двухцветной комбинации.
Клавиатура
В проекте используется PS/2 клавиатура, которая взаимодействует через модуль ps2scan из штатных примеров платы OMDAZZ с небольшой доработкой.
Модуль в составе проекта возвращает не последнее нажатое значение, а текущую нажатую клавишу, что позволяет более просто реализовать функцию getchar(). Взаимодействие осуществляется через порт микроконтроллера.
Модуль возвращает только ASCII код латинских прописных символов. Также, через порт port5_in подключается счетчик, который работает и как таймер и как генератор случайных чисел..
Внешняя память
Традиционно, для загрузки программ в домашних компьютерах использовался магнитофон, и для загрузки программы было необходимо выполнить определенные действия: найти кассету, при помощи счетчика отмотать на нужное место и после нажатия определенных клавиш запустить проигрывание на магнитофоне.
$ ./07_upload_soft_to_fpga.bash
В данном проекте используется сходная идея, но загрузка осуществляется через последовательный порт при помощи скрипта. Загрузка производится в оперативную память, при помощи модулей разработанных Юрием Панчулом. Формат загружаемых программ соответствует HEX формату используемому в функции $readmemh. В отличие от функции $readmemh, в данном методе загрузка происходит через шину AHB-Lite, что позволяет загружать программы не только в BRAM ПЛИС, но и в ОЗУ основанное на реальных микросхемах.
ОЗУ
Базовое ОЗУ проекта основано на узком регистровом файле, и в отличии от [31:0] mem[...] который предлагается в Харрис и Харрис, используется регистровый файл вида [7:0] mem[...]. Как было сказано выше, ядро разработано для использования узкой 16 битной шины данных (и без большого труда может быть доработано для использования 8 битной шины данных). Узкая шина позволяет взаимодействовать с реальными микросхемами памяти, с шиной 8 и 16 бит. Одной из задач проекта является проверка возможности работы с внешним SRAM ОЗУ, скорость доступа которым составляет 55-70нс, поэтому тактовая частота ядра уменьшена до 12 МГц.
Процессор YRV
Поддерживаемые стандарты
Базовый набор инструкций RV32I
Инструкции стандарта RV32C (кроме c.mul, опционально)
Атомарные операции с памятью RV32A: amoadd.w, aamoand.w, amoor.w, amoswap.w and amoxor.w
Операции с несогласованной атомарной памятью (Zam)
Операции манипуляции с битами ( Zbb, Zbs , Zbkb) , кроме clz, cpop, ctz, max, maxu, min, minu and orc.b zip and unzip
Расширение для счетчиков и таймеров ( Zicntr, опционально)
Расширение для CSR (включая внешний интерфейс)
Инструкция, обеспечивающие явную синхронизацию операций чтения и записи в память (Zifencei)
Независимое от внешних данных время выполнения (Zkt)
Интерфейс отладки Sdext
Прерывания, CSR, отладка
Ядро поддерживает четыре типа прерываний: внешние, немаскируемое, программное и таймерное. Кроме того, поддерживаются шестнадцать пользовательских локальных прерываний. Немаскируемое прерывание имеет наибольший приоритет, за которым следуют локальные прерывания, а затем внешние прерывания. Шестнадцать локальных прерываний с меньшим номером, имеющим более высокий приоритет.
Внешний интерфейс CSR аналогичен сигналам и протоколу APB. Все обращения к регистрам отображаются на шине.
Ядро YRV не включает модуль отладки, но включает основные функции, необходимые для поддержки модуля отладки реализующим стандарт.
Программное обеспечение
Toolchain
В проекте используется стандартный компилятор GCC версии 12.1.0 и выше. Для удобства используется готовый toolchain для NEORV32 RISC-V Processor. Так как процессор поддерживает различные виды прерываний и стартовая точка размещена по адресу 0x200, то набор стартовых подпрограмм crt0 формируется из нескольких ассемблерных файлов которые линкуются при помощи ld скрипта. Настройки компилятора и алгоритм создания ld скрипта аналогичен скриптам процессоров Cortex-M, поэтому все учебные материалы по данной тематики для процессоров ARM будут актуальны и для процессора YRV. Так же актуальны и материалы для процессоров SiFive. Преобразование бинарного файла в HEX для дальнейшей загрузки в оперативную память осуществляется при помощи утилиты elf2hex компании SiFive.
Целочисленная математика
Код для целочисленной математики: деления и умножения взяты из стандартного исходного кода для GCC для Lattice Mico32, так как эта реализация сделана на языке С. Исходный код для целочисленной математики находится в директории static каждого из проектов.
Стандартная библиотека
Набор необходимых C функций таких как strlen был сформирован опытным путем во время портирования теста CoreMark для более раннего проекта. Из-за ограничений памяти и нацеленности проекта на изучение языка ассемблера RISC-V, для сборки не используются стандартные библиотеки типа newlib и picolib, функции добавляются по мере необходимости. Для вывода на экран используется функция ee_printf(..) из состава CoreMark, для чтения клавиатуры getchar().
Изначально планировался QVGA режим 320х240 аналогичный int 13h, поэтому видеопамять размещена по адресу 0xA0000000. Функция вывода символа на экран выглядит следующим образом:
static char *VGA=(char *)0xA0000000L;
void putc(int x, int y, char c) {
VGA[80*x + y] = c;
}
Динамическое управление памятью
На данный момент динамическое распределение памяти и реализации функций malloc и free в проекте отсутствуют.
Взаимодействие с портами
Имена портов определены в заголовочном файле memory_mapped_registers.h. Необходимо помнить, что тип переменной char, short или int определяет какая процессорная инструкция lb, lh или lw будет использоваться.
#define IO_PORT54_ADDR 0xFFFF0008
#define port4 (* (volatile unsigned short*) IO_PORT54_ADDR )
....
char getchar() {
return (char) port4;
}
Будьте внимательны, при использовании типа int вы можете неявно передавать 0 в соседний порт, так как компилятор будет использовать функцию lw, а не lh.
Заключение
Так как ресурсы платы достаточно малы по сравнению с платами типа DE10, то исходный код проекта был перенесен на GitHub в отдельный репозиторий.
Полученный результат конечно не может сравниться с контроллерами от SiFive, но будет вполне достаточным для тех, кто дошел до 8 главы Харрис и Харрис и хочет поморгать светодиодами на RISC-V. Изначально проект предназначался как платформа изучения ассемблера, а портирование тулчейна - всего лишь доказательство того, что процессор работоспособен. Но по иронии судьбы, в репозитории я разместил математику реализованную на C, не смотря на то, что в проектах есть реализация на ассемблере RV32C.
Автор выражает благодарность @YuriPanchul, а также огромную благодарность @KeisN13 , за все его добрые дела, без которых этот проект не состоялся бы.
Комментарии (14)
DanilinS
00.00.0000 00:00+1Если все делать "по феншую" - имеет смысл и процессор k580wm80a на железе синтезировать. Со всеми остальными чипами. В 6К элементов уложится с большим запасом.
Я сейчас доделываю свой вариант Радио-86РК. Плата: 20K GOWIN GW2A FPGA GoAI Core Board, отображение - HDMI выход, клавиатура - USB. Внешнее хранилище - MicroSD карта. Естественно МОНИТОР правленный.
tormozedison
00.00.0000 00:00Здесь машина не "Радио-86РК-подобная", а "уровня Радио-86РК", т.е., несовместимая, но со схожим объёмом ОЗУ.
Pyhesty
00.00.0000 00:00интересно ;)
попробуйте запустить мое демо для Апогея (клон РК86) ;) если будет нужно, дам исходик, подправим различие в адресации)
XanderBass
00.00.0000 00:00Вот любопытно, каков был бы в наше время размер у микросхемы, в точности повторяющей схему "Радио-86РК"? Что-то подсказывает, что не больше microSD-карточки вместе с корпусом учитывая разводку. Вон 486-й же в своё время впихнули в форм-фактор рисового зёрнышка.
DanilinS
00.00.0000 00:00Ориентировочно все уложится в чип 5*5 мм. И это размер корпуса. Все остальное - внешняя развязка.
nafikovr
00.00.0000 00:00думаю корпус упрется в количество ног
DanilinS
00.00.0000 00:00Нет. Можно много ног напихать и очень плотно. Смотри :
Чип GOWIN GW1NR-9 (отладка https://aliexpress.ru/item/1005004275570427.html), на борту 9К логики и куча памяти. Размер чипа 10*10 мм. 70 ног для пользователя. А если брать в корпусе MG100P - размер 5*5 мм и 87 ног общего назначения.
А в этой линейки есть и чипы в корпусе MG49 с размерами 3.8*3.8 мм. правда для 2К чипов и 30 ногами общего назначения.
Думаю и у других производителей есть аналогичные чипы.
nafikovr
00.00.0000 00:00ну вот, при реализации полноценной платы "Радио-86РК" 87 ног это уже как минимум на грани (не факт что хватит на самом деле), так как только на порт расширения уйдет больше 50.
DanilinS
00.00.0000 00:00Да. 50 - порт расширения. Хотя кому если честно он в полном объёме нужен? Можно вывести только матрицу клавиатуры. + видеовыход, аудио выход и вход, 3 (?) светодиода, динамик. Это примерно 10-15-20 ног. Итого 70 ног максимум.
Но лично у меня мнение, что повторять схему нужно без фанатизма. Например зачем ненужные линии внешнего разьема расширения и аудио-интерфейс магнитофона?
И потому сейчас оттягиваюсь понемногу, создаю копию Р-86РК. Из особенностей - все 100 реализовано на verilog. 100% совместимость по регистрам железа. Но магнитофонного выхода и входа нет. Добавлена SD карта ( корректно имплантирована в свободное адресное пространство). Клавиатура - USB, светодиоды отрабатывают логику родных светодиодов РК. Разумеется имитировалась работа матрицы клавиатуры для корректной работы программ, которые решат самостоятельно опрашивать клавиши.
Pyhesty
Коллеги, несколько ремарок, которые, имеет смысл посмотреть:
Оформите архитектуру процессора и его шины в виде схемы, очень сложно вникать с текста.
Шину ОЗУ все же имеет смысл сразу размещать в общем 32битном пространстве шины AHB.
Шину переферии в общем адресном пространстве и выбрать какой-то стандарт типа APB (обычный синхронный интерфейс с сигналами wr, rd).
Таким образом сильно все упростится) И да,раз уж 86РК, то нужно не забыть трехканальный звукогенератор ВИ53 ;)
MainBelia
Чем обусловлено такое странное число максимальных подключений SPI, I2C, UART и таймеров в данной архитектуре? Ожидаемо такие вещи ограничиваются степенью двойки, а здесь три. Четвёртый вариант задействован как-то внутренне или это просто прихоть авторов?
Pyhesty
у Китая число 3 считается счастливым ;)
tormozedison
В ПЛИС может хватить места не для одного, а для нескольких ВИ53, можно сделать как в RMIF TI-3, только по стереоканалам их раскидать: некоторые - в один, некоторые - в другой, а некоторые - в оба одновременно, гулять так гулять. Не исключено, что Game Boy классический переплюнет.