Появился третий бэк-энд, на этот раз для MSP430.
Язык пришлось несколько сократить, исключены:
- DISPOSE (практически невозможно реализовать для МК - недостаточно памяти)
- WCHAR (есть сложности и практически не нужно для МК)
- Вещественная арифметика (сложно, неэффективно и не очень нужно, но, в принципе, можно будет добавить в виде неявных вызовов RTL)
- Системные флаги (пока не нужно)
Качество кодогенерации пока оставляет желать лучшего. Размер пустой программы (один RTL) ~3 Кб.
Минимальные требования: ОЗУ 128 байт, ПЗУ 4096 байт.
Использование регистров:
R4 ... R7 - регистровый стэк
R8 ... R12 - не используются
R13 - используется при обработке прерываний
R14 - указатель "кучи"
R15 - указатель кадра стэка
В дальнейшем, для улучшения качества кодогенерации можно:
- задействовать регистры R8 ... R12 для хранения локальных переменных
- переписать RTL на асме (маш. кодах)
- удалять неиспользуемые процедуры RTL
Компилятор производит файл прошивки в hex-формате.
Пример командной строки:
Compiler.exe test.ob07 test.hex msp430 -ram 512 -rom 16384
Код: "OBERON"
(*
Пример для LaunchPad MSP-EXP430G2 Rev1.5
Мигает зеленый светодиод.
При нажатии на кнопку P1.3, включается/выключается красный светодиод.
*)
MODULE Button;
IMPORT SYSTEM, MSP430;
CONST
REDLED = {0};
GREENLED = {6};
BUTTON = {3};
(* регистры порта P1 *)
P1OUT = 21H;
P1DIR = 22H;
P1IFG = 23H;
P1IE = 25H;
P1REN = 27H;
PROCEDURE test_bits (mem: INTEGER; bits: SET): SET;
VAR
b: BYTE;
BEGIN
SYSTEM.GET(mem, b)
RETURN bits * BITS(b)
END test_bits;
PROCEDURE set_bits (mem: INTEGER; bits: SET);
VAR
b: BYTE;
BEGIN
SYSTEM.GET(mem, b);
SYSTEM.PUT8(mem, BITS(b) + bits)
END set_bits;
PROCEDURE clr_bits (mem: INTEGER; bits: SET);
VAR
b: BYTE;
BEGIN
SYSTEM.GET(mem, b);
SYSTEM.PUT8(mem, BITS(b) - bits)
END clr_bits;
PROCEDURE inv_bits (mem: INTEGER; bits: SET);
VAR
b: BYTE;
BEGIN
SYSTEM.GET(mem, b);
SYSTEM.PUT8(mem, BITS(b) / bits)
END inv_bits;
(* обработчик прерываний *)
PROCEDURE int (priority: INTEGER; interrupt: MSP430.TInterrupt);
BEGIN
IF priority = 18 THEN (* прерывание от порта P1 *)
IF test_bits(P1IFG, BUTTON) = BUTTON THEN (* нажата кнопка *)
inv_bits(P1OUT, REDLED); (* изменить состояние светодиода *)
MSP430.Delay(500); (* задержка для отпускания кнопки *)
clr_bits(P1IFG, BUTTON) (* сбросить флаг прерывания *)
END
END
END int;
PROCEDURE main;
BEGIN
(* инициализация регистров порта P1 *)
SYSTEM.PUT8(P1DIR, REDLED + GREENLED); (* выход *)
set_bits(P1REN, BUTTON); (* включить подтягивающий резистор *)
set_bits(P1OUT, BUTTON); (* подтяжка к питанию *)
set_bits(P1IE, BUTTON); (* разрешить прерывания от кнопки *)
MSP430.SetIntProc(int); (* назначить обработчик прерываний *)
MSP430.EInt; (* разрешить прерывания *)
(* бесконечный цикл *)
WHILE TRUE DO
inv_bits(P1OUT, GREENLED); (* изменить состояние светодиода *)
MSP430.Delay(800) (* задержка *)
END
END main;
BEGIN
main
END Button.
Пока, в программах интенсивно используются SYSTEM.PUT, SYSTEM.GET и даже SYSTEM.CODE, что не добавляет наглядности. Но это решаемо (можно добавить псевдопроцедуры в SYSTEM). Возможна также реализация встроенного ассемблера (система команд простая). Также, рассмотрю возможность добавления в язык константных массивов - это важно для микроконтроллеров.