Вопросы создания системного или инструментального программного обеспечения для софт-ядер архитектуры RISC-V
Это основной оператор switch функции синтаксического анализа riscv_ip(), который обрабатывает различные операнды. Ориентировочное положение в файле - в районе строки с номером 2000.
match: полученное ранее значение MATCH
mask: аналогично для MASK
match_opcode: указатель на функцию, которую вы хотели бы использовать, чтобы "определить", какой код операции вы используете
pinfo: Используется для указания некоторого специального поведения. В основном используется с инструкциями перехода и сжатыми инструкциями RISC-V. Значение равно 0, если нет специального поведения.
Аналогично первых шагам процесса необходимо пересобрать RISC-V GNU/GCC Compiler Toolchain
Теперь можно использовать свои пользовательские инструкции в своих программах. Чтобы иметь возможность вызывать свои пользовательские инструкции, следует использовать ассемблерные вставки.
Наконец, инструкции RISC-V собираются в машинный код. Можно использовать obj-dump для проверки сгенерированных двоичных файлов RISC-V и проверить, где вызывается новая инструкция.
В общем - такой путь модификации инструментария не радует - 7 гигабайт трафика, около часа процессорного времени на перекомпиляцию за сомнительное удовольствие работать с ассемблерными вставками.
Конечно, на самом деле настроить компилятор языка высокого уровня на работу с "крафтовыми" командами достаточно комплексная задача, особенно если требуется оптимизированный код.
Open source ассемблеры
Ситуация с ассемблерами с открытым исходным кодом несколько проще, также как и в случае с gcc-risc-v имеются исходные тексты компиляторов. Случае с исходниками на Python разобраться с исходными текстами и правилами модификации исходной версии ассемблерного компилятора относительно не сложно.
Относительно простой переход к языкам высокого уровня в проектах FPGA с софт-процессорами возможен для языков с т.н. "виртуальными машинами" (ВМ) - наподобие упомянутого уже LISP, экзотического в современном мире Forth или Java. Связано это с тем, что реализуется на низком уровне ядро ВМ (возможно даже с учетом принятого в RISC-V ABI), а далее просто идет ее развитие в требуемом направлении.
Для относительно широкого применения, снижения "входного порога", а также для повторного использования кода и применения наработок кода, целесообразнее перейти на ЯВУ, отличный от Форта (отчасти это связано с суевериями и заблуждениями майн-стрим программистов относительно сложностей данного языка и читабельности его кода (к слову, один из авторов данной работы аналогичного мнения о С-подобных языках)).
Интересен вариант с адаптацией некоторого ограниченного подмножества языка Python к RISC-V. Python - высокоуровневый язык программирования общего назначения, ориентированный на повышение производительности разработчика и читаемости кода, поддерживающий несколько парадигм программирования, в том числе структурное, объектно-ориентированное, функциональное, императивное и аспектно-ориентированное, плюс - "его преподают даже в детском садике".
Некоторое время назад был анонсирован компилятор Uzh - небольшой компилятор для программного процессора FPGA Zmey. Uzh - это также статически скомпилированное подмножество Python, основывается на перспективном инструментарии raddsl (набор инструментов для быстрого создания прототипов DSL-компиляторов).
Компилятор Uzh принимает код на языке Python и формирует на выходе загрузочный поток для инициации памяти программ и памяти данных процессора (да, практически любой язык программирования можно использовать и в варианте интерпретатора, и в варианте компилятора с той или иной степенью комфорта), ключевым моментом является то, что на этапе компиляции доступен весь функционал языка.
Для установки компилятора Uzh достаточно скачать его архив и распаковать в любую удобную папку (лучше придерживаться общих рекомендаций для специализированного программного обеспечения - избегать путей, содержащих кириллицу и пробелы). Также необходимо скачать и распаковать в основную папку компилятора инструментарий raddsl.
Папка test компилятора содержит примеры программ для софт-процессора, папка src - исходные тексты элементов компилятора. Для удобства работы лучше создать небольшой командный файл (расширение .cmd) с содержимым: c.py C:\D\My_Docs\Documents\uzh-master\tests\abc.py , где abc.py - имя файла с программой для софт-процессора.
Для адаптации компилятора Uzh-а к конкретному процессору потребуются некоторые изменения в его исходном коде. К счастью, мест, подлежащих корректировке в компиляторе не много. Основные "аппаратно-зависимые" файлы:
- asm.py - ассемблер и формирование чисел (литералов);
- gen.py - низкоуровневые правила формирования кода (функции, переменные, переходы и условия);
- stream.py - формирование загрузочного потока;
- macro.py - макроопределения, по факту - расширения базового языка аппаратно-специфичными функциями.
Следующие изменения в компиляторе коснутся модуля asm.py в котором описывается система команд процессора (прописываются мнемоники команд и опкоды команд) и способ представления/компиляции числовых значений - литералов.
Команды упаковываются в словарь, а за литералы отвечает функция lit(). Если с системой команд все просто - просто меняется список мнемоник и соответствующих им опкодов, то с литералами дело обстоит немного иначе.
Основные и самые ответственные изменения/определения - в модуле gen.py. Данный модуль определяет основную логику работы/исполнения высокоуровневого кода на уровне ассемблера:
- условные и безусловные переходы;
- вызов функций и передача им аргументов;
- возврат из функций и возвращение результатов;
- подстройки под размеры памяти программ, памяти данных и стеков;
- последовательность действий при старте процессора.
Для поддержки ЯВУ процессор должен уметь достаточно произвольно работать с памятью и указателями и иметь область памяти для хранения локальных переменных функций - здесь вполне логично распределить функциональность регистров в соответствии с принятым в RISC-V ABI.
Теперь можно приступить к модификации кода модуля gen.py.
Переменные *_SIZE в комментариях не нуждаются и требуют только подстановки значений, заданных в проекте процессорного ядра.
Список STUB - временная заглушка для формирования места для адресов переходов с последующим их заполнением компилятором (текущие значения соответствуют 24-битному адресному пространству памяти кода).
Список STARTUP - задает последовательность действий, выполняемых ядром после сброса - будет задан начальный адрес памяти локальных переменных - 900, и переход на точку старта.
Функция func() прописывает действия, производимые при вызове функции, а именно - перенос аргументов функции в область локальных переменных, выделение памяти для собственных локальных переменных функции.
Epilog() определяет действия при возвращении из функции - освобождение памяти временных переменных, возврат на точку вызова.
Работа с переменными идет посредством их адресов, ключевое определение для этого - push_local(), возвращающее адрес "высокоуровневой" переменной.
Следующие ключевые моменты - это условный и безусловный переходы. И основное определение компилятора на низком уровне - набор правил для операций языка и работы с памятью.
Модуль macro.py позволяет несколько "расширить" словарь целевого языка за счет макроопределений на ассемблере целевого процессора. Для компилятора языка высокого уровня определения в macro.py не будут отличаться от "родных" операторов и функций языка.
Путь создания своего компилятора, несмотря на возможно чувствительный по времени цикл разработки, представляется перспективным. Плюсы - возможность быстрой и простой адаптации инструмента под текущий проект.
- http://github.com/riscv/riscv-gnu-toolchain
- Adding custom instructions compilation support, to RISCV toolchain. - http://medium.com/@viveksgt/adding-custom-instructions-compilation-support-to-riscv-toolchain-78ce1b6efcf4
- Adding Custom Instructions to the RISC-V GNU-GCC toolchain - http://hsandid.github.io/posts/risc-v-custom-instruction/
- GNU toolchain for RISC-V, including GCC - http://github.com/riscvcollab/riscv-gnu-toolchain
- http://github.com/celebi-pkg/riscv-assembler
- Lisp RISC-V Assembler - http://gitmemories.com/technoblogy/lisp-riscvassembler
- GitHub - true-grue_uzh_ Uzh compiler // http://github.com/true-grue/uzh
- GitHub - true-grue_raddsl_ Tools for rapid prototyping of DSL compilers // http://github.com/true-grue/raddsl
- http://sovietov.com/txt/dsl_python_conf.pdf

