ZX Murmulator - одноплатный ультрадешевый микрокомпьютер на основе платы Raspberry Pi Pico (далее "пика"), которая, в свою очередь, основана на микроконтроллере - RP2040.
RP2040 - одна из наиболее известных двухъядерных реализаций ARM Cortex-M0+ с 264 КБ встроенной SRAM памяти и от 2-ух до 16-ти МБ flash-памяти подключаемых по QSPI интерфейсу, распаянной на плате пики. Данный микроконтроллер легко гонится до 400 МГц без какого либо радиатора, не смотря на свои штатные 133. Что позволяет запускать на нём достаточно прожорливые задачи.
В предыдущей статье (https://habr.com/ru/articles/839960/) я упомянул, что для Мурмулятора в настоящее время разрабатывается собственная операционная система. Возникает вопрос - зачем микрокомпьютеру с 264 КБ памяти вообще понадобилась ОС?
Основная задача любой операционной системы - предоставить приложениям возможность унифицированного способа доступа к ресурсам оборудования, а пользователю - запускать и останавливать работающие приложения.
На самом деле, почти все прикладные задачи Мурмулятора можно решать без всякой ОС - достаточно установить бут-лоадер (см. https://github.com/xrip/pico-launcher), который позволит управлять прошивками, загружая их с SD-карточки. Основной недостаток бут-лоадера - невозможность редактирования конфиг-файлов эмуляторов легко решается путём его дописывания. Но если понадобится что-то ещё? Можно на каждый чих писать отдельную прошивку, или модифицировать существующую. Т.е. Murmulator OS (далее - просто МОС) должна решить эту проблему - дать более гибкий способ расширения функциональности.
Что ещё полезного может предоставить операционная система? - Унификация доступа к оборудованию. В настоящее время, каждая отдельная прошивка содержит все необходимые для функционирования приложения драйвера устройств, т.е. на лицо явная избыточность. Если ОС будет содержать все нужные драйвера, то приложение сможет сконцентрироваться только на своей функциональности, а остальное запрашивать у ОС.
Ещё одним дополнительным профитом наличия для устройства какой-то ОС является возможность использования данного устройства для обучения детей основным концепциям информатики. А учитывая, что изначально Мурмулятор - платформа игровая, для которой существует множество эмуляторов ретро-компьютеров, то можно познакомить детвору и с историей развития вычислительной техники, показать игры 80-ых и начала 90-ых годов прошлого века различных платформ, стран и концепций.
Не стоит также забывать, что Мурмулятор - ультрабюджетное решение, т.е. позволить себе такое устройство может практически кто угодно. Добыть PS/2 клавиатуру и VGA-монитор - в наше время тоже задача крайне бюджетная. Т.е. в этаком "offline-режиме", ребёнку необходимо будет только где-то заполучить файлы прошивок (эмуляторы) и ретро-игры к ним. Думаю, что наши бизнесмены, что продают готовые мурмуляторы, вполне могут предоставлять их с SD-карточкой, на которой уже будет записана вся коллекция. Ну, это уже не относится к самой ОС.
Когда я только задумался о написании ОС к Мурмулятору, была мысль, что можно создавать целые компьютерные классы мурмуляторов, но просмотрев (по-диагонали) программу обучения информатике в школе, понял - поздно, т.к. оно уже никому не нужно, там учат окошки по десктопу таскать и в экселе таблички править. Ну, может, программа ещё изменится, и основы таки начнут преподавать. Или оно пригодится в ретро-компьютерных клубах. А есть такие? Если нет - дарю бизнес-идею ))
Вернёмся к самой ОС. Выбирая ядро для будущей ОС, я перелопатил кучу уже готового кода, в котором меня что-то да не устраивало. Ближе всего к требуемым параметрам оказалась FreeRTOS (https://github.com/FreeRTOS/FreeRTOS-Community-Supported-Demos/tree/3d475bddf7ac8af425da67cdaa2485e90a57a881/CORTEX_M0%2B_RP2040), единственным недостатком которой является её достоинство - она очень простая и при этом крайне несамодостаточная. Т.е. нельзя скачать где-то дистрибутив данной ОС под RP2040 и поставить на какое-то оборудование, пусть даже несовместимое с Мурмулятором. FreeRTOS, в данном случае - встраиваемое решение, т.е. если вам понадобилась многозадачность, то она вам её обеспечит, но вот с файловыми операциями, драйверами клавиатуры, видео-подсистемы, звука и любого чиха - это всё на вас.
Зачем вообще мне понадобилась многозадачность? Вон, древние MS DOS или Windows 3.1 вполне без неё обходились, и ничего. Тут очень сложно пояснить человеку, который никогда не писал программы под ОС с добровольной многозадачностью. Скажу кратко - это крайне утомительно и крайне ненадёжно. Нет никакой гарантии, что твоя программа получит доступ к ресурсу вовремя. Т.е. тебе бы в буфер саундкарты что-то записать надо, но нет - программа форматирования дискеты в это время заняла все ресурсы и не отдаёт, а саундкарта в это время выводит одну ноту, т.к. новой нотой её никто не снабдил. В общем, я выбрал себе ядро будущей ОС, и принялся активно обшивать его драйверами доступных устройств.
Ещё пару слов надо сказать про ARM Cortex M0+ - это ядро не имеет полноценного MMU - только примитивный MPU и малополезный для нас, в данном случае, XIP. Т.е. о виртуальной памяти можно сразу забыть. Попытка её построить на одном MPU приведёт к таким тормозам, что можно просто установить эмулятор IBM PC XT и получить аналогичную производительность.
Отсутствие выделенного адресного пространства на процесс с отсутствием трансляции адресов - приговор неперемещаемым программам. Т.е. после компиляции у нас обычно получается объектный файл, который ещё ни к каким адресам в памяти не привязан (кроме адресов оборудования), а вот после линковки - всё, адреса прибиты гвоздями к получившемуся коду. Причём уже нельзя разделить, какие адреса привязаны "по-делу", т.к. ссылаются на адреса какого-то оборудования, а какие "просто так", потому что линковщик так захотел, при этом часть адресации будет нормальной - относительной.
Переписывать линковщик - задача явно не моего уровня (или потребует несоразмерного времени), поэтому было принято решение от него избавиться. Совсем. Возможно, в будущем, я напишу линковщик под МОС, как и компилятор под неё, и всё остальное... но пока-то его нет (подходящего). Соответственно, результатом компиляции программы в объектный файл на данном этапе мы и удовлетворимся. Теперь задача ОС - расположить где-то в свободной памяти код из объектника, разрезолвить адреса и передать управление функции main
.
Возникает вопрос - а как программа будет обращаться к API самой ОС? Ну, поскольку ОС - обычная .uf2 прошивка, в которой адреса функций таки можно прибить гвоздями к определённым адресам, задав их в .ld файле, проблемы как-бы и нет, но это крайне громоздкое и неудобное решение - прописывать для каждой функции АПИ её адрес. Лучше сделать таблицу адресов функций (указателей на них), её начало прибить к определённому адресу, а наполнение пусть сам линкер резолвит.
В этом случае, для приложений достаточно предоставить заголовочный файл, в котором будут конструкции типа:
#define M_OS_API_SYS_TABLE_BASE ((void*)(0x10000000ul + (16 << 20) - (4 << 10)))
static const unsigned long * const _sys_table_ptrs = (const unsigned long * const)M_OS_API_SYS_TABLE_BASE;
inline static int kill(uint32_t task_n) {
typedef int (*fn_ptr_t)(uint32_t);
return ((fn_ptr_t)_sys_table_ptrs[244])(task_n);
}
что позволит не заботиться о реальных адресах функций, они хранятся в той самой таблице указателей, которая прибита гвоздями к нужному адресу.
Надо заметить, что из-за особенностей Cortex-M0+ все приложения МОС будут разделять общую память, а это обозначает снижение надёжности всей системы. К сожалению, я так и не придумал хорошего решения данной проблемы. Может быть, позже я к этому вернусь и попробую задействовать существующий в процессоре MPU для недопущения обращения к "чужой" памяти, но пока этой функциональности просто нет, и при разработке программ это необходимо учитывать.
Также необходимо учитывать, что если какая-то программа совершит нечто "запрещённое", что приведёт к HardFault ядра процессора, то никакая FreeRTOS тут уже не поможет - ядро остановится - т.е. повиснет. У меня имеются ряд идей по перехвату HardFault и дальнейшему удалению контекста задачи, но это также пока не реализовано.
Аналог SIGKILL для задач тоже пока не реализован, вместо этого имеется аналог SIGTERM, что предполагает обработку данного сигнала самой программой (для этого имеется предопределённый хэндлер "signal", на который и надо вешать логику выхода из задачи).
Есть вероятность, что с выходом Raspberry Pi Pico 2, на чипе RP2350 (2 x ARM Cortex-M33) все проблемы можно будет решить штатной виртуализацией, и этот кусок реализации ОС придётся выкинуть. Но это уже будет другой Мурмулятор (2.0?)...
Исходники МОС можно изучать тут: https://github.com/DnCraptor/murmulator-os
Чуть позже выложу ещё статью про МОС с точки зрения пользователя.
Комментарии (28)
lumag
31.08.2024 07:13+1Еще, было бы интересно узнать, чем ZephyrOS не понравилась
mikeveng73 Автор
31.08.2024 07:13А к ней есть порт под RP2040?
lumag
31.08.2024 07:13mikeveng73 Автор
31.08.2024 07:13просмотрел доку по-быстрому. пока принципиальных отличий от FreeRTOS не нашёл.
lumag
31.08.2024 07:13Очень смелое заявление. FreeRTOS -- это, скорее, фреймворк по переключению задач. А Zephyr -- это полноценная ось с сетевым стеком на несколько протоколов, драйверов оборудования и т.п.
mikeveng73 Автор
31.08.2024 07:13Если учесть, что пике неоткуда взять сеть (если не брать pico w, для которой можно поискать драйвер в Зефире), а в Зефире нет драйверов для тех устройств, что используются в Мурмуляторе, то остаётся только голое ядро для переключения задач, и особой разницы уже как бы и нет.
mafia8
31.08.2024 07:13Добыть PS/2 клавиатуру...
В одном сетевом магазине:
Bluetooth (193), PS/2 (4) USB (539)
Indemsys
31.08.2024 07:13Плату с микронтроллером сделать гораздо легче чем фреймворк с осью, middleware и драйверами. Поэтому по уму выбирают сначала ось с фреймворком, а потом берут то железо под которое она портировна. Так проще и быстрее.
Под Raspberry Pi Pico пока не видно нигде полноценных фреймворков.
mikeveng73 Автор
31.08.2024 07:13Ну, тут задача была обратная - аппаратура уже есть, а ОСи - нет )
Indemsys
31.08.2024 07:13Не, ошибся.
Там оказывается все есть в виде Raspberry Pi Pico SDK. Там же и RTOS, WiFi, BLE, USB.
Единственно нет графического движка.
Но сам чип слабый, даже RP2350 будет все еще сильно слабее лидеров от ST, Renesas, NXP.mikeveng73 Автор
31.08.2024 07:13Ну, он сильно бюджетный. А RP2350/54 - ждём. Пока в доступных точках их нет. Не из Британии же заказывать ))
mikeveng73 Автор
31.08.2024 07:13Кстати, под винду есть удобный инсталлер: https://github.com/raspberrypi/pico-setup-windows/releases (но требует Win10 или выше).
ABy
31.08.2024 07:13"Ничего не понял, но очень интересно"
Вот, допустим, пилю я портативку на rp2040 с spi экранчиком 128х128. Смогу я этот мурмулятор использовать в своем проекте?
mikeveng73 Автор
31.08.2024 07:13Мурмулятор ОС пока не поддерживает экраны-матрицы, а вот в pico-launcher можно подсмотреть управление матрицей 240*320 ST7789 по i2c. Исходники тут: https://github.com/xrip/pico-launcher/tree/main/drivers/st7789, там рядом есть ещё поддержка ws2812.
EvilTeacher
31.08.2024 07:13Не надо такое в школы детям. Когда дитё придет на урок информатики с телефоном, в котором и мощности, и возможностей гораздо больше - желание слушать информатичку улетучится мгновенно. А кто (где и когда?) будет учить информатичку, выкормленную Виндой? Даже в вузах показывать подобные вещи нужно только отдельным специальностям, а учить - тем более. В системе образования даже перевод с Винды на Линукс вызвал такой шторм... А тут, по сути - совсем другая идеология.
mikeveng73 Автор
31.08.2024 07:13Это не другая идеология, а общая база для всех ОС. Командной строке надо учить всех, а не одних задротов, иначе мы никогда не выберемся из "поколения-ЕГ".
Indemsys
31.08.2024 07:13Командная строка - удел слабых архаичных архитектур. В сильных архитектурах используют командные приложения с GUI и голосовым вводом.
Сейчас даже дешевые Wi-Fi extender-ы выполняют голосовые команды для управления сетевыми настройками. Учебные проекты однозначно должны поддерживать взаимодействие с AI и IoT.
Для AI нужны нужны хорошие объемы RAM, для IoT тоже нужно больше RAM чем в RP2350/54 .
Вывод - RP2350/54 не для базы учебного проекта, это просто экстендеры для их базы на Raspberry Pi 5. Потому у RP2xxx и нет графического движка.Наличие же интерфейса HSTX для реализации DVI и HDMI говорит, что да, для эмуляторов ретрокомпьютеров RP235x годен, но не более.
vadimk91
31.08.2024 07:13+1Тут я с Вами согласен, но даже в техническом ВУЗе в 90-х прошлого века изучение Микролаба К580 (про него есть статья на Хабре) вызывало у студентов непонимание, зачем вот это всё - регистры, биты, мнемокоды... тогда еще не было смартфонов и персональные ПК были редкостью, но программирование на языке ассемблера наверное у 95% однокурсников вызывало отвращение :)
IgorIlyin
31.08.2024 07:13+2У меня мурмулятор лежит на рабочем столе, используется в основном для прослушки честной чиптюн музыки, под которую люблю работать Иногда - для ностальгических игр на эмуляторе, на телевизоре. И вот по поводу игр была мысль - что это же готовая игровая консоль, с джойстиками и подключением к телевизору. Если даже просто набросать фреймворк, который позволяет собирать простые игры (arcanoid, tetris и т.п.), это может быть вполне себе увлекательная обучающая среда для детей, т.к. ты можешь модифицировать игру, и тут же попробовать её с приятелем. Ради этого, кстати хотел посмотреть на Murmulator OS, и вот, кажется пришло время.
lumag
Есть подход под названием ELF FDPIC. Это стандартный ELF, просто слинкованный не совсем стандартным образом. Весь код остается не зависящим от адреса загqрузки, вся зависимость от адреса загрузки уходит в PLT. В итоге сегмент кода так и остается read only и может шариться между задачами на MMU-less системах.
mikeveng73 Автор
Сборка с флагом -fPIC у меня не прошла. Не смог я подобрать правильные ключики...
lumag
-mfdpic
, а не просто-fPIC
.mikeveng73 Автор
спасибо, попробую. интересно даже, что получится )
mikeveng73 Автор
добрался проверить. нифига не вышло:
unimplemented: FDPIC mode is not supported in Thumb-1 mode
lumag
Забавно. Действительно FDPIC делали для ARMv7-M / Thumb-2, но есть подозрение, что это требование связано с командой BL (которая есть на C-M0 / C-M0+).