- PVSM.RU - https://www.pvsm.ru -
Томными зимними вечерами, когда солнце лениво пробегало сквозь пелену дней — я нашел в себе силы заняться реализацией давней мечты: разобраться как же устроены процессоры. Эта мечта привела меня к написанию формально спецификации RISC-V процессора. Проект на Github [1]

Подобное желание у меня появилось достаточно давно, когда 20 лет назад я стал заниматься первыми своими проектами. По большей части это были научные исследования, математическое моделирование в рамках курсовых работ и научных статей. Это были времена Pascal и Delphi. Однако уже тогда мой интерес привлек Haskell и функциональное программирование. Прошло время, менялись языки проектов и технологии в которые я был вовлечен. Но с тех пор красной нитью проходил интерес к функциональным языкам программирования, и ими стали: Haskell, Idris, Agda. Однако в последнее время мои проекты были на языке Rust. Более глубокое изучение его меня привело к изучение Embedded устройств.
Возможности Rust настолько широки, а community настолько активно, что Embedded разработка стала поддерживать широкий спектр устройств. И это был мой первый шаг в более низкоуровневое понимание процессоров.
Первой моей платой стало: STM32F407VET6. Это было погружение в мир микроконтроллеров, от которого я на тот момент был очень далек, и достаточно приблизительно понимал как происходит работа на низком уровне.
Постепенно сюда добавились платы esp32, ATmega328 (в лице платы Ukraino UNO [2]). Погружение в stm32 оказалось достаточно болезненным — информация достаточно обильная и часто не та, которая мне нужна. И оказалось, что разработка, к примеру, на Assembler — достаточно рутинная и неблагодарная задача, с их подмножеством более 1000 инструкций. Однако Rust с этим справлялся бодро, хотя порой возникали трудности с интеграцией для конкретных китайских плат.
Архитектура AVR оказалась заметно проще и прозрачнее. Обильные мануалы мне дали достаточное понимание как работать с таким достаточно ограниченным набором инструкций, и тем не менее иметь возможность создавать очень интересные решения. Тем не менее путь Arduino меня совсем не радовал, но вот написание на Asm/C/Rust оказалось куда увлекательнее.
И в этот момент возникает логичный вопрос — а где же RISC-V CPU?
Именно минималистичность AVR и достаточная его документирование, меня вернуло к прежней мечте разобраться как же работает процессор. К этому времени у меня появилась FPGA плата и первые реализации для нее в виде взаимодействия с VGA устройствами, вывода графики, взаимодействия с периферией.
Моими проводниками в архитектуру процессоров стали книги:
Казалось бы — уже все давно написано и реализовано.
разнообразные реализации на HDL, и языках программирония. Кстати достаточно интересная реализация RISC-V на Rust [5].
Однако что может быть интереснее, чем разобраться самому, и создать свое. Свой велосипед? Или внести свой вклад в велосипеда-строение? Кроме личного глубокого интереса у меня возникла идея — а как попробовать популяризировать, заинтересовать. И найти свою форму, свой подход. А это значит представить достаточно скучную документацию по RISC-V ISA в виде официальной спецификации [6] в ином виде. И мне кажется путь формализации в этом смысле достаточно интересен.
Что я понимаю под формализацией? Достаточно обширное понятие. Представление определенного набора данных в формальном виде. В данном случае через описание структур и функционального описания. И в этом смысле функциональные языки программирования обладают своим очарованием. Также задача в том — чтобы человек который не сильно погружен в программирование мог прочитать код как спецификацию, по-возможности минимально вникая в специфику языка, на котором это описано.
Декларативный подход, так сказать. Есть высказывание, а как именно это работает — это уже не существенно. Главное читабельность, наглядность, и конечно же корректность. Соответствие формальных высказываний вкладываемому в них смыслу.

И того — мне действительно любопытно передать свой интерес другим. Есть некая иллюзия того — что интерес движущая сила к поступкам. Через что становится и проявляется индивидуальность. И в этом есть часть самореализации, воплощение творческого начала.
Амбициозно и немного лирики. Что же дальше?
Они есть и на данный момент их агрегирует проект: RISC-V Formal Verification [4].
Список формальных спецификаций (включая мою работу): https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/references.md [7]
Как видно — по большей части это формализации на языке Haskell. Это стало отправной идеей в выборе другого функционального языка. И мой выбор пал на F#.
F#Так случилось, что про F# мне известно давно, но все как-то в суете повседневности не имел возможности познакомиться ближе. Еще одним фактором была .NET платформа. Беря во внимание что я под Linux-ом, долгое время меня не устраивали IDE, и mono выглядело достаточно сырым. А возвращение в Windows только ради MS Visual Studio — достаточно сомнительная идея.
Однако время не стоит на месте, а звезды на небе не спешат меняться. Но к этому времени Jetbrains Rider [8] — развился до полноценного и удобного инструмента, а .NET Core для Linux не приносит боль при одном взгляде на него.
Стал вопрос — какой функциональный язык выбрать. То что это должен быть именно функциональный язык — в несколько патетическом виде я аргументировал выше.
Haskell, Idris, Agda? F# — с ним я не знаком. Отличный повод узнать новые краски мира функциональных языков.
Да F# не чисто-функциональный. Но что мешает придерживаться "чистоты"? И тут оказалось — что F# документация [9] достаточно подробная и целостная. Читабельная, и я бы даже сказал интересная.
Чем сейчас для меня стал F#? Достаточно гибким языком, с очень удобными IDE (Rider, Visual Studio). Вполне развитыми типами (хотя конечно до Idris очень далеко). И в целом достаточно милым с точки зрения читабельности. Однако как оказалось его функциональная "не чистота" — может приводить код к совершенно невменяемому виду как с точки зрения читабельности, так и логики. Анализ пакетов в Nugget [10] это наглядно показывает.
Еще одной интересной и загадочной особенностью для меня стало открытие, что написать формализацию RISC-V ISA на F# ранее никого не интересовало (официально или в доступном для поиска виде). А это значит, что у меня есть шанс внести новую струю в это сообщество, язык, "экосистему".
Самой сложной частью оказалось реализация Execution flow. Часто оказывалось, что не до конца понятно как инструкция должна работать. К сожалению надежного товарища, которому можно было бы позвонить в 3 часа ночи и взволнованным голосом с придыханием спросить: "А знаешь, BLTU инструкция наверное по-другому signextend-иться..." — у меня нет. В этом смысле иметь квалифицированных товарищей, которые добрым словом, и уместным квалифицированным советом помогут — очень желанно.
Какие были трудности и подводные камни. Попробую тезисно:
int32, int64 не оказалось. Потребовалось время на написание своего пакета и на его тестирование.x32 и x64 одновременно. Невнимательность привела к тому, что я в некоторых местах использовал int64. Выявить это мне помогли unit-тесты. Но на это потребовалось время.[A, M, C, F, D] на данный момент очевидны. В особенности реализация [F,D] не через soft float.Теперь пожалуй наиболее техническая часть. Какие возможности на данный момент:
rv32iobjdump виде при дизассемблировании.Работа программы разделена на такие этапы и циклы:
Что входит в планы:
Для того чтобы запустить программу необходимо наличие .NET Core. Если у вас не установлено, то к примеру, под Ubuntu 16.04 необходимо выполнить такой набор команд:
$ wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
$ sudo dpkg -i packages-microsoft-prod.deb
$ sudo apt-get update
$ sudo apt-get install apt-transport-https
$ sudo apt-get update
$ sudo apt-get install dotnet-sdk-3.0
Чтобы проверить, что что-то в жизни изменилось — запустите:
$ dotnet --version
И жизнь должна заиграть новыми красками!
Теперь попробуем запустить. Для этого запаситесь любимым чаем или кофе, шоколадкой с плюшками, включите любимую музыку и выполните такой набор команд:
$ cd some/my/dev/dir
$ git clone https://github.com/mrLSD/riscv-fs
$ cd riscv-fs
$ dotnet build
$ dotnet run -- --help
и ваша консоль должна игриво подмигнуть вам справочным сообщением.
Запуск же:
$ dotnet run
Строгим тоном скажет — что нужны параметры. Поэтому запускаем:
$ dotnet run -- -A rv32i -v myapp.elf
Это тот самый неловкий момент, когда оказывается, что все-таки нам нужна уже готовая ready for execution программа под RISC-V. И тут есть мне чем вам помочь. Однако вам понадобиться GNU toolchain for RISC-V [12]. Его установка пусть будет домашним заданием — в описании к репозиторию [12] достаточно детально описано как это делать.
Далее, для получения заветного тестового ELF-файла, выполняем такие действия:
$ cd Tests/asm/
$ make build32
если у вас RISC-V toolchain есть в наличии то все должно пройти гладко. И файлики должны красоваться в директории:
$ ls Tests/asm/build/
add32 alu32 alui32 br32 j32 mem32 sys32 ui32
и теперь смело, без оглядки пробуем команду:
$ dotnet run -- -A rv32i -v Tests/asm/build/ui32
Важно отметить, что Tests/asm не является тестовыми программами, но их основная цель — это тестовые инструкции и их коды для написания тестов. Поэтому если вам что-то по душе более масштабное и героическое, то в вашей воле меняя мир — найти самостоятельно исполняемый 32-битный ELF файл с поддержкой только rv32i инструкций.
Однако набор инструкций и расширений будет пополняться, набирать обороты и приобретать вес.
Получилось немного патетическое, приправленное личной историей повествование. Временами техническое, порой субъективное. Однако воодушевленное и с легким налетом энтузиазма.
С моей же стороны мне интересно от вас услышать: отзывы, впечатления, добрые напутствия. А для самых смелых — помощь в поддержании проекта.
Интересен ли вам такой формат повествования и хотели бы вы продолжений?
Автор: sfxws2006
Источник [16]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/net/335200
Ссылки в тексте:
[1] Проект на Github: https://github.com/mrLSD/riscv-fs
[2] Ukraino UNO: https://www.mini-tech.com.ua/ukraino-uno
[3] RISC-V Cores and SoC Overview: https://riscv.org/risc-v-cores/
[4] RISC-V Formal Verification: https://github.com/SymbioticEDA/riscv-formal
[5] реализация RISC-V на Rust: https://github.com/stephank/rvsim
[6] официальной спецификации: https://RISC.org/specifications/
[7] https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/references.md: https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/references.md
[8] Jetbrains Rider: https://www.jetbrains.COM/rider/
[9] F# документация: https://docs.Microsoft.COM/en-us/dotnet/fsharp/
[10] Nugget: https://www.nugget.org/
[11] Data.Bits: http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Bits.html
[12] GNU toolchain for RISC-V: https://github.com/riscv/riscv-gnu-toolchain
[13] RISC-V specifications: https://riscv.org/specifications/
[14] Awesome F# (мой проект также включен): https://github.com/fsprojects/awesome-fsharp
[15] Ariane — a 6-stage RISC-V CPU based on Verilog: https://github.com/pulp-platform/ariane
[16] Источник: https://habr.com/ru/post/473714/?utm_campaign=473714&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.