RISC-V компьютер
RISC-V компьютер

Введение

Основным инструментом “Школы дизайна цифровых схем” является недорогая отладочная плата 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)


  1. Pyhesty
    00.00.0000 00:00
    +4

    Коллеги, несколько ремарок, которые, имеет смысл посмотреть:

    1. Оформите архитектуру процессора и его шины в виде схемы, очень сложно вникать с текста.

    2. Шину ОЗУ все же имеет смысл сразу размещать в общем 32битном пространстве шины AHB.

    3. Шину переферии в общем адресном пространстве и выбрать какой-то стандарт типа APB (обычный синхронный интерфейс с сигналами wr, rd).

      Таким образом сильно все упростится) И да,раз уж 86РК, то нужно не забыть трехканальный звукогенератор ВИ53 ;)

    мне нравится такая архитектура RISC-V процессора, а уже вокруг в ПЛИС строим переферию (типа внешнего ОЗУ, ПЗУ, видео, звук)
    мне нравится такая архитектура RISC-V процессора, а уже вокруг в ПЛИС строим переферию (типа внешнего ОЗУ, ПЗУ, видео, звук)


    1. MainBelia
      00.00.0000 00:00
      +1

      Чем обусловлено такое странное число максимальных подключений SPI, I2C, UART и таймеров в данной архитектуре? Ожидаемо такие вещи ограничиваются степенью двойки, а здесь три. Четвёртый вариант задействован как-то внутренне или это просто прихоть авторов?


      1. Pyhesty
        00.00.0000 00:00

        у Китая число 3 считается счастливым ;)


    1. tormozedison
      00.00.0000 00:00

      В ПЛИС может хватить места не для одного, а для нескольких ВИ53, можно сделать как в RMIF TI-3, только по стереоканалам их раскидать: некоторые - в один, некоторые - в другой, а некоторые - в оба одновременно, гулять так гулять. Не исключено, что Game Boy классический переплюнет.


  1. tormozedison
    00.00.0000 00:00

    Весьма!


  1. DanilinS
    00.00.0000 00:00
    +1

    Если все делать "по феншую" - имеет смысл и процессор k580wm80a на железе синтезировать. Со всеми остальными чипами. В 6К элементов уложится с большим запасом.

    Я сейчас доделываю свой вариант Радио-86РК. Плата: 20K GOWIN GW2A FPGA GoAI Core Board, отображение - HDMI выход, клавиатура - USB. Внешнее хранилище - MicroSD карта. Естественно МОНИТОР правленный.


    1. tormozedison
      00.00.0000 00:00

      Здесь машина не "Радио-86РК-подобная", а "уровня Радио-86РК", т.е., несовместимая, но со схожим объёмом ОЗУ.


    1. Pyhesty
      00.00.0000 00:00

      интересно ;)

      попробуйте запустить мое демо для Апогея (клон РК86) ;) если будет нужно, дам исходик, подправим различие в адресации)


  1. XanderBass
    00.00.0000 00:00

    Вот любопытно, каков был бы в наше время размер у микросхемы, в точности повторяющей схему "Радио-86РК"? Что-то подсказывает, что не больше microSD-карточки вместе с корпусом учитывая разводку. Вон 486-й же в своё время впихнули в форм-фактор рисового зёрнышка.


    1. DanilinS
      00.00.0000 00:00

      Ориентировочно все уложится в чип 5*5 мм. И это размер корпуса. Все остальное - внешняя развязка.


      1. nafikovr
        00.00.0000 00:00

        думаю корпус упрется в количество ног


        1. 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 ногами общего назначения.

          Думаю и у других производителей есть аналогичные чипы.


          1. nafikovr
            00.00.0000 00:00

            ну вот, при реализации полноценной платы "Радио-86РК" 87 ног это уже как минимум на грани (не факт что хватит на самом деле), так как только на порт расширения уйдет больше 50.


            1. DanilinS
              00.00.0000 00:00

              Да. 50 - порт расширения. Хотя кому если честно он в полном объёме нужен? Можно вывести только матрицу клавиатуры. + видеовыход, аудио выход и вход, 3 (?) светодиода, динамик. Это примерно 10-15-20 ног. Итого 70 ног максимум.

              Но лично у меня мнение, что повторять схему нужно без фанатизма. Например зачем ненужные линии внешнего разьема расширения и аудио-интерфейс магнитофона?

              И потому сейчас оттягиваюсь понемногу, создаю копию Р-86РК. Из особенностей - все 100 реализовано на verilog. 100% совместимость по регистрам железа. Но магнитофонного выхода и входа нет. Добавлена SD карта ( корректно имплантирована в свободное адресное пространство). Клавиатура - USB, светодиоды отрабатывают логику родных светодиодов РК. Разумеется имитировалась работа матрицы клавиатуры для корректной работы программ, которые решат самостоятельно опрашивать клавиши.