Итак, портируем RISC-V систему SCR1 от компании Syntacore на плату Марсоход3. Я уже писал, почему я выбрал именно эту систему для изучения в предыдущей статье. Что нужно для запуска этой системы на нашу плату? Посмотрим, что там у них в исходниках на github: https://github.com/syntacore/scr1-sdk
В репозитории есть директории doc, fpga, images, scr1, sw. При этом, директория fpga и scr1 это субмодули git, указывающие на другие репозитории. Внутри папки sw так же есть два субмодуля это папки sc-bl и zephir. Ну что ж, приступим к работе!
Я сделал fork всех репозиториев и готовлюсь добавлять в них свои изменения, касающиеся нашей платы Марсоход3. Взять мой форк можно здесь https://github.com/marsohod4you/scr1-sdk
Выполните команды
> git clone https://github.com/marsohod4you/scr1-sdk
> cd scr1-sdk
> git submodule update --init --recursive
После этого у вас появятся все нужные исходники для работы с проектом.
Давайте еще раз внимательно посмотрим, что тут есть. Вообще, сразу видно, что изначально компания Syntacore подготовила SDK для использования на нескольких разных платах FPGA. Предлагаемые варианты плат это:
- Altera Arria-V Starter Kit,
- Digilent Arty Edition,
- Terasic DE10-Lite Edition,
- Digilent Nexys4DDR Edition.
К этим платам соответственно подготовлена документация в папке doc. К этим же платам есть готовые образы для загрузки в платы в папке image. В папке fpga есть исходники соответствующих FPGA проектов к каждой плате. Папка scr1 общая для всех проектов и содержит ядро RISC-V. Ну и остается папка sw в которой расположены исходники запускаемых программ: hello, tests, sc-bl, zephyr. Наиболее интересной здесь для меня является программа начальной загрузки, bootloader sc-bl. Она должна быть откомпилирована и её бинарный образ должен быть зашит в статическую память системы SCR1 для успешной инициализации и дальнейшей работы микропроцессора RISC-V при включении питания платы.
Первое, что я буду делать - создам свой проект Quartus Prime Lite в папке fpga/marsohod3. Я добавляю поддержку нашей платы в SDK. На самом деле будет очень разумно изначально скопировать к примеру проект для платы Terasic DE10-Lite Edition в мою папку. Почему я выбираю именно этот проект как прототип моего будущего проекта? Ответ прост: и плата DE10 и плата Марсоход3 имеют FPGA одного семейства Intel MAX10. Да, конечно, платы разные, но хоть в чем-то они да похожи, а именно семейством ПЛИС.
Можно попробовать сразу без изменений откомпилировать этот проект. Я попробовал с установленным у меня Intel Quartus Prime Lite v20.1. Попробовал и у меня не получилось - ошибки сборки. Оказывается, проект изначально выполнен в среде Quartus Prime Standard Edition v17.1. У меня стоит версия Lite версии 20.1 и, к сожалению, в новых версиях квартуса отсутствует поддержка контроллера микросхем SDRAM. Мы на нашем сайте принципиально делаем проекты к нашим FPGA платам Марсоход только в бесплатных версиях Quartus, чтобы большее число людей смогло познакомиться с технологией FPGA. Похоже, что версия Intel Quartus Prime Lite 17.1 была последней, которая содержит контроллер SDRAM, который можно запросто использовать в своих проектах. Я скачал версию Lite 17.1 и у меня теперь исходный проект для DE10 собирается без проблем, но да, квартус выдает предупреждение, что в следующих версиях квартуса бесплатной поддержки SDRAM не будет. Вот же вредители.
Теперь, когда прототип есть нужно попробовать его изменить под особенности платы Марсоход3. Первое, что я сделал, это переименовал все исходные файлы с de10lite_scr1.* в соответствующие файлы m3_scr1.*.
Дальше вручную редактируем файл настроек проекта m3_scr1.qsf (Quartus Settings File).
Задаем тип микросхемы FPGA, указываем, что на нашей плате Марсоход3 стоит ПЛИС 10M50SAE144C8, а так же указываем новое имя топ модуля:
set_global_assignment -name FAMILY "MAX 10"
set_global_assignment -name DEVICE 10M50SAE144C8G
set_global_assignment -name TOP_LEVEL_ENTITY "m3_scr1"
Аналогично переименовываем и файл de10lite_sopc.qsys в файл qsys/m3_sopc.qsys. В настройках проекта указываем новое имя для QSYS:
set_global_assignment -name QSYS_FILE qsys/m3_sopc.qsys
Следующее очень важное изменение - нужно исправить назначения выводов FPGA. В нашем чипе и выводов меньше и разведены на печатной плате эти выводы совсем подругому. Нужно найти все настройки set_location_assignment и удалить их. Вместо этих настроек нужно поставить свои. Их можно взять из любого другого марсоходовского проекта. Да хоть из этого https://github.com/marsohod4you/light-music из файла max10_50.qsf. Я перенес назначения сигналов из того проекта в этот. Ещё одно важное замечание. На плате DE10-Lite есть семисегментные индикаторы, светодиоды и переключатели. На плате Марсоход3 только светодиоды и две кнопочки. Чтобы как-то соответствовать я пожалуй установлю на плату Марсоход3 наш шилд семисегментного индикатора:
Теперь у меня и кнопок больше и четыре цифры индикатора есть. Что дальше?
Дальше редактируем Verilog файл модуля самого верхнего уровня m3_scr1.sv. В этом файле я заменяю все упоминания "de10lite_" на мои "m3_". Теперь модуль верхнего уровня называется m3_scr1, как и указано в файле настроек m3_src1.qsf.
В модуле верхнего уровня m2_scr1 я удаляю входы и выходы соответствующие семисегментным индикаторам HEX0-HEX5 и переключателям SW. Вместо них я поставлю выводы inout wire [15:0]IO, которые идут к контактам шилда платы Марсоход3.
На шилде есть 4 кнопочки, пусть это будут как будто переключатели SW платы. Я не исправляю весь модуль Verilog, SW как входы модуля я удалил, но определил эти сигналы заново как wire:
//use shield 4 buttons as Switchers
wire [9:0]SW; assign SW[9:4] = 0;
assign SW[3] = ~IO[11];
assign SW[2] = ~IO[10];
assign SW[1] = ~IO[ 9];
assign SW[0] = ~IO[ 8];
Младшие четыре SW[3:0] подключены к четырем кнопкам шилда семисегментного индикатора.
С семисегментными индикаторами чуть сложнее. В исходном проекте De10-Lite не экономят выводы к семисегментным индикаторам. Там чип FPGA в другом корпусе, используется BGA микросхема и из-за этого свободных выводов у них много. На каждый сегмент в индикаторе там просто идет один вывод FPGA. В случае с платой Марсоход3 шилд семисегментного индикатора использует динамическую адресацию сегментов с целью экономии выводов. Поэтому я в проект добавил еще один файл seg4x7.v, который содержит простой Verilog модуль
module seg4x7(
input wire clk, // 20MHZ
input wire [31:0] in,
output reg [3:0] digit_sel,
output reg [7:0] out
);
reg [19:0] cnt;
always @ (posedge clk)
cnt<= cnt +1'b1;
wire [1:0]digit_idx; assign digit_idx = cnt[17:16];
reg [31:0]in_fixed;
always @ (posedge clk)
begin
digit_sel<= 4'b0001 << digit_idx;
in_fixed<= in;
out<= in_fixed >> (digit_idx*8);
end
endmodule
Этот модуль принимает 32 бита для 4-х отображаемых цифр и выдает 4 селектора отображаемой цифры и восемь бит самой цифры. Вот и получается экономия выводов: вместо 32-х выводов при динамической индикации используется всего 12.
В модуле верхнего уровня m3_scr1 я устанавливаю экземпляр моего модуля seg4x7 и подключаю его сигналы к выходам IO:
// m3 board 7seg shield
wire [3:0]seg_digit_sel;
wire [7:0]seg_out;
seg4x7 seg4x7_instance(
.clk( cpu_clk ),
.in( { pio_hex_3_2, pio_hex_1_0 } ),
.digit_sel( seg_digit_sel ),
.out( seg_out )
);
assign { IO[15],IO[13],IO[12],IO[14] } = seg_digit_sel;
assign IO[7:0] = seg_out;
Еще очень важное изменение, которое нужно сделать касается тактовой частоты. На плате DE10-Lite стоит генератор 50МГц, а на плате Марсоход3 стоит 100МГц. Сигналы в исходном проекте имели имена osc_50_clk и MAX10_CLK2_50 и я их везде переименовал в osc_100_clk и в CLK100MHZ. Однако, просто переименование сигналов это только косметическое изменение. Конечно я не поднимаю тактовую частоту проекта в два раза. Мне нужно перенастроить сам PLL в проекте. Для этого в навигаторе проекта Quartus нужно выбрать вид отображения IP Components и кликнуть на m3_sops.
После клика на m3_sops откроется новое окно Platform Designer в котором настраивается взаимосвязь имеющихся в системе компонентов.Меня интересует компонент sys_pll. Нужно выбрать его и справа в окне Parameters нажать кнопку Edit Parameters.
Тут уже открывается обычное окно редактирования параметров PLL.
Была входная частота 50МГц, я поставил 100МГц. Но при этом выходная частота сигнала с0 у PLL была 50/5*2=20МГц. Теперь я умножитель ставлю равным единице и, таким образом, выходная частота остается такой же, как и раньше 20МГц. Два других выхода PLL сигналы c1 и c2 так же имели умножитель "2" и выходная частота у них получалась 100МГц. У мен же входная 100МГц, так что я просто ставлю умножитель в единицу и все. Свойства PLL я поменял, но по итогу выходные частоты остались такие же, как и были раньше. На процессоре будет 20МГц, на памяти SDRAM будет 100МГц.
Пожалуй основные изменения проекта сделаны, теперь можно компилировать и пробовать запускать в плате Марсоход3.
Обращаю внимание, что я в первый раз запускал проект в плате прямо с оригинальным загрузчиком, который использовался с платой DE10-Lite. Программа начального загрузчика скомпилирована и ее образ находится в файле ip/scbl.hex. Этот файл используется квартусом при компиляции проекта. Содержимое scbl.hex помещается в компонент onchip_ram системы. Это статическая память размером 64 килобайта. Загрузчик должен быть меньше этого объема. Настройки onchip_ram так же делаются в Platform Designer.
Для испытания проекта скомпилируйте его и загрузите в плату Марсоход3. На плате имеется встроенный программатор MBFTDI на базе двухканальной микросхемы FT2232H. Первый канал используется для программатора JTAG, а второй канал это просто последовательный порт который соединен с FPGA. Наш проект SCR1 имеет встроенный модуль последовательного порта UART. Через этот последовательный порт я могу подавать из консоли команды в начальный загрузчик. На компьютере нужно запустить терминал на последовательный порт, например, Putty или TeraTerm. Скорость связи 115200, 8 бит, 1 стоп, без четности.
На этом скриншоте показан программатор MBFTDI и терминал TeraTerm. По нажатию в терминале кнопки "i" начальный загрузчик системы SCR1 выводит начальную информацию о версии SOC, используемой RISC-V ISA RV32IMC (о! есть умножитель и поддержка сжатых команд?), а так же назначенные диапазоны памяти и других устройств ввода вывода. Пока используется загрузчик от проекта к de10lite, поэтому он отображает такое же имя платформы.
Должен сказать, что пока семисегментный индикатор отображает какую-то белиберду и видимо перепутаны биты в сегментах. Это можно починить как на аппаратном уровне перетасовав биты, как и на программном уровне исправив загрузчик.
Как раз моя следующая задача будет исправить загрузчик, научиться его компилировать и встроить в мой проект для платы Марсоход3.
Подробнее...