forked from KolibriOS/kolibrios
2f54c7de00
git-svn-id: svn://kolibrios.org@8097 a494cfbc-eb01-0410-851d-a64ba20cac60
520 lines
28 KiB
Plaintext
520 lines
28 KiB
Plaintext
Компилятор языка программирования Oberon-07/16 для
|
||
микроконтроллеров MSP430x{1,2}xx.
|
||
------------------------------------------------------------------------------
|
||
|
||
Параметры командной строки
|
||
|
||
Вход - текстовые файлы модулей с расширением ".ob07", кодировка ANSI или
|
||
UTF-8 с BOM-сигнатурой.
|
||
Выход - hex-файл прошивки.
|
||
Параметры:
|
||
1) имя главного модуля
|
||
2) "msp430"
|
||
3) необязательные параметры-ключи
|
||
-out <file_name> имя результирующего файла; по умолчанию,
|
||
совпадает с именем главного модуля, но с расширением ".hex"
|
||
-ram <size> размер ОЗУ в байтах (128 - 2048) по умолчанию 128
|
||
-rom <size> размер ПЗУ в байтах (2048 - 24576) по умолчанию 2048
|
||
-nochk <"ptibcwra"> отключить проверки при выполнении
|
||
-lower разрешить ключевые слова и встроенные идентификаторы в
|
||
нижнем регистре
|
||
-def <имя> задать символ условной компиляции
|
||
|
||
параметр -nochk задается в виде строки из символов:
|
||
"p" - указатели
|
||
"t" - типы
|
||
"i" - индексы
|
||
"b" - неявное приведение INTEGER к BYTE
|
||
"c" - диапазон аргумента функции CHR
|
||
"a" - все проверки
|
||
|
||
Порядок символов может быть любым. Наличие в строке того или иного
|
||
символа отключает соответствующую проверку.
|
||
|
||
Например: -nochk it - отключить проверку индексов и охрану типа.
|
||
-nochk a - отключить все отключаемые проверки.
|
||
|
||
Например:
|
||
|
||
Compiler.exe "C:\example.ob07" msp430 -ram 128 -rom 4096 -nochk pti
|
||
Compiler.exe "C:\example.ob07" msp430 -out "C:\Ex1.hex" -ram 512 -rom 16384
|
||
|
||
В случае успешной компиляции, компилятор передает код завершения 0, иначе 1.
|
||
При работе компилятора в KolibriOS, код завершения не передается.
|
||
|
||
------------------------------------------------------------------------------
|
||
Отличия от оригинала
|
||
|
||
1. Расширен псевдомодуль SYSTEM
|
||
2. В идентификаторах допускается символ "_"
|
||
3. Усовершенствован оператор CASE (добавлены константные выражения в
|
||
метках вариантов и необязательная ветка ELSE)
|
||
4. Расширен набор стандартных процедур
|
||
5. Семантика охраны/проверки типа уточнена для нулевого указателя
|
||
6. Добавлены однострочные комментарии (начинаются с пары символов "//")
|
||
7. Разрешено наследование от типа-указателя
|
||
8. "Строки" можно заключать также в одиночные кавычки: 'строка'
|
||
9. Добавлена операция конкатенации строковых и символьных констант
|
||
10. Добавлены кодовые процедуры
|
||
11. Не реализована вещественная арифметика
|
||
|
||
------------------------------------------------------------------------------
|
||
Особенности реализации
|
||
|
||
1. Основные типы
|
||
|
||
Тип Диапазон значений Размер, байт
|
||
|
||
INTEGER -32768 .. 32767 2
|
||
CHAR символ ASCII (0X .. 0FFX) 1
|
||
BOOLEAN FALSE, TRUE 1
|
||
SET множество из целых чисел {0 .. 15} 2
|
||
BYTE 0 .. 255 1
|
||
|
||
2. Максимальная длина идентификаторов - 1024 символов
|
||
3. Максимальная длина строковых констант - 1024 символов (UTF-8)
|
||
4. Максимальная размерность открытых массивов - 5
|
||
5. Процедура NEW заполняет нулями выделенный блок памяти
|
||
6. Локальные переменные инициализируются нулями
|
||
7. В отличие от многих Oberon-реализаций, сборщик мусора и динамическая
|
||
модульность отсутствуют
|
||
8. Тип BYTE в выражениях всегда приводится к INTEGER
|
||
9. Контроль переполнения значений выражений не производится
|
||
10. Ошибки времени выполнения:
|
||
|
||
номер ошибка
|
||
|
||
1 ASSERT(x), при x = FALSE
|
||
2 разыменование нулевого указателя
|
||
3 целочисленное деление на неположительное число
|
||
4 вызов процедуры через процедурную переменную с нулевым значением
|
||
5 ошибка охраны типа
|
||
6 нарушение границ массива
|
||
7 непредусмотренное значение выражения в операторе CASE
|
||
8 ошибка копирования массивов v := x, если LEN(v) < LEN(x)
|
||
9 CHR(x), если (x < 0) OR (x > 255)
|
||
11 неявное приведение x:INTEGER к v:BYTE, если (x < 0) OR (x > 255)
|
||
|
||
------------------------------------------------------------------------------
|
||
Псевдомодуль SYSTEM
|
||
|
||
Псевдомодуль SYSTEM содержит низкоуровневые и небезопасные процедуры,
|
||
ошибки при использовании процедур псевдомодуля SYSTEM могут привести к
|
||
повреждению данных времени выполнения и аварийному завершению программы.
|
||
|
||
PROCEDURE ADR(v: любой тип): INTEGER
|
||
v - переменная или процедура;
|
||
возвращает адрес v
|
||
|
||
PROCEDURE SADR(x: строковая константа): INTEGER
|
||
возвращает адрес x
|
||
|
||
PROCEDURE SIZE(T): INTEGER
|
||
возвращает размер типа T
|
||
|
||
PROCEDURE TYPEID(T): INTEGER
|
||
T - тип-запись или тип-указатель,
|
||
возвращает номер типа в таблице типов-записей
|
||
|
||
PROCEDURE MOVE(Source, Dest, n: INTEGER)
|
||
Копирует n байт памяти из Source в Dest,
|
||
области Source и Dest не могут перекрываться
|
||
|
||
PROCEDURE GET(a: INTEGER;
|
||
VAR v: любой основной тип, PROCEDURE, POINTER)
|
||
v := Память[a]
|
||
|
||
PROCEDURE GET8(a: INTEGER; VAR x: INTEGER, SET, BYTE, CHAR)
|
||
Эквивалентно
|
||
SYSTEM.MOVE(a, SYSTEM.ADR(x), 1)
|
||
|
||
PROCEDURE PUT(a: INTEGER; x: любой основной тип, PROCEDURE, POINTER)
|
||
Память[a] := x;
|
||
Если x: BYTE, то значение x будет расширено до 16 бит,
|
||
для записи байтов использовать SYSTEM.PUT8
|
||
|
||
PROCEDURE PUT8(a: INTEGER; x: INTEGER, SET, BYTE, CHAR)
|
||
Память[a] := младшие 8 бит (x)
|
||
|
||
PROCEDURE CODE(word1, word2,... : INTEGER)
|
||
Вставка машинного кода,
|
||
word1, word2 ... - целочисленные константы (константные
|
||
выражения) - машинные слова, например:
|
||
SYSTEM.CODE(0D032H, 0010H) (* BIS #16, SR; CPUOFF *)
|
||
|
||
|
||
Функции псевдомодуля SYSTEM нельзя использовать в константных выражениях.
|
||
|
||
------------------------------------------------------------------------------
|
||
Оператор CASE
|
||
|
||
Синтаксис оператора CASE:
|
||
|
||
CaseStatement =
|
||
CASE Expression OF Сase {"|" Сase}
|
||
[ELSE StatementSequence] END.
|
||
Case = [CaseLabelList ":" StatementSequence].
|
||
CaseLabelList = CaseLabels {"," CaseLabels}.
|
||
CaseLabels = ConstExpression [".." ConstExpression].
|
||
|
||
Например:
|
||
|
||
CASE x OF
|
||
|-1: DoSomething1
|
||
| 1: DoSomething2
|
||
| 0: DoSomething3
|
||
ELSE
|
||
DoSomething4
|
||
END
|
||
|
||
В метках вариантов можно использовать константные выражения, ветка ELSE
|
||
необязательна. Если значение x не соответствует ни одному варианту и ELSE
|
||
отсутствует, то программа прерывается с ошибкой времени выполнения.
|
||
|
||
------------------------------------------------------------------------------
|
||
Конкатенация строковых и символьных констант
|
||
|
||
Допускается конкатенация ("+") константных строк и символов типа CHAR:
|
||
|
||
str = CHR(39) + "string" + CHR(39); (* str = "'string'" *)
|
||
|
||
newline = 0DX + 0AX;
|
||
|
||
------------------------------------------------------------------------------
|
||
Проверка и охрана типа нулевого указателя
|
||
|
||
Оригинальное сообщение о языке не определяет поведение программы при
|
||
выполнении охраны p(T) и проверки типа p IS T при p = NIL. Во многих
|
||
Oberon-реализациях выполнение такой операции приводит к ошибке времени
|
||
выполнения. В данной реализации охрана типа нулевого указателя не приводит к
|
||
ошибке, а проверка типа дает результат FALSE. В ряде случаев это позволяет
|
||
значительно сократить частоту применения охраны типа.
|
||
|
||
------------------------------------------------------------------------------
|
||
Дополнительные стандартные процедуры
|
||
|
||
|
||
COPY (x: ARRAY OF CHAR; VAR v: ARRAY OF CHAR);
|
||
v := x;
|
||
Если LEN(v) < LEN(x), то строка x будет скопирована
|
||
не полностью.
|
||
|
||
LSR (x, n: INTEGER): INTEGER
|
||
Логический сдвиг x на n бит вправо.
|
||
|
||
MIN (a, b: INTEGER): INTEGER
|
||
Минимум из двух значений.
|
||
|
||
MAX (a, b: INTEGER): INTEGER
|
||
Максимум из двух значений.
|
||
|
||
BITS (x: INTEGER): SET
|
||
Интерпретирует x как значение типа SET.
|
||
Выполняется на этапе компиляции.
|
||
|
||
LENGTH (s: ARRAY OF CHAR): INTEGER
|
||
Длина 0X-завершенной строки s, без учета символа 0X.
|
||
Если символ 0X отсутствует, функция возвращает длину
|
||
массива s. s не может быть константой.
|
||
|
||
------------------------------------------------------------------------------
|
||
Использование регистров общего назначения R4 - R15
|
||
|
||
R4 - R7: регистровый стэк (промежуточные значения выражений)
|
||
R8 - R13: не используются
|
||
R14: указатель кучи
|
||
R15: используется при обработке прерываний
|
||
|
||
------------------------------------------------------------------------------
|
||
Вызов процедур и кадр стэка
|
||
|
||
Правила вызова похожи на соглашение cdecl (x86):
|
||
- параметры передаются через стэк справа налево
|
||
- результат, если есть, передается через регистр R4
|
||
- вызывающая процедура очищает стэк
|
||
|
||
Состояние стэка при выполнении процедуры:
|
||
|
||
меньшие адреса <- |var3|var2|var1|PC|arg1|arg2|arg3| -> бОльшие адреса
|
||
|
||
PC - значение регистра PC перед вызовом (адрес возврата)
|
||
argX - параметры в порядке объявления (слева направо)
|
||
varX - локальные переменные в порядке использования в процедуре
|
||
|
||
Размер каждого элемента в стэке (кроме локальных переменных структурных
|
||
типов) - 1 машинное слово (2 байта). Структурные переменные (массивы и
|
||
записи) занимают место в стэке в соответствии с их размером (с учетом
|
||
выравнивания).
|
||
|
||
Размещение локальных переменных зависит от их размеров и порядка
|
||
использования, и в общем случае неопределенно. Если переменная не
|
||
используется явно, то компилятор не выделяет для нее место в стэке.
|
||
|
||
------------------------------------------------------------------------------
|
||
Скрытые параметры процедур
|
||
|
||
Некоторые процедуры могут иметь скрытые параметры, они отсутствуют в списке
|
||
формальных параметров, но учитываются компилятором при трансляции вызовов.
|
||
Это возможно в следующих случаях:
|
||
|
||
1. Процедура имеет формальный параметр открытый массив:
|
||
PROCEDURE Proc (x: ARRAY OF ARRAY OF REAL);
|
||
Вызов транслируется так:
|
||
Proc(LEN(x), LEN(x[0]), SYSTEM.ADR(x))
|
||
2. Процедура имеет формальный параметр-переменную типа RECORD:
|
||
PROCEDURE Proc (VAR x: Rec);
|
||
Вызов транслируется так:
|
||
Proc(SYSTEM.TYPEID(Rec), SYSTEM.ADR(x))
|
||
|
||
------------------------------------------------------------------------------
|
||
Кодовые процедуры
|
||
|
||
Компилятор поддерживает процедуры, написаные в машинных кодах.
|
||
Синтаксис:
|
||
|
||
PROCEDURE "[code]" имя [ (параметры): ТипРезультата ]
|
||
МашСлово, МашСлово,... МашСлово;
|
||
|
||
";" после заголовка и END "имя" в конце процедуры не ставятся.
|
||
МашСлово - целочисленная константа (в том числе и константное выражение).
|
||
Например:
|
||
|
||
PROCEDURE [code] asr (n, x: INTEGER): INTEGER (* ASR(x, n) -> R4 *)
|
||
4115H, 2, (* MOV 2(SP), R5; R5 <- n *)
|
||
4114H, 4, (* MOV 4(SP), R4; R4 <- x *)
|
||
0F035H, 15, (* AND #15, R5 *)
|
||
2400H + 3, (* JZ L1 *)
|
||
(* L2: *)
|
||
1104H, (* RRA R4 *)
|
||
8315H, (* SUB #1, R5 *)
|
||
2000H + 400H - 3; (* JNZ L2 *)
|
||
(* L1: *)
|
||
|
||
Компилятор автоматически добавляет к такой процедуре команду RET.
|
||
Способ передачи параметров и результата не изменяется.
|
||
|
||
Кодовые процедуры можно использовать также и для добавления в программу
|
||
константных данных:
|
||
|
||
PROCEDURE [code] sqr
|
||
0, 1, 4, 9, 16, 25, 36, 49, 64, 81;
|
||
|
||
Получить адрес такой "процедуры": SYSTEM.ADR(sqr).
|
||
Получить адрес n-го машинного слова: SYSTEM.ADR(sqr) + n * 2.
|
||
|
||
Чтобы использовать кодовые процедуры, необходимо импортировать псевдомодуль
|
||
SYSTEM.
|
||
|
||
------------------------------------------------------------------------------
|
||
Обработка прерываний
|
||
|
||
При появлении запроса на прерывание, процессор:
|
||
- помещает в стэк значение регистра PC
|
||
- помещает в стэк значение регистра SR
|
||
- очищает регистр SR
|
||
- выполняет переход по адресу IV[priority], где
|
||
IV - таблица векторов прерываний,
|
||
priority - приоритет прерывания (номер элемента в таблице IV) (0..30)
|
||
|
||
Компилятор генерирует код обработки прерываний:
|
||
|
||
; IV[0] = адрес следующей команды
|
||
PUSH #0 ; поместить в стэк приоритет прерывания
|
||
JMP Label ; перейти к обработчику
|
||
|
||
; IV[1] = адрес следующей команды
|
||
PUSH #1 ; поместить в стэк приоритет прерывания
|
||
JMP Label ; перейти к обработчику
|
||
|
||
...
|
||
; IV[priority] = адрес следующей команды
|
||
PUSH #priority ; поместить в стэк приоритет прерывания
|
||
JMP Label ; перейти к обработчику
|
||
|
||
...
|
||
; IV[30] = адрес следующей команды
|
||
PUSH #30 ; поместить в стэк приоритет прерывания
|
||
|
||
Label:
|
||
MOV SP, R15 ; настроить R15 на структуру данных прерывания (см. далее)
|
||
PUSH R4 ; сохранить рабочие регистры (R4 - R7)
|
||
...
|
||
PUSH R7
|
||
PUSH R15 ; передать параметр interrupt в обработчик (см. далее)
|
||
PUSH @R15 ; передать параметр priority в обработчик (см. далее)
|
||
CALL int ; вызвать обработчик (см. далее)
|
||
ADD #4, SP ; удалить из стэка параметры обработчика
|
||
POP R7 ; восстановить рабочие регистры (R7 - R4)
|
||
...
|
||
POP R4
|
||
ADD #2, SP ; удалить из стэка значение priority
|
||
RETI ; возврат из прерывания (восстановить SR и PC)
|
||
|
||
------------------------------------------------------------------------------
|
||
Обработка ошибок
|
||
|
||
В случае возникновения ошибки при выполнении программы, будет вызван общий
|
||
обработчик ошибок, который:
|
||
|
||
- запрещает прерывания
|
||
- сбрасывает стэк (во избежание переполнения в процессе обработки ошибки)
|
||
- передает параметры в пользовательский обработчик (см. далее)
|
||
- вызывает пользовательский обработчик (если он назначен)
|
||
- повторно запрещает прерывания
|
||
- выключает CPU и все тактовые сигналы
|
||
|
||
Если выключать CPU не требуется, то пользовательский обработчик может,
|
||
например, перезапустить программу.
|
||
|
||
------------------------------------------------------------------------------
|
||
Инициализация и финализация программы
|
||
|
||
В начало программы компилятор вставляет код, который:
|
||
- инициализирует регистры SP и R14
|
||
- выключает сторожевой таймер
|
||
- назначает пустой обработчик прерываний
|
||
- сбрасывает обработчик ошибок
|
||
|
||
В конец программы добавляет команду
|
||
BIS #16, SR; выключить CPU
|
||
|
||
------------------------------------------------------------------------------
|
||
Структура ОЗУ (RAM)
|
||
|
||
начало -> | спец. переменные | глобальные переменные | куча/стэк | <- конец
|
||
|
||
Компилятор поддерживает размер ОЗУ 128..2048 байт. В нижних адресах
|
||
располагаются специальные переменные, и далее пользовательские глобальные
|
||
переменные. Оставшаяся часть памяти отводится для кучи и стэка (не менее 64
|
||
байта). При старте программы, в регистр R14 записывается адрес начала области
|
||
кучи/стэка, а регистр SP настраивается на конец ОЗУ (начало_ОЗУ + размер_ОЗУ).
|
||
При выделении памяти процедурой NEW, значение регистра R14 увеличивается (если
|
||
есть свободная память). Таким образом, стэк и куча растут навстречу друг
|
||
другу. Проверка переполнения стэка не производится.
|
||
|
||
------------------------------------------------------------------------------
|
||
Структура ПЗУ (RОM)
|
||
|
||
начало -> |код|свободная область|спец. данные|векторы прерываний| <- конец
|
||
|
||
Компилятор поддерживает размер ПЗУ 2048..24576 байт. В верхних адресах
|
||
располагается таблица векторов прерываний (64 байта), адреса 0FFC0H..0FFFFH.
|
||
Непосредственно перед ней размещаются специальные данные. Программный
|
||
код начинается с адреса (10000H - размер_ПЗУ), этот адрес является также и
|
||
точкой входа в программу. Между кодом и спец. данными может оставаться
|
||
свободное пространство. Если размер ПЗУ больше, чем указан при компиляции,
|
||
то перед кодом будет свободная область. Таким способом можно зарезервировать
|
||
нижние сегменты флэш-памяти для записи во время выполнения программы.
|
||
|
||
==============================================================================
|
||
MODULE MSP430
|
||
|
||
CONST
|
||
|
||
биты регистра SR:
|
||
|
||
GIE = {3}
|
||
CPUOFF = {4}
|
||
OSCOFF = {5}
|
||
SCG0 = {6}
|
||
SCG1 = {7}
|
||
|
||
|
||
TYPE
|
||
|
||
TInterrupt = RECORD priority: INTEGER; sr: SET; pc: INTEGER END
|
||
структура данных прерывания
|
||
|
||
priority - приоритет прерывания:
|
||
|
||
адрес приоритет
|
||
0FFFEH 31
|
||
0FFFCH 30
|
||
0FFFAH 29
|
||
...
|
||
0FFC0H 0
|
||
|
||
sr - сохраненное значение регистра SR
|
||
pc - сохраненное значение регистра PC
|
||
|
||
|
||
TTrapProc = PROCEDURE (modNum, modName, err, line: INTEGER);
|
||
Процедура-обработчик ошибок.
|
||
|
||
modNum - номер модуля (в отчете о компиляции:
|
||
compiling (modNum) "modName" )
|
||
modName - адрес имени модуля
|
||
err - номер ошибки
|
||
line - номер строки
|
||
|
||
|
||
TIntProc = PROCEDURE (priority: INTEGER; interrupt: TInterrupt)
|
||
Процедура-обработчик прерываний.
|
||
|
||
priority - приоритет прерывания
|
||
interrupt - структура данных прерывания
|
||
|
||
|
||
PROCEDURE SetTrapProc (TrapProc: TTrapProc)
|
||
Назначить обработчик ошибок.
|
||
|
||
|
||
PROCEDURE SetIntProc (IntProc: TIntProc)
|
||
Назначить обработчик прерываний.
|
||
|
||
Нельзя вызывать эту процедуру с параметром NIL, т. к. для экономии
|
||
тактов, значение адреса обработчика прерываний не проверяется на NIL.
|
||
|
||
|
||
PROCEDURE Restart
|
||
Перезапустить программу.
|
||
При этом: очищается регистр SR, повторно выполняется код инициализации
|
||
программы (см. выше). Всё прочее состояние ОЗУ и регистров устройств
|
||
сохраняется.
|
||
|
||
|
||
PROCEDURE SetIntPC (interrupt: TInterrupt; NewPC: INTEGER)
|
||
interrupt.pc := NewPC
|
||
После возврата из прерывания, регистр PC получит значение NewPC.
|
||
|
||
|
||
PROCEDURE SetIntSR (interrupt: TInterrupt; NewSR: SET)
|
||
interrupt.sr := NewSR
|
||
После возврата из прерывания, регистр SR получит значение NewSR.
|
||
|
||
|
||
PROCEDURE DInt
|
||
Запретить прерывания.
|
||
|
||
|
||
PROCEDURE EInt
|
||
Разрешить прерывания.
|
||
|
||
|
||
PROCEDURE CpuOff
|
||
Выключить CPU (установить бит CPUOFF регистра SR).
|
||
|
||
|
||
PROCEDURE Halt
|
||
Запретить прерывания, выключить CPU и все тактовые сигналы.
|
||
|
||
|
||
PROCEDURE SetSR (bits: SET)
|
||
Установить биты bits регистра SR.
|
||
|
||
|
||
PROCEDURE ClrSR (bits: SET)
|
||
Сбросить биты bits регистра SR.
|
||
|
||
|
||
PROCEDURE GetFreeFlash (VAR address, size: INTEGER)
|
||
Получить адрес и размер свободной области Flash/ROM
|
||
(между кодом и данными).
|
||
|
||
|
||
PROCEDURE Delay (n: INTEGER)
|
||
Задержка выполнения программы на 1000*n тактов,
|
||
но не менее чем на 2000 тактов.
|
||
|
||
|
||
============================================================================== |