Недавно я занимался портированием системы Syntacore RISC-V на плату Марсоход3. В принципе, это было не очень трудно, так как на этой плате используется емкий FPGA чип MAX10 с 50ю тысячами логических элементов. А можно ли запустить хоть какой-то RISC-V на более слабом FPGA чипе? Попробую плату Марсоход3bis. На этой плате, как и на плате Марсоход3, стоит Intel MAX10, но здесь всего 8 тысяч логических элементов. На плате Марсоход3bis стоит микросхема FPGA 10M08SAE144C8. Так получится или нет?
Напомню, что мой RISC-V проект https://github.com/marsohod4you/scr1-sdk это форк проекта Syntacore.
В папке-субмодуле scr1-sdk\fpga\ расположены Quartus Prime проекты для конкретных FPGA плат. Я сюда добавил ранее marsohod3 и теперь добавил marsohod3bis. Эти проекты отличаются не очень сильно, но отличия конечно есть.
Главный файл конфигурации ядра это файл scr1-sdk\scr1\src\includes\scr1_arch_description.svh
Но в нем есть такие строки:
`ifdef SCR1_ARCH_CUSTOM
`include "scr1_arch_custom.svh"
`endif // SCR1_ARCH_CUSTOM
То есть получается, что ядро может быть сконфигурировано несколькими разными способами и это может определяться пользовательским конфигурационным файлом.
Это "может" в свою очередь определяется Verilog макросом SCR1_ARCH_CUSTOM в файле scr1-sdk\fpga\marsohod3bis\scr1\m3_scr1.qsf
set_global_assignment -name VERILOG_MACRO "SCR1_ARCH_CUSTOM=1"
Пользовательский конфигурационный файл ядра процессора находится в папке scr1-sdk\fpga\marsohod3bis\scr1\ip\. Здесь есть файл scr1_arch_custom.svh, в котором определены многие важные параметры системы.
Здесь есть вот такое определение
// Uncomment to select recommended core architecture configurations
// Default SCR1 FPGA SDK created for RV32IMC_MAX config
//`define SCR1_CFG_RV32IMC_MAX
//`define SCR1_CFG_RV32IC_BASE
`define SCR1_CFG_RV32EC_MIN
Я закомментировал значение SCR1_CFG_RV32IMC_MAX и раскомментировал значение SCR1_CFG_RV32EC_MIN. Ядро процессора станет более компактным. Почему? Ну, во-первых, в процессоре не будет аппаратного целочисленного умножителя и делителя. Во-вторых, длина конвейера (pipeline) будет всего 2 стадии, а могла бы быть 3 или 4 стадии для RV32IC_BASE и RV32IMC_MAX соответственно. Конечно, при этом процессор станет медленнее. Но такова цена компактности.
К сожалению, в чипе 10M08SAE144C8 меньше не только логических элементов, но и встроенных блоков памяти.
В исходном проекте RISC-V системы основные потребители встроенной памяти это OnChip RAM и Tightly Coupled Memory. Оба этих блока занимают по 64 килобайта памяти, что конечно очень много.
Tightly Coupled Memory (TCM) это память непосредственно встроенная в ядро scr1. Она очень близка к исполнительным блокам процессора, поэтому очень быстрая. Я нашел, что размер этой памяти можно менять изменяя параметр концигурации
parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TCM_ADDR_MASK = 'hFFFFC000; // TCM mask and size
в файле scr1_arch_custom.svh
Параметр был SCR1_TCM_ADDR_MASK = 'hFFFF0000, а теперь стал SCR1_TCM_ADDR_MASK = 'hFFFFC000;
Таким образом, я уменьшил количество адресов TCM на 2 бита, то есть размер памяти TCM уменьшил в 4 раза, и стало 16 килобайт.
Всё равно, расход памяти всё еще большой. Где ещё можно сэкономить?
Второй значительны блок памяти - это OnChip RAM. Этот блок находится внутри m3_sops qsys проекта Quartus Prime.
Изменять параметры системы можно с помощью инструмента Quartus Platform Designer (меню Tools -> Platform Designer).
Честно говоря я не большой любитель таких средств. На мой взгляд это примерно так же плохо, как рисовать схемы в графическом редакторе.
В общем, размер этой памяти определяется здесь в Platform Designer. Я здесь так же ставлю 16 килобайт памяти и располагаться они будут по адресам 0xFFFFC000-0xFFFFFFFF, в самом верху всего адресного пространства процессора. Обратите внимание, что в этой памяти содержится программа загрузчик в виде scbl.hex файла.
Есть некоторые опасения, что программа загрузчик может не поместиться в этот размер 16К. Но посмотрим.
Попробуем скомпилировать наш FPGA проект под чип 10M08.
После компиляции видно, что занято всего 6,907 / 8,064 ( 86 % ) логических элементов и 263,424 / 387,072 ( 68 % ) битов встроенной памяти. Мне кажется это совсем не плохо. Еще и место осталось для других компонентов системы, если кто-то решит что-то свое добавить в проект.
Следущий этап моей эпопеи - скомпилировать загрузчик для этой системы. Оригинальный загрузчик не подойдет, так как у этого варианта RISC-V процессора нет умножителей/делителей. Компилировать нужно заново с учетом изменившейся архитектуры. Кроме того, базовый адрес памяти загрузчика изменился и изменился размер памяти OnChip RAM. Можно ли что-то с этим сделать? Без нового загрузчика и пробовать не получится.
Исходный код загрузчика для системы RISC-V находится в папке scr1-sdk/sw/sc-bl.
Мне пришлось внести некоторые изменения. Я добавил новую платформу plf_marsohod3bis_scr1.h, которая описывает ресурсы платы Марсоход3bis. Кроме этого, мне пришлось создать новый файл для линковщика scr1-sdk\sw\sc-bl\common\scbl16.ld в котором описано местоположение загрузчика в адресном пространстве и размер этой памяти:
RAM (rwx) : ORIGIN = 0-16K, LENGTH = 16K
И еще одно важное изменение - я уменьшил размер стека до 4х килобайт:
STACK_SIZE = 4K;
Надеюсь хватит?
Подробно о компиляции программ для RISC-V я писал в другой статье. Здесь же всё примерно так же с небобольшими отличиями.
Компилирую загрузчик вот такими командами:
>export CROSS_PATH=/d/Programs/riscv/riscv-gcc-w64-10.2.0-gb693c14--200904T1226/bin
>FLAGS_MARCH=rv32ec FLAGS_MABI=ilp32e LDSCRIPT=scbl16.ld make PLATFORM=marsohod3bis_scr1
Получаю файл scr1-sdk/sw/sc-bl/build.marsohod3bis_scr1/scbl.hex и копирую его в проект FPGA в папку scr1-sdk\fpga\marsohod3bis\scr1\ip\
Компилирую проект в квартусе с получившимся новым bootloader. Теперь загружаю прошивку в FPGA платы Марсоход3bis и подключаюсь к плате через последовательный порт. По нажатию клавиши i в консоли последовательного порта я вижу вот такую надпись от bootloader:
Значит процессор RISC-V работает в плате Марсоход3bis!
Это кстати еще видно по мигающим светодиодам и по цифрам отображаемым на подключенном к плате семисегментном индикаторе.
PS: есть еще один нюанс с назначением сигналов на плате Марсоход3bis.
Прежде всего, хочу сказать, что проект RISC-V будет работать в платах Марсоход3 и Марсоход3bis даже без микросхемы SDRAM на плате. Загрузчик стартует из OnChip RAM, если нужно загрузить программу на исполнение через последовательный порт по протоколу xmodem - её можно загрузить в TCM память. Без SDRAM в некоторых случаях можно обойтись, но и иногда она нужна.
К сожалению, на этой плате Марсоход3bis оказался баг связанный с SDRAM на плате. Баг стал проявляться начиная с версий Quartus Prime Lite старше v15.1
Один из сигналов идущих к микросхеме SDRAM на плате (DRAM_DQ[15], PIN_27) оказался рядом со входом тактовой частоты ПЛИС (PIN_26). По каким-то неведомым нам причинам, квартус v15.1 не считал это проблемой, а более старшие версии квартуса теперь считают это проблемой и не компилируют проект. Самое простое решение - это не использовать пин 27 вообще, а вместо него допаять на плату проводок с зарезервированного вывода PIN_114 платы Марсоход3bis на вход микросхемы памяти SDRAM. Вот так:
Я это решение попробовал - оно работает.
Подробнее...