О проекте: Пишем один код — собираем на разные 8 бит МК!
https://vm5277.ru— это универсальное решение для embedded-разработки, которое позволяет сократить время создания прошивки для 8 бит микроконтроллеров в разы.
Как это работает:
-
Пишешь код на Java подобном языке (чистое ООП, без головной боли с указателями и не читабельным кодом)
-
Компилятор автоматически генерирует оптимизированный ассемблерный код под выбранную платформу
-
Код работает поверх легковесной RTOS, написанной на ассемблере для максимальной производительности
-
Ассемблер-сборщик финализирует проект в бинарный файл прошивки
Что входит в решение:
-
Высокоуровневый компилятор с Java подобным синтаксисом
-
Максимально оптимизированная RTOS, целиком на ассемблере для каждой платформы
-
Унифицированные драйвера — один API для UART, SPI, I2C, GPIO на всех МК
-
Стандартные библиотеки (Runtime): Базовые типы данных (Float, String), математические функции (Math), работа с памятью и другие абстракции, не зависящие от платформы.
-
Драйверы верхнего уровня (High-Level Drivers): Унифицированные API для работы с периферийными устройствами: датчиками (I2C/SPI), дисплеями, SD-картами, беспроводными модулями (ESP8266, Bluetooth).
Ключевые преимущества:
-
Скорость разработки: Создавайте функционал на высокоуровневом языке быстрее, чем на Си
-
Производительность: RTOS и драйверы оптимизированы до уровня чистого ассемблера, экономя каждый байт и такт
-
Переносимость: Переход с AVR на PIC или STM8 — дело нескольких правок, а не изучение и адаптация библиотек
Проект находится на ранней стадии, но я активно над ним работаю. Уже можно видеть, как высокоуровневый код на Java-подобном языке превращается в чистый и эффективный ассемблер! Это ещё не итоговый вариант, но прогресс уже есть.
Что уже работает в этом примере:
-
Наследование интерфейсов: Test implements Number
-
Динамическое выделение памяти: оператор new
-
Полиморфизм: вызов метода через переменную интерфейсного типа (Number.toByte())
-
Проверка типа во время выполнения: оператор is (аналог instanceof)
-
Полноценная работа с объектами: конструкторы, методы, поля.
-
Интеграция с RTOS: вызов системных функций (System.out).
Исходный код custom.j8b:
import rtos.System; import rtos.RTOSParam; class Main { interface Number { byte toByte(); } interface Test implements Number { byte toByte(); void test(); } public class Byte implements Test { privatebytevalue; public Byte(byte value) { this.value = value; } public byte toByte() { return value; } public void test() { } } public static void main() { System.setParam(RTOSParam.STDOUT_PORT, 0x12); Number b1 = new Byte(0x08); if(b1 is Byte) { System.out(b1.toByte()); } } }
Итоговый ассемблер код(черновой, могут быть ошибки)
.equ stdout_port = 18 .set OS_FT_DRAM = 1 .set OS_FT_STDOUT = 1 .include "devices/atmega328p.def" .include "core/core.asm" .include "dmem/dram.asm" .include "j8b/inc_refcount.asm" .include "j8b/dec_refcount.asm" .include "j8b/instanceof.asm" .include "j8b/clear_fields.asm" .include "j8b/invoke_method.asm" .include "stdio/out_num8.asm" Main: jmp j8bCMainMmain ;======== enter CLASS Main ======================== ;======== enter CLASS Byte ======================== _j8b_meta10: .db 15,2,13,1,14,2 .dw j8bC14CByteMtoByte,j8bC14CByteMtoByte,0 j8bC11CByteMByte: ldi r16,6 ldi r17,0 mcall os_dram_alloc std z+0,r16 std z+1,r17 std z+2,c0x00 ldi r16,low(_j8b_meta10*2) std z+3,r16 ldi r16,high(_j8b_meta10*2) std z+4,r16 mcall j8bproc_clear_fields_nr _j8b_cinit12: ldd r16,y+0 std z+5,r16 _j8b_methodend13: ret j8bC14CByteMtoByte: ldd r16,z+5 jmp _j8b_methodend15 _j8b_methodend15: ret ;======== leave CLASS Byte ======================== j8bCmainMmain: push_z ldi zl,low(_j8b_retpoint20) push zl ldi zl,high(_j8b_retpoint20) push zl ldi zl,8 push zl jmp j8bC11CByteMByte _j8b_retpoint20: pop_z mov r20,r16 mov r21,r17 _j8b_ifbegin22: push_z mov r30,r20 mov r31,r21 ldi r17,15 mcall j8bproc_instanceof_nr pop_z brne _j8b_ifend25 _j8b_ifthen23: push_z ldi zl,low(_j8b_retpoint21) push zl ldi zl,high(_j8b_retpoint21) push zl mov r30,r20 mov r31,r21 ldi r16,13 ldi r17,0 jmp j8bproc_invoke_method_nr _j8b_retpoint21: pop_z mcall os_out_num8 _j8b_methodend19: _j8b_ifend25: _j8b_methodend18: ret ;======== leave CLASS Main ========================
Одна из функций RTOS(код сырой, может содержать ошибки)
.IFNDEF J8BPROC_INVOKE_METHOD_NR ;----------------------------------------------------------- J8BPROC_INVOKE_METHOD_NR:;NR-NO_RESTORE - не восстанавливаю регистры ;----------------------------------------------------------- ;Переходим на код метода ;IN: Z-адрес HEAP,ACCUM_L-ид интерфейса, ACCUM_H-порядковый ;номер метода в интерфейсе ;----------------------------------------------------------- PUSH_Z ADIW ZL,0x03 LD ACCUM_EH,Z+ LD ZH,Z MOV ZL,ACCUM_EH ADIW ZL,0x01;Пропускаем ид типа класса LPM ACCUM_EH,Z+;Получаем количество пар(ид интерфейс + кол-во методов) MOV YL,ACCUM_EH;Вычисляю адрес блока адресов методов LDI YH,0x00 LSL YL ROL YH ADD YL,ZL ADC YH,ZH LDI TEMP_L,0x00;Порядковый номер метода в классе _J8BPROC_INVOKE_METHOD_NR__IFACEIDS_LOOP: LPM ACCUM_EL,Z+;Получаю id интерфейса CP ACCUM_EL,ACCUM_L BREQ _J8BPROC_INVOKE_METHOD_NR__GOT_IFACE LPM ACCUM_EL,Z+;Получаю количество методов в интерфейсе ADD ACCUM_H,ACCUM_EL DEC ACCUM_EH BRNE _J8BPROC_INVOKE_METHOD_NR__IFACEIDS_LOOP _J8BPROC_INVOKE_METHOD_NR__GOT_IFACE: POP_Z LSL ACCUM_H;Смещаюсь на адрес с учетом порядкового номера метода в классе ADD YL,ACCUM_H ADC YH,C0x00 PUSH_Y RET .ENDIF
Ключевые фрагменты сгенерированного ассемблерного кода:
1. Метаданные класса:
Компилятор автоматически формирует структуру для поддержки RTTI (Run-Time Type Information), необходимую для instanceof.
_j8b_meta10: .db 15,2,13,1,14,2 ; <-- Вот эти метаданные класса `Byte` .dw j8bC14CByteMtoByte, j8bC14CByteMtoByte, 0
2. Динамическое создание объекта в куче:
Код конструктора new Byte(0x08) транслируется в вызов менеджера динамической памяти (os_dram_alloc) и инициализацию полей.
j8bC11CByteMByte: ldi r16,6 ; Размер объекта: 6 байт! mcall os_dram_alloc std z+5, r16 ; Инициализация поля `value`
3. Проверка типа (is / instanceof):
Оператор if(b1 is Byte) компилируется в вызов процедуры j8bproc_instanceof_nr, которая проверяет метаданные объекта.
mcall j8bproc_instanceof_nr ; Магия проверки типа происходит здесь! brne _j8b_ifend25 ; Условный переход на основе результата
4. Полиморфный вызов метода:
Вызов b1.toByte() через интерфейс Number преобразуется в универсальный механизм поиска и диспетчеризации метода.
; invokeInterfaceMethod byte Number.toByte ldi r16, 13 ldi r17, 0 jmp j8bproc_invoke_method_nr ; Динамический вызов метода!
5. Интеграция с системными сервисами:
Вывод в «консоль» (System.out) — это вызов системного сервиса ОСРВ.
mcall os_out_num8 ; Вывод числа через системный вызов RTOS
Что это значит?
Это доказывает, что подход vm5277 работоспособен. Мы можем писать на высокоуровневом ООП-языке, а под капотом получать код, который:
-
Эффективно использует память: объекты размещаются в куче, метаданные компактны.
-
Сохраняет производительность: ключевые операции (выделение памяти, проверка типов) вынесены в оптимизированные ассемблерные процедуры.
-
Является переносимым: этот же Java-like-код, после завершения работы над платформами, сможет работать на PIC и STM8 (ограничений почти нет).
ссылка на оригинал статьи https://habr.com/ru/articles/942258/
Добавить комментарий