Итак, для нашей системы на кристалле нужна программа, которая бы стартовала из bootrom. Естественно, нужно начинать с чего-то самого простого. В папке нашего проекта Amber есть такая программа sw/hello-world. Я так понимаю при включении процессора он должен выводить в консоль, в последовательный порт вот это сообщение “Hello, World!”.
Попробуем!
Я не стал вносить изменения в эту программу. Вместо этого я создал копию этой папки sw/hello-world-my и уже здесь буду делать изменения.
Собственно все изменения можно отслеживать в GitHub https://github.com/marsohod4you/Amber-Marsohod2 , где я работаю над проектом.
Компилировать программу очень легко. Компилятор Sourcery CodeBench у нас уже установлен. После запуска терминала в Linux нужно один раз набрать в консоли
source sw/init
чтобы установить нужные переменные окружения. Потом для компиляции:
make
После компиляции, если нет ошибок появляются много новых объектных и текстовых файлов *.o, *.elf, *.map, *.mem и другие. На самом деле меня интересует файл hello-world.mem в нем в текстовом виде описано содержимое памяти bootrom.
Выглядит этот файл как-то вот так:
// Section name .text
// Type SHT_PROGBITS, Size 0xddc, Start address 0x00000000, File offset 0x8000, boffset 0
// Section name .text.startup
// Type SHT_PROGBITS, Size 0x24, Start address 0x00000ddc, File offset 0x8ddc, boffset 0
// Section name .rodata.str1.4
// Type SHT_PROGBITS, Size 0x24, Start address 0x00000e00, File offset 0x8e00, boffset 0
// Section name .rodata.str1.1
// Type SHT_PROGBITS, Size 0x7, Start address 0x00000e24, File offset 0x8e24, boffset 0
// Section name .bss
// Type SHT_NOBITS, Size 0x4, Start address 0x00000e2b, File offset 0x8e2b, boffset 3
// .bss Dump Zeros
// Section name .ARM.attributes
// Type ???, Size 0x2b, Start address 0x00000000, File offset 0x8e2b, boffset 3
// Section name .shstrtab
// Type SHT_STRTAB, Size 0x62, Start address 0x00000000, File offset 0x8e56, boffset 2
// Section name .symtab
// Type SHT_SYMTAB, Size 0x3a0, Start address 0x00000000, File offset 0x9048, boffset 0
// Section name .strtab
// Type SHT_STRTAB, Size 0x167, Start address 0x00000000, File offset 0x93e8, boffset 0
@00000000 e3a00000
@00000004 e13ff000
@00000008 e3e00000
@0000000c ee030f10
@00000010 e3a00001
@00000014 ee020f10
@00000018 e59fd004
@0000001c eb00036e
@00000020 ea000110
Тут есть проблемка – такой файл нельзя использовать в проектах Altera Quartus II. В среде Quartus II в ПЛИС можно создавать блоки статической памяти и задавать начальное содержимое памяти с помощью так называемых Memory Initialization File, MIF.
Поэтому я написал маленькую утилитку для преобразования MEM файла в MIF файл. Она находится в проекте в папке sw/tools/mem2mif. Ее то же нужно сперва скомпилировать: зайдите в sw/tools и наберите make. Теперь, находясь в папке hello-world можно преобразовать полученный mem файл в mif файл командой в консоли
../tools/mem2mif hello-world.mem > hello-world.mif
Теперь расскажу о сделанных мною изменениях:
Первое. Почему-то, непонятно почему в файле sections.lds начальный адрес программы был установлен в 0x8000
ENTRY(main)
SECTIONS {
. = 0x008000;
.text : { start*(.text); *(.text); }
.data : { *(.data); }
Это очень странно, так как в комментарии выше написано в этом же section.lds:
// Description //
// Sections linker file for the hello-world application. //
// Note that the address map starts at 0x0 because this is //
// a stand-alone application, not using the boot-loader. //
// As such, it would need to be put into the FPGA during //
// synthesis.
Я честно сказать не знаю, что такое этот файл section.lds, но обратил сюда внимание потому, что при компиляции в файле mem начальные адреса с нуля по 0x8000 содержали нули. Ну не может такого быть. Дело в том, что память в ПЛИС это довольно ограниченный ресурс. Не могу подумать, чтобы она так расточительно использовалась. В общем поставил базовый адрес ноль. Чисто из здравого смысла.
Второе изменение, которое я сделал – в файле start.S перенес адрес указателя стека. У них в системе была память DDR, а у нас пока нет внешней памяти. Я поставил стек под верх памяти bootrom – 0х1FF0 там пока похоже есть немного пустого места.
Ну и третье изменение, которое я сделал – исправил само сообщение “Hello, World!” на “ “Marsohod2: Hello, World!” ну это так – косметическое исправление.
Теперь компилирую и преобразовываю в MIF файл:
make
../tools/mem2mif hello-world.mem > hello-world.mif
Получается файл hello-world.mif который нам нужно как-то подключить к bootrom проекта. Как это сделать?
Если в Altera Quartus II выполнить команду меню Processing => Start => Analisis & Elaboration, то после этого в Project Navigator можно посмотреть иерархию проекта. Там есть компонент bootmem и видно компоненты из которых он простроен.
Самый низкий в иерархии – sram_2048_32_byte_en:sram, он изображен с магической палочкой. Кликаем на него – открывается Wizard (которым я этот компонент и создавал в начале).
На странице 4 wizarda можно задать начальное содержимое памяти после включения ПЛИС. Там я задаю hello-world.mif.
Ну вот в общем, кажется все готово.
Компилирую проект. Запускаю программатор, еще запускаю программу терминала PUTTY и в ней открываю мой COM9, ожидая получить в консоли сообщение Marsohod2: Hello, World!
Загружаю проект в ПЛИС из программатора, и вот (там та-ра-рам!!!!) – ничего не происходит...
Ну, как бы так бывает. Что-то еще не учтено. Получается как в лучших детективных романах, пока только завязка сюжета
На самом деле есть еще ряд непонятных моментов. Например, я не знаю, на какой скорости передает Amber данные в COM-порт. Хотя вариантов не так и много – попробовав открывать порт с разной скоростью приема я все больше убеждаюсь, что проект не работает.
Буду чинить.
Подробнее...