В своей предыдущей статье я обещал, что расскажу, как скомпилировать загрузчик для системы Syntacore RISC-V Scr1 работающей в плате Марсоход3. У нас уже есть все исходники проекта взятые на github. У нас есть и само ядро RISC-V от Syntacore и FPGA обвязка к нему - мы её уже портировали на плату Марсоход3. Есть у нас и некоторые программы для scr1 и в том числе загрузчик. Загрузчик, или bootloader - это первое, что запускается при старте системы. Программная часть проекта scr1-sdk находится в директории sw. Тут есть поддиректории hello, sc-bl, tests, zephyr. Это разные программы, которые работают в scr1. Программа начального загрузчика находится в папке sw/sc-bl. Её и буду компилировать в первую очередь.
Собственно компиляция, как таковая, не должна быть проблемой. Этот процесс довольно просто описан в файле sw/sc-bl/README.md. Файл README.md рассказывает, как самостоятельно собрать компилятор RISC-V gcc в ОС Linux. Думаю сейчас это лишнее. Просто скачаем готовые бинарные файлы по указанной в документации ссылке http://syntacore.com/page/products/sw-tools и будем использовать их. Конечно, есть разница будете вы работать в ОС Linux или в ОС Windows.
В Linux всё немного проще. Скачиваем файл riscv-gcc-10.2.0-gb693c14--200904T1226.tar.gz,
создаем папку для компилятора, например, riscv-gcc, копируем туда скачанный файл и распаковываем его там:
>mkdir riscv-gcc
>cp riscv-gcc-10.2.0-gb693c14--200904T1226.tar.gz riscv-gcc
>cd riscv-gcc
>tar -xzf riscv-gcc-10.2.0-gb693c14--200904T1226.tar.gz
После этого, нужно экспортировать переменную окружения CROSS_PATH, чтобы она указывала на компилятор. Для этого в терминале выполним команду
>export CROSS_PATH=~/risc-gcc/riscv-gcc-10.2.0-gb693c14--200904T1226/bin
Теперь можно компилировать командой
>make PLATFORM=marsohod3_scr1
Проект загрузчика sc-bl написан сразу для нескольких разных плат. Загрузчик должен работать на разных FPGA платах. Специфические особенности каждой платы описаны в отдельных заголовочных файлах. Например, файл платформы для платы Arria V GX FPGA Starter Kit называется plf_a5_scr1.h, а файл платформы plf_de10lite_scr1.h это для FPGA платы Terasic De10Lite. Я добавил для нашей платы Марсоход3 свой собственный файл plf_marsohod3_scr1.h, созданный как раз по образу plf_de10lite_scr1.h. Когда запускаете компиляцию командой make передаете параметр PLATFORM, который как раз и указывает, для какой платы вы компилируете.
Я компилирую для платы Марсоход3 и вот что я вижу в результате компиляции:
nick@ubuntu:~/risc-v/scr1-sdk/sw/sc-bl$ make PLATFORM=marsohod3_scr1
mkdir -p build.marsohod3_scr1
CC src/scbl.c
CC common/uart.c
CC src/xmodem.c
CC src/init.c
CC src/trap.c
CC common/leds.c
AS src/startup.S
LD build.marsohod3_scr1/scbl.elf
/home/nick/risc-v/riscv-gcc-10.2.0-gb693c14--200904T1226/bin/riscv64-unknown-elf-gcc -march=rv32im -mabi=ilp32 -static -T common/scbl.ld -Xlinker -nostdlib -nostartfiles -ffast-math -Wl,--gc-sections -Wl,-Map=build.marsohod3_scr1/scbl.map -o build.marsohod3_scr1/scbl.elf build.marsohod3_scr1/scbl.o build.marsohod3_scr1/uart.o build.marsohod3_scr1/xmodem.o build.marsohod3_scr1/init.o build.marsohod3_scr1/trap.o build.marsohod3_scr1/leds.o build.marsohod3_scr1/startup.o -lgcc -lc
/home/nick/risc-v/riscv-gcc-10.2.0-gb693c14--200904T1226/bin/riscv64-unknown-elf-objdump -w -x -s -S build.marsohod3_scr1/scbl.elf > build.marsohod3_scr1/scbl.dump
/home/nick/risc-v/riscv-gcc-10.2.0-gb693c14--200904T1226/bin/riscv64-unknown-elf-objcopy -Obinary -S build.marsohod3_scr1/scbl.elf build.marsohod3_scr1/scbl.bin
echo "@00000000" > build.marsohod3_scr1/scbl.mem && hexdump -v -e '4/1 "%02x" "\n"' build.marsohod3_scr1/scbl.bin >> build.marsohod3_scr1/scbl.mem
./mk_altera_hex.sh build.marsohod3_scr1/scbl.bin build.marsohod3_scr1/scbl.hex
Кажется все прошло успешно. Итоговый скомпилированный файл загрузчика это build.marsohod3_scr1/scbl.bin. Однако, это двоичный файл. Он конвертируется в HEX файл build.marsohod3_scr1/scbl.hex, который подходит для САПР Intel Quartus Prime. Скопируем его в FPGA проект в папку ../../fpga/marsohod3/scr1/ip/scbl.hex
Когда я буду компилировать FPGA проект scr1 с помощью квартуса данные из этого файла будет загружены в статическую память компонента onchip_ram:
В среде САПР Intel Quartus Prime в окне Platform Designer среди компонентов разрабатываемой нами системы можно найти компонент onchip-ram и в его свойствах как раз указывается, что эта память будет не пустая, а будет содержать данные из файла scbl.hex.
При старте RISC-V процессор как раз будет брать команды из этой памяти и исполнять их. Так стартует начальный загрузчик.
Обычно проекты для FPGA компилируются не очень быстро. Не очень удобно после исправления и компиляции загрузчика еще и проект FPGA пересобирать. Однако, при замене файла scbl.hex не обязательно перекомпилировать весь FPGA проект. Можно поступить проще: можно просто заменить файл scbl.hex на новый, потом нужно выбрать в меню САПР Quartus пункт Processing -> Update Memory Initialization File, а затем запустить ассемблер через пункты меню Processing -> Start -> Start Assembler. После этого новая прошивка для FPGA уже будет содержать внутри и новвые данные памяти в onchip-ram..
Если вы работаете в ОС Windows, то компилировать загрузчик можно, но не так просто, как хотелось бы. В чем тут проблема? Дело в том, что нужен не просто компилятор gcc для RISC-V процессора. Готовый компилятор можно легко скачать по той же ссылке предоставленной компанией Syntacore. Кроме компилятора gcc потребуется еще утилита make и интерпретатор скриптов bash. На мой взгляд проще всего в Windows установить программу GitBash https://gitforwindows.org/ и использовать ее как среду/терминал для компиляции. GitBash это средство работы с исходными кодами и контроля версий ПО. Очень удобное средство, оно всё равно нужно при работе с git. Примечательно, что в консоли GitBash сразу можно использовать многие команды Linux: ls, rm, ldd, ssh и многие другие. Конечно GitBash может исполнять bash скрипты. Нужно заметить еще кое что о путях к файлам в GitBash. Традиционно Windows использует доступ к дискам по буквам c:\ или d:\ а так же символ обратной косой черты для разделения имен папок. Теперь же в консоли GitBash можно указывать пути в стиле Linux, например, вот так:
>export CROSS_PATH=/d/Programs/riscv/riscv-gcc-w64-10.2.0-gb693c14--200904T1226/bin/
Начало пути /d/ обозначает диск d:\
Остается сюда в GitBash добавить make. Здесь описано, как это можно сделать. Нужно скачать портированный для Windows make (это файл make-4.3-without-guile-w32-bin.zip) с сайта https://sourceforge.net/projects/ezwinports/files/. Потом нужно распаковать скачанный архив и скопировать его содержимое в папку c:\Program Files\Git\mingw64\. При копировании не перезаписывайте старые файлы, если таковые окажутся. После всех этих действий в консоли GitBash будет работать и утилита make. Запускаем её в консоли GitBash:
>make PLATFORM=marsohod3_scr1
Останется еще небольшая проблемка. Имеющийся Makefile создает не только HEX файл для FPGA проекта для САПР Intel Quartus, но и еще создает *.mem файл для САПР Xilinx ISE Design Suite. Для этого Makefile использует утилиту hexdump, которой нет в Windows и нет в GitBash. В нашем случае проще всего в Makefile закомментировать строку
#echo "@00000000" > $(@:.hex=.mem) && hexdump -v -e '4/1 "%02x" "\n"' $(@:.hex=.bin) >> $(@:.hex=.mem)
Я закомментировал и теперь могу без проблем компилировать загрузчик в Windows в терминале GitBash. Самый первый рисунок в этой статье как раз демонстрирует весь этот процесс компиляции.
Ну вот собственно с компиляцией разобрались.
А теперь самое главное. Я адаптирую имеющийся FPGA проект scr1-sdk/fpga/de10lite под мою плату marsohod3. Естественно платы отличаются, в итоге у меня будет немного другая система, другое количество светодиодов, кнопок, индикаторов, у меня другой объем памяти SDRAM на плате. Естественно программа загрузчика должна быть изменена соответствующим образом. Резонный вопрос: "что нужно изменить в программе загрузчика?".
В САПР Intel Quartus откройте FPGA проект scr1-sdk\fpga\marsohod3\scr1\m3_scr1.qpf. Дальше в окне Project Navigator выбирайте IP Components -> m3_sops.qsys. Откроется новое окно Platform Designer.
На вкладке Address Map указаны назначенные адреса для всех компонентов системы: UART, портов ввода-вывода PIO, адреса и размер onchip ram и прочее. Все эти значения должны совпадать с соответствующими значениями в заголовочном файле plf_marsohod3_scr1.h.
Например, в Platform Designer указан адрес компонента последовательного порта avl_uart.s0 как 0xff010000. В заголовочном файле plf_marsohod3_scr1.h указано
#define PLF_MMIO_BASE (0xff000000)
...
#define PLF_UART0_BASE (PLF_MMIO_BASE + 0x10000)
То есть указано все правильно. Таким образом, повторюсь, все реальные аппаратные ресурсы должны быть правильно объявлены в загрузчике, чтобы он смог обращаться к этим всем устройствам.
Вот теперь пожалуй всё.
Я назначил все ресурсы, скомпилировал загрузчик, файл его HEX образа поместил в FPGA проект и пересобрал проект FPGA. После загрузки ПЛИС я запускаю на моем ПК терминал и общаюсь с платой через последовательный порт:
По нажатию клавиши "i" в терминале появляется вся информация о системе и загрузчике. Обратите внимание, что имя платформы пишет marsohod3_scr1. То есть это теперь действительно мною скомпилированный bootloader.
Этот простой загрузчик позволяет в интерактивном режиме загружать и запускать другие программы через последовательный порт по протоколу xmodem. Как это сделать я расскажу и покажу в следующей статье.
Подробнее...