﻿        Компилятор языка программирования Oberon-07/16 для
            микроконтроллеров STM32 Cortex-M3.

------------------------------------------------------------------------------
        Параметры командной строки

  Вход - текстовые файлы модулей с расширением ".ob07", кодировка ANSI или
UTF-8 с BOM-сигнатурой.
  Выход - hex-файл прошивки.
  Параметры:
  1) имя главного модуля
  2) "stm32cm3"
  3) необязательные параметры-ключи
      -out <file_name> имя результирующего файла; по умолчанию,
          совпадает с именем главного модуля, но с расширением ".hex"
      -ram <size> размер ОЗУ в килобайтах (4 - 65536) по умолчанию 4
      -rom <size> размер ПЗУ в килобайтах (16 - 65536) по умолчанию 16
      -tab <width> размер табуляции (используется для вычисления координат в
          исходном коде), по умолчанию - 4
      -nochk <"ptibcwra"> отключить проверки при выполнении
      -lower разрешить ключевые слова и встроенные идентификаторы в
          нижнем регистре (по умолчанию)
      -upper только верхний регистр для ключевых слов и встроенных
          идентификаторов
      -def <имя> задать символ условной компиляции
      -uses вывести список импортированных модулей

      параметр -nochk задается в виде строки из символов:
      "p" - указатели
      "t" - типы
      "i" - индексы
      "b" - неявное приведение INTEGER к BYTE
      "c" - диапазон аргумента функции CHR
      "w" - диапазон аргумента функции WCHR
      "r" - эквивалентно "bcw"
      "a" - все проверки

      Порядок символов может быть любым. Наличие в строке того или иного
      символа отключает соответствующую проверку.

      Например: -nochk it - отключить проверку индексов и охрану типа.
      -nochk a - отключить все отключаемые проверки.

  Например:

  Compiler.exe "C:\example.ob07" stm32cm3 -ram 32 -rom 256 -nochk pti
  Compiler.exe "C:\example.ob07" stm32cm3 -out "C:\Ex1.hex" -ram 8 -rom 32

  В случае успешной компиляции, компилятор передает код завершения 0, иначе 1.

------------------------------------------------------------------------------
        Отличия от оригинала

 1.     Расширен псевдомодуль SYSTEM
 2.     В идентификаторах допускается символ "_"
 3.     Усовершенствован оператор CASE (добавлены константные выражения в
        метках вариантов и необязательная ветка ELSE)
 4.     Расширен набор стандартных процедур
 5.     Семантика охраны/проверки типа уточнена для нулевого указателя
 6.     Добавлены однострочные комментарии (начинаются с пары символов "//")
 7.     Разрешено наследование от типа-указателя
 8.     "Строки" можно заключать также в одиночные кавычки: 'строка'
 9.     Добавлен тип WCHAR
10.     Добавлена операция конкатенации строковых и символьных констант
11.     Добавлены кодовые процедуры
12.     Возможен импорт модулей с указанием пути и имени файла
13.     Добавлен специальный синтаксис для условной компиляции (см. CC.txt)
14.     Имя процедуры в конце объявления (после END) необязательно
15.     Разрешено использовать нижний регистр для ключевых слов

------------------------------------------------------------------------------
        Особенности реализации

1.      Основные типы

          Тип              Диапазон значений               Размер, байт

        INTEGER       -2147483648 .. 2147483647                 4
        REAL          1.17E-38 .. 3.40E+38                      4
        CHAR          символ ASCII (0X .. 0FFX)                 1
        BOOLEAN       FALSE, TRUE                               1
        SET           множество из целых чисел {0 .. 31}        4
        BYTE          0 .. 255                                  1
        WCHAR         символ юникода (0X .. 0FFFFX)             2

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: строковая константа (CHAR UTF-8)): INTEGER
                возвращает адрес x

        PROCEDURE WSADR(x: строковая константа (WCHAR)): INTEGER
                возвращает адрес x

        PROCEDURE VAL(v: любой тип; T): T
                v - переменная;
                интерпретирует v, как переменную типа T

        PROCEDURE SIZE(T): INTEGER
                возвращает размер типа T

        PROCEDURE TYPEID(T): INTEGER
                T - тип-запись или тип-указатель,
                возвращает номер типа в таблице типов-записей

        PROCEDURE INF(): REAL
                возвращает специальное вещественное значение "бесконечность"

        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, WCHAR, SYSTEM.CARD32)
                Эквивалентно
                SYSTEM.MOVE(a, SYSTEM.ADR(x), 1)

        PROCEDURE GET16(a: INTEGER;
                        VAR x: INTEGER, SET, WCHAR, SYSTEM.CARD32)
                Эквивалентно
                SYSTEM.MOVE(a, SYSTEM.ADR(x), 2)

        PROCEDURE GET32(a: INTEGER; VAR x: INTEGER, SET, SYSTEM.CARD32)
                Эквивалентно
                SYSTEM.MOVE(a, SYSTEM.ADR(x), 4)

        PROCEDURE PUT(a: INTEGER; x: любой основной тип, PROCEDURE, POINTER)
                Память[a] := x;
                Если x: BYTE или x: WCHAR, то значение x будет расширено
                до 32 бит, для записи байтов использовать SYSTEM.PUT8,
                для WCHAR -- SYSTEM.PUT16

        PROCEDURE PUT8(a: INTEGER;
                       x: INTEGER, SET, BYTE, CHAR, WCHAR, SYSTEM.CARD32)
                Память[a] := младшие 8 бит (x)

        PROCEDURE PUT16(a: INTEGER;
                        x: INTEGER, SET, BYTE, CHAR, WCHAR, SYSTEM.CARD32)
                Память[a] := младшие 16 бит (x)

        PROCEDURE PUT32(a: INTEGER;
                        x: INTEGER, SET, BYTE, CHAR, WCHAR, SYSTEM.CARD32)
                Память[a] := младшие 32 бит (x)

        PROCEDURE CODE(hword1, hword2,... : INTEGER)
                Вставка машинного кода,
                hword1, hword2 ... - константы в диапазоне 0..65535,
                например:
                SYSTEM.CODE(0BF30H) (* wfi *)

  Также, в модуле SYSTEM определен тип CARD32 (4 байта). Для типа CARD32 не
допускаются никакие явные операции, за исключением присваивания.

  Функции псевдомодуля 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
отсутствует, то программа прерывается с ошибкой времени выполнения.

------------------------------------------------------------------------------
        Тип WCHAR

  Тип WCHAR добавлен в язык для удобной поддежки юникода. Для типов WCHAR и
ARRAY OF WCHAR допускаются все те же операции, как для типов CHAR и
ARRAY OF CHAR, за исключением встроенной процедуры CHR, которая возвращает
только тип CHAR. Для получения значения типа WCHAR, следует использовать
процедуру WCHR вместо CHR. Для правильной работы с типом, необходимо сохранять
исходный код в кодировке UTF-8 с BOM.

------------------------------------------------------------------------------
        Конкатенация строковых и символьных констант

  Допускается конкатенация ("+") константных строк и символов типа 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/WCHAR; VAR v: ARRAY OF CHAR/WCHAR);
                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/WCHAR): INTEGER
                Длина 0X-завершенной строки s, без учета символа 0X.
                Если символ 0X отсутствует, функция возвращает длину
                массива s. s не может быть константой.

        WCHR (n: INTEGER): WCHAR
                Преобразование типа, аналогично CHR(n: INTEGER): CHAR

------------------------------------------------------------------------------
        Импорт модулей с указанием пути и имени файла

Примеры:

    IMPORT Math IN "./lib/math.ob07"; (* относительно текущего модуля *)

    IMPORT M1 IN "C:\lib\math.ob07"; (* абсолютный путь *)

------------------------------------------------------------------------------
        Плавающая точка

  Компилятор предназначен для устройств на ядре Cortex-M3 и, возможно, после
небольшой доработки, также для Cortex-M0. В таких микроконтроллерах нет
встроенной поддержки плавающей точки, поэтому операции с вещественными числами
одинарной точности эмулируются (модуль lib/STM32CM3/FPU.ob07). Компилятор
подставляет вызовы процедур в месте операций с вещественными числами.

  Сохраняется возможность доработки компилятора в будущем для устройств со
встроенной поддержкой вещественных чисел.

------------------------------------------------------------------------------
        Использование регистров общего назначения R0 - R12

        R0 - R3:  регистровый стэк (промежуточные значения выражений),
                  волатильные регистры (не требуют сохранения)

        R4 - R7:  не используются компилятором, могут использоваться в кодовых
                  процедурах, неволатильные (требуется сохранять перед
                  использованием и восстанавливать после)

        R8 - R12: зарезервированы для возможного специального назначения в
                  будущем

------------------------------------------------------------------------------
        Вызов процедур и кадр стэка

  Правила вызова похожи на соглашение cdecl (x86):
  - параметры передаются через стэк справа налево
  - результат, если есть, передается через регистр R0
  - вызывающая процедура очищает стэк

  Состояние стэка при выполнении процедуры:

  меньшие адреса <- |var3|var2|var1|LR|arg1|arg2|arg3| -> бОльшие адреса

  LR   - сохраненный регистр LR (адрес возврата)
  argX - параметры в порядке объявления (слева направо)
  varX - локальные переменные в порядке использования в процедуре

  Размер каждого элемента в стэке (кроме локальных переменных структурных
  типов) - 1 машинное слово (4 байта). Структурные переменные (массивы и
  записи) занимают место в стэке в соответствии с их размером (с учетом
  выравнивания).

  Размещение локальных переменных зависит от их размеров и порядка
  использования, и в общем случае неопределенно. Если переменная не
  используется явно, то компилятор не выделяет для нее место в стэке.

------------------------------------------------------------------------------
        Скрытые параметры процедур

  Некоторые процедуры могут иметь скрытые параметры, они отсутствуют в списке
формальных параметров, но учитываются компилятором при трансляции вызовов.
Это возможно в следующих случаях:

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 "имя" в конце процедуры не ставятся.
  МашКом - целочисленная константа [0..65535] (в том числе и константное
  выражение).

  Примеры:

  PROCEDURE [code] WFI
      0BF30H; (* wfi *)

  (* сумма квадратов (a*a + b*b) -> r0 *)
  PROCEDURE [code] SqrSum (a, b: INTEGER): INTEGER
      0B430H, (* push {r4, r5}    *) (* сохранить все используемые регистры,
                                        кроме r0, r1, r2, r3 *)
      09C02H, (* ldr r4, [sp, 8]  *) (* r4 <- a *)
      09D03H, (* ldr r5, [sp, 12] *) (* r5 <- b *)
      04364H, (* muls r4, r4      *) (* r4 := r4 * r4 *)
      0436DH, (* muls r5, r5      *) (* r5 := r5 * r5 *)
      01960H, (* adds r0, r4, r5  *) (* r0 := r4 + r5; результат в r0 *)
      0BC30H; (* pop {r4, r5}     *) (* восстановить регистры *)

  Компилятор автоматически добавляет к такой процедуре команду возврата
(bx LR). Способ передачи параметров и результата не изменяется. Регистр LR,
при входе в процедуру не сохраняется.

  Чтобы использовать кодовые процедуры, необходимо импортировать псевдомодуль
SYSTEM.

------------------------------------------------------------------------------
        Обработка прерываний

  При возникновении прерывания, будет вызван обработчик (если он объявлен).
Объявление обработчика:

    PROCEDURE handler_name [iv]; (* процедура без параметров *)

iv - целочисленная константа (константное выражение), номер вектора прерывания
в таблице векторов, iv >= 2:

     0       начальное значение SP
     1       сброс
    ...
    15       SysTick
    ...
    59       TIM6
    60       TIM7
    ...

например:

    (* обработчик прерываний от TIM6 *)
    PROCEDURE tim6 [59];
    BEGIN
        (* код обработки *)
    END tim6;

  Также, можно объявить общий обработчик (iv = 0), который будет вызван, если
не назначен индивидуальный. Общий обработчик получает параметр - номер вектора
прерывания. По значению этого параметра, обработчик должен определить источник
прерывания и выполнить соответствующие действия:

    PROCEDURE handler (iv: INTEGER) [0];
    BEGIN
        IF iv = 59 THEN
            (* TIM6 *)
        ELSIF iv = 60 THEN
            (* TIM7 *)
        ELSIF ....
        ....
        END
    END handler;

------------------------------------------------------------------------------
        Обработка ошибок

  В случае возникновения ошибки при выполнении программы, будет вызван
пользовательский обработчик (если он объявлен). Перед вызовом обработчика,
будут запрещены прерывания.

Объявление обработчика ошибок:

    PROCEDURE trap (modNum, modName, err, line: INTEGER) [1];
    BEGIN
    END trap;

    где,
        modNum  - номер модуля (в отчете о компиляции:
                  compiling (modNum) "modName" )
        modName - адрес имени модуля
        err     - код ошибки
        line    - номер строки

Коды ошибок:

 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       WCHR(x), если (x < 0) OR (x > 65535)
11       неявное приведение x:INTEGER к v:BYTE, если (x < 0) OR (x > 255)

После возврата из обработчика, программа будет перезапущена.

------------------------------------------------------------------------------