| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- Компилятор языка программирования 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
- -tab <width> размер табуляции (используется для вычисления координат в
- исходном коде), по умолчанию - 4
- -nochk <"ptibcwra"> отключить проверки при выполнении
- -lower разрешить ключевые слова и встроенные идентификаторы в
- нижнем регистре (по умолчанию)
- -upper только верхний регистр для ключевых слов и встроенных
- идентификаторов
- -def <имя> задать символ условной компиляции
- -uses вывести список импортированных модулей
- параметр -nochk задается в виде строки из символов:
- "p" - указатели
- "t" - типы
- "i" - индексы
- "b" - неявное приведение INTEGER к BYTE
- "c" - диапазон аргумента функции CHR
- "s" - переполнение стэка
- "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.
- ------------------------------------------------------------------------------
- Отличия от оригинала
- 1. Расширен псевдомодуль SYSTEM
- 2. В идентификаторах допускается символ "_"
- 3. Усовершенствован оператор CASE (добавлены константные выражения в
- метках вариантов и необязательная ветка ELSE)
- 4. Расширен набор стандартных процедур
- 5. Семантика охраны/проверки типа уточнена для нулевого указателя
- 6. Добавлены однострочные комментарии (начинаются с пары символов "//")
- 7. Разрешено наследование от типа-указателя
- 8. "Строки" можно заключать также в одиночные кавычки: 'строка'
- 9. Добавлена операция конкатенации строковых и символьных констант
- 10. Добавлены кодовые процедуры
- 11. Не реализована вещественная арифметика
- 12. Возможен импорт модулей с указанием пути и имени файла
- 13. Добавлен специальный синтаксис для условной компиляции (см. CC.txt)
- 14. Имя процедуры в конце объявления (после END) необязательно
- 15. Разрешено использовать нижний регистр для ключевых слов
- ------------------------------------------------------------------------------
- Особенности реализации
- 1. Основные типы
- Тип Диапазон значений Размер, байт
- INTEGER -32768 .. 32767 2
- CHAR символ ASCII (0X .. 0FFX) 1
- BOOLEAN FALSE, TRUE 1
- SET множество из целых чисел {0 .. 15} 2
- BYTE 0 .. 255 1
- 2. Максимальная длина идентификаторов - 255 символов
- 3. Максимальная длина строковых констант - 511 символов (UTF-8)
- 4. Максимальная размерность открытых массивов - 5
- 5. Процедура NEW заполняет нулями выделенный блок памяти
- 6. Локальные переменные инициализируются нулями
- 7. В отличие от многих Oberon-реализаций, сборщик мусора и динамическая
- модульность отсутствуют
- 8. Тип BYTE в выражениях всегда приводится к INTEGER
- 9. Контроль переполнения значений выражений не производится
- ------------------------------------------------------------------------------
- Псевдомодуль SYSTEM
- Псевдомодуль SYSTEM содержит низкоуровневые и небезопасные процедуры,
- ошибки при использовании процедур псевдомодуля SYSTEM могут привести к
- повреждению данных времени выполнения и аварийному завершению программы.
- PROCEDURE ADR(v: любой тип): INTEGER
- v - переменная или процедура;
- возвращает адрес v
- PROCEDURE SADR(x: строковая константа): INTEGER
- возвращает адрес x
- PROCEDURE VAL(v: любой тип; T): T
- v - переменная;
- интерпретирует v, как переменную типа T
- 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 Case {"|" Case}
- [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 не может быть константой.
- ------------------------------------------------------------------------------
- Импорт модулей с указанием пути и имени файла
- Примеры:
- IMPORT Math IN "./lib/math.ob07"; (* относительно текущего модуля *)
- IMPORT M1 IN "C:\lib\math.ob07"; (* абсолютный путь *)
- ------------------------------------------------------------------------------
- Использование регистров общего назначения R4 - R15
- R4 - R7: регистровый стэк (промежуточные значения выражений),
- волатильные регистры (не требуют сохранения)
- R8 - R11: не используются компилятором, могут использоваться в кодовых
- процедурах, неволатильные (требуется сохранять перед
- использованием и восстанавливать после)
- R12 - R14: зарезервированы для возможного специального назначения в
- будущем
- R15: указатель кучи, используется в стандартной процедуре NEW, а
- также для контроля переполнения стэка
- ------------------------------------------------------------------------------
- Вызов процедур и кадр стэка
- Правила вызова похожи на соглашение 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:
- PUSH R4 ; сохранить рабочие регистры (R4 - R7)
- ...
- PUSH R7
- MOV SP, R4 ; настроить R4 на структуру данных прерывания (см. далее)
- ADD #8, R4
- PUSH R4 ; передать параметр interrupt в обработчик (см. далее)
- PUSH @R4 ; передать параметр priority в обработчик (см. далее)
- CALL int ; вызвать обработчик (см. далее)
- ADD #4, SP ; удалить из стэка параметры обработчика
- POP R7 ; восстановить рабочие регистры (R7 - R4)
- ...
- POP R4
- ADD #2, SP ; удалить из стэка значение priority
- RETI ; возврат из прерывания (восстановить SR и PC)
- ------------------------------------------------------------------------------
- Обработка ошибок
- В случае возникновения ошибки при выполнении программы, будет вызван общий
- обработчик ошибок, который:
- - запрещает прерывания
- - сбрасывает стэк (во избежание переполнения в процессе обработки ошибки)
- - передает параметры в пользовательский обработчик (см. далее)
- - вызывает пользовательский обработчик (если он назначен)
- - повторно запрещает прерывания
- - выключает CPU и все тактовые сигналы
- Если выключать CPU не требуется, то пользовательский обработчик может,
- например, перезапустить программу.
- Коды ошибок:
- 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)
- 10 переполнение стэка
- 11 неявное приведение x:INTEGER к v:BYTE, если (x < 0) OR (x > 255)
- ------------------------------------------------------------------------------
- Инициализация и финализация программы
- В начало программы компилятор вставляет код, который:
- - инициализирует регистры SP и R15
- - выключает сторожевой таймер
- - назначает пустой обработчик прерываний и пустой обработчик ошибок
- В конец программы добавляет команду
- BIS #16, SR; выключить CPU
- ------------------------------------------------------------------------------
- Структура ОЗУ (RAM)
- начало -> | куча/стэк | спец. переменные | глобальные переменные | <- конец
- Компилятор поддерживает размер ОЗУ 128..2048 байт. В верхних адресах
- располагаются пользовательские глобальные переменные и скрытые специальные
- переменные. Оставшаяся часть памяти отводится для кучи и стэка (не менее 40
- байт, минимально необходимо для обработки прерываний и ошибок). При старте
- программы, в регистр R15 записывается адрес начала области кучи/стэка, а
- регистр SP настраивается на конец этой области (адрес спец. переменных). При
- выделении памяти процедурой NEW, значение регистра R15 увеличивается (если
- есть свободная память). Таким образом, стэк и куча растут навстречу друг
- другу.
- Проверка переполнения стэка производится только при входе в процедуру, если
- эта проверка не отключена при компиляции (-nochk s).
- Проверка стэка не производится:
- - в процессе выполнения процедуры
- - при входе в кодовую процедуру
- - при выполнении тела модуля
- ------------------------------------------------------------------------------
- Структура ПЗУ (ROM)
- начало -> | свободная область | код | данные | векторы прерываний | <- конец
- Компилятор поддерживает размер ПЗУ 2048..24576 байт. В верхних адресах
- располагается таблица векторов прерываний (64 байта), адреса 0FFC0H..0FFFFH.
- Непосредственно перед ней размещаются данные (таблица типов, строки,
- множества) и перед данными - программный код. Адрес начала кода совпадает с
- точкой входа в программу (вектор сброса). Если размер ПЗУ больше, чем размер
- программы, то перед кодом останется свободная область.
- ==============================================================================
- 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)
- Назначить обработчик прерываний.
- 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 Delay (n: INTEGER)
- Задержка выполнения программы на 1000*n тактов,
- но не менее чем на 2000 тактов.
- ==============================================================================
|