reallyMach — Mach, но без лишнего.
Это микроядро, но без тонны жира.
Здесь мы отошли от стандартных способов сделать многозадачность на MicroPython.
Мы сделали ставку на порты.
У нас есть данные технологии:
- Handoff scheduling - шлёшь сообщение и другой процесс уже обрабатывает его.
- Reference counting (на порты) - чтобы не было пустых портов в памяти.
- VM для процессов - вы скажете что это ненормально, но это единственный способ сделать MicroPython с вытеснением.
- O(1) Linux 2.6 scheduler - есть недочеты, но работает примерно в O(1).
- State machines - для событий и handoff scheduling.
- Асинхронные порты - ну... Единственный способ общение.
- Software isolating - в VM нету команд "залезть в чужую память".
- Права на порты - чтобы чужие процессы не лезли в порты которые им не дали.
Очень сложный механизм, но 702 строк вы прочитаете с удовольствием.
Также у нас 4 уровня:
- Железо. Тут процессор и всё такое
- MicroPython.
- Ядро.
- VM.
- Процессы.
Если от нуля считать то их 4.
Да. Ядро на MicroPython. А что?
Создаем порт и выводим сообщение:
CREATE_PORT # 1. Создали порт (ID теперь в стеке)
STORE my_port # 2. Сохранили ID в переменную 'my_port' (стек пуст)
PUSH 42 # 3. Положили данные (42)
PUSH 0 # 4. Порт для ответа (нам не нужен, пишем 0)
FETCH my_port # 5. Достали ID порта из переменной (куда слать)
SEND # 6. Улетело! (Стек снова пуст)
FETCH my_port # 7. Снова берем ID нашего порта
RECV # 8. Ядро лезет в порт, достает '42' и кладет в СТЕК!
PRINT # 9. ВОТ ТЕПЕРЬ ОНО ВЫВЕДЕТ 42
HALT # 10. КонецВо-первых, почитайте о Mach. Это будет большой бонус вам.
Во-вторых, почитайте код main.py - там основной функционал.
Вот команды для VirtualMachine:
- PUSH [val] — Положить число или объект в стек. Основа всего.
- FETCH [var] — Взять значение переменной из окружения (
env) и положить в стек. - STORE [var] — Забрать значение из стека и сохранить в переменную.
- ADD, SUB, MUL, DIV — Классическая арифметика над двумя верхними значениями стека.
- LT, GT, EQ, NOTEQ — Логика сравнения. Результат (1 или 0) падает обратно в стек.
- JZ / JNZ [addr] — Переход по адресу, если в стеке 0 (или не 0). Основа циклов и условий.
- JMP [addr] — Безусловный прыжок. Навигация по байт-коду.
- SEND — Системный вызов: забрать из стека (данные, порт_ответа, порт_назначения) и отправить.
- RECV — Системный вызов: ждать сообщения на порту. Если пусто — VM засыпает (
WAITING). - CREATE_PORT — Рождение новой точки доступа. Возвращает ID порта в стек.
- LIST / DICT — Сборка сложных структур данных из последних
nэлементов стека. - INDEX — Доступ к элементу списка или словаря по ключу/индексу из стека.
- APPEND [var] — Добавление элемента в существующий список или словарь.
- PRINT — Вывод верхнего элемента стека в консоль.
- RETURN - yield в моей vm.
- HALT — Завершение исполнения.
Но, если что почитайте src/proc.py.
VM вроде понятная.
Может быть немного проблемно понять стек, но если чуть-чуть поиспытать то у вас все получится.
Также у нас есть инлайнинг:
.func TEST
PUSH 1
PUSH 2
ADD
STORE a
.endВот как вызвать такое:
TESTЛучше делать JMP из функций.
И ещё кстати появились метки:
# Программа которая слушает порт
.func receive
FETCH my_port
RECV
STORE res
FETCH res
PRINT
.end
CREATE_PORT
STORE my_port
:LOOP
receive
JMP :LOOPЧто-то вроде так ^-^.
В последнее время добавил:
- ^ - пробел (hello^world)
- ~ - срез строки (hello~world выдаст: hello world)
В-третьих, копируйте все файлы из src на контроллер. Не саму папку.
Также, можете почитать rMachIPC() из файла src/ipc.py.
Вот тест памяти:
from sched import *
from ipc import *
import gc
sched = PrioSched()
ipc = rMachIPC()
kernel = Kernel(sched, ipc)
gc.collect()
free = gc.mem_free()
alloc = gc.mem_alloc()
total = free + alloc
usage_pct = (alloc / total) * 100
f_kb = free / 1024
a_kb = alloc / 1024
print(f"{f_kb:.1f}")
print(f"{a_kb:.1f} ({usage_pct:.2f}%)")Результат:
181.5
19.5 (9.69%)
181.5 - свободно КБ.
19.5 - КБ используется.
9.69% занято.
Во-первых, платформа ещё в тестировании.
Во-вторых, при багах:
Мой gmail, пишите что хотите.
Кстати.
Если увидите DIED в конце работы main.py - это нормально. Просто там небольшой race condition.