From ce8fecbc6b3514c85b38da9f8b8dc42bdafd3947 Mon Sep 17 00:00:00 2001 From: Anton Krotov Date: Fri, 3 Sep 2021 17:21:37 +0000 Subject: [PATCH] Oberon07: v1.53 git-svn-id: svn://kolibrios.org@9177 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/oberon07/Compiler | Bin 302008 -> 302392 bytes programs/develop/oberon07/Compiler.exe | Bin 303616 -> 304128 bytes programs/develop/oberon07/Compiler.kex | Bin 73874 -> 74115 bytes programs/develop/oberon07/doc/x86.txt | 826 +-- programs/develop/oberon07/doc/x86_64.txt | 788 +-- .../develop/oberon07/source/Compiler.ob07 | 43 +- programs/develop/oberon07/source/HEX.ob07 | 232 +- programs/develop/oberon07/source/IL.ob07 | 2340 ++++---- programs/develop/oberon07/source/MSP430.ob07 | 3558 ++++++------ .../develop/oberon07/source/MSP430RTL.ob07 | 1340 ++--- programs/develop/oberon07/source/PROG.ob07 | 2 +- programs/develop/oberon07/source/RVMxI.ob07 | 2854 +++++----- programs/develop/oberon07/source/TARGETS.ob07 | 304 +- programs/develop/oberon07/source/TEXTDRV.ob07 | 26 +- programs/develop/oberon07/source/THUMB.ob07 | 4930 ++++++++--------- programs/develop/oberon07/source/UTILS.ob07 | 4 +- 16 files changed, 8639 insertions(+), 8608 deletions(-) diff --git a/programs/develop/oberon07/Compiler b/programs/develop/oberon07/Compiler index a36067d15dbebd73a52b2f7239f7628a6007c533..6ffa7ec6cb98fe6e5ee96b602f23aaf1f2478a33 100644 GIT binary patch delta 38250 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 delta 37012 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 literal 73874 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 имя результирующего файла; по умолчанию, - совпадает с именем главного модуля, но с другим расширением - (соответствует типу исполняемого файла) - -stk размер стэка в мегабайтах (по умолчанию 2 Мб, - допустимо от 1 до 32 Мб) - -nochk <"ptibcwra"> отключить проверки при выполнении (см. ниже) - -lower разрешить ключевые слова и встроенные идентификаторы в - нижнем регистре - -def <имя> задать символ условной компиляции - -ver версия программы (только для kosdll) - - параметр -nochk задается в виде строки из символов: - "p" - указатели - "t" - типы - "i" - индексы - "b" - неявное приведение INTEGER к BYTE - "c" - диапазон аргумента функции CHR - "w" - диапазон аргумента функции WCHR - "r" - эквивалентно "bcw" - "a" - все проверки - - Порядок символов может быть любым. Наличие в строке того или иного - символа отключает соответствующую проверку. - - Например: -nochk it - отключить проверку индексов и охрану типа. - -nochk a - отключить все отключаемые проверки. - - Например: - - Compiler.exe "C:\example.ob07" win32con -out "C:\example.exe" -stk 1 - Compiler.exe "C:\example.ob07" win32dll -out "C:\example.dll" - Compiler.exe "C:\example.ob07" win32gui -out "C:\example.exe" -stk 4 - Compiler.exe "C:\example.ob07" win32con -out "C:\example.exe" -nochk pti - Compiler.kex "/tmp0/1/example.ob07" kosexe -out "/tmp0/1/example.kex" -stk 4 - Compiler.kex "/tmp0/1/example.ob07" kosdll -out "/tmp0/1/mydll.obj" -ver 2.7 - Compiler.exe "C:\example.ob07" linux32exe -out "C:\example" -stk 1 -nochk a - - В случае успешной компиляции, компилятор передает код завершения 0, иначе 1. -При работе компилятора в KolibriOS, код завершения не передается. - ------------------------------------------------------------------------------- - Отличия от оригинала - -1. Расширен псевдомодуль SYSTEM -2. В идентификаторах допускается символ "_" -3. Добавлены системные флаги -4. Усовершенствован оператор CASE (добавлены константные выражения в - метках вариантов и необязательная ветка ELSE) -5. Расширен набор стандартных процедур -6. Семантика охраны/проверки типа уточнена для нулевого указателя -7. Добавлены однострочные комментарии (начинаются с пары символов "//") -8. Разрешено наследование от типа-указателя -9. Добавлен синтаксис для импорта процедур из внешних библиотек -10. "Строки" можно заключать также в одиночные кавычки: 'строка' -11. Добавлен тип WCHAR -12. Добавлена операция конкатенации строковых и символьных констант -13. Возможен импорт модулей с указанием пути и имени файла -14. Добавлен специальный синтаксис для условной компиляции (см. CC.txt) -15. Имя процедуры в конце объявления (после END) необязательно - ------------------------------------------------------------------------------- - Особенности реализации - -1. Основные типы - - Тип Диапазон значений Размер, байт - - INTEGER -2147483648 .. 2147483647 4 - REAL 4.94E-324 .. 1.70E+308 8 - 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. Контроль переполнения значений выражений не производится -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) -10 WCHR(x), если (x < 0) OR (x > 65535) -11 неявное приведение x:INTEGER к v:BYTE, если (x < 0) OR (x > 255) - ------------------------------------------------------------------------------- - Псевдомодуль SYSTEM - - Псевдомодуль SYSTEM содержит низкоуровневые и небезопасные процедуры, -ошибки при использовании процедур псевдомодуля SYSTEM могут привести к -повреждению данных времени выполнения и аварийному завершению программы. - - PROCEDURE ADR(v: любой тип): INTEGER - v - переменная или процедура; - возвращает адрес v - - PROCEDURE SADR(x: строковая константа (CHAR UTF-8)): INTEGER - возвращает адрес x - - PROCEDURE WSADR(x: строковая константа (WCHAR)): INTEGER - возвращает адрес x - - 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 COPY(VAR Source: любой тип; VAR Dest: любой тип; n: INTEGER) - Копирует n байт памяти из Source в Dest. - Эквивалентно - SYSTEM.MOVE(SYSTEM.ADR(Source), SYSTEM.ADR(Dest), n) - - PROCEDURE CODE(byte1, byte2,... : INTEGER) - Вставка машинного кода, - byte1, byte2 ... - константы в диапазоне 0..255, - например: - SYSTEM.CODE(08BH, 045H, 008H) (* mov eax, dword [ebp + 08h] *) - - Также, в модуле SYSTEM определен тип CARD32 (4 байта). Для типа CARD32 не -допускаются никакие явные операции, за исключением присваивания. - - Функции псевдомодуля SYSTEM нельзя использовать в константных выражениях. - ------------------------------------------------------------------------------- - Системные флаги - - При объявлении процедурных типов и глобальных процедур, после ключевого -слова PROCEDURE может быть указан флаг соглашения о вызове: [stdcall], -[cdecl], [ccall], [windows], [linux], [oberon]. Например: - - PROCEDURE [ccall] MyProc (x, y, z: INTEGER): INTEGER; - - Если указан флаг [ccall], то принимается соглашение cdecl, но перед -вызовом указатель стэка будет выравнен по границе 16 байт. - Флаг [windows] - синоним для [stdcall], [linux] - синоним для [ccall]. - Знак "-" после имени флага ([stdcall-], [linux-], ...) означает, что -результат процедуры можно игнорировать (не допускается для типа REAL). - Если флаг не указан или указан флаг [oberon], то принимается внутреннее -соглашение о вызове. - - При объявлении типов-записей, после ключевого слова RECORD может быть -указан флаг [noalign]. Флаг [noalign] означает отсутствие выравнивания полей -записи. Записи с системным флагом не могут иметь базовый тип и не могут быть -базовыми типами для других записей. - Для использования системных флагов, требуется импортировать 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. В ряде случаев это позволяет -значительно сократить частоту применения охраны типа. - ------------------------------------------------------------------------------- - Дополнительные стандартные процедуры - - DISPOSE (VAR v: любой_указатель) - Освобождает память, выделенную процедурой NEW для - динамической переменной v^, и присваивает переменной v - значение NIL. - - 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"; (* абсолютный путь *) - ------------------------------------------------------------------------------- - Импортированные процедуры - - Синтаксис импорта: - - PROCEDURE [callconv, library, function] proc_name (FormalParam): Type; - - - callconv -- соглашение о вызове - - library -- имя файла динамической библиотеки (строковая константа) - - function -- имя импортируемой процедуры (строковая константа), если - указана пустая строка, то имя процедуры = proc_name - - например: - - PROCEDURE [windows, "kernel32.dll", ""] ExitProcess (code: INTEGER); - - PROCEDURE [stdcall, "Console.obj", "con_exit"] exit (bCloseWindow: BOOLEAN); - - В конце объявления может быть добавлено (необязательно) "END proc_name;" - - Объявления импортированных процедур должны располагаться в глобальной - области видимости модуля после объявления переменных, вместе с объявлением - "обычных" процедур, от которых импортированные отличаются только отсутствием - тела процедуры. В остальном, к таким процедурам применимы те же правила: - их можно вызвать, присвоить процедурной переменной или получить адрес. - - Так как импортированная процедура всегда имеет явное указание соглашения о - вызове, то совместимый процедурный тип тоже должен быть объявлен с указанием - соглашения о вызове: - - VAR - ExitProcess: PROCEDURE [windows] (code: INTEGER); - con_exit: PROCEDURE [stdcall] (bCloseWindow: BOOLEAN); - - В KolibriOS импортировать процедуры можно только из библиотек, размещенных - в /rd/1/lib. Импортировать и вызывать функции инициализации библиотек - (lib_init, START) при этом не нужно. - - Для Linux, импортированные процедуры не реализованы. - ------------------------------------------------------------------------------- - Скрытые параметры процедур - - Некоторые процедуры могут иметь скрытые параметры, они отсутствуют в списке -формальных параметров, но учитываются компилятором при трансляции вызовов. -Это возможно в следующих случаях: - -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)) - - Скрытые параметры необходимо учитывать при связи с внешними приложениями. - ------------------------------------------------------------------------------- - Модуль RTL - - Все программы неявно используют модуль RTL. Компилятор транслирует -некоторые операции (проверка и охрана типа, сравнение строк, сообщения об -ошибках времени выполнения и др.) как вызовы процедур этого модуля. Не -следует вызывать эти процедуры явно. - Сообщения об ошибках времени выполнения выводятся в диалоговых окнах -(Windows), в терминал (Linux), на доску отладки (KolibriOS). - ------------------------------------------------------------------------------- - Модуль API - - Существуют несколько реализаций модуля API (для различных ОС). - Как и модуль RTL, модуль API не предназначен для прямого использования. -Он обеспечивает связь RTL с ОС. - ------------------------------------------------------------------------------- - Генерация исполняемых файлов DLL - - Разрешается экспортировать только процедуры. Для этого, процедура должна -находиться в главном модуле программы, и ее имя должно быть отмечено символом -экспорта ("*"). Нельзя экспортировать процедуры, которые импортированы из -других dll-библиотек. - - KolibriOS DLL всегда экспортируют идентификаторы "version" (версия -программы) и "lib_init" - адрес процедуры инициализации DLL: - - PROCEDURE [stdcall] lib_init (): INTEGER - -Эта процедура должна быть вызвана перед использованием DLL. + Компилятор языка программирования Oberon-07/16 для i486 + Windows/Linux/KolibriOS. +------------------------------------------------------------------------------ + + Параметры командной строки + + Вход - текстовые файлы модулей с расширением ".ob07", кодировка ANSI или +UTF-8 с BOM-сигнатурой. + Выход - испоняемый файл формата PE32, ELF или MENUET01/MSCOFF. + Параметры: + 1) имя главного модуля + 2) тип приложения + "win32con" - Windows console + "win32gui" - Windows GUI + "win32dll" - Windows DLL + "linux32exe" - Linux ELF-EXEC + "linux32so" - Linux ELF-SO + "kosexe" - KolibriOS + "kosdll" - KolibriOS DLL + + 3) необязательные параметры-ключи + -out имя результирующего файла; по умолчанию, + совпадает с именем главного модуля, но с другим расширением + (соответствует типу исполняемого файла) + -stk размер стэка в мегабайтах (по умолчанию 2 Мб, + допустимо от 1 до 32 Мб) + -tab размер табуляции (используется для вычисления координат в + исходном коде), по умолчанию - 4 + -nochk <"ptibcwra"> отключить проверки при выполнении (см. ниже) + -lower разрешить ключевые слова и встроенные идентификаторы в + нижнем регистре + -def <имя> задать символ условной компиляции + -ver версия программы (только для kosdll) + + параметр -nochk задается в виде строки из символов: + "p" - указатели + "t" - типы + "i" - индексы + "b" - неявное приведение INTEGER к BYTE + "c" - диапазон аргумента функции CHR + "w" - диапазон аргумента функции WCHR + "r" - эквивалентно "bcw" + "a" - все проверки + + Порядок символов может быть любым. Наличие в строке того или иного + символа отключает соответствующую проверку. + + Например: -nochk it - отключить проверку индексов и охрану типа. + -nochk a - отключить все отключаемые проверки. + + Например: + + Compiler.exe "C:\example.ob07" win32con -out "C:\example.exe" -stk 1 + Compiler.exe "C:\example.ob07" win32dll -out "C:\example.dll" + Compiler.exe "C:\example.ob07" win32gui -out "C:\example.exe" -stk 4 + Compiler.exe "C:\example.ob07" win32con -out "C:\example.exe" -nochk pti + Compiler.kex "/tmp0/1/example.ob07" kosexe -out "/tmp0/1/example.kex" -stk 4 + Compiler.kex "/tmp0/1/example.ob07" kosdll -out "/tmp0/1/mydll.obj" -ver 2.7 + Compiler.exe "C:\example.ob07" linux32exe -out "C:\example" -stk 1 -nochk a + + В случае успешной компиляции, компилятор передает код завершения 0, иначе 1. +При работе компилятора в KolibriOS, код завершения не передается. + +------------------------------------------------------------------------------ + Отличия от оригинала + +1. Расширен псевдомодуль SYSTEM +2. В идентификаторах допускается символ "_" +3. Добавлены системные флаги +4. Усовершенствован оператор CASE (добавлены константные выражения в + метках вариантов и необязательная ветка ELSE) +5. Расширен набор стандартных процедур +6. Семантика охраны/проверки типа уточнена для нулевого указателя +7. Добавлены однострочные комментарии (начинаются с пары символов "//") +8. Разрешено наследование от типа-указателя +9. Добавлен синтаксис для импорта процедур из внешних библиотек +10. "Строки" можно заключать также в одиночные кавычки: 'строка' +11. Добавлен тип WCHAR +12. Добавлена операция конкатенации строковых и символьных констант +13. Возможен импорт модулей с указанием пути и имени файла +14. Добавлен специальный синтаксис для условной компиляции (см. CC.txt) +15. Имя процедуры в конце объявления (после END) необязательно + +------------------------------------------------------------------------------ + Особенности реализации + +1. Основные типы + + Тип Диапазон значений Размер, байт + + INTEGER -2147483648 .. 2147483647 4 + REAL 4.94E-324 .. 1.70E+308 8 + 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. Контроль переполнения значений выражений не производится +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) +10 WCHR(x), если (x < 0) OR (x > 65535) +11 неявное приведение x:INTEGER к v:BYTE, если (x < 0) OR (x > 255) + +------------------------------------------------------------------------------ + Псевдомодуль SYSTEM + + Псевдомодуль SYSTEM содержит низкоуровневые и небезопасные процедуры, +ошибки при использовании процедур псевдомодуля SYSTEM могут привести к +повреждению данных времени выполнения и аварийному завершению программы. + + PROCEDURE ADR(v: любой тип): INTEGER + v - переменная или процедура; + возвращает адрес v + + PROCEDURE SADR(x: строковая константа (CHAR UTF-8)): INTEGER + возвращает адрес x + + PROCEDURE WSADR(x: строковая константа (WCHAR)): INTEGER + возвращает адрес x + + 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 COPY(VAR Source: любой тип; VAR Dest: любой тип; n: INTEGER) + Копирует n байт памяти из Source в Dest. + Эквивалентно + SYSTEM.MOVE(SYSTEM.ADR(Source), SYSTEM.ADR(Dest), n) + + PROCEDURE CODE(byte1, byte2,... : INTEGER) + Вставка машинного кода, + byte1, byte2 ... - константы в диапазоне 0..255, + например: + SYSTEM.CODE(08BH, 045H, 008H) (* mov eax, dword [ebp + 08h] *) + + Также, в модуле SYSTEM определен тип CARD32 (4 байта). Для типа CARD32 не +допускаются никакие явные операции, за исключением присваивания. + + Функции псевдомодуля SYSTEM нельзя использовать в константных выражениях. + +------------------------------------------------------------------------------ + Системные флаги + + При объявлении процедурных типов и глобальных процедур, после ключевого +слова PROCEDURE может быть указан флаг соглашения о вызове: [stdcall], +[cdecl], [ccall], [windows], [linux], [oberon]. Например: + + PROCEDURE [ccall] MyProc (x, y, z: INTEGER): INTEGER; + + Если указан флаг [ccall], то принимается соглашение cdecl, но перед +вызовом указатель стэка будет выравнен по границе 16 байт. + Флаг [windows] - синоним для [stdcall], [linux] - синоним для [ccall]. + Знак "-" после имени флага ([stdcall-], [linux-], ...) означает, что +результат процедуры можно игнорировать (не допускается для типа REAL). + Если флаг не указан или указан флаг [oberon], то принимается внутреннее +соглашение о вызове. + + При объявлении типов-записей, после ключевого слова RECORD может быть +указан флаг [noalign]. Флаг [noalign] означает отсутствие выравнивания полей +записи. Записи с системным флагом не могут иметь базовый тип и не могут быть +базовыми типами для других записей. + Для использования системных флагов, требуется импортировать 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. В ряде случаев это позволяет +значительно сократить частоту применения охраны типа. + +------------------------------------------------------------------------------ + Дополнительные стандартные процедуры + + DISPOSE (VAR v: любой_указатель) + Освобождает память, выделенную процедурой NEW для + динамической переменной v^, и присваивает переменной v + значение NIL. + + 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"; (* абсолютный путь *) + +------------------------------------------------------------------------------ + Импортированные процедуры + + Синтаксис импорта: + + PROCEDURE [callconv, library, function] proc_name (FormalParam): Type; + + - callconv -- соглашение о вызове + - library -- имя файла динамической библиотеки (строковая константа) + - function -- имя импортируемой процедуры (строковая константа), если + указана пустая строка, то имя процедуры = proc_name + + например: + + PROCEDURE [windows, "kernel32.dll", ""] ExitProcess (code: INTEGER); + + PROCEDURE [stdcall, "Console.obj", "con_exit"] exit (bCloseWindow: BOOLEAN); + + В конце объявления может быть добавлено (необязательно) "END proc_name;" + + Объявления импортированных процедур должны располагаться в глобальной + области видимости модуля после объявления переменных, вместе с объявлением + "обычных" процедур, от которых импортированные отличаются только отсутствием + тела процедуры. В остальном, к таким процедурам применимы те же правила: + их можно вызвать, присвоить процедурной переменной или получить адрес. + + Так как импортированная процедура всегда имеет явное указание соглашения о + вызове, то совместимый процедурный тип тоже должен быть объявлен с указанием + соглашения о вызове: + + VAR + ExitProcess: PROCEDURE [windows] (code: INTEGER); + con_exit: PROCEDURE [stdcall] (bCloseWindow: BOOLEAN); + + В KolibriOS импортировать процедуры можно только из библиотек, размещенных + в /rd/1/lib. Импортировать и вызывать функции инициализации библиотек + (lib_init, START) при этом не нужно. + + Для Linux, импортированные процедуры не реализованы. + +------------------------------------------------------------------------------ + Скрытые параметры процедур + + Некоторые процедуры могут иметь скрытые параметры, они отсутствуют в списке +формальных параметров, но учитываются компилятором при трансляции вызовов. +Это возможно в следующих случаях: + +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)) + + Скрытые параметры необходимо учитывать при связи с внешними приложениями. + +------------------------------------------------------------------------------ + Модуль RTL + + Все программы неявно используют модуль RTL. Компилятор транслирует +некоторые операции (проверка и охрана типа, сравнение строк, сообщения об +ошибках времени выполнения и др.) как вызовы процедур этого модуля. Не +следует вызывать эти процедуры явно. + Сообщения об ошибках времени выполнения выводятся в диалоговых окнах +(Windows), в терминал (Linux), на доску отладки (KolibriOS). + +------------------------------------------------------------------------------ + Модуль API + + Существуют несколько реализаций модуля API (для различных ОС). + Как и модуль RTL, модуль API не предназначен для прямого использования. +Он обеспечивает связь RTL с ОС. + +------------------------------------------------------------------------------ + Генерация исполняемых файлов DLL + + Разрешается экспортировать только процедуры. Для этого, процедура должна +находиться в главном модуле программы, и ее имя должно быть отмечено символом +экспорта ("*"). Нельзя экспортировать процедуры, которые импортированы из +других dll-библиотек. + + KolibriOS DLL всегда экспортируют идентификаторы "version" (версия +программы) и "lib_init" - адрес процедуры инициализации DLL: + + PROCEDURE [stdcall] lib_init (): INTEGER + +Эта процедура должна быть вызвана перед использованием DLL. Процедура всегда возвращает 1. \ No newline at end of file diff --git a/programs/develop/oberon07/doc/x86_64.txt b/programs/develop/oberon07/doc/x86_64.txt index c4a523f8cf..59c192db2e 100644 --- a/programs/develop/oberon07/doc/x86_64.txt +++ b/programs/develop/oberon07/doc/x86_64.txt @@ -1,394 +1,396 @@ - Компилятор языка программирования Oberon-07/16 для x86_64 - Windows/Linux ------------------------------------------------------------------------------- - - Параметры командной строки - - Вход - текстовые файлы модулей с расширением ".ob07", кодировка ANSI или -UTF-8 с BOM-сигнатурой. - Выход - испоняемый файл формата PE32+ или ELF64. - Параметры: - 1) имя главного модуля - 2) тип приложения - "win64con" - Windows64 console - "win64gui" - Windows64 GUI - "win64dll" - Windows64 DLL - "linux64exe" - Linux ELF64-EXEC - "linux64so" - Linux ELF64-SO - - 3) необязательные параметры-ключи - -out имя результирующего файла; по умолчанию, - совпадает с именем главного модуля, но с другим расширением - (соответствует типу исполняемого файла) - -stk размер стэка в мегабайтах (по умолчанию 2 Мб, - допустимо от 1 до 32 Мб) - -nochk <"ptibcwra"> отключить проверки при выполнении - -lower разрешить ключевые слова и встроенные идентификаторы в - нижнем регистре - -def <имя> задать символ условной компиляции - - параметр -nochk задается в виде строки из символов: - "p" - указатели - "t" - типы - "i" - индексы - "b" - неявное приведение INTEGER к BYTE - "c" - диапазон аргумента функции CHR - "w" - диапазон аргумента функции WCHR - "r" - эквивалентно "bcw" - "a" - все проверки - - Порядок символов может быть любым. Наличие в строке того или иного - символа отключает соответствующую проверку. - - Например: -nochk it - отключить проверку индексов и охрану типа. - -nochk a - отключить все отключаемые проверки. - - Например: - - Compiler.exe "C:\example.ob07" win64con -out "C:\example.exe" -stk 1 - Compiler.exe "C:\example.ob07" win64dll -out "C:\example.dll" -nochk pti - Compiler "source/Compiler.ob07" linux64exe -out "source/Compiler" -nochk a - - В случае успешной компиляции, компилятор передает код завершения 0, иначе 1. - ------------------------------------------------------------------------------- - Отличия от оригинала - -1. Расширен псевдомодуль SYSTEM -2. В идентификаторах допускается символ "_" -3. Добавлены системные флаги -4. Усовершенствован оператор CASE (добавлены константные выражения в - метках вариантов и необязательная ветка ELSE) -5. Расширен набор стандартных процедур -6. Семантика охраны/проверки типа уточнена для нулевого указателя -7. Добавлены однострочные комментарии (начинаются с пары символов "//") -8. Разрешено наследование от типа-указателя -9. Добавлен синтаксис для импорта процедур из внешних библиотек -10. "Строки" можно заключать также в одиночные кавычки: 'строка' -11. Добавлен тип WCHAR -12. Добавлена операция конкатенации строковых и символьных констант -13. Возможен импорт модулей с указанием пути и имени файла -14. Добавлен специальный синтаксис для условной компиляции (см. CC.txt) -15. Имя процедуры в конце объявления (после END) необязательно - ------------------------------------------------------------------------------- - Особенности реализации - -1. Основные типы - - Тип Диапазон значений Размер, байт - - INTEGER -9223372036854775808 .. 9223372036854775807 8 - REAL 4.94E-324 .. 1.70E+308 8 - CHAR символ ASCII (0X .. 0FFX) 1 - BOOLEAN FALSE, TRUE 1 - SET множество из целых чисел {0 .. 63} 8 - 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. Контроль переполнения значений выражений не производится -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) -10 WCHR(x), если (x < 0) OR (x > 65535) -11 неявное приведение x:INTEGER к v:BYTE, если (x < 0) OR (x > 255) - ------------------------------------------------------------------------------- - Псевдомодуль SYSTEM - - Псевдомодуль SYSTEM содержит низкоуровневые и небезопасные процедуры, -ошибки при использовании процедур псевдомодуля SYSTEM могут привести к -повреждению данных времени выполнения и аварийному завершению программы. - - PROCEDURE ADR(v: любой тип): INTEGER - v - переменная или процедура; - возвращает адрес v - - PROCEDURE SADR(x: строковая константа (CHAR UTF-8)): INTEGER - возвращает адрес x - - PROCEDURE WSADR(x: строковая константа (WCHAR)): INTEGER - возвращает адрес x - - 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 будет расширено - до 64 бит, для записи байтов использовать 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 COPY(VAR Source: любой тип; VAR Dest: любой тип; n: INTEGER) - Копирует n байт памяти из Source в Dest. - Эквивалентно - SYSTEM.MOVE(SYSTEM.ADR(Source), SYSTEM.ADR(Dest), n) - - PROCEDURE CODE(byte1, byte2,... : BYTE) - Вставка машинного кода, - byte1, byte2 ... - константы в диапазоне 0..255, - например: - - SYSTEM.CODE(048H,08BH,045H,010H) (* mov rax,qword[rbp+16] *) - - Также, в модуле SYSTEM определен тип CARD32 (4 байта). Для типа CARD32 не -допускаются никакие явные операции, за исключением присваивания. - - Функции псевдомодуля SYSTEM нельзя использовать в константных выражениях. - ------------------------------------------------------------------------------- - Системные флаги - - При объявлении процедурных типов и глобальных процедур, после ключевого -слова PROCEDURE может быть указан флаг соглашения о вызове: -[win64], [systemv], [windows], [linux], [oberon], [ccall]. -Например: - - PROCEDURE [win64] MyProc (x, y, z: INTEGER): INTEGER; - - Флаг [windows] - синоним для [win64], [linux] - синоним для [systemv]. - Флаг [ccall] - синоним для [win64] или [systemv] (зависит от целевой ОС). - Знак "-" после имени флага ([win64-], [linux-], ...) означает, что -результат процедуры можно игнорировать (не допускается для типа REAL). - Если флаг не указан или указан флаг [oberon], то принимается внутреннее -соглашение о вызове. [win64] и [systemv] используются для связи с -операционной системой и внешними приложениями. - - При объявлении типов-записей, после ключевого слова RECORD может быть -указан флаг [noalign]. Флаг [noalign] означает отсутствие выравнивания полей -записи. Записи с системным флагом не могут иметь базовый тип и не могут быть -базовыми типами для других записей. - Для использования системных флагов, требуется импортировать 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. В ряде случаев это позволяет -значительно сократить частоту применения охраны типа. - ------------------------------------------------------------------------------- - Дополнительные стандартные процедуры - - DISPOSE (VAR v: любой_указатель) - Освобождает память, выделенную процедурой NEW для - динамической переменной v^, и присваивает переменной v - значение NIL. - - 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"; (* абсолютный путь *) - ------------------------------------------------------------------------------- - Импортированные процедуры - - Синтаксис импорта: - - PROCEDURE [callconv, library, function] proc_name (FormalParam): Type; - - - callconv -- соглашение о вызове - - library -- имя файла динамической библиотеки (строковая константа) - - function -- имя импортируемой процедуры (строковая константа), если - указана пустая строка, то имя процедуры = proc_name - - например: - - PROCEDURE [windows, "kernel32.dll", "ExitProcess"] exit (code: INTEGER); - - PROCEDURE [windows, "kernel32.dll", ""] GetTickCount (): INTEGER; - - В конце объявления может быть добавлено (необязательно) "END proc_name;" - - Объявления импортированных процедур должны располагаться в глобальной - области видимости модуля после объявления переменных, вместе с объявлением - "обычных" процедур, от которых импортированные отличаются только отсутствием - тела процедуры. В остальном, к таким процедурам применимы те же правила: - их можно вызвать, присвоить процедурной переменной или получить адрес. - - Так как импортированная процедура всегда имеет явное указание соглашения о - вызове, то совместимый процедурный тип тоже должен быть объявлен с указанием - соглашения о вызове: - - VAR - ExitProcess: PROCEDURE [windows] (code: INTEGER); - - Для Linux, импортированные процедуры не реализованы. - ------------------------------------------------------------------------------- - Скрытые параметры процедур - - Некоторые процедуры могут иметь скрытые параметры, они отсутствуют в списке -формальных параметров, но учитываются компилятором при трансляции вызовов. -Это возможно в следующих случаях: - -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)) - - Скрытые параметры необходимо учитывать при связи с внешними приложениями. - ------------------------------------------------------------------------------- - Модуль RTL - - Все программы неявно используют модуль RTL. Компилятор транслирует -некоторые операции (проверка и охрана типа, сравнение строк, сообщения об -ошибках времени выполнения и др.) как вызовы процедур этого модуля. Не -следует вызывать эти процедуры явно. - Сообщения об ошибках времени выполнения выводятся в диалоговых окнах -(Windows), в терминал (Linux). - ------------------------------------------------------------------------------- - Модуль API - - Существуют несколько реализаций модуля API (для различных ОС). - Как и модуль RTL, модуль API не предназначен для прямого использования. -Он обеспечивает связь RTL с ОС. - ------------------------------------------------------------------------------- - Генерация исполняемых файлов DLL - - Разрешается экспортировать только процедуры. Для этого, процедура должна -находиться в главном модуле программы, ее имя должно быть отмечено символом -экспорта ("*") и должно быть указано соглашение о вызове. Нельзя + Компилятор языка программирования Oberon-07/16 для x86_64 + Windows/Linux +------------------------------------------------------------------------------ + + Параметры командной строки + + Вход - текстовые файлы модулей с расширением ".ob07", кодировка ANSI или +UTF-8 с BOM-сигнатурой. + Выход - испоняемый файл формата PE32+ или ELF64. + Параметры: + 1) имя главного модуля + 2) тип приложения + "win64con" - Windows64 console + "win64gui" - Windows64 GUI + "win64dll" - Windows64 DLL + "linux64exe" - Linux ELF64-EXEC + "linux64so" - Linux ELF64-SO + + 3) необязательные параметры-ключи + -out имя результирующего файла; по умолчанию, + совпадает с именем главного модуля, но с другим расширением + (соответствует типу исполняемого файла) + -stk размер стэка в мегабайтах (по умолчанию 2 Мб, + допустимо от 1 до 32 Мб) + -tab размер табуляции (используется для вычисления координат в + исходном коде), по умолчанию - 4 + -nochk <"ptibcwra"> отключить проверки при выполнении + -lower разрешить ключевые слова и встроенные идентификаторы в + нижнем регистре + -def <имя> задать символ условной компиляции + + параметр -nochk задается в виде строки из символов: + "p" - указатели + "t" - типы + "i" - индексы + "b" - неявное приведение INTEGER к BYTE + "c" - диапазон аргумента функции CHR + "w" - диапазон аргумента функции WCHR + "r" - эквивалентно "bcw" + "a" - все проверки + + Порядок символов может быть любым. Наличие в строке того или иного + символа отключает соответствующую проверку. + + Например: -nochk it - отключить проверку индексов и охрану типа. + -nochk a - отключить все отключаемые проверки. + + Например: + + Compiler.exe "C:\example.ob07" win64con -out "C:\example.exe" -stk 1 + Compiler.exe "C:\example.ob07" win64dll -out "C:\example.dll" -nochk pti + Compiler "source/Compiler.ob07" linux64exe -out "source/Compiler" -nochk a + + В случае успешной компиляции, компилятор передает код завершения 0, иначе 1. + +------------------------------------------------------------------------------ + Отличия от оригинала + +1. Расширен псевдомодуль SYSTEM +2. В идентификаторах допускается символ "_" +3. Добавлены системные флаги +4. Усовершенствован оператор CASE (добавлены константные выражения в + метках вариантов и необязательная ветка ELSE) +5. Расширен набор стандартных процедур +6. Семантика охраны/проверки типа уточнена для нулевого указателя +7. Добавлены однострочные комментарии (начинаются с пары символов "//") +8. Разрешено наследование от типа-указателя +9. Добавлен синтаксис для импорта процедур из внешних библиотек +10. "Строки" можно заключать также в одиночные кавычки: 'строка' +11. Добавлен тип WCHAR +12. Добавлена операция конкатенации строковых и символьных констант +13. Возможен импорт модулей с указанием пути и имени файла +14. Добавлен специальный синтаксис для условной компиляции (см. CC.txt) +15. Имя процедуры в конце объявления (после END) необязательно + +------------------------------------------------------------------------------ + Особенности реализации + +1. Основные типы + + Тип Диапазон значений Размер, байт + + INTEGER -9223372036854775808 .. 9223372036854775807 8 + REAL 4.94E-324 .. 1.70E+308 8 + CHAR символ ASCII (0X .. 0FFX) 1 + BOOLEAN FALSE, TRUE 1 + SET множество из целых чисел {0 .. 63} 8 + 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. Контроль переполнения значений выражений не производится +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) +10 WCHR(x), если (x < 0) OR (x > 65535) +11 неявное приведение x:INTEGER к v:BYTE, если (x < 0) OR (x > 255) + +------------------------------------------------------------------------------ + Псевдомодуль SYSTEM + + Псевдомодуль SYSTEM содержит низкоуровневые и небезопасные процедуры, +ошибки при использовании процедур псевдомодуля SYSTEM могут привести к +повреждению данных времени выполнения и аварийному завершению программы. + + PROCEDURE ADR(v: любой тип): INTEGER + v - переменная или процедура; + возвращает адрес v + + PROCEDURE SADR(x: строковая константа (CHAR UTF-8)): INTEGER + возвращает адрес x + + PROCEDURE WSADR(x: строковая константа (WCHAR)): INTEGER + возвращает адрес x + + 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 будет расширено + до 64 бит, для записи байтов использовать 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 COPY(VAR Source: любой тип; VAR Dest: любой тип; n: INTEGER) + Копирует n байт памяти из Source в Dest. + Эквивалентно + SYSTEM.MOVE(SYSTEM.ADR(Source), SYSTEM.ADR(Dest), n) + + PROCEDURE CODE(byte1, byte2,... : BYTE) + Вставка машинного кода, + byte1, byte2 ... - константы в диапазоне 0..255, + например: + + SYSTEM.CODE(048H,08BH,045H,010H) (* mov rax,qword[rbp+16] *) + + Также, в модуле SYSTEM определен тип CARD32 (4 байта). Для типа CARD32 не +допускаются никакие явные операции, за исключением присваивания. + + Функции псевдомодуля SYSTEM нельзя использовать в константных выражениях. + +------------------------------------------------------------------------------ + Системные флаги + + При объявлении процедурных типов и глобальных процедур, после ключевого +слова PROCEDURE может быть указан флаг соглашения о вызове: +[win64], [systemv], [windows], [linux], [oberon], [ccall]. +Например: + + PROCEDURE [win64] MyProc (x, y, z: INTEGER): INTEGER; + + Флаг [windows] - синоним для [win64], [linux] - синоним для [systemv]. + Флаг [ccall] - синоним для [win64] или [systemv] (зависит от целевой ОС). + Знак "-" после имени флага ([win64-], [linux-], ...) означает, что +результат процедуры можно игнорировать (не допускается для типа REAL). + Если флаг не указан или указан флаг [oberon], то принимается внутреннее +соглашение о вызове. [win64] и [systemv] используются для связи с +операционной системой и внешними приложениями. + + При объявлении типов-записей, после ключевого слова RECORD может быть +указан флаг [noalign]. Флаг [noalign] означает отсутствие выравнивания полей +записи. Записи с системным флагом не могут иметь базовый тип и не могут быть +базовыми типами для других записей. + Для использования системных флагов, требуется импортировать 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. В ряде случаев это позволяет +значительно сократить частоту применения охраны типа. + +------------------------------------------------------------------------------ + Дополнительные стандартные процедуры + + DISPOSE (VAR v: любой_указатель) + Освобождает память, выделенную процедурой NEW для + динамической переменной v^, и присваивает переменной v + значение NIL. + + 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"; (* абсолютный путь *) + +------------------------------------------------------------------------------ + Импортированные процедуры + + Синтаксис импорта: + + PROCEDURE [callconv, library, function] proc_name (FormalParam): Type; + + - callconv -- соглашение о вызове + - library -- имя файла динамической библиотеки (строковая константа) + - function -- имя импортируемой процедуры (строковая константа), если + указана пустая строка, то имя процедуры = proc_name + + например: + + PROCEDURE [windows, "kernel32.dll", "ExitProcess"] exit (code: INTEGER); + + PROCEDURE [windows, "kernel32.dll", ""] GetTickCount (): INTEGER; + + В конце объявления может быть добавлено (необязательно) "END proc_name;" + + Объявления импортированных процедур должны располагаться в глобальной + области видимости модуля после объявления переменных, вместе с объявлением + "обычных" процедур, от которых импортированные отличаются только отсутствием + тела процедуры. В остальном, к таким процедурам применимы те же правила: + их можно вызвать, присвоить процедурной переменной или получить адрес. + + Так как импортированная процедура всегда имеет явное указание соглашения о + вызове, то совместимый процедурный тип тоже должен быть объявлен с указанием + соглашения о вызове: + + VAR + ExitProcess: PROCEDURE [windows] (code: INTEGER); + + Для Linux, импортированные процедуры не реализованы. + +------------------------------------------------------------------------------ + Скрытые параметры процедур + + Некоторые процедуры могут иметь скрытые параметры, они отсутствуют в списке +формальных параметров, но учитываются компилятором при трансляции вызовов. +Это возможно в следующих случаях: + +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)) + + Скрытые параметры необходимо учитывать при связи с внешними приложениями. + +------------------------------------------------------------------------------ + Модуль RTL + + Все программы неявно используют модуль RTL. Компилятор транслирует +некоторые операции (проверка и охрана типа, сравнение строк, сообщения об +ошибках времени выполнения и др.) как вызовы процедур этого модуля. Не +следует вызывать эти процедуры явно. + Сообщения об ошибках времени выполнения выводятся в диалоговых окнах +(Windows), в терминал (Linux). + +------------------------------------------------------------------------------ + Модуль API + + Существуют несколько реализаций модуля API (для различных ОС). + Как и модуль RTL, модуль API не предназначен для прямого использования. +Он обеспечивает связь RTL с ОС. + +------------------------------------------------------------------------------ + Генерация исполняемых файлов DLL + + Разрешается экспортировать только процедуры. Для этого, процедура должна +находиться в главном модуле программы, ее имя должно быть отмечено символом +экспорта ("*") и должно быть указано соглашение о вызове. Нельзя экспортировать процедуры, которые импортированы из других dll-библиотек. \ No newline at end of file diff --git a/programs/develop/oberon07/source/Compiler.ob07 b/programs/develop/oberon07/source/Compiler.ob07 index 0a30e6123d..6bc6d7007f 100644 --- a/programs/develop/oberon07/source/Compiler.ob07 +++ b/programs/develop/oberon07/source/Compiler.ob07 @@ -8,7 +8,7 @@ MODULE Compiler; IMPORT ST := STATEMENTS, PARS, UTILS, PATHS, PROG, C := CONSOLE, - ERRORS, STRINGS, WRITER, MSP430, THUMB, TARGETS, SCAN; + ERRORS, STRINGS, WRITER, MSP430, THUMB, TARGETS, SCAN, TEXTDRV; CONST @@ -30,6 +30,23 @@ VAR major: INTEGER; checking: SET; + + PROCEDURE getVal (VAR i: INTEGER; VAR value: INTEGER); + VAR + param: PARS.PATH; + val: INTEGER; + BEGIN + INC(i); + UTILS.GetArg(i, param); + IF STRINGS.StrToInt(param, val) THEN + value := val + END; + IF param[0] = "-" THEN + DEC(i) + END + END getVal; + + BEGIN out := ""; checking := options.checking; @@ -57,25 +74,14 @@ BEGIN out := param END + ELSIF param = "-tab" THEN + getVal(i, options.tab) + ELSIF param = "-ram" THEN - INC(i); - UTILS.GetArg(i, param); - IF STRINGS.StrToInt(param, value) THEN - options.ram := value - END; - IF param[0] = "-" THEN - DEC(i) - END + getVal(i, options.ram) ELSIF param = "-rom" THEN - INC(i); - UTILS.GetArg(i, param); - IF STRINGS.StrToInt(param, value) THEN - options.rom := value - END; - IF param[0] = "-" THEN - DEC(i) - END + getVal(i, options.rom) ELSIF param = "-nochk" THEN INC(i); @@ -182,6 +188,7 @@ VAR BEGIN options.stack := 2; + options.tab := TEXTDRV.defTabSize; options.version := 65536; options.pic := FALSE; options.lower := FALSE; @@ -237,6 +244,7 @@ BEGIN C.StringLn(" -ver set version of program (KolibriOS DLL)"); C.Ln; C.StringLn(" -ram set size of RAM in bytes (MSP430) or Kbytes (STM32)"); C.Ln; C.StringLn(" -rom set size of ROM in bytes (MSP430) or Kbytes (STM32)"); C.Ln; + C.StringLn(" -tab set width for tabs"); C.Ln; UTILS.Exit(0) END; @@ -285,6 +293,7 @@ BEGIN STRINGS.append(lib_path, UTILS.slash); keys(options, outname); + TEXTDRV.setTabSize(options.tab); IF outname = "" THEN outname := path; STRINGS.append(outname, modname); diff --git a/programs/develop/oberon07/source/HEX.ob07 b/programs/develop/oberon07/source/HEX.ob07 index c1f35780f4..f8d2469510 100644 --- a/programs/develop/oberon07/source/HEX.ob07 +++ b/programs/develop/oberon07/source/HEX.ob07 @@ -1,117 +1,117 @@ -(* - BSD 2-Clause License - - Copyright (c) 2020, Anton Krotov - All rights reserved. -*) - -MODULE HEX; - -IMPORT WRITER, CHL := CHUNKLISTS, UTILS; - - -VAR - - chksum: INTEGER; - - -PROCEDURE Byte (byte: BYTE); -BEGIN - WRITER.WriteByte(UTILS.hexdgt(byte DIV 16)); - WRITER.WriteByte(UTILS.hexdgt(byte MOD 16)); - INC(chksum, byte) -END Byte; - - -PROCEDURE Byte4 (a, b, c, d: BYTE); -BEGIN - Byte(a); - Byte(b); - Byte(c); - Byte(d) -END Byte4; - - -PROCEDURE NewLine; -BEGIN - Byte((-chksum) MOD 256); - chksum := 0; - WRITER.WriteByte(0DH); - WRITER.WriteByte(0AH) -END NewLine; - - -PROCEDURE StartCode; -BEGIN - WRITER.WriteByte(ORD(":")); - chksum := 0 -END StartCode; - - -PROCEDURE Data* (mem: ARRAY OF BYTE; idx, cnt: INTEGER); -VAR - i, len: INTEGER; - -BEGIN - WHILE cnt > 0 DO - len := MIN(cnt, 16); - StartCode; - Byte4(len, idx DIV 256, idx MOD 256, 0); - FOR i := 1 TO len DO - Byte(mem[idx]); - INC(idx) - END; - DEC(cnt, len); - NewLine - END -END Data; - - -PROCEDURE ExtLA* (LA: INTEGER); -BEGIN - ASSERT((0 <= LA) & (LA <= 0FFFFH)); - StartCode; - Byte4(2, 0, 0, 4); - Byte(LA DIV 256); - Byte(LA MOD 256); - NewLine -END ExtLA; - - -PROCEDURE Data2* (mem: CHL.BYTELIST; idx, cnt, LA: INTEGER); -VAR - i, len, offset: INTEGER; - -BEGIN - ExtLA(LA); - offset := 0; - WHILE cnt > 0 DO - ASSERT(offset <= 65536); - IF offset = 65536 THEN - INC(LA); - ExtLA(LA); - offset := 0 - END; - len := MIN(cnt, 16); - StartCode; - Byte4(len, offset DIV 256, offset MOD 256, 0); - FOR i := 1 TO len DO - Byte(CHL.GetByte(mem, idx)); - INC(idx); - INC(offset) - END; - DEC(cnt, len); - NewLine - END -END Data2; - - -PROCEDURE End*; -BEGIN - StartCode; - Byte4(0, 0, 0, 1); - NewLine -END End; - - +(* + BSD 2-Clause License + + Copyright (c) 2020, Anton Krotov + All rights reserved. +*) + +MODULE HEX; + +IMPORT WRITER, CHL := CHUNKLISTS, UTILS; + + +VAR + + chksum: INTEGER; + + +PROCEDURE Byte (byte: BYTE); +BEGIN + WRITER.WriteByte(UTILS.hexdgt(byte DIV 16)); + WRITER.WriteByte(UTILS.hexdgt(byte MOD 16)); + INC(chksum, byte) +END Byte; + + +PROCEDURE Byte4 (a, b, c, d: BYTE); +BEGIN + Byte(a); + Byte(b); + Byte(c); + Byte(d) +END Byte4; + + +PROCEDURE NewLine; +BEGIN + Byte((-chksum) MOD 256); + chksum := 0; + WRITER.WriteByte(0DH); + WRITER.WriteByte(0AH) +END NewLine; + + +PROCEDURE StartCode; +BEGIN + WRITER.WriteByte(ORD(":")); + chksum := 0 +END StartCode; + + +PROCEDURE Data* (mem: ARRAY OF BYTE; idx, cnt: INTEGER); +VAR + i, len: INTEGER; + +BEGIN + WHILE cnt > 0 DO + len := MIN(cnt, 16); + StartCode; + Byte4(len, idx DIV 256, idx MOD 256, 0); + FOR i := 1 TO len DO + Byte(mem[idx]); + INC(idx) + END; + DEC(cnt, len); + NewLine + END +END Data; + + +PROCEDURE ExtLA* (LA: INTEGER); +BEGIN + ASSERT((0 <= LA) & (LA <= 0FFFFH)); + StartCode; + Byte4(2, 0, 0, 4); + Byte(LA DIV 256); + Byte(LA MOD 256); + NewLine +END ExtLA; + + +PROCEDURE Data2* (mem: CHL.BYTELIST; idx, cnt, LA: INTEGER); +VAR + i, len, offset: INTEGER; + +BEGIN + ExtLA(LA); + offset := 0; + WHILE cnt > 0 DO + ASSERT(offset <= 65536); + IF offset = 65536 THEN + INC(LA); + ExtLA(LA); + offset := 0 + END; + len := MIN(cnt, 16); + StartCode; + Byte4(len, offset DIV 256, offset MOD 256, 0); + FOR i := 1 TO len DO + Byte(CHL.GetByte(mem, idx)); + INC(idx); + INC(offset) + END; + DEC(cnt, len); + NewLine + END +END Data2; + + +PROCEDURE End*; +BEGIN + StartCode; + Byte4(0, 0, 0, 1); + NewLine +END End; + + END HEX. \ No newline at end of file diff --git a/programs/develop/oberon07/source/IL.ob07 b/programs/develop/oberon07/source/IL.ob07 index e7033b37b9..72430a489d 100644 --- a/programs/develop/oberon07/source/IL.ob07 +++ b/programs/develop/oberon07/source/IL.ob07 @@ -1,1171 +1,1171 @@ -(* - BSD 2-Clause License - - Copyright (c) 2018-2021, Anton Krotov - All rights reserved. -*) - -MODULE IL; - -IMPORT LISTS, SCAN, STRINGS, CHL := CHUNKLISTS, C := COLLECTIONS, TARGETS, PATHS; - - -CONST - - call_stack* = 0; - call_win64* = 1; - call_sysv* = 2; - - begin_loop* = 1; end_loop* = 2; - - opJMP* = 0; opLABEL* = 1; opCOPYS* = 2; opGADR* = 3; opCONST* = 4; opLLOAD32* = 5; - opCOPYA* = 6; opCASET* = 7; opMULC* = 8; opMUL* = 9; opDIV* = 10; opMOD* = 11; - opDIVL* = 12; opMODL* = 13; opDIVR* = 14; opMODR* = 15; opUMINUS* = 16; - opADD* = 17; opSUB* = 18; opONERR* = 19; opSUBL* = 20; opADDC* = 21; opSUBR* = 22; - opSAVE* = 23; opSAVEC* = 24; opSAVE8* = 25; opSAVE8C* = 26; opCHKBYTE* = 27; opDROP* = 28; - opNOT* = 29; - - opEQ* = 30; opNE* = opEQ + 1; opLT* = opEQ + 2; opLE* = opEQ + 3; opGT* = opEQ + 4; opGE* = opEQ + 5 (* 35 *); - opEQC* = 36; opNEC* = opEQC + 1; opLTC* = opEQC + 2; opLEC* = opEQC + 3; opGTC* = opEQC + 4; opGEC* = opEQC + 5; (* 41 *) - opEQF* = 42; opNEF* = opEQF + 1; opLTF* = opEQF + 2; opLEF* = opEQF + 3; opGTF* = opEQF + 4; opGEF* = opEQF + 5; (* 47 *) - opEQS* = 48; opNES* = opEQS + 1; opLTS* = opEQS + 2; opLES* = opEQS + 3; opGTS* = opEQS + 4; opGES* = opEQS + 5; (* 53 *) - opEQSW* = 54; opNESW* = opEQSW + 1; opLTSW* = opEQSW + 2; opLESW* = opEQSW + 3; opGTSW* = opEQSW + 4; opGESW* = opEQSW + 5 (* 59 *); - - opVLOAD32* = 60; opGLOAD32* = 61; - - opJZ* = 62; opJNZ* = 63; - - opSAVE32* = 64; opLLOAD8* = 65; - - opCONSTF* = 66; opLOADF* = 67; opSAVEF* = 68; opMULF* = 69; opDIVF* = 70; opDIVFI* = 71; - opUMINF* = 72; opSAVEFI* = 73; opSUBFI* = 74; opADDF* = 75; opSUBF* = 76; - - opJNZ1* = 77; opJG* = 78; - opINCCB* = 79; opDECCB* = 80; opINCB* = 81; opDECB* = 82; - - opCASEL* = 83; opCASER* = 84; opCASELR* = 85; - - opPOPSP* = 86; - opWIN64CALL* = 87; opWIN64CALLI* = 88; opWIN64CALLP* = 89; opAND* = 90; opOR* = 91; - - opLOAD8* = 92; opLOAD16* = 93; opLOAD32* = 94; opPRECALL* = 95; opRES* = 96; opRESF* = 97; - opPUSHC* = 98; opSWITCH* = 99; - - opSBOOL* = 100; opSBOOLC* = 101; opNOP* = 102; - - opMULS* = 103; opMULSC* = 104; opDIVS* = 105; opDIVSC* = 106; - opADDS* = 107; opSUBS* = 108; opERR* = 109; opSUBSL* = 110; opADDSC* = 111; opSUBSR* = 112; - opUMINS* = 113; opIN* = 114; opINL* = 115; opINR* = 116; - opRSET* = 117; opRSETL* = 118; opRSETR* = 119; opRSET1* = 120; opLENGTH* = 121; - - opLEAVEC* = 122; opCODE* = 123; opALIGN16* = 124; - opINCC* = 125; opINC* = 126; opDEC* = 127; - opINCL* = 128; opEXCL* = 129; opINCLC* = 130; opEXCLC* = 131; opNEW* = 132; opDISP* = 133; - opPACK* = 134; opPACKC* = 135; opUNPK* = 136; opCOPY* = 137; opENTER* = 138; opLEAVE* = 139; - opCALL* = 140; opSAVEP* = 141; opCALLP* = 142; opEQP* = 143; opNEP* = 144; opLEAVER* = 145; - opGET* = 146; opSAVE16* = 147; opABS* = 148; opFABS* = 149; opFLOOR* = 150; opFLT* = 151; - opGETC* = 152; opORD* = 153; opASR* = 154; opLSL* = 155; opROR* = 156; - opASR1* = 157; opLSL1* = 158; opROR1* = 159; opASR2* = 160; opLSL2* = 161; opROR2* = 162; - opPUSHP* = 163; opLADR* = 164; opTYPEGP* = 165; opIS* = 166; opPUSHF* = 167; opVADR* = 168; - opPUSHT* = 169; opTYPEGR* = 170; opISREC* = 171; opCHKIDX* = 172; opPARAM* = 173; - opCHKIDX2* = 174; opLEN* = 175; opROT* = 176; opSAVES* = 177; opSADR* = 178; opLENGTHW* = 179; - - opCHR* = 180; opENDSW* = 181; opLEAVEF* = 182; opCLEANUP* = 183; opMOVE* = 184; - opLSR* = 185; opLSR1* = 186; opLSR2* = 187; - opMIN* = 188; opMINC* = 189; opMAX* = 190; opMAXC* = 191; opSYSVALIGN16* = 192; - opEQB* = 193; opNEB* = 194; opINF* = 195; opWIN64ALIGN16* = 196; opVLOAD8* = 197; opGLOAD8* = 198; - opLLOAD16* = 199; opVLOAD16* = 200; opGLOAD16* = 201; - opLOAD64* = 202; opLLOAD64* = 203; opVLOAD64* = 204; opGLOAD64* = 205; opSAVE64* = 206; - - opTYPEGD* = 207; opCALLI* = 208; opPUSHIP* = 209; opSAVEIP* = 210; opEQIP* = 211; opNEIP* = 212; - opSAVE16C* = 213; opWCHR* = 214; opHANDLER* = 215; - - opSYSVCALL* = 216; opSYSVCALLI* = 217; opSYSVCALLP* = 218; opFNAME* = 219; - - - opSADR_PARAM* = -1; opLOAD64_PARAM* = -2; opLLOAD64_PARAM* = -3; opGLOAD64_PARAM* = -4; - opVADR_PARAM* = -5; opCONST_PARAM* = -6; opGLOAD32_PARAM* = -7; opLLOAD32_PARAM* = -8; - opLOAD32_PARAM* = -9; - - opLADR_SAVEC* = -10; opGADR_SAVEC* = -11; opLADR_SAVE* = -12; - - opLADR_INCC* = -13; opLADR_INCCB* = -14; opLADR_DECCB* = -15; - opLADR_INC* = -16; opLADR_DEC* = -17; opLADR_INCB* = -18; opLADR_DECB* = -19; - opLADR_INCL* = -20; opLADR_EXCL* = -21; opLADR_INCLC* = -22; opLADR_EXCLC* = -23; - opLADR_UNPK* = -24; - - - _init *= 0; - _move *= 1; - _strcmpw *= 2; - _exit *= 3; - _set *= 4; - _set1 *= 5; - _lengthw *= 6; - _strcpy *= 7; - _length *= 8; - _divmod *= 9; - _dllentry *= 10; - _sofinit *= 11; - _arrcpy *= 12; - _rot *= 13; - _new *= 14; - _dispose *= 15; - _strcmp *= 16; - _error *= 17; - _is *= 18; - _isrec *= 19; - _guard *= 20; - _guardrec *= 21; - - _fmul *= 22; - _fdiv *= 23; - _fdivi *= 24; - _fadd *= 25; - _fsub *= 26; - _fsubi *= 27; - _fcmp *= 28; - _floor *= 29; - _flt *= 30; - _pack *= 31; - _unpk *= 32; - - -TYPE - - COMMAND* = POINTER TO RECORD (LISTS.ITEM) - - opcode*: INTEGER; - param1*: INTEGER; - param2*: INTEGER; - param3*: INTEGER; - float*: REAL - - END; - - FNAMECMD* = POINTER TO RECORD (COMMAND) - - fname*: PATHS.PATH - - END; - - CMDSTACK = POINTER TO RECORD - - data: ARRAY 1000 OF COMMAND; - top: INTEGER - - END; - - EXPORT_PROC* = POINTER TO RECORD (LISTS.ITEM) - - label*: INTEGER; - name*: SCAN.IDSTR - - END; - - IMPORT_LIB* = POINTER TO RECORD (LISTS.ITEM) - - name*: SCAN.TEXTSTR; - procs*: LISTS.LIST - - END; - - IMPORT_PROC* = POINTER TO RECORD (LISTS.ITEM) - - label*: INTEGER; - lib*: IMPORT_LIB; - name*: SCAN.TEXTSTR; - count: INTEGER - - END; - - - CODES = RECORD - - last: COMMAND; - begcall: CMDSTACK; - endcall: CMDSTACK; - commands*: LISTS.LIST; - export*: LISTS.LIST; - _import*: LISTS.LIST; - types*: CHL.INTLIST; - data*: CHL.BYTELIST; - dmin*: INTEGER; - lcount*: INTEGER; - bss*: INTEGER; - rtl*: ARRAY 33 OF INTEGER; - errlabels*: ARRAY 12 OF INTEGER; - - charoffs: ARRAY 256 OF INTEGER; - wcharoffs: ARRAY 65536 OF INTEGER; - - wstr: ARRAY 4*1024 OF WCHAR - END; - - -VAR - - codes*: CODES; - CPU: INTEGER; - - commands: C.COLLECTION; - - -PROCEDURE set_dmin* (value: INTEGER); -BEGIN - codes.dmin := value -END set_dmin; - - -PROCEDURE set_bss* (value: INTEGER); -BEGIN - codes.bss := value -END set_bss; - - -PROCEDURE set_rtl* (idx, label: INTEGER); -BEGIN - codes.rtl[idx] := label -END set_rtl; - - -PROCEDURE NewCmd (): COMMAND; -VAR - cmd: COMMAND; - citem: C.ITEM; - -BEGIN - citem := C.pop(commands); - IF citem = NIL THEN - NEW(cmd) - ELSE - cmd := citem(COMMAND) - END - - RETURN cmd -END NewCmd; - - -PROCEDURE setlast* (cmd: COMMAND); -BEGIN - codes.last := cmd -END setlast; - - -PROCEDURE getlast* (): COMMAND; - RETURN codes.last -END getlast; - - -PROCEDURE PutByte (b: BYTE); -BEGIN - CHL.PushByte(codes.data, b) -END PutByte; - - -PROCEDURE putstr* (s: ARRAY OF CHAR): INTEGER; -VAR - i, n, res: INTEGER; -BEGIN - res := CHL.Length(codes.data); - - i := 0; - n := LENGTH(s); - WHILE i < n DO - PutByte(ORD(s[i])); - INC(i) - END; - - PutByte(0) - - RETURN res -END putstr; - - -PROCEDURE putstr1* (c: INTEGER): INTEGER; -VAR - res: INTEGER; - -BEGIN - IF codes.charoffs[c] = -1 THEN - res := CHL.Length(codes.data); - PutByte(c); - PutByte(0); - codes.charoffs[c] := res - ELSE - res := codes.charoffs[c] - END - - RETURN res -END putstr1; - - -PROCEDURE putstrW* (s: ARRAY OF CHAR): INTEGER; -VAR - i, n, res: INTEGER; - -BEGIN - res := CHL.Length(codes.data); - - IF ODD(res) THEN - PutByte(0); - INC(res) - END; - - n := STRINGS.Utf8To16(s, codes.wstr); - - i := 0; - WHILE i < n DO - IF TARGETS.LittleEndian THEN - PutByte(ORD(codes.wstr[i]) MOD 256); - PutByte(ORD(codes.wstr[i]) DIV 256) - ELSE - PutByte(ORD(codes.wstr[i]) DIV 256); - PutByte(ORD(codes.wstr[i]) MOD 256) - END; - INC(i) - END; - - PutByte(0); - PutByte(0) - - RETURN res -END putstrW; - - -PROCEDURE putstrW1* (c: INTEGER): INTEGER; -VAR - res: INTEGER; - -BEGIN - IF codes.wcharoffs[c] = -1 THEN - res := CHL.Length(codes.data); - - IF ODD(res) THEN - PutByte(0); - INC(res) - END; - - IF TARGETS.LittleEndian THEN - PutByte(c MOD 256); - PutByte(c DIV 256) - ELSE - PutByte(c DIV 256); - PutByte(c MOD 256) - END; - - PutByte(0); - PutByte(0); - - codes.wcharoffs[c] := res - ELSE - res := codes.wcharoffs[c] - END - - RETURN res -END putstrW1; - - -PROCEDURE push (stk: CMDSTACK; cmd: COMMAND); -BEGIN - INC(stk.top); - stk.data[stk.top] := cmd -END push; - - -PROCEDURE pop (stk: CMDSTACK): COMMAND; -VAR - res: COMMAND; -BEGIN - res := stk.data[stk.top]; - DEC(stk.top) - RETURN res -END pop; - - -PROCEDURE pushBegEnd* (VAR beg, _end: COMMAND); -BEGIN - push(codes.begcall, beg); - push(codes.endcall, _end); - beg := codes.last; - _end := beg.next(COMMAND) -END pushBegEnd; - - -PROCEDURE popBegEnd* (VAR beg, _end: COMMAND); -BEGIN - beg := pop(codes.begcall); - _end := pop(codes.endcall) -END popBegEnd; - - -PROCEDURE AddRec* (base: INTEGER); -BEGIN - CHL.PushInt(codes.types, base) -END AddRec; - - -PROCEDURE insert (cur, nov: COMMAND); -VAR - old_opcode, param2: INTEGER; - - - PROCEDURE set (cur: COMMAND; opcode, param2: INTEGER); - BEGIN - cur.opcode := opcode; - cur.param1 := cur.param2; - cur.param2 := param2 - END set; - - -BEGIN - IF CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64, TARGETS.cpuMSP430} THEN - - old_opcode := cur.opcode; - param2 := nov.param2; - - IF (nov.opcode = opPARAM) & (param2 = 1) THEN - - CASE old_opcode OF - |opGLOAD64: cur.opcode := opGLOAD64_PARAM - |opLLOAD64: cur.opcode := opLLOAD64_PARAM - |opLOAD64: cur.opcode := opLOAD64_PARAM - |opGLOAD32: cur.opcode := opGLOAD32_PARAM - |opLLOAD32: cur.opcode := opLLOAD32_PARAM - |opLOAD32: cur.opcode := opLOAD32_PARAM - |opSADR: cur.opcode := opSADR_PARAM - |opVADR: cur.opcode := opVADR_PARAM - |opCONST: cur.opcode := opCONST_PARAM - ELSE - old_opcode := -1 - END - - ELSIF old_opcode = opLADR THEN - - CASE nov.opcode OF - |opSAVEC: set(cur, opLADR_SAVEC, param2) - |opSAVE: cur.opcode := opLADR_SAVE - |opINC: cur.opcode := opLADR_INC - |opDEC: cur.opcode := opLADR_DEC - |opINCB: cur.opcode := opLADR_INCB - |opDECB: cur.opcode := opLADR_DECB - |opINCL: cur.opcode := opLADR_INCL - |opEXCL: cur.opcode := opLADR_EXCL - |opUNPK: cur.opcode := opLADR_UNPK - |opINCC: set(cur, opLADR_INCC, param2) - |opINCCB: set(cur, opLADR_INCCB, param2) - |opDECCB: set(cur, opLADR_DECCB, param2) - |opINCLC: set(cur, opLADR_INCLC, param2) - |opEXCLC: set(cur, opLADR_EXCLC, param2) - ELSE - old_opcode := -1 - END - - ELSIF (nov.opcode = opSAVEC) & (old_opcode = opGADR) THEN - set(cur, opGADR_SAVEC, param2) - - ELSIF (nov.opcode = opMULC) & (old_opcode = opMULC) THEN - cur.param2 := cur.param2 * param2 - - ELSIF (nov.opcode = opADDC) & (old_opcode = opADDC) THEN - INC(cur.param2, param2) - - ELSE - old_opcode := -1 - END - - ELSIF CPU IN {TARGETS.cpuTHUMB, TARGETS.cpuRVM32I, TARGETS.cpuRVM64I} THEN - - old_opcode := cur.opcode; - param2 := nov.param2; - - IF (old_opcode = opLADR) & (nov.opcode = opSAVE) THEN - cur.opcode := opLADR_SAVE - ELSIF (old_opcode = opLADR) & (nov.opcode = opINCC) THEN - set(cur, opLADR_INCC, param2) - ELSIF (nov.opcode = opMULC) & (old_opcode = opMULC) THEN - cur.param2 := cur.param2 * param2 - ELSIF (nov.opcode = opADDC) & (old_opcode = opADDC) THEN - INC(cur.param2, param2) - ELSE - old_opcode := -1 - END - - ELSE - old_opcode := -1 - END; - - IF old_opcode = -1 THEN - LISTS.insert(codes.commands, cur, nov); - codes.last := nov - ELSE - C.push(commands, nov); - codes.last := cur - END -END insert; - - -PROCEDURE AddCmd* (opcode: INTEGER; param: INTEGER); -VAR - cmd: COMMAND; -BEGIN - cmd := NewCmd(); - cmd.opcode := opcode; - cmd.param1 := 0; - cmd.param2 := param; - insert(codes.last, cmd) -END AddCmd; - - -PROCEDURE AddCmd2* (opcode: INTEGER; param1, param2: INTEGER); -VAR - cmd: COMMAND; -BEGIN - cmd := NewCmd(); - cmd.opcode := opcode; - cmd.param1 := param1; - cmd.param2 := param2; - insert(codes.last, cmd) -END AddCmd2; - - -PROCEDURE Const* (val: INTEGER); -BEGIN - AddCmd(opCONST, val) -END Const; - - -PROCEDURE StrAdr* (adr: INTEGER); -BEGIN - AddCmd(opSADR, adr) -END StrAdr; - - -PROCEDURE Param1*; -BEGIN - AddCmd(opPARAM, 1) -END Param1; - - -PROCEDURE NewLabel* (): INTEGER; -BEGIN - INC(codes.lcount) - RETURN codes.lcount - 1 -END NewLabel; - - -PROCEDURE SetLabel* (label: INTEGER); -BEGIN - AddCmd2(opLABEL, label, 0) -END SetLabel; - - -PROCEDURE SetErrLabel* (errno: INTEGER); -BEGIN - codes.errlabels[errno] := NewLabel(); - SetLabel(codes.errlabels[errno]) -END SetErrLabel; - - -PROCEDURE AddCmd0* (opcode: INTEGER); -BEGIN - AddCmd(opcode, 0) -END AddCmd0; - - -PROCEDURE delete (cmd: COMMAND); -BEGIN - LISTS.delete(codes.commands, cmd); - C.push(commands, cmd) -END delete; - - -PROCEDURE delete2* (first, last: LISTS.ITEM); -VAR - cur, next: LISTS.ITEM; - -BEGIN - cur := first; - - IF first # last THEN - REPEAT - next := cur.next; - LISTS.delete(codes.commands, cur); - C.push(commands, cur); - cur := next - UNTIL cur = last - END; - - LISTS.delete(codes.commands, cur); - C.push(commands, cur) -END delete2; - - -PROCEDURE Jmp* (opcode: INTEGER; label: INTEGER); -VAR - prev: COMMAND; - not: BOOLEAN; - -BEGIN - prev := codes.last; - not := prev.opcode = opNOT; - IF not THEN - IF opcode = opJNZ THEN - opcode := opJZ - ELSIF opcode = opJZ THEN - opcode := opJNZ - ELSE - not := FALSE - END - END; - - AddCmd2(opcode, label, label); - - IF not THEN - delete(prev) - END -END Jmp; - - -PROCEDURE AndOrOpt* (VAR label: INTEGER); -VAR - cur, prev: COMMAND; - i, op, l: INTEGER; - jz, not: BOOLEAN; - -BEGIN - cur := codes.last; - not := cur.opcode = opNOT; - IF not THEN - cur := cur.prev(COMMAND) - END; - - IF cur.opcode = opAND THEN - op := opAND - ELSIF cur.opcode = opOR THEN - op := opOR - ELSE - op := -1 - END; - - cur := codes.last; - - IF op # -1 THEN - IF not THEN - IF op = opAND THEN - op := opOR - ELSE (* op = opOR *) - op := opAND - END; - prev := cur.prev(COMMAND); - delete(cur); - cur := prev - END; - - FOR i := 1 TO 9 DO - IF i = 8 THEN - l := cur.param1 - ELSIF i = 9 THEN - jz := cur.opcode = opJZ - END; - prev := cur.prev(COMMAND); - delete(cur); - cur := prev - END; - - setlast(cur); - - IF op = opAND THEN - label := l; - jz := ~jz - END; - - IF jz THEN - Jmp(opJZ, label) - ELSE - Jmp(opJNZ, label) - END; - - IF op = opOR THEN - SetLabel(l) - END - ELSE - Jmp(opJZ, label) - END; - - setlast(codes.last) -END AndOrOpt; - - -PROCEDURE OnError* (line, error: INTEGER); -BEGIN - AddCmd2(opONERR, codes.errlabels[error], line) -END OnError; - - -PROCEDURE TypeGuard* (op, t: INTEGER; line, error: INTEGER); -VAR - label: INTEGER; -BEGIN - AddCmd(op, t); - label := NewLabel(); - Jmp(opJNZ, label); - OnError(line, error); - SetLabel(label) -END TypeGuard; - - -PROCEDURE TypeCheck* (t: INTEGER); -BEGIN - AddCmd(opIS, t) -END TypeCheck; - - -PROCEDURE TypeCheckRec* (t: INTEGER); -BEGIN - AddCmd(opISREC, t) -END TypeCheckRec; - - -PROCEDURE New* (size, typenum: INTEGER); -BEGIN - AddCmd2(opNEW, typenum, size) -END New; - - -PROCEDURE not*; -VAR - prev: COMMAND; -BEGIN - prev := codes.last; - IF prev.opcode = opNOT THEN - codes.last := prev.prev(COMMAND); - delete(prev) - ELSE - AddCmd0(opNOT) - END -END not; - - -PROCEDURE _ord*; -BEGIN - IF (codes.last.opcode # opAND) & (codes.last.opcode # opOR) THEN - AddCmd0(opORD) - END -END _ord; - - -PROCEDURE Enter* (label, params: INTEGER): COMMAND; -VAR - cmd: COMMAND; - -BEGIN - cmd := NewCmd(); - cmd.opcode := opENTER; - cmd.param1 := label; - cmd.param3 := params; - insert(codes.last, cmd) - - RETURN codes.last -END Enter; - - -PROCEDURE Leave* (result, float: BOOLEAN; locsize, paramsize: INTEGER): COMMAND; -BEGIN - IF result THEN - IF float THEN - AddCmd2(opLEAVEF, locsize, paramsize) - ELSE - AddCmd2(opLEAVER, locsize, paramsize) - END - ELSE - AddCmd2(opLEAVE, locsize, paramsize) - END - - RETURN codes.last -END Leave; - - -PROCEDURE EnterC* (label: INTEGER): COMMAND; -BEGIN - SetLabel(label) - RETURN codes.last -END EnterC; - - -PROCEDURE LeaveC* (): COMMAND; -BEGIN - AddCmd0(opLEAVEC) - RETURN codes.last -END LeaveC; - - -PROCEDURE Call* (proc, callconv, fparams: INTEGER); -BEGIN - CASE callconv OF - |call_stack: Jmp(opCALL, proc) - |call_win64: Jmp(opWIN64CALL, proc) - |call_sysv: Jmp(opSYSVCALL, proc) - END; - codes.last(COMMAND).param2 := fparams -END Call; - - -PROCEDURE CallImp* (proc: LISTS.ITEM; callconv, fparams: INTEGER); -BEGIN - CASE callconv OF - |call_stack: Jmp(opCALLI, proc(IMPORT_PROC).label) - |call_win64: Jmp(opWIN64CALLI, proc(IMPORT_PROC).label) - |call_sysv: Jmp(opSYSVCALLI, proc(IMPORT_PROC).label) - END; - codes.last(COMMAND).param2 := fparams -END CallImp; - - -PROCEDURE CallP* (callconv, fparams: INTEGER); -BEGIN - CASE callconv OF - |call_stack: AddCmd0(opCALLP) - |call_win64: AddCmd(opWIN64CALLP, fparams) - |call_sysv: AddCmd(opSYSVCALLP, fparams) - END -END CallP; - - -PROCEDURE AssignProc* (proc: INTEGER); -BEGIN - Jmp(opSAVEP, proc) -END AssignProc; - - -PROCEDURE AssignImpProc* (proc: LISTS.ITEM); -BEGIN - Jmp(opSAVEIP, proc(IMPORT_PROC).label) -END AssignImpProc; - - -PROCEDURE PushProc* (proc: INTEGER); -BEGIN - Jmp(opPUSHP, proc) -END PushProc; - - -PROCEDURE PushImpProc* (proc: LISTS.ITEM); -BEGIN - Jmp(opPUSHIP, proc(IMPORT_PROC).label) -END PushImpProc; - - -PROCEDURE ProcCmp* (proc: INTEGER; eq: BOOLEAN); -BEGIN - IF eq THEN - Jmp(opEQP, proc) - ELSE - Jmp(opNEP, proc) - END -END ProcCmp; - - -PROCEDURE ProcImpCmp* (proc: LISTS.ITEM; eq: BOOLEAN); -BEGIN - IF eq THEN - Jmp(opEQIP, proc(IMPORT_PROC).label) - ELSE - Jmp(opNEIP, proc(IMPORT_PROC).label) - END -END ProcImpCmp; - - -PROCEDURE load* (size: INTEGER); -VAR - last: COMMAND; - -BEGIN - last := codes.last; - CASE size OF - |1: - IF last.opcode = opLADR THEN - last.opcode := opLLOAD8 - ELSIF last.opcode = opVADR THEN - last.opcode := opVLOAD8 - ELSIF last.opcode = opGADR THEN - last.opcode := opGLOAD8 - ELSE - AddCmd0(opLOAD8) - END - - |2: - IF last.opcode = opLADR THEN - last.opcode := opLLOAD16 - ELSIF last.opcode = opVADR THEN - last.opcode := opVLOAD16 - ELSIF last.opcode = opGADR THEN - last.opcode := opGLOAD16 - ELSE - AddCmd0(opLOAD16) - END - - |4: - IF last.opcode = opLADR THEN - last.opcode := opLLOAD32 - ELSIF last.opcode = opVADR THEN - last.opcode := opVLOAD32 - ELSIF last.opcode = opGADR THEN - last.opcode := opGLOAD32 - ELSE - AddCmd0(opLOAD32) - END - - |8: - IF last.opcode = opLADR THEN - last.opcode := opLLOAD64 - ELSIF last.opcode = opVADR THEN - last.opcode := opVLOAD64 - ELSIF last.opcode = opGADR THEN - last.opcode := opGLOAD64 - ELSE - AddCmd0(opLOAD64) - END - END -END load; - - -PROCEDURE SysPut* (size: INTEGER); -BEGIN - CASE size OF - |1: AddCmd0(opSAVE8) - |2: AddCmd0(opSAVE16) - |4: AddCmd0(opSAVE32) - |8: AddCmd0(opSAVE64) - END -END SysPut; - - -PROCEDURE savef* (inv: BOOLEAN); -BEGIN - IF inv THEN - AddCmd0(opSAVEFI) - ELSE - AddCmd0(opSAVEF) - END -END savef; - - -PROCEDURE saves* (offset, length: INTEGER); -BEGIN - AddCmd2(opSAVES, length, offset) -END saves; - - -PROCEDURE abs* (real: BOOLEAN); -BEGIN - IF real THEN - AddCmd0(opFABS) - ELSE - AddCmd0(opABS) - END -END abs; - - -PROCEDURE shift_minmax* (op: CHAR); -BEGIN - CASE op OF - |"A": AddCmd0(opASR) - |"L": AddCmd0(opLSL) - |"O": AddCmd0(opROR) - |"R": AddCmd0(opLSR) - |"m": AddCmd0(opMIN) - |"x": AddCmd0(opMAX) - END -END shift_minmax; - - -PROCEDURE shift_minmax1* (op: CHAR; x: INTEGER); -BEGIN - CASE op OF - |"A": AddCmd(opASR1, x) - |"L": AddCmd(opLSL1, x) - |"O": AddCmd(opROR1, x) - |"R": AddCmd(opLSR1, x) - |"m": AddCmd(opMINC, x) - |"x": AddCmd(opMAXC, x) - END -END shift_minmax1; - - -PROCEDURE shift_minmax2* (op: CHAR; x: INTEGER); -BEGIN - CASE op OF - |"A": AddCmd(opASR2, x) - |"L": AddCmd(opLSL2, x) - |"O": AddCmd(opROR2, x) - |"R": AddCmd(opLSR2, x) - |"m": AddCmd(opMINC, x) - |"x": AddCmd(opMAXC, x) - END -END shift_minmax2; - - -PROCEDURE len* (dim: INTEGER); -BEGIN - AddCmd(opLEN, dim) -END len; - - -PROCEDURE Float* (r: REAL; line, col: INTEGER); -VAR - cmd: COMMAND; - -BEGIN - cmd := NewCmd(); - cmd.opcode := opCONSTF; - cmd.float := r; - cmd.param1 := line; - cmd.param2 := col; - insert(codes.last, cmd) -END Float; - - -PROCEDURE drop*; -BEGIN - AddCmd0(opDROP) -END drop; - - -PROCEDURE _case* (a, b, L, R: INTEGER); -VAR - cmd: COMMAND; - -BEGIN - IF a = b THEN - cmd := NewCmd(); - cmd.opcode := opCASELR; - cmd.param1 := a; - cmd.param2 := L; - cmd.param3 := R; - insert(codes.last, cmd) - ELSE - AddCmd2(opCASEL, a, L); - AddCmd2(opCASER, b, R) - END -END _case; - - -PROCEDURE fname* (name: PATHS.PATH); -VAR - cmd: FNAMECMD; - -BEGIN - NEW(cmd); - cmd.opcode := opFNAME; - cmd.fname := name; - insert(codes.last, cmd) -END fname; - - -PROCEDURE AddExp* (label: INTEGER; name: SCAN.IDSTR); -VAR - exp: EXPORT_PROC; - -BEGIN - NEW(exp); - exp.label := label; - exp.name := name; - LISTS.push(codes.export, exp) -END AddExp; - - -PROCEDURE AddImp* (dll, proc: SCAN.TEXTSTR): IMPORT_PROC; -VAR - lib: IMPORT_LIB; - p: IMPORT_PROC; - -BEGIN - lib := codes._import.first(IMPORT_LIB); - WHILE (lib # NIL) & (lib.name # dll) DO - lib := lib.next(IMPORT_LIB) - END; - - IF lib = NIL THEN - NEW(lib); - lib.name := dll; - lib.procs := LISTS.create(NIL); - LISTS.push(codes._import, lib) - END; - - p := lib.procs.first(IMPORT_PROC); - WHILE (p # NIL) & (p.name # proc) DO - p := p.next(IMPORT_PROC) - END; - - IF p = NIL THEN - NEW(p); - p.name := proc; - p.label := NewLabel(); - p.lib := lib; - p.count := 1; - LISTS.push(lib.procs, p) - ELSE - INC(p.count) - END - - RETURN p -END AddImp; - - -PROCEDURE DelImport* (imp: LISTS.ITEM); -VAR - lib: IMPORT_LIB; - -BEGIN - DEC(imp(IMPORT_PROC).count); - IF imp(IMPORT_PROC).count = 0 THEN - lib := imp(IMPORT_PROC).lib; - LISTS.delete(lib.procs, imp); - IF lib.procs.first = NIL THEN - LISTS.delete(codes._import, lib) - END - END -END DelImport; - - -PROCEDURE init* (pCPU: INTEGER); -VAR - cmd: COMMAND; - i: INTEGER; - -BEGIN - commands := C.create(); - - CPU := pCPU; - - NEW(codes.begcall); - codes.begcall.top := -1; - NEW(codes.endcall); - codes.endcall.top := -1; - codes.commands := LISTS.create(NIL); - codes.export := LISTS.create(NIL); - codes._import := LISTS.create(NIL); - codes.types := CHL.CreateIntList(); - codes.data := CHL.CreateByteList(); - - NEW(cmd); cmd.opcode := opNOP; LISTS.push(codes.commands, cmd); - codes.last := cmd; - NEW(cmd); cmd.opcode := opNOP; LISTS.push(codes.commands, cmd); - - AddRec(0); - - codes.lcount := 0; - - FOR i := 0 TO LEN(codes.charoffs) - 1 DO - codes.charoffs[i] := -1 - END; - - FOR i := 0 TO LEN(codes.wcharoffs) - 1 DO - codes.wcharoffs[i] := -1 - END - -END init; - - +(* + BSD 2-Clause License + + Copyright (c) 2018-2021, Anton Krotov + All rights reserved. +*) + +MODULE IL; + +IMPORT LISTS, SCAN, STRINGS, CHL := CHUNKLISTS, C := COLLECTIONS, TARGETS, PATHS; + + +CONST + + call_stack* = 0; + call_win64* = 1; + call_sysv* = 2; + + begin_loop* = 1; end_loop* = 2; + + opJMP* = 0; opLABEL* = 1; opCOPYS* = 2; opGADR* = 3; opCONST* = 4; opLLOAD32* = 5; + opCOPYA* = 6; opCASET* = 7; opMULC* = 8; opMUL* = 9; opDIV* = 10; opMOD* = 11; + opDIVL* = 12; opMODL* = 13; opDIVR* = 14; opMODR* = 15; opUMINUS* = 16; + opADD* = 17; opSUB* = 18; opONERR* = 19; opSUBL* = 20; opADDC* = 21; opSUBR* = 22; + opSAVE* = 23; opSAVEC* = 24; opSAVE8* = 25; opSAVE8C* = 26; opCHKBYTE* = 27; opDROP* = 28; + opNOT* = 29; + + opEQ* = 30; opNE* = opEQ + 1; opLT* = opEQ + 2; opLE* = opEQ + 3; opGT* = opEQ + 4; opGE* = opEQ + 5 (* 35 *); + opEQC* = 36; opNEC* = opEQC + 1; opLTC* = opEQC + 2; opLEC* = opEQC + 3; opGTC* = opEQC + 4; opGEC* = opEQC + 5; (* 41 *) + opEQF* = 42; opNEF* = opEQF + 1; opLTF* = opEQF + 2; opLEF* = opEQF + 3; opGTF* = opEQF + 4; opGEF* = opEQF + 5; (* 47 *) + opEQS* = 48; opNES* = opEQS + 1; opLTS* = opEQS + 2; opLES* = opEQS + 3; opGTS* = opEQS + 4; opGES* = opEQS + 5; (* 53 *) + opEQSW* = 54; opNESW* = opEQSW + 1; opLTSW* = opEQSW + 2; opLESW* = opEQSW + 3; opGTSW* = opEQSW + 4; opGESW* = opEQSW + 5 (* 59 *); + + opVLOAD32* = 60; opGLOAD32* = 61; + + opJZ* = 62; opJNZ* = 63; + + opSAVE32* = 64; opLLOAD8* = 65; + + opCONSTF* = 66; opLOADF* = 67; opSAVEF* = 68; opMULF* = 69; opDIVF* = 70; opDIVFI* = 71; + opUMINF* = 72; opSAVEFI* = 73; opSUBFI* = 74; opADDF* = 75; opSUBF* = 76; + + opJNZ1* = 77; opJG* = 78; + opINCCB* = 79; opDECCB* = 80; opINCB* = 81; opDECB* = 82; + + opCASEL* = 83; opCASER* = 84; opCASELR* = 85; + + opPOPSP* = 86; + opWIN64CALL* = 87; opWIN64CALLI* = 88; opWIN64CALLP* = 89; opAND* = 90; opOR* = 91; + + opLOAD8* = 92; opLOAD16* = 93; opLOAD32* = 94; opPRECALL* = 95; opRES* = 96; opRESF* = 97; + opPUSHC* = 98; opSWITCH* = 99; + + opSBOOL* = 100; opSBOOLC* = 101; opNOP* = 102; + + opMULS* = 103; opMULSC* = 104; opDIVS* = 105; opDIVSC* = 106; + opADDS* = 107; opSUBS* = 108; opERR* = 109; opSUBSL* = 110; opADDSC* = 111; opSUBSR* = 112; + opUMINS* = 113; opIN* = 114; opINL* = 115; opINR* = 116; + opRSET* = 117; opRSETL* = 118; opRSETR* = 119; opRSET1* = 120; opLENGTH* = 121; + + opLEAVEC* = 122; opCODE* = 123; opALIGN16* = 124; + opINCC* = 125; opINC* = 126; opDEC* = 127; + opINCL* = 128; opEXCL* = 129; opINCLC* = 130; opEXCLC* = 131; opNEW* = 132; opDISP* = 133; + opPACK* = 134; opPACKC* = 135; opUNPK* = 136; opCOPY* = 137; opENTER* = 138; opLEAVE* = 139; + opCALL* = 140; opSAVEP* = 141; opCALLP* = 142; opEQP* = 143; opNEP* = 144; opLEAVER* = 145; + opGET* = 146; opSAVE16* = 147; opABS* = 148; opFABS* = 149; opFLOOR* = 150; opFLT* = 151; + opGETC* = 152; opORD* = 153; opASR* = 154; opLSL* = 155; opROR* = 156; + opASR1* = 157; opLSL1* = 158; opROR1* = 159; opASR2* = 160; opLSL2* = 161; opROR2* = 162; + opPUSHP* = 163; opLADR* = 164; opTYPEGP* = 165; opIS* = 166; opPUSHF* = 167; opVADR* = 168; + opPUSHT* = 169; opTYPEGR* = 170; opISREC* = 171; opCHKIDX* = 172; opPARAM* = 173; + opCHKIDX2* = 174; opLEN* = 175; opROT* = 176; opSAVES* = 177; opSADR* = 178; opLENGTHW* = 179; + + opCHR* = 180; opENDSW* = 181; opLEAVEF* = 182; opCLEANUP* = 183; opMOVE* = 184; + opLSR* = 185; opLSR1* = 186; opLSR2* = 187; + opMIN* = 188; opMINC* = 189; opMAX* = 190; opMAXC* = 191; opSYSVALIGN16* = 192; + opEQB* = 193; opNEB* = 194; opINF* = 195; opWIN64ALIGN16* = 196; opVLOAD8* = 197; opGLOAD8* = 198; + opLLOAD16* = 199; opVLOAD16* = 200; opGLOAD16* = 201; + opLOAD64* = 202; opLLOAD64* = 203; opVLOAD64* = 204; opGLOAD64* = 205; opSAVE64* = 206; + + opTYPEGD* = 207; opCALLI* = 208; opPUSHIP* = 209; opSAVEIP* = 210; opEQIP* = 211; opNEIP* = 212; + opSAVE16C* = 213; opWCHR* = 214; opHANDLER* = 215; + + opSYSVCALL* = 216; opSYSVCALLI* = 217; opSYSVCALLP* = 218; opFNAME* = 219; + + + opSADR_PARAM* = -1; opLOAD64_PARAM* = -2; opLLOAD64_PARAM* = -3; opGLOAD64_PARAM* = -4; + opVADR_PARAM* = -5; opCONST_PARAM* = -6; opGLOAD32_PARAM* = -7; opLLOAD32_PARAM* = -8; + opLOAD32_PARAM* = -9; + + opLADR_SAVEC* = -10; opGADR_SAVEC* = -11; opLADR_SAVE* = -12; + + opLADR_INCC* = -13; opLADR_INCCB* = -14; opLADR_DECCB* = -15; + opLADR_INC* = -16; opLADR_DEC* = -17; opLADR_INCB* = -18; opLADR_DECB* = -19; + opLADR_INCL* = -20; opLADR_EXCL* = -21; opLADR_INCLC* = -22; opLADR_EXCLC* = -23; + opLADR_UNPK* = -24; + + + _init *= 0; + _move *= 1; + _strcmpw *= 2; + _exit *= 3; + _set *= 4; + _set1 *= 5; + _lengthw *= 6; + _strcpy *= 7; + _length *= 8; + _divmod *= 9; + _dllentry *= 10; + _sofinit *= 11; + _arrcpy *= 12; + _rot *= 13; + _new *= 14; + _dispose *= 15; + _strcmp *= 16; + _error *= 17; + _is *= 18; + _isrec *= 19; + _guard *= 20; + _guardrec *= 21; + + _fmul *= 22; + _fdiv *= 23; + _fdivi *= 24; + _fadd *= 25; + _fsub *= 26; + _fsubi *= 27; + _fcmp *= 28; + _floor *= 29; + _flt *= 30; + _pack *= 31; + _unpk *= 32; + + +TYPE + + COMMAND* = POINTER TO RECORD (LISTS.ITEM) + + opcode*: INTEGER; + param1*: INTEGER; + param2*: INTEGER; + param3*: INTEGER; + float*: REAL + + END; + + FNAMECMD* = POINTER TO RECORD (COMMAND) + + fname*: PATHS.PATH + + END; + + CMDSTACK = POINTER TO RECORD + + data: ARRAY 1000 OF COMMAND; + top: INTEGER + + END; + + EXPORT_PROC* = POINTER TO RECORD (LISTS.ITEM) + + label*: INTEGER; + name*: SCAN.IDSTR + + END; + + IMPORT_LIB* = POINTER TO RECORD (LISTS.ITEM) + + name*: SCAN.TEXTSTR; + procs*: LISTS.LIST + + END; + + IMPORT_PROC* = POINTER TO RECORD (LISTS.ITEM) + + label*: INTEGER; + lib*: IMPORT_LIB; + name*: SCAN.TEXTSTR; + count: INTEGER + + END; + + + CODES = RECORD + + last: COMMAND; + begcall: CMDSTACK; + endcall: CMDSTACK; + commands*: LISTS.LIST; + export*: LISTS.LIST; + _import*: LISTS.LIST; + types*: CHL.INTLIST; + data*: CHL.BYTELIST; + dmin*: INTEGER; + lcount*: INTEGER; + bss*: INTEGER; + rtl*: ARRAY 33 OF INTEGER; + errlabels*: ARRAY 12 OF INTEGER; + + charoffs: ARRAY 256 OF INTEGER; + wcharoffs: ARRAY 65536 OF INTEGER; + + wstr: ARRAY 4*1024 OF WCHAR + END; + + +VAR + + codes*: CODES; + CPU: INTEGER; + + commands: C.COLLECTION; + + +PROCEDURE set_dmin* (value: INTEGER); +BEGIN + codes.dmin := value +END set_dmin; + + +PROCEDURE set_bss* (value: INTEGER); +BEGIN + codes.bss := value +END set_bss; + + +PROCEDURE set_rtl* (idx, label: INTEGER); +BEGIN + codes.rtl[idx] := label +END set_rtl; + + +PROCEDURE NewCmd (): COMMAND; +VAR + cmd: COMMAND; + citem: C.ITEM; + +BEGIN + citem := C.pop(commands); + IF citem = NIL THEN + NEW(cmd) + ELSE + cmd := citem(COMMAND) + END + + RETURN cmd +END NewCmd; + + +PROCEDURE setlast* (cmd: COMMAND); +BEGIN + codes.last := cmd +END setlast; + + +PROCEDURE getlast* (): COMMAND; + RETURN codes.last +END getlast; + + +PROCEDURE PutByte (b: BYTE); +BEGIN + CHL.PushByte(codes.data, b) +END PutByte; + + +PROCEDURE putstr* (s: ARRAY OF CHAR): INTEGER; +VAR + i, n, res: INTEGER; +BEGIN + res := CHL.Length(codes.data); + + i := 0; + n := LENGTH(s); + WHILE i < n DO + PutByte(ORD(s[i])); + INC(i) + END; + + PutByte(0) + + RETURN res +END putstr; + + +PROCEDURE putstr1* (c: INTEGER): INTEGER; +VAR + res: INTEGER; + +BEGIN + IF codes.charoffs[c] = -1 THEN + res := CHL.Length(codes.data); + PutByte(c); + PutByte(0); + codes.charoffs[c] := res + ELSE + res := codes.charoffs[c] + END + + RETURN res +END putstr1; + + +PROCEDURE putstrW* (s: ARRAY OF CHAR): INTEGER; +VAR + i, n, res: INTEGER; + +BEGIN + res := CHL.Length(codes.data); + + IF ODD(res) THEN + PutByte(0); + INC(res) + END; + + n := STRINGS.Utf8To16(s, codes.wstr); + + i := 0; + WHILE i < n DO + IF TARGETS.LittleEndian THEN + PutByte(ORD(codes.wstr[i]) MOD 256); + PutByte(ORD(codes.wstr[i]) DIV 256) + ELSE + PutByte(ORD(codes.wstr[i]) DIV 256); + PutByte(ORD(codes.wstr[i]) MOD 256) + END; + INC(i) + END; + + PutByte(0); + PutByte(0) + + RETURN res +END putstrW; + + +PROCEDURE putstrW1* (c: INTEGER): INTEGER; +VAR + res: INTEGER; + +BEGIN + IF codes.wcharoffs[c] = -1 THEN + res := CHL.Length(codes.data); + + IF ODD(res) THEN + PutByte(0); + INC(res) + END; + + IF TARGETS.LittleEndian THEN + PutByte(c MOD 256); + PutByte(c DIV 256) + ELSE + PutByte(c DIV 256); + PutByte(c MOD 256) + END; + + PutByte(0); + PutByte(0); + + codes.wcharoffs[c] := res + ELSE + res := codes.wcharoffs[c] + END + + RETURN res +END putstrW1; + + +PROCEDURE push (stk: CMDSTACK; cmd: COMMAND); +BEGIN + INC(stk.top); + stk.data[stk.top] := cmd +END push; + + +PROCEDURE pop (stk: CMDSTACK): COMMAND; +VAR + res: COMMAND; +BEGIN + res := stk.data[stk.top]; + DEC(stk.top) + RETURN res +END pop; + + +PROCEDURE pushBegEnd* (VAR beg, _end: COMMAND); +BEGIN + push(codes.begcall, beg); + push(codes.endcall, _end); + beg := codes.last; + _end := beg.next(COMMAND) +END pushBegEnd; + + +PROCEDURE popBegEnd* (VAR beg, _end: COMMAND); +BEGIN + beg := pop(codes.begcall); + _end := pop(codes.endcall) +END popBegEnd; + + +PROCEDURE AddRec* (base: INTEGER); +BEGIN + CHL.PushInt(codes.types, base) +END AddRec; + + +PROCEDURE insert (cur, nov: COMMAND); +VAR + old_opcode, param2: INTEGER; + + + PROCEDURE set (cur: COMMAND; opcode, param2: INTEGER); + BEGIN + cur.opcode := opcode; + cur.param1 := cur.param2; + cur.param2 := param2 + END set; + + +BEGIN + IF CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64, TARGETS.cpuMSP430} THEN + + old_opcode := cur.opcode; + param2 := nov.param2; + + IF (nov.opcode = opPARAM) & (param2 = 1) THEN + + CASE old_opcode OF + |opGLOAD64: cur.opcode := opGLOAD64_PARAM + |opLLOAD64: cur.opcode := opLLOAD64_PARAM + |opLOAD64: cur.opcode := opLOAD64_PARAM + |opGLOAD32: cur.opcode := opGLOAD32_PARAM + |opLLOAD32: cur.opcode := opLLOAD32_PARAM + |opLOAD32: cur.opcode := opLOAD32_PARAM + |opSADR: cur.opcode := opSADR_PARAM + |opVADR: cur.opcode := opVADR_PARAM + |opCONST: cur.opcode := opCONST_PARAM + ELSE + old_opcode := -1 + END + + ELSIF old_opcode = opLADR THEN + + CASE nov.opcode OF + |opSAVEC: set(cur, opLADR_SAVEC, param2) + |opSAVE: cur.opcode := opLADR_SAVE + |opINC: cur.opcode := opLADR_INC + |opDEC: cur.opcode := opLADR_DEC + |opINCB: cur.opcode := opLADR_INCB + |opDECB: cur.opcode := opLADR_DECB + |opINCL: cur.opcode := opLADR_INCL + |opEXCL: cur.opcode := opLADR_EXCL + |opUNPK: cur.opcode := opLADR_UNPK + |opINCC: set(cur, opLADR_INCC, param2) + |opINCCB: set(cur, opLADR_INCCB, param2) + |opDECCB: set(cur, opLADR_DECCB, param2) + |opINCLC: set(cur, opLADR_INCLC, param2) + |opEXCLC: set(cur, opLADR_EXCLC, param2) + ELSE + old_opcode := -1 + END + + ELSIF (nov.opcode = opSAVEC) & (old_opcode = opGADR) THEN + set(cur, opGADR_SAVEC, param2) + + ELSIF (nov.opcode = opMULC) & (old_opcode = opMULC) THEN + cur.param2 := cur.param2 * param2 + + ELSIF (nov.opcode = opADDC) & (old_opcode = opADDC) THEN + INC(cur.param2, param2) + + ELSE + old_opcode := -1 + END + + ELSIF CPU IN {TARGETS.cpuTHUMB, TARGETS.cpuRVM32I, TARGETS.cpuRVM64I} THEN + + old_opcode := cur.opcode; + param2 := nov.param2; + + IF (old_opcode = opLADR) & (nov.opcode = opSAVE) THEN + cur.opcode := opLADR_SAVE + ELSIF (old_opcode = opLADR) & (nov.opcode = opINCC) THEN + set(cur, opLADR_INCC, param2) + ELSIF (nov.opcode = opMULC) & (old_opcode = opMULC) THEN + cur.param2 := cur.param2 * param2 + ELSIF (nov.opcode = opADDC) & (old_opcode = opADDC) THEN + INC(cur.param2, param2) + ELSE + old_opcode := -1 + END + + ELSE + old_opcode := -1 + END; + + IF old_opcode = -1 THEN + LISTS.insert(codes.commands, cur, nov); + codes.last := nov + ELSE + C.push(commands, nov); + codes.last := cur + END +END insert; + + +PROCEDURE AddCmd* (opcode: INTEGER; param: INTEGER); +VAR + cmd: COMMAND; +BEGIN + cmd := NewCmd(); + cmd.opcode := opcode; + cmd.param1 := 0; + cmd.param2 := param; + insert(codes.last, cmd) +END AddCmd; + + +PROCEDURE AddCmd2* (opcode: INTEGER; param1, param2: INTEGER); +VAR + cmd: COMMAND; +BEGIN + cmd := NewCmd(); + cmd.opcode := opcode; + cmd.param1 := param1; + cmd.param2 := param2; + insert(codes.last, cmd) +END AddCmd2; + + +PROCEDURE Const* (val: INTEGER); +BEGIN + AddCmd(opCONST, val) +END Const; + + +PROCEDURE StrAdr* (adr: INTEGER); +BEGIN + AddCmd(opSADR, adr) +END StrAdr; + + +PROCEDURE Param1*; +BEGIN + AddCmd(opPARAM, 1) +END Param1; + + +PROCEDURE NewLabel* (): INTEGER; +BEGIN + INC(codes.lcount) + RETURN codes.lcount - 1 +END NewLabel; + + +PROCEDURE SetLabel* (label: INTEGER); +BEGIN + AddCmd2(opLABEL, label, 0) +END SetLabel; + + +PROCEDURE SetErrLabel* (errno: INTEGER); +BEGIN + codes.errlabels[errno] := NewLabel(); + SetLabel(codes.errlabels[errno]) +END SetErrLabel; + + +PROCEDURE AddCmd0* (opcode: INTEGER); +BEGIN + AddCmd(opcode, 0) +END AddCmd0; + + +PROCEDURE delete (cmd: COMMAND); +BEGIN + LISTS.delete(codes.commands, cmd); + C.push(commands, cmd) +END delete; + + +PROCEDURE delete2* (first, last: LISTS.ITEM); +VAR + cur, next: LISTS.ITEM; + +BEGIN + cur := first; + + IF first # last THEN + REPEAT + next := cur.next; + LISTS.delete(codes.commands, cur); + C.push(commands, cur); + cur := next + UNTIL cur = last + END; + + LISTS.delete(codes.commands, cur); + C.push(commands, cur) +END delete2; + + +PROCEDURE Jmp* (opcode: INTEGER; label: INTEGER); +VAR + prev: COMMAND; + not: BOOLEAN; + +BEGIN + prev := codes.last; + not := prev.opcode = opNOT; + IF not THEN + IF opcode = opJNZ THEN + opcode := opJZ + ELSIF opcode = opJZ THEN + opcode := opJNZ + ELSE + not := FALSE + END + END; + + AddCmd2(opcode, label, label); + + IF not THEN + delete(prev) + END +END Jmp; + + +PROCEDURE AndOrOpt* (VAR label: INTEGER); +VAR + cur, prev: COMMAND; + i, op, l: INTEGER; + jz, not: BOOLEAN; + +BEGIN + cur := codes.last; + not := cur.opcode = opNOT; + IF not THEN + cur := cur.prev(COMMAND) + END; + + IF cur.opcode = opAND THEN + op := opAND + ELSIF cur.opcode = opOR THEN + op := opOR + ELSE + op := -1 + END; + + cur := codes.last; + + IF op # -1 THEN + IF not THEN + IF op = opAND THEN + op := opOR + ELSE (* op = opOR *) + op := opAND + END; + prev := cur.prev(COMMAND); + delete(cur); + cur := prev + END; + + FOR i := 1 TO 9 DO + IF i = 8 THEN + l := cur.param1 + ELSIF i = 9 THEN + jz := cur.opcode = opJZ + END; + prev := cur.prev(COMMAND); + delete(cur); + cur := prev + END; + + setlast(cur); + + IF op = opAND THEN + label := l; + jz := ~jz + END; + + IF jz THEN + Jmp(opJZ, label) + ELSE + Jmp(opJNZ, label) + END; + + IF op = opOR THEN + SetLabel(l) + END + ELSE + Jmp(opJZ, label) + END; + + setlast(codes.last) +END AndOrOpt; + + +PROCEDURE OnError* (line, error: INTEGER); +BEGIN + AddCmd2(opONERR, codes.errlabels[error], line) +END OnError; + + +PROCEDURE TypeGuard* (op, t: INTEGER; line, error: INTEGER); +VAR + label: INTEGER; +BEGIN + AddCmd(op, t); + label := NewLabel(); + Jmp(opJNZ, label); + OnError(line, error); + SetLabel(label) +END TypeGuard; + + +PROCEDURE TypeCheck* (t: INTEGER); +BEGIN + AddCmd(opIS, t) +END TypeCheck; + + +PROCEDURE TypeCheckRec* (t: INTEGER); +BEGIN + AddCmd(opISREC, t) +END TypeCheckRec; + + +PROCEDURE New* (size, typenum: INTEGER); +BEGIN + AddCmd2(opNEW, typenum, size) +END New; + + +PROCEDURE not*; +VAR + prev: COMMAND; +BEGIN + prev := codes.last; + IF prev.opcode = opNOT THEN + codes.last := prev.prev(COMMAND); + delete(prev) + ELSE + AddCmd0(opNOT) + END +END not; + + +PROCEDURE _ord*; +BEGIN + IF (codes.last.opcode # opAND) & (codes.last.opcode # opOR) THEN + AddCmd0(opORD) + END +END _ord; + + +PROCEDURE Enter* (label, params: INTEGER): COMMAND; +VAR + cmd: COMMAND; + +BEGIN + cmd := NewCmd(); + cmd.opcode := opENTER; + cmd.param1 := label; + cmd.param3 := params; + insert(codes.last, cmd) + + RETURN codes.last +END Enter; + + +PROCEDURE Leave* (result, float: BOOLEAN; locsize, paramsize: INTEGER): COMMAND; +BEGIN + IF result THEN + IF float THEN + AddCmd2(opLEAVEF, locsize, paramsize) + ELSE + AddCmd2(opLEAVER, locsize, paramsize) + END + ELSE + AddCmd2(opLEAVE, locsize, paramsize) + END + + RETURN codes.last +END Leave; + + +PROCEDURE EnterC* (label: INTEGER): COMMAND; +BEGIN + SetLabel(label) + RETURN codes.last +END EnterC; + + +PROCEDURE LeaveC* (): COMMAND; +BEGIN + AddCmd0(opLEAVEC) + RETURN codes.last +END LeaveC; + + +PROCEDURE Call* (proc, callconv, fparams: INTEGER); +BEGIN + CASE callconv OF + |call_stack: Jmp(opCALL, proc) + |call_win64: Jmp(opWIN64CALL, proc) + |call_sysv: Jmp(opSYSVCALL, proc) + END; + codes.last(COMMAND).param2 := fparams +END Call; + + +PROCEDURE CallImp* (proc: LISTS.ITEM; callconv, fparams: INTEGER); +BEGIN + CASE callconv OF + |call_stack: Jmp(opCALLI, proc(IMPORT_PROC).label) + |call_win64: Jmp(opWIN64CALLI, proc(IMPORT_PROC).label) + |call_sysv: Jmp(opSYSVCALLI, proc(IMPORT_PROC).label) + END; + codes.last(COMMAND).param2 := fparams +END CallImp; + + +PROCEDURE CallP* (callconv, fparams: INTEGER); +BEGIN + CASE callconv OF + |call_stack: AddCmd0(opCALLP) + |call_win64: AddCmd(opWIN64CALLP, fparams) + |call_sysv: AddCmd(opSYSVCALLP, fparams) + END +END CallP; + + +PROCEDURE AssignProc* (proc: INTEGER); +BEGIN + Jmp(opSAVEP, proc) +END AssignProc; + + +PROCEDURE AssignImpProc* (proc: LISTS.ITEM); +BEGIN + Jmp(opSAVEIP, proc(IMPORT_PROC).label) +END AssignImpProc; + + +PROCEDURE PushProc* (proc: INTEGER); +BEGIN + Jmp(opPUSHP, proc) +END PushProc; + + +PROCEDURE PushImpProc* (proc: LISTS.ITEM); +BEGIN + Jmp(opPUSHIP, proc(IMPORT_PROC).label) +END PushImpProc; + + +PROCEDURE ProcCmp* (proc: INTEGER; eq: BOOLEAN); +BEGIN + IF eq THEN + Jmp(opEQP, proc) + ELSE + Jmp(opNEP, proc) + END +END ProcCmp; + + +PROCEDURE ProcImpCmp* (proc: LISTS.ITEM; eq: BOOLEAN); +BEGIN + IF eq THEN + Jmp(opEQIP, proc(IMPORT_PROC).label) + ELSE + Jmp(opNEIP, proc(IMPORT_PROC).label) + END +END ProcImpCmp; + + +PROCEDURE load* (size: INTEGER); +VAR + last: COMMAND; + +BEGIN + last := codes.last; + CASE size OF + |1: + IF last.opcode = opLADR THEN + last.opcode := opLLOAD8 + ELSIF last.opcode = opVADR THEN + last.opcode := opVLOAD8 + ELSIF last.opcode = opGADR THEN + last.opcode := opGLOAD8 + ELSE + AddCmd0(opLOAD8) + END + + |2: + IF last.opcode = opLADR THEN + last.opcode := opLLOAD16 + ELSIF last.opcode = opVADR THEN + last.opcode := opVLOAD16 + ELSIF last.opcode = opGADR THEN + last.opcode := opGLOAD16 + ELSE + AddCmd0(opLOAD16) + END + + |4: + IF last.opcode = opLADR THEN + last.opcode := opLLOAD32 + ELSIF last.opcode = opVADR THEN + last.opcode := opVLOAD32 + ELSIF last.opcode = opGADR THEN + last.opcode := opGLOAD32 + ELSE + AddCmd0(opLOAD32) + END + + |8: + IF last.opcode = opLADR THEN + last.opcode := opLLOAD64 + ELSIF last.opcode = opVADR THEN + last.opcode := opVLOAD64 + ELSIF last.opcode = opGADR THEN + last.opcode := opGLOAD64 + ELSE + AddCmd0(opLOAD64) + END + END +END load; + + +PROCEDURE SysPut* (size: INTEGER); +BEGIN + CASE size OF + |1: AddCmd0(opSAVE8) + |2: AddCmd0(opSAVE16) + |4: AddCmd0(opSAVE32) + |8: AddCmd0(opSAVE64) + END +END SysPut; + + +PROCEDURE savef* (inv: BOOLEAN); +BEGIN + IF inv THEN + AddCmd0(opSAVEFI) + ELSE + AddCmd0(opSAVEF) + END +END savef; + + +PROCEDURE saves* (offset, length: INTEGER); +BEGIN + AddCmd2(opSAVES, length, offset) +END saves; + + +PROCEDURE abs* (real: BOOLEAN); +BEGIN + IF real THEN + AddCmd0(opFABS) + ELSE + AddCmd0(opABS) + END +END abs; + + +PROCEDURE shift_minmax* (op: CHAR); +BEGIN + CASE op OF + |"A": AddCmd0(opASR) + |"L": AddCmd0(opLSL) + |"O": AddCmd0(opROR) + |"R": AddCmd0(opLSR) + |"m": AddCmd0(opMIN) + |"x": AddCmd0(opMAX) + END +END shift_minmax; + + +PROCEDURE shift_minmax1* (op: CHAR; x: INTEGER); +BEGIN + CASE op OF + |"A": AddCmd(opASR1, x) + |"L": AddCmd(opLSL1, x) + |"O": AddCmd(opROR1, x) + |"R": AddCmd(opLSR1, x) + |"m": AddCmd(opMINC, x) + |"x": AddCmd(opMAXC, x) + END +END shift_minmax1; + + +PROCEDURE shift_minmax2* (op: CHAR; x: INTEGER); +BEGIN + CASE op OF + |"A": AddCmd(opASR2, x) + |"L": AddCmd(opLSL2, x) + |"O": AddCmd(opROR2, x) + |"R": AddCmd(opLSR2, x) + |"m": AddCmd(opMINC, x) + |"x": AddCmd(opMAXC, x) + END +END shift_minmax2; + + +PROCEDURE len* (dim: INTEGER); +BEGIN + AddCmd(opLEN, dim) +END len; + + +PROCEDURE Float* (r: REAL; line, col: INTEGER); +VAR + cmd: COMMAND; + +BEGIN + cmd := NewCmd(); + cmd.opcode := opCONSTF; + cmd.float := r; + cmd.param1 := line; + cmd.param2 := col; + insert(codes.last, cmd) +END Float; + + +PROCEDURE drop*; +BEGIN + AddCmd0(opDROP) +END drop; + + +PROCEDURE _case* (a, b, L, R: INTEGER); +VAR + cmd: COMMAND; + +BEGIN + IF a = b THEN + cmd := NewCmd(); + cmd.opcode := opCASELR; + cmd.param1 := a; + cmd.param2 := L; + cmd.param3 := R; + insert(codes.last, cmd) + ELSE + AddCmd2(opCASEL, a, L); + AddCmd2(opCASER, b, R) + END +END _case; + + +PROCEDURE fname* (name: PATHS.PATH); +VAR + cmd: FNAMECMD; + +BEGIN + NEW(cmd); + cmd.opcode := opFNAME; + cmd.fname := name; + insert(codes.last, cmd) +END fname; + + +PROCEDURE AddExp* (label: INTEGER; name: SCAN.IDSTR); +VAR + exp: EXPORT_PROC; + +BEGIN + NEW(exp); + exp.label := label; + exp.name := name; + LISTS.push(codes.export, exp) +END AddExp; + + +PROCEDURE AddImp* (dll, proc: SCAN.TEXTSTR): IMPORT_PROC; +VAR + lib: IMPORT_LIB; + p: IMPORT_PROC; + +BEGIN + lib := codes._import.first(IMPORT_LIB); + WHILE (lib # NIL) & (lib.name # dll) DO + lib := lib.next(IMPORT_LIB) + END; + + IF lib = NIL THEN + NEW(lib); + lib.name := dll; + lib.procs := LISTS.create(NIL); + LISTS.push(codes._import, lib) + END; + + p := lib.procs.first(IMPORT_PROC); + WHILE (p # NIL) & (p.name # proc) DO + p := p.next(IMPORT_PROC) + END; + + IF p = NIL THEN + NEW(p); + p.name := proc; + p.label := NewLabel(); + p.lib := lib; + p.count := 1; + LISTS.push(lib.procs, p) + ELSE + INC(p.count) + END + + RETURN p +END AddImp; + + +PROCEDURE DelImport* (imp: LISTS.ITEM); +VAR + lib: IMPORT_LIB; + +BEGIN + DEC(imp(IMPORT_PROC).count); + IF imp(IMPORT_PROC).count = 0 THEN + lib := imp(IMPORT_PROC).lib; + LISTS.delete(lib.procs, imp); + IF lib.procs.first = NIL THEN + LISTS.delete(codes._import, lib) + END + END +END DelImport; + + +PROCEDURE init* (pCPU: INTEGER); +VAR + cmd: COMMAND; + i: INTEGER; + +BEGIN + commands := C.create(); + + CPU := pCPU; + + NEW(codes.begcall); + codes.begcall.top := -1; + NEW(codes.endcall); + codes.endcall.top := -1; + codes.commands := LISTS.create(NIL); + codes.export := LISTS.create(NIL); + codes._import := LISTS.create(NIL); + codes.types := CHL.CreateIntList(); + codes.data := CHL.CreateByteList(); + + NEW(cmd); cmd.opcode := opNOP; LISTS.push(codes.commands, cmd); + codes.last := cmd; + NEW(cmd); cmd.opcode := opNOP; LISTS.push(codes.commands, cmd); + + AddRec(0); + + codes.lcount := 0; + + FOR i := 0 TO LEN(codes.charoffs) - 1 DO + codes.charoffs[i] := -1 + END; + + FOR i := 0 TO LEN(codes.wcharoffs) - 1 DO + codes.wcharoffs[i] := -1 + END + +END init; + + END IL. \ No newline at end of file diff --git a/programs/develop/oberon07/source/MSP430.ob07 b/programs/develop/oberon07/source/MSP430.ob07 index 9df92b6196..abba309e77 100644 --- a/programs/develop/oberon07/source/MSP430.ob07 +++ b/programs/develop/oberon07/source/MSP430.ob07 @@ -1,1780 +1,1780 @@ -(* - BSD 2-Clause License - - Copyright (c) 2019-2021, Anton Krotov - All rights reserved. -*) - -MODULE MSP430; - -IMPORT IL, LISTS, REG, CHL := CHUNKLISTS, ERRORS, WR := WRITER, HEX, - UTILS, C := CONSOLE, PROG, RTL := MSP430RTL; - - -CONST - - chkSTK* = 6; - - minRAM* = 128; maxRAM* = 2048; - minROM* = 2048; maxROM* = 24576; - - StkReserve = RTL.StkReserve; - - IntVectorSize* = RTL.IntVectorSize; - - PC = 0; SP = 1; SR = 2; CG = 3; - - R4 = 4; R5 = 5; R6 = 6; R7 = 7; - - HP = RTL.HP; - - ACC = R4; - - opRRC = 1000H; opSWPB = 1080H; opRRA = 1100H; opSXT = 1180H; - opPUSH = 1200H; opCALL = 1280H; opRETI = 1300H; - - opMOV = 04000H; opADD = 05000H; opADDC = 06000H; opSUBC = 07000H; - opSUB = 08000H; opCMP = 09000H; opDADD = 0A000H; opBIT = 0B000H; - opBIC = 0C000H; opBIS = 0D000H; opXOR = 0E000H; opAND = 0F000H; - - opJNE = 2000H; opJEQ = 2400H; opJNC = 2800H; opJC = 2C00H; - opJN = 3000H; opJGE = 3400H; opJL = 3800H; opJMP = 3C00H; - - sREG = 0; sIDX = 16; sINDIR = 32; sINCR = 48; BW = 64; dIDX = 128; - - NOWORD = 10000H; - - RCODE = 0; RDATA = 1; RBSS = 2; - - je = 0; jne = je + 1; - jge = 2; jl = jge + 1; - jle = 4; jg = jle + 1; - jb = 6; - - -TYPE - - ANYCODE = POINTER TO RECORD (LISTS.ITEM) - - offset: INTEGER - - END; - - WORD = POINTER TO RECORD (ANYCODE) - - val: INTEGER - - END; - - LABEL = POINTER TO RECORD (ANYCODE) - - num: INTEGER - - END; - - JMP = POINTER TO RECORD (ANYCODE) - - cc, label: INTEGER; - short: BOOLEAN - - END; - - CALL = POINTER TO RECORD (ANYCODE) - - label: INTEGER - - END; - - COMMAND = IL.COMMAND; - - RELOC = POINTER TO RECORD (LISTS.ITEM) - - section: INTEGER; - WordPtr: WORD - - END; - - -VAR - - R: REG.REGS; - - CodeList: LISTS.LIST; - RelList: LISTS.LIST; - - mem: ARRAY 65536 OF BYTE; - - Labels: CHL.INTLIST; - - IV: ARRAY RTL.LenIV OF INTEGER; - - IdxWords: RECORD src, dst: INTEGER END; - - StkCnt, MaxStkCnt: INTEGER; - - -PROCEDURE CheckProcDataSize* (VarSize, RamSize: INTEGER): BOOLEAN; - RETURN (VarSize + 1) * 2 + StkReserve + RTL.VarSize < RamSize -END CheckProcDataSize; - - -PROCEDURE EmitLabel (L: INTEGER); -VAR - label: LABEL; - -BEGIN - NEW(label); - label.num := L; - LISTS.push(CodeList, label) -END EmitLabel; - - -PROCEDURE EmitWord (val: INTEGER); -VAR - word: WORD; - -BEGIN - IF val < 0 THEN - ASSERT(val >= -32768); - val := val MOD 65536 - ELSE - ASSERT(val <= 65535) - END; - NEW(word); - word.val := val; - LISTS.push(CodeList, word) -END EmitWord; - - -PROCEDURE EmitJmp (cc, label: INTEGER); -VAR - jmp: JMP; - -BEGIN - NEW(jmp); - jmp.cc := cc; - jmp.label := label; - jmp.short := FALSE; - LISTS.push(CodeList, jmp) -END EmitJmp; - - -PROCEDURE EmitCall (label: INTEGER); -VAR - call: CALL; - -BEGIN - NEW(call); - call.label := label; - LISTS.push(CodeList, call) -END EmitCall; - - -PROCEDURE IncStk; -BEGIN - INC(StkCnt); - MaxStkCnt := MAX(StkCnt, MaxStkCnt) -END IncStk; - - -PROCEDURE bw (b: BOOLEAN): INTEGER; - RETURN BW * ORD(b) -END bw; - - -PROCEDURE src_x (x, Rn: INTEGER): INTEGER; -VAR - res: INTEGER; - -BEGIN - IF (x = 0) & ~(Rn IN {PC, SR, CG}) THEN - res := Rn * 256 + sINDIR - ELSE - IdxWords.src := x; - res := Rn * 256 + sIDX - END - - RETURN res -END src_x; - - -PROCEDURE dst_x (x, Rn: INTEGER): INTEGER; -BEGIN - IdxWords.dst := x - RETURN Rn + dIDX -END dst_x; - - -PROCEDURE indir (Rn: INTEGER): INTEGER; - RETURN Rn * 256 + sINDIR -END indir; - - -PROCEDURE incr (Rn: INTEGER): INTEGER; - RETURN Rn * 256 + sINCR -END incr; - - -PROCEDURE imm (x: INTEGER): INTEGER; -VAR - res: INTEGER; - -BEGIN - CASE x OF - | 0: res := CG * 256 - | 1: res := CG * 256 + sIDX - | 2: res := indir(CG) - | 4: res := indir(SR) - | 8: res := incr(SR) - |-1: res := incr(CG) - ELSE - res := incr(PC); - IdxWords.src := x - END - - RETURN res -END imm; - - -PROCEDURE Op2 (op, src, dst: INTEGER); -BEGIN - ASSERT(BITS(op) - {6, 12..15} = {}); - ASSERT(BITS(src) - {4, 5, 8..11} = {}); - ASSERT(BITS(dst) - {0..3, 7} = {}); - - EmitWord(op + src + dst); - - IF IdxWords.src # NOWORD THEN - EmitWord(IdxWords.src); - IdxWords.src := NOWORD - END; - - IF IdxWords.dst # NOWORD THEN - EmitWord(IdxWords.dst); - IdxWords.dst := NOWORD - END -END Op2; - - -PROCEDURE Op1 (op, reg, As: INTEGER); -BEGIN - EmitWord(op + reg + As) -END Op1; - - -PROCEDURE MovRR (src, dst: INTEGER); -BEGIN - Op2(opMOV, src * 256, dst) -END MovRR; - - -PROCEDURE PushImm (imm: INTEGER); -BEGIN - imm := UTILS.Long(imm); - CASE imm OF - | 0: Op1(opPUSH, CG, sREG) - | 1: Op1(opPUSH, CG, sIDX) - | 2: Op1(opPUSH, CG, sINDIR) - |-1: Op1(opPUSH, CG, sINCR) - ELSE - Op1(opPUSH, PC, sINCR); - EmitWord(imm) - END; - IncStk -END PushImm; - - -PROCEDURE PutWord (word: INTEGER; VAR adr: INTEGER); -BEGIN - ASSERT(~ODD(adr)); - ASSERT((0 <= word) & (word <= 65535)); - mem[adr] := word MOD 256; - mem[adr + 1] := word DIV 256; - INC(adr, 2) -END PutWord; - - -PROCEDURE NewLabel (): INTEGER; -BEGIN - CHL.PushInt(Labels, 0) - RETURN IL.NewLabel() -END NewLabel; - - -PROCEDURE LabelOffs (n: INTEGER): INTEGER; - RETURN CHL.GetInt(Labels, n) -END LabelOffs; - - -PROCEDURE Fixup (CodeAdr, IntVectorSize: INTEGER): INTEGER; -VAR - cmd: ANYCODE; - adr: INTEGER; - offset: INTEGER; - diff: INTEGER; - cc: INTEGER; - shorted: BOOLEAN; - -BEGIN - REPEAT - shorted := FALSE; - offset := CodeAdr DIV 2; - - cmd := CodeList.first(ANYCODE); - WHILE cmd # NIL DO - cmd.offset := offset; - CASE cmd OF - |LABEL: CHL.SetInt(Labels, cmd.num, offset) - |JMP: INC(offset); - IF ~cmd.short THEN - INC(offset); - IF cmd.cc # opJMP THEN - INC(offset) - END - END - - |CALL: INC(offset, 2) - |WORD: INC(offset) - END; - cmd := cmd.next(ANYCODE) - END; - - cmd := CodeList.first(ANYCODE); - WHILE cmd # NIL DO - IF (cmd IS JMP) & ~cmd(JMP).short THEN - diff := LabelOffs(cmd(JMP).label) - cmd.offset - 1; - IF ABS(diff) <= 512 THEN - cmd(JMP).short := TRUE; - shorted := TRUE - END - END; - cmd := cmd.next(ANYCODE) - END - - UNTIL ~shorted; - - IF offset * 2 > 10000H - IntVectorSize THEN - ERRORS.Error(203) - END; - - adr := CodeAdr; - cmd := CodeList.first(ANYCODE); - WHILE cmd # NIL DO - CASE cmd OF - |LABEL: - - |JMP: IF ~cmd.short THEN - CASE cmd.cc OF - |opJNE: cc := opJEQ - |opJEQ: cc := opJNE - |opJNC: cc := opJC - |opJC: cc := opJNC - |opJGE: cc := opJL - |opJL: cc := opJGE - |opJMP: cc := opJMP - END; - - IF cc # opJMP THEN - PutWord(cc + 2, adr) (* jcc L *) - END; - - PutWord(4030H, adr); (* MOV @PC+, PC *) - PutWord(LabelOffs(cmd.label) * 2, adr) - (* L: *) - ELSE - diff := LabelOffs(cmd.label) - cmd.offset - 1; - ASSERT((-512 <= diff) & (diff <= 511)); - PutWord(cmd.cc + diff MOD 1024, adr) - END - - |CALL: PutWord(12B0H, adr); (* CALL @PC+ *) - PutWord(LabelOffs(cmd.label) * 2, adr) - - |WORD: PutWord(cmd.val, adr) - - END; - cmd := cmd.next(ANYCODE) - END - - RETURN adr - CodeAdr -END Fixup; - - -PROCEDURE Push (reg: INTEGER); -BEGIN - Op1(opPUSH, reg, sREG); - IncStk -END Push; - - -PROCEDURE Pop (reg: INTEGER); -BEGIN - Op2(opMOV, incr(SP), reg); - DEC(StkCnt) -END Pop; - - -PROCEDURE Test (reg: INTEGER); -BEGIN - Op2(opCMP, imm(0), reg) -END Test; - - -PROCEDURE Clear (reg: INTEGER); -BEGIN - Op2(opMOV, imm(0), reg) -END Clear; - - -PROCEDURE mov (dst, src: INTEGER); -BEGIN - MovRR(src, dst) -END mov; - - -PROCEDURE xchg (reg1, reg2: INTEGER); -BEGIN - Push(reg1); - mov(reg1, reg2); - Pop(reg2) -END xchg; - - -PROCEDURE Reloc (section: INTEGER); -VAR - reloc: RELOC; - -BEGIN - NEW(reloc); - reloc.section := section; - reloc.WordPtr := CodeList.last(WORD); - LISTS.push(RelList, reloc) -END Reloc; - - -PROCEDURE CallRTL (proc, params: INTEGER); -BEGIN - IncStk; - DEC(StkCnt); - EmitCall(RTL.rtl[proc].label); - RTL.Used(proc); - IF params > 0 THEN - Op2(opADD, imm(params * 2), SP); - DEC(StkCnt, params) - END -END CallRTL; - - -PROCEDURE UnOp (VAR reg: INTEGER); -BEGIN - REG.UnOp(R, reg) -END UnOp; - - -PROCEDURE BinOp (VAR reg1, reg2: INTEGER); -BEGIN - REG.BinOp(R, reg1, reg2) -END BinOp; - - -PROCEDURE GetRegA; -BEGIN - ASSERT(REG.GetReg(R, ACC)) -END GetRegA; - - -PROCEDURE drop; -BEGIN - REG.Drop(R) -END drop; - - -PROCEDURE GetAnyReg (): INTEGER; - RETURN REG.GetAnyReg(R) -END GetAnyReg; - - -PROCEDURE PushAll (NumberOfParameters: INTEGER); -BEGIN - REG.PushAll(R); - DEC(R.pushed, NumberOfParameters) -END PushAll; - - -PROCEDURE PushAll_1; -BEGIN - REG.PushAll_1(R) -END PushAll_1; - - -PROCEDURE cond (op: INTEGER): INTEGER; -VAR - res: INTEGER; - -BEGIN - CASE op OF - |IL.opGT, IL.opGTC: res := jg - |IL.opGE, IL.opGEC: res := jge - |IL.opLT, IL.opLTC: res := jl - |IL.opLE, IL.opLEC: res := jle - |IL.opEQ, IL.opEQC: res := je - |IL.opNE, IL.opNEC: res := jne - END - - RETURN res -END cond; - - -PROCEDURE jcc (cc, label: INTEGER); -VAR - L: INTEGER; - -BEGIN - CASE cc OF - |jne: - EmitJmp(opJNE, label) - |je: - EmitJmp(opJEQ, label) - |jge: - EmitJmp(opJGE, label) - |jl: - EmitJmp(opJL, label) - |jle: - EmitJmp(opJL, label); - EmitJmp(opJEQ, label) - |jg: - L := NewLabel(); - EmitJmp(opJEQ, L); - EmitJmp(opJGE, label); - EmitLabel(L) - |jb: - EmitJmp(opJNC, label) - END -END jcc; - - -PROCEDURE setcc (cc, reg: INTEGER); -VAR - L: INTEGER; - -BEGIN - L := NewLabel(); - Op2(opMOV, imm(1), reg); - jcc(cc, L); - Clear(reg); - EmitLabel(L) -END setcc; - - -PROCEDURE Shift2 (op, reg, n: INTEGER); -VAR - reg2: INTEGER; - -BEGIN - IF n >= 8 THEN - CASE op OF - |IL.opASR2: Op1(opSWPB, reg, sREG); Op1(opSXT, reg, sREG) - |IL.opROR2: Op1(opSWPB, reg, sREG) - |IL.opLSL2: Op1(opSWPB, reg, sREG); Op2(opBIC, imm(255), reg) - |IL.opLSR2: Op2(opBIC, imm(255), reg); Op1(opSWPB, reg, sREG) - END; - DEC(n, 8) - END; - - IF (op = IL.opROR2) & (n > 0) THEN - reg2 := GetAnyReg(); - MovRR(reg, reg2) - ELSE - reg2 := -1 - END; - - WHILE n > 0 DO - CASE op OF - |IL.opASR2: Op1(opRRA, reg, sREG) - |IL.opROR2: Op1(opRRC, reg2, sREG); Op1(opRRC, reg, sREG) - |IL.opLSL2: Op2(opADD, reg * 256, reg) - |IL.opLSR2: Op2(opBIC, imm(1), SR); Op1(opRRC, reg, sREG) - END; - DEC(n) - END; - - IF reg2 # -1 THEN - drop - END - -END Shift2; - - -PROCEDURE Neg (reg: INTEGER); -BEGIN - Op2(opXOR, imm(-1), reg); - Op2(opADD, imm(1), reg) -END Neg; - - -PROCEDURE LocalOffset (offset: INTEGER): INTEGER; - RETURN (offset + StkCnt - ORD(offset > 0)) * 2 -END LocalOffset; - - -PROCEDURE LocalDst (offset: INTEGER): INTEGER; - RETURN dst_x(LocalOffset(offset), SP) -END LocalDst; - - -PROCEDURE LocalSrc (offset: INTEGER): INTEGER; - RETURN src_x(LocalOffset(offset), SP) -END LocalSrc; - - -PROCEDURE translate (chk_stk: BOOLEAN); -VAR - cmd, next: COMMAND; - - opcode, param1, param2, L, a, n, c1, c2: INTEGER; - - reg1, reg2: INTEGER; - - cc: INTEGER; - - word: WORD; - -BEGIN - cmd := IL.codes.commands.first(COMMAND); - - WHILE cmd # NIL DO - - param1 := cmd.param1; - param2 := cmd.param2; - - opcode := cmd.opcode; - - CASE opcode OF - |IL.opJMP: - EmitJmp(opJMP, param1) - - |IL.opCALL: - IncStk; - DEC(StkCnt); - EmitCall(param1) - - |IL.opCALLP: - IncStk; - DEC(StkCnt); - UnOp(reg1); - Op1(opCALL, reg1, sREG); - drop; - ASSERT(R.top = -1) - - |IL.opPRECALL: - PushAll(0) - - |IL.opLABEL: - EmitLabel(param1) - - |IL.opSADR_PARAM: - Op1(opPUSH, PC, sINCR); - IncStk; - EmitWord(param2); - Reloc(RDATA) - - |IL.opERR: - CallRTL(RTL._error, 2) - - |IL.opPUSHC: - PushImm(param2) - - |IL.opONERR: - DEC(StkCnt); - EmitWord(0C232H); (* BIC #8, SR; DINT *) - EmitWord(4303H); (* MOV R3, R3; NOP *) - PushImm(param2); - EmitJmp(opJMP, param1) - - |IL.opLEAVEC: - Pop(PC) - - |IL.opENTER: - ASSERT(R.top = -1); - EmitLabel(param1); - n := param2 MOD 65536; - param2 := param2 DIV 65536; - StkCnt := 0; - IF chk_stk THEN - L := NewLabel(); - Op2(opMOV, SP * 256, R4); - Op2(opSUB, HP * 256, R4); - Op2(opCMP, imm(StkReserve), R4); - word := CodeList.last(WORD); - jcc(jge, L); - DEC(StkCnt); - EmitWord(0C232H); (* BIC #8, SR; DINT *) - EmitWord(4303H); (* MOV R3, R3; NOP *) - PushImm(n); - EmitJmp(opJMP, cmd.param3); - EmitLabel(L) - END; - - IF param2 > 8 THEN - Op2(opMOV, imm(param2), R4); - L := NewLabel(); - EmitLabel(L); - Push(CG); - Op2(opSUB, imm(1), R4); - jcc(jne, L) - ELSE - FOR n := 1 TO param2 DO - Push(CG) - END - END; - StkCnt := param2; - MaxStkCnt := StkCnt - - |IL.opLEAVE, IL.opLEAVER: - ASSERT(param2 = 0); - IF opcode = IL.opLEAVER THEN - UnOp(reg1); - IF reg1 # ACC THEN - mov(ACC, reg1) - END; - drop - END; - ASSERT(R.top = -1); - ASSERT(StkCnt = param1); - IF chk_stk THEN - INC(word.val, MaxStkCnt * 2) - END; - IF param1 > 0 THEN - Op2(opADD, imm(param1 * 2), SP) - END; - Pop(PC) - - |IL.opRES: - ASSERT(R.top = -1); - GetRegA - - |IL.opCLEANUP: - IF param2 # 0 THEN - Op2(opADD, imm(param2 * 2), SP); - DEC(StkCnt, param2) - END - - |IL.opCONST: - next := cmd.next(COMMAND); - IF next.opcode = IL.opCONST THEN - c1 := param2; - c2 := next.param2; - next := next.next(COMMAND); - IF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN - Op2(opMOV + bw(next.opcode = IL.opSAVE8), imm(c1), dst_x(c2, SR)); - cmd := next - ELSE - Op2(opMOV, imm(param2), GetAnyReg()) - END - ELSIF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN - UnOp(reg1); - Op2(opMOV + bw(next.opcode = IL.opSAVE8), reg1 * 256, dst_x(param2, SR)); - drop; - cmd := next - ELSE - Op2(opMOV, imm(param2), GetAnyReg()) - END - - |IL.opSADR: - Op2(opMOV, incr(PC), GetAnyReg()); - EmitWord(param2); - Reloc(RDATA) - - |IL.opGADR: - Op2(opMOV, incr(PC), GetAnyReg()); - EmitWord(param2); - Reloc(RBSS) - - |IL.opLADR: - reg1 := GetAnyReg(); - n := LocalOffset(param2); - Op2(opMOV, SP * 256, reg1); - IF n # 0 THEN - Op2(opADD, imm(n), reg1) - END - - |IL.opLLOAD8: - Op2(opMOV + BW, LocalSrc(param2), GetAnyReg()) - - |IL.opLLOAD16, IL.opVADR: - Op2(opMOV, LocalSrc(param2), GetAnyReg()) - - |IL.opGLOAD8: - Op2(opMOV + BW, src_x(param2, SR), GetAnyReg()); - Reloc(RBSS) - - |IL.opGLOAD16: - Op2(opMOV, src_x(param2, SR), GetAnyReg()); - Reloc(RBSS) - - |IL.opLOAD8: - UnOp(reg1); - Op2(opMOV + BW, indir(reg1), reg1) - - |IL.opLOAD16: - UnOp(reg1); - Op2(opMOV, indir(reg1), reg1) - - |IL.opVLOAD8: - reg1 := GetAnyReg(); - Op2(opMOV, LocalSrc(param2), reg1); - Op2(opMOV + BW, indir(reg1), reg1) - - |IL.opVLOAD16: - reg1 := GetAnyReg(); - Op2(opMOV, LocalSrc(param2), reg1); - Op2(opMOV, indir(reg1), reg1) - - |IL.opSAVE, IL.opSAVE16: - BinOp(reg2, reg1); - Op2(opMOV, reg2 * 256, dst_x(0, reg1)); - drop; - drop - - |IL.opSAVE8: - BinOp(reg2, reg1); - Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1)); - drop; - drop - - |IL.opSAVE8C: - UnOp(reg1); - Op2(opMOV + BW, imm(param2), dst_x(0, reg1)); - drop - - |IL.opSAVE16C, IL.opSAVEC: - UnOp(reg1); - Op2(opMOV, imm(param2), dst_x(0, reg1)); - drop - - |IL.opUMINUS: - UnOp(reg1); - Neg(reg1) - - |IL.opADD: - BinOp(reg1, reg2); - Op2(opADD, reg2 * 256, reg1); - drop - - |IL.opADDC: - IF param2 # 0 THEN - UnOp(reg1); - Op2(opADD, imm(param2), reg1) - END - - |IL.opSUB: - BinOp(reg1, reg2); - Op2(opSUB, reg2 * 256, reg1); - drop - - |IL.opSUBR, IL.opSUBL: - UnOp(reg1); - IF param2 # 0 THEN - Op2(opSUB, imm(param2), reg1) - END; - IF opcode = IL.opSUBL THEN - Neg(reg1) - END - - |IL.opLADR_SAVEC: - Op2(opMOV, imm(param2), LocalDst(param1)) - - |IL.opLADR_SAVE: - UnOp(reg1); - Op2(opMOV, reg1 * 256, LocalDst(param2)); - drop - - |IL.opGADR_SAVEC: - Op2(opMOV, imm(param2), dst_x(param1, SR)); - Reloc(RBSS) - - |IL.opCONST_PARAM: - PushImm(param2) - - |IL.opPARAM: - IF param2 = 1 THEN - UnOp(reg1); - Push(reg1); - drop - ELSE - ASSERT(R.top + 1 <= param2); - PushAll(param2) - END - - |IL.opEQ..IL.opGE, - IL.opEQC..IL.opGEC: - - IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN - BinOp(reg1, reg2); - Op2(opCMP, reg2 * 256, reg1); - drop - ELSE - UnOp(reg1); - Op2(opCMP, imm(param2), reg1) - END; - - drop; - cc := cond(opcode); - next := cmd.next(COMMAND); - - IF next.opcode = IL.opJNZ THEN - jcc(cc, next.param1); - cmd := next - ELSIF next.opcode = IL.opJZ THEN - jcc(ORD(BITS(cc) / {0}), next.param1); - cmd := next - ELSE - setcc(cc, GetAnyReg()) - END - - |IL.opNOP, IL.opAND, IL.opOR: - - |IL.opCODE: - EmitWord(param2) - - |IL.opDROP: - UnOp(reg1); - drop - - |IL.opJNZ1: - UnOp(reg1); - Test(reg1); - jcc(jne, param1) - - |IL.opJG: - UnOp(reg1); - Test(reg1); - jcc(jg, param1) - - |IL.opJNZ: - UnOp(reg1); - Test(reg1); - jcc(jne, param1); - drop - - |IL.opJZ: - UnOp(reg1); - Test(reg1); - jcc(je, param1); - drop - - |IL.opNOT: - UnOp(reg1); - Test(reg1); - setcc(je, reg1) - - |IL.opORD: - UnOp(reg1); - Test(reg1); - setcc(jne, reg1) - - |IL.opGET: - BinOp(reg1, reg2); - drop; - drop; - Op2(opMOV + bw(param2 = 1), indir(reg1), dst_x(0, reg2)) - - |IL.opGETC: - UnOp(reg2); - drop; - Op2(opMOV + bw(param2 = 1), src_x(param1, SR), dst_x(0, reg2)) - - |IL.opCHKBYTE: - BinOp(reg1, reg2); - Op2(opCMP, imm(256), reg1); - jcc(jb, param1) - - |IL.opCHKIDX: - UnOp(reg1); - Op2(opCMP, imm(param2), reg1); - jcc(jb, param1) - - |IL.opCHKIDX2: - BinOp(reg1, reg2); - IF param2 # -1 THEN - Op2(opCMP, reg1 * 256, reg2); - jcc(jb, param1) - END; - INCL(R.regs, reg1); - DEC(R.top); - R.stk[R.top] := reg2 - - |IL.opINCC, IL.opINCCB: - UnOp(reg1); - Op2(opADD + bw(opcode = IL.opINCCB), imm(param2), dst_x(0, reg1)); - drop - - |IL.opDECCB: - UnOp(reg1); - Op2(opSUB + BW, imm(param2), dst_x(0, reg1)); - drop - - |IL.opINC, IL.opINCB: - BinOp(reg1, reg2); - Op2(opADD + bw(opcode = IL.opINCB), reg1 * 256, dst_x(0, reg2)); - drop; - drop - - |IL.opDEC, IL.opDECB: - BinOp(reg1, reg2); - Op2(opSUB + bw(opcode = IL.opDECB), reg1 * 256, dst_x(0, reg2)); - drop; - drop - - |IL.opLADR_INCC, IL.opLADR_INCCB: - Op2(opADD + bw(opcode = IL.opLADR_INCCB), imm(param2), LocalDst(param1)) - - |IL.opLADR_DECCB: - Op2(opSUB + BW, imm(param2), LocalDst(param1)) - - |IL.opLADR_INC, IL.opLADR_INCB: - UnOp(reg1); - Op2(opADD + bw(opcode = IL.opLADR_INCB), reg1 * 256, LocalDst(param2)); - drop - - |IL.opLADR_DEC, IL.opLADR_DECB: - UnOp(reg1); - Op2(opSUB + bw(opcode = IL.opLADR_DECB), reg1 * 256, LocalDst(param2)); - drop - - |IL.opPUSHT: - UnOp(reg1); - Op2(opMOV, src_x(-2, reg1), GetAnyReg()) - - |IL.opISREC: - PushAll(2); - PushImm(param2); - CallRTL(RTL._guardrec, 3); - GetRegA - - |IL.opIS: - PushAll(1); - PushImm(param2); - CallRTL(RTL._is, 2); - GetRegA - - |IL.opTYPEGR: - PushAll(1); - PushImm(param2); - CallRTL(RTL._guardrec, 2); - GetRegA - - |IL.opTYPEGP: - UnOp(reg1); - PushAll(0); - Push(reg1); - PushImm(param2); - CallRTL(RTL._guard, 2); - GetRegA - - |IL.opTYPEGD: - UnOp(reg1); - PushAll(0); - Op1(opPUSH, reg1, sIDX); - IncStk; - EmitWord(-2); - PushImm(param2); - CallRTL(RTL._guardrec, 2); - GetRegA - - |IL.opMULS: - BinOp(reg1, reg2); - Op2(opAND, reg2 * 256, reg1); - drop - - |IL.opMULSC: - UnOp(reg1); - Op2(opAND, imm(param2), reg1) - - |IL.opDIVS: - BinOp(reg1, reg2); - Op2(opXOR, reg2 * 256, reg1); - drop - - |IL.opDIVSC: - UnOp(reg1); - Op2(opXOR, imm(param2), reg1) - - |IL.opADDS: - BinOp(reg1, reg2); - Op2(opBIS, reg2 * 256, reg1); - drop - - |IL.opSUBS: - BinOp(reg1, reg2); - Op2(opBIC, reg2 * 256, reg1); - drop - - |IL.opADDSC: - UnOp(reg1); - Op2(opBIS, imm(param2), reg1) - - |IL.opSUBSL: - UnOp(reg1); - Op2(opXOR, imm(-1), reg1); - Op2(opAND, imm(param2), reg1) - - |IL.opSUBSR: - UnOp(reg1); - Op2(opBIC, imm(param2), reg1) - - |IL.opUMINS: - UnOp(reg1); - Op2(opXOR, imm(-1), reg1) - - |IL.opLENGTH: - PushAll(2); - CallRTL(RTL._length, 2); - GetRegA - - |IL.opMAX,IL.opMIN: - BinOp(reg1, reg2); - Op2(opCMP, reg2 * 256, reg1); - IF opcode = IL.opMIN THEN - cc := opJL + 1 - ELSE - cc := opJGE + 1 - END; - EmitWord(cc); (* jge/jl L *) - MovRR(reg2, reg1); - (* L: *) - drop - - |IL.opMAXC, IL.opMINC: - UnOp(reg1); - Op2(opCMP, imm(param2), reg1); - L := NewLabel(); - IF opcode = IL.opMINC THEN - cc := jl - ELSE - cc := jge - END; - jcc(cc, L); - Op2(opMOV, imm(param2), reg1); - EmitLabel(L) - - |IL.opSWITCH: - UnOp(reg1); - IF param2 = 0 THEN - reg2 := ACC - ELSE - reg2 := R5 - END; - IF reg1 # reg2 THEN - ASSERT(REG.GetReg(R, reg2)); - ASSERT(REG.Exchange(R, reg1, reg2)); - drop - END; - drop - - |IL.opENDSW: - - |IL.opCASEL: - Op2(opCMP, imm(param1), ACC); - jcc(jl, param2) - - |IL.opCASER: - Op2(opCMP, imm(param1), ACC); - jcc(jg, param2) - - |IL.opCASELR: - Op2(opCMP, imm(param1), ACC); - IF param2 = cmd.param3 THEN - jcc(jne, param2) - ELSE - jcc(jl, param2); - jcc(jg, cmd.param3) - END - - |IL.opSBOOL: - BinOp(reg2, reg1); - Test(reg2); - setcc(jne, reg2); - Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1)); - drop; - drop - - |IL.opSBOOLC: - UnOp(reg1); - Op2(opMOV + BW, imm(param2), dst_x(0, reg1)); - drop - - |IL.opEQS .. IL.opGES: - PushAll(4); - PushImm((opcode - IL.opEQS) * 12); - CallRTL(RTL._strcmp, 5); - GetRegA - - |IL.opLEN: - UnOp(reg1); - drop; - EXCL(R.regs, reg1); - - WHILE param2 > 0 DO - UnOp(reg2); - drop; - DEC(param2) - END; - - INCL(R.regs, reg1); - ASSERT(REG.GetReg(R, reg1)) - - |IL.opLSL, IL.opASR, IL.opROR, IL.opLSR: - PushAll(2); - CASE opcode OF - |IL.opLSL: CallRTL(RTL._lsl, 2) - |IL.opASR: CallRTL(RTL._asr, 2) - |IL.opROR: CallRTL(RTL._ror, 2) - |IL.opLSR: CallRTL(RTL._lsr, 2) - END; - GetRegA - - |IL.opLSL1, IL.opASR1, IL.opROR1, IL.opLSR1: - UnOp(reg1); - PushAll_1; - PushImm(param2); - Push(reg1); - drop; - CASE opcode OF - |IL.opLSL1: CallRTL(RTL._lsl, 2) - |IL.opASR1: CallRTL(RTL._asr, 2) - |IL.opROR1: CallRTL(RTL._ror, 2) - |IL.opLSR1: CallRTL(RTL._lsr, 2) - END; - GetRegA - - |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: - param2 := param2 MOD 16; - IF param2 # 0 THEN - UnOp(reg1); - Shift2(opcode, reg1, param2) - END - - |IL.opMUL: - PushAll(2); - CallRTL(RTL._mul, 2); - GetRegA - - |IL.opMULC: - UnOp(reg1); - - a := param2; - IF a > 1 THEN - n := UTILS.Log2(a) - ELSIF a < -1 THEN - n := UTILS.Log2(-a) - ELSE - n := -1 - END; - - IF a = 1 THEN - - ELSIF a = -1 THEN - Neg(reg1) - ELSIF a = 0 THEN - Clear(reg1) - ELSE - IF n > 0 THEN - IF a < 0 THEN - Neg(reg1) - END; - Shift2(IL.opLSL2, reg1, n) - ELSE - PushAll(1); - PushImm(a); - CallRTL(RTL._mul, 2); - GetRegA - END - END - - |IL.opDIV: - PushAll(2); - CallRTL(RTL._divmod, 2); - GetRegA - - |IL.opDIVR: - ASSERT(param2 > 0); - - IF param2 > 1 THEN - n := UTILS.Log2(param2); - IF n > 0 THEN - UnOp(reg1); - Shift2(IL.opASR2, reg1, n) - ELSE - PushAll(1); - PushImm(param2); - CallRTL(RTL._divmod, 2); - GetRegA - END - END - - |IL.opDIVL: - UnOp(reg1); - PushAll_1; - PushImm(param2); - Push(reg1); - drop; - CallRTL(RTL._divmod, 2); - GetRegA - - |IL.opMOD: - PushAll(2); - CallRTL(RTL._divmod, 2); - ASSERT(REG.GetReg(R, R5)) - - |IL.opMODR: - ASSERT(param2 > 0); - - IF param2 = 1 THEN - UnOp(reg1); - Clear(reg1) - ELSE - IF UTILS.Log2(param2) > 0 THEN - UnOp(reg1); - Op2(opAND, imm(param2 - 1), reg1) - ELSE - PushAll(1); - PushImm(param2); - CallRTL(RTL._divmod, 2); - ASSERT(REG.GetReg(R, R5)) - END - END - - |IL.opMODL: - UnOp(reg1); - PushAll_1; - PushImm(param2); - Push(reg1); - drop; - CallRTL(RTL._divmod, 2); - ASSERT(REG.GetReg(R, R5)) - - |IL.opCOPYS: - ASSERT(R.top = 3); - Push(R.stk[2]); - Push(R.stk[0]); - Op2(opCMP, R.stk[1] * 256, R.stk[3]); - EmitWord(3801H); (* JL L1 *) - MovRR(R.stk[1], R.stk[3]); - (* L1: *) - Push(R.stk[3]); - drop; - drop; - drop; - drop; - CallRTL(RTL._move, 3) - - |IL.opCOPY: - PushAll(2); - PushImm(param2); - CallRTL(RTL._move, 3) - - |IL.opMOVE: - PushAll(3); - CallRTL(RTL._move, 3) - - |IL.opCOPYA: - PushAll(4); - PushImm(param2); - CallRTL(RTL._arrcpy, 5); - GetRegA - - |IL.opROT: - PushAll(0); - MovRR(SP, ACC); - Push(ACC); - PushImm(param2); - CallRTL(RTL._rot, 2) - - |IL.opSAVES: - UnOp(reg1); - PushAll_1; - Op1(opPUSH, PC, sINCR); - IncStk; - EmitWord(param2); - Reloc(RDATA); - Push(reg1); - drop; - PushImm(param1); - CallRTL(RTL._move, 3) - - |IL.opCASET: - Push(R5); - Push(R5); - PushImm(param2); - CallRTL(RTL._guardrec, 2); - Pop(R5); - Test(ACC); - jcc(jne, param1) - - |IL.opCHR: - UnOp(reg1); - Op2(opAND, imm(255), reg1) - - |IL.opABS: - UnOp(reg1); - Test(reg1); - L := NewLabel(); - jcc(jge, L); - Neg(reg1); - EmitLabel(L) - - |IL.opEQB, IL.opNEB: - BinOp(reg1, reg2); - drop; - - Test(reg1); - L := NewLabel(); - jcc(je, L); - Op2(opMOV, imm(1), reg1); - EmitLabel(L); - - Test(reg2); - L := NewLabel(); - jcc(je, L); - Op2(opMOV, imm(1), reg2); - EmitLabel(L); - - Op2(opCMP, reg2 * 256, reg1); - IF opcode = IL.opEQB THEN - setcc(je, reg1) - ELSE - setcc(jne, reg1) - END - - |IL.opSAVEP: - UnOp(reg1); - Op2(opMOV, incr(PC), reg1 + dIDX); - EmitWord(param2); - Reloc(RCODE); - EmitWord(0); - drop - - |IL.opPUSHP: - Op2(opMOV, incr(PC), GetAnyReg()); - EmitWord(param2); - Reloc(RCODE) - - |IL.opEQP, IL.opNEP: - UnOp(reg1); - Op2(opCMP, incr(PC), reg1); - EmitWord(param1); - Reloc(RCODE); - drop; - reg1 := GetAnyReg(); - - IF opcode = IL.opEQP THEN - setcc(je, reg1) - ELSIF opcode = IL.opNEP THEN - setcc(jne, reg1) - END - - |IL.opVADR_PARAM: - reg1 := GetAnyReg(); - Op2(opMOV, LocalSrc(param2), reg1); - Push(reg1); - drop - - |IL.opNEW: - PushAll(1); - n := param2 + 2; - ASSERT(UTILS.Align(n, 2)); - PushImm(n); - PushImm(param1); - CallRTL(RTL._new, 3) - - |IL.opRSET: - PushAll(2); - CallRTL(RTL._set, 2); - GetRegA - - |IL.opRSETR: - PushAll(1); - PushImm(param2); - CallRTL(RTL._set, 2); - GetRegA - - |IL.opRSETL: - UnOp(reg1); - PushAll_1; - PushImm(param2); - Push(reg1); - drop; - CallRTL(RTL._set, 2); - GetRegA - - |IL.opRSET1: - PushAll(1); - CallRTL(RTL._set1, 1); - GetRegA - - |IL.opINCLC: - UnOp(reg1); - Op2(opBIS, imm(ORD({param2})), dst_x(0, reg1)); - drop - - |IL.opEXCLC: - UnOp(reg1); - Op2(opBIC, imm(ORD({param2})), dst_x(0, reg1)); - drop - - |IL.opIN: - PushAll(2); - CallRTL(RTL._in, 2); - GetRegA - - |IL.opINR: - PushAll(1); - PushImm(param2); - CallRTL(RTL._in, 2); - GetRegA - - |IL.opINL: - PushAll(1); - PushImm(param2); - CallRTL(RTL._in2, 2); - GetRegA - - |IL.opINCL: - PushAll(2); - CallRTL(RTL._incl, 2) - - |IL.opEXCL: - PushAll(2); - CallRTL(RTL._excl, 2) - - |IL.opLADR_INCL, IL.opLADR_EXCL: - PushAll(1); - MovRR(SP, ACC); - n := LocalOffset(param2); - IF n # 0 THEN - Op2(opADD, imm(n), ACC) - END; - Push(ACC); - IF opcode = IL.opLADR_INCL THEN - CallRTL(RTL._incl, 2) - ELSIF opcode = IL.opLADR_EXCL THEN - CallRTL(RTL._excl, 2) - END - - |IL.opLADR_INCLC: - Op2(opBIS, imm(ORD({param2})), LocalDst(param1)) - - |IL.opLADR_EXCLC: - Op2(opBIC, imm(ORD({param2})), LocalDst(param1)) - - END; - - cmd := cmd.next(COMMAND) - END; - - ASSERT(R.pushed = 0); - ASSERT(R.top = -1) -END translate; - - -PROCEDURE prolog; -VAR - i: INTEGER; - -BEGIN - RTL.Init(EmitLabel, EmitWord, EmitCall); - FOR i := 0 TO LEN(RTL.rtl) - 1 DO - RTL.Set(i, NewLabel()) - END; - - IV[LEN(IV) - 1] := NewLabel(); - EmitLabel(IV[LEN(IV) - 1]); - Op2(opMOV, incr(PC), SP); - EmitWord(0); - Op2(opMOV, incr(PC), HP); - EmitWord(0); - Op2(opMOV, imm(5A80H), dst_x(0120H, SR)); (* stop WDT *) - Op2(opMOV, imm(RTL.empty_proc), dst_x(0, SP)); - Op2(opMOV, imm(RTL.empty_proc), dst_x(2, SP)); -END prolog; - - -PROCEDURE epilog; -VAR - L1, i, n: INTEGER; - -BEGIN - Op2(opBIS, imm(10H), SR); (* CPUOFF *) - - L1 := NewLabel(); - FOR i := 0 TO LEN(IV) - 2 DO - IV[i] := NewLabel(); - EmitLabel(IV[i]); - PushImm(i); - IF i # LEN(IV) - 2 THEN - EmitJmp(opJMP, L1) - END - END; - - EmitLabel(L1); - - n := 0; - FOR i := 0 TO 15 DO - IF i IN R.regs THEN - Push(i); - INC(n) - END - END; - - MovRR(SP, R4); - Op2(opADD, imm(n * 2), R4); - - Push(R4); - Op1(opPUSH, R4, sINDIR); - Op1(opCALL, SR, sIDX); EmitWord(-RTL.VarSize); Reloc(RBSS); (* call int *) - Op2(opADD, imm(4), SP); - - FOR i := 15 TO 0 BY -1 DO - IF i IN R.regs THEN - Pop(i) - END - END; - - Op2(opADD, imm(2), SP); - Op1(opRETI, 0, 0); - - RTL.Gen -END epilog; - - -PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); -VAR - i, adr, heap, stack, TextSize, TypesSize, bits, n, val: INTEGER; - - Code, Data, Bss: RECORD address, size: INTEGER END; - - ram, rom: INTEGER; - - reloc: RELOC; - -BEGIN - IdxWords.src := NOWORD; - IdxWords.dst := NOWORD; - - ram := options.ram; - rom := options.rom; - - IF ODD(ram) THEN DEC(ram) END; - IF ODD(rom) THEN DEC(rom) END; - - ram := MIN(MAX(ram, minRAM), maxRAM); - rom := MIN(MAX(rom, minROM), maxROM); - - IF IL.codes.bss > ram - StkReserve - RTL.VarSize THEN - ERRORS.Error(204) - END; - - Labels := CHL.CreateIntList(); - FOR i := 1 TO IL.codes.lcount DO - CHL.PushInt(Labels, 0) - END; - - CodeList := LISTS.create(NIL); - RelList := LISTS.create(NIL); - REG.Init(R, Push, Pop, mov, xchg, {R4, R5, R6, R7}); - - prolog; - translate(chkSTK IN options.checking); - epilog; - - TypesSize := CHL.Length(IL.codes.types) * 2; - Data.size := CHL.Length(IL.codes.data); - IF ODD(Data.size) THEN - CHL.PushByte(IL.codes.data, 0); - INC(Data.size) - END; - Code.size := Fixup(0, IntVectorSize + TypesSize + Data.size); - Code.address := 10000H - (IntVectorSize + TypesSize + Data.size + Code.size); - IF Code.address < 10000H - rom THEN - ERRORS.Error(203) - END; - Code.size := Fixup(Code.address, IntVectorSize + TypesSize + Data.size); - Data.address := Code.address + Code.size; - TextSize := Code.size + Data.size; - - IF Code.address + TextSize + MAX(IL.codes.dmin - Data.size, IntVectorSize + TypesSize) > 10000H THEN - ERRORS.Error(203) - END; - - stack := RTL.ram + ram; - Bss.size := IL.codes.bss + IL.codes.bss MOD 2; - DEC(stack, Bss.size); - Bss.address := stack; - DEC(stack, RTL.VarSize); - heap := RTL.ram; - ASSERT(stack - heap >= StkReserve); - adr := Code.address + 2; - PutWord(stack, adr); - adr := Code.address + 6; - PutWord(heap, adr); - - reloc := RelList.first(RELOC); - WHILE reloc # NIL DO - adr := reloc.WordPtr.offset * 2; - val := reloc.WordPtr.val; - CASE reloc.section OF - |RCODE: PutWord(LabelOffs(val) * 2, adr) - |RDATA: PutWord(val + Data.address, adr) - |RBSS: PutWord((val + Bss.address) MOD 65536, adr) - END; - reloc := reloc.next(RELOC) - END; - - adr := Data.address; - - FOR i := 0 TO Data.size - 1 DO - mem[adr] := CHL.GetByte(IL.codes.data, i); - INC(adr) - END; - - FOR i := TypesSize DIV 2 - 1 TO 0 BY -1 DO - PutWord(CHL.GetInt(IL.codes.types, i), adr) - END; - - FOR i := 0 TO 15 DO - PutWord((33 - i) * i, adr); - END; - - FOR n := 0 TO 15 DO - bits := ORD({0 .. n}); - FOR i := 0 TO 15 - n DO - PutWord(bits, adr); - bits := LSL(bits, 1) - END - END; - - PutWord(4130H, adr); (* RET *) - PutWord(stack, adr); - PutWord(0001H, adr); (* bsl signature (adr 0FFBEH) *) - - FOR i := 0 TO LEN(IV) - 1 DO - PutWord(LabelOffs(IV[i]) * 2, adr) - END; - - INC(TextSize, IntVectorSize + TypesSize + Code.address MOD 16); - INC(Bss.size, StkReserve + RTL.VarSize); - - WR.Create(outname); - HEX.Data(mem, Code.address - Code.address MOD 16, TextSize); - HEX.End; - WR.Close; - - C.Dashes; - C.String(" rom: "); C.Int(TextSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(TextSize * 100 DIV rom); C.StringLn("%)"); - C.Ln; - C.String(" ram: "); C.Int(Bss.size); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(Bss.size * 100 DIV ram); C.StringLn("%)") -END CodeGen; - - +(* + BSD 2-Clause License + + Copyright (c) 2019-2021, Anton Krotov + All rights reserved. +*) + +MODULE MSP430; + +IMPORT IL, LISTS, REG, CHL := CHUNKLISTS, ERRORS, WR := WRITER, HEX, + UTILS, C := CONSOLE, PROG, RTL := MSP430RTL; + + +CONST + + chkSTK* = 6; + + minRAM* = 128; maxRAM* = 2048; + minROM* = 2048; maxROM* = 24576; + + StkReserve = RTL.StkReserve; + + IntVectorSize* = RTL.IntVectorSize; + + PC = 0; SP = 1; SR = 2; CG = 3; + + R4 = 4; R5 = 5; R6 = 6; R7 = 7; + + HP = RTL.HP; + + ACC = R4; + + opRRC = 1000H; opSWPB = 1080H; opRRA = 1100H; opSXT = 1180H; + opPUSH = 1200H; opCALL = 1280H; opRETI = 1300H; + + opMOV = 04000H; opADD = 05000H; opADDC = 06000H; opSUBC = 07000H; + opSUB = 08000H; opCMP = 09000H; opDADD = 0A000H; opBIT = 0B000H; + opBIC = 0C000H; opBIS = 0D000H; opXOR = 0E000H; opAND = 0F000H; + + opJNE = 2000H; opJEQ = 2400H; opJNC = 2800H; opJC = 2C00H; + opJN = 3000H; opJGE = 3400H; opJL = 3800H; opJMP = 3C00H; + + sREG = 0; sIDX = 16; sINDIR = 32; sINCR = 48; BW = 64; dIDX = 128; + + NOWORD = 10000H; + + RCODE = 0; RDATA = 1; RBSS = 2; + + je = 0; jne = je + 1; + jge = 2; jl = jge + 1; + jle = 4; jg = jle + 1; + jb = 6; + + +TYPE + + ANYCODE = POINTER TO RECORD (LISTS.ITEM) + + offset: INTEGER + + END; + + WORD = POINTER TO RECORD (ANYCODE) + + val: INTEGER + + END; + + LABEL = POINTER TO RECORD (ANYCODE) + + num: INTEGER + + END; + + JMP = POINTER TO RECORD (ANYCODE) + + cc, label: INTEGER; + short: BOOLEAN + + END; + + CALL = POINTER TO RECORD (ANYCODE) + + label: INTEGER + + END; + + COMMAND = IL.COMMAND; + + RELOC = POINTER TO RECORD (LISTS.ITEM) + + section: INTEGER; + WordPtr: WORD + + END; + + +VAR + + R: REG.REGS; + + CodeList: LISTS.LIST; + RelList: LISTS.LIST; + + mem: ARRAY 65536 OF BYTE; + + Labels: CHL.INTLIST; + + IV: ARRAY RTL.LenIV OF INTEGER; + + IdxWords: RECORD src, dst: INTEGER END; + + StkCnt, MaxStkCnt: INTEGER; + + +PROCEDURE CheckProcDataSize* (VarSize, RamSize: INTEGER): BOOLEAN; + RETURN (VarSize + 1) * 2 + StkReserve + RTL.VarSize < RamSize +END CheckProcDataSize; + + +PROCEDURE EmitLabel (L: INTEGER); +VAR + label: LABEL; + +BEGIN + NEW(label); + label.num := L; + LISTS.push(CodeList, label) +END EmitLabel; + + +PROCEDURE EmitWord (val: INTEGER); +VAR + word: WORD; + +BEGIN + IF val < 0 THEN + ASSERT(val >= -32768); + val := val MOD 65536 + ELSE + ASSERT(val <= 65535) + END; + NEW(word); + word.val := val; + LISTS.push(CodeList, word) +END EmitWord; + + +PROCEDURE EmitJmp (cc, label: INTEGER); +VAR + jmp: JMP; + +BEGIN + NEW(jmp); + jmp.cc := cc; + jmp.label := label; + jmp.short := FALSE; + LISTS.push(CodeList, jmp) +END EmitJmp; + + +PROCEDURE EmitCall (label: INTEGER); +VAR + call: CALL; + +BEGIN + NEW(call); + call.label := label; + LISTS.push(CodeList, call) +END EmitCall; + + +PROCEDURE IncStk; +BEGIN + INC(StkCnt); + MaxStkCnt := MAX(StkCnt, MaxStkCnt) +END IncStk; + + +PROCEDURE bw (b: BOOLEAN): INTEGER; + RETURN BW * ORD(b) +END bw; + + +PROCEDURE src_x (x, Rn: INTEGER): INTEGER; +VAR + res: INTEGER; + +BEGIN + IF (x = 0) & ~(Rn IN {PC, SR, CG}) THEN + res := Rn * 256 + sINDIR + ELSE + IdxWords.src := x; + res := Rn * 256 + sIDX + END + + RETURN res +END src_x; + + +PROCEDURE dst_x (x, Rn: INTEGER): INTEGER; +BEGIN + IdxWords.dst := x + RETURN Rn + dIDX +END dst_x; + + +PROCEDURE indir (Rn: INTEGER): INTEGER; + RETURN Rn * 256 + sINDIR +END indir; + + +PROCEDURE incr (Rn: INTEGER): INTEGER; + RETURN Rn * 256 + sINCR +END incr; + + +PROCEDURE imm (x: INTEGER): INTEGER; +VAR + res: INTEGER; + +BEGIN + CASE x OF + | 0: res := CG * 256 + | 1: res := CG * 256 + sIDX + | 2: res := indir(CG) + | 4: res := indir(SR) + | 8: res := incr(SR) + |-1: res := incr(CG) + ELSE + res := incr(PC); + IdxWords.src := x + END + + RETURN res +END imm; + + +PROCEDURE Op2 (op, src, dst: INTEGER); +BEGIN + ASSERT(BITS(op) - {6, 12..15} = {}); + ASSERT(BITS(src) - {4, 5, 8..11} = {}); + ASSERT(BITS(dst) - {0..3, 7} = {}); + + EmitWord(op + src + dst); + + IF IdxWords.src # NOWORD THEN + EmitWord(IdxWords.src); + IdxWords.src := NOWORD + END; + + IF IdxWords.dst # NOWORD THEN + EmitWord(IdxWords.dst); + IdxWords.dst := NOWORD + END +END Op2; + + +PROCEDURE Op1 (op, reg, As: INTEGER); +BEGIN + EmitWord(op + reg + As) +END Op1; + + +PROCEDURE MovRR (src, dst: INTEGER); +BEGIN + Op2(opMOV, src * 256, dst) +END MovRR; + + +PROCEDURE PushImm (imm: INTEGER); +BEGIN + imm := UTILS.Long(imm); + CASE imm OF + | 0: Op1(opPUSH, CG, sREG) + | 1: Op1(opPUSH, CG, sIDX) + | 2: Op1(opPUSH, CG, sINDIR) + |-1: Op1(opPUSH, CG, sINCR) + ELSE + Op1(opPUSH, PC, sINCR); + EmitWord(imm) + END; + IncStk +END PushImm; + + +PROCEDURE PutWord (word: INTEGER; VAR adr: INTEGER); +BEGIN + ASSERT(~ODD(adr)); + ASSERT((0 <= word) & (word <= 65535)); + mem[adr] := word MOD 256; + mem[adr + 1] := word DIV 256; + INC(adr, 2) +END PutWord; + + +PROCEDURE NewLabel (): INTEGER; +BEGIN + CHL.PushInt(Labels, 0) + RETURN IL.NewLabel() +END NewLabel; + + +PROCEDURE LabelOffs (n: INTEGER): INTEGER; + RETURN CHL.GetInt(Labels, n) +END LabelOffs; + + +PROCEDURE Fixup (CodeAdr, IntVectorSize: INTEGER): INTEGER; +VAR + cmd: ANYCODE; + adr: INTEGER; + offset: INTEGER; + diff: INTEGER; + cc: INTEGER; + shorted: BOOLEAN; + +BEGIN + REPEAT + shorted := FALSE; + offset := CodeAdr DIV 2; + + cmd := CodeList.first(ANYCODE); + WHILE cmd # NIL DO + cmd.offset := offset; + CASE cmd OF + |LABEL: CHL.SetInt(Labels, cmd.num, offset) + |JMP: INC(offset); + IF ~cmd.short THEN + INC(offset); + IF cmd.cc # opJMP THEN + INC(offset) + END + END + + |CALL: INC(offset, 2) + |WORD: INC(offset) + END; + cmd := cmd.next(ANYCODE) + END; + + cmd := CodeList.first(ANYCODE); + WHILE cmd # NIL DO + IF (cmd IS JMP) & ~cmd(JMP).short THEN + diff := LabelOffs(cmd(JMP).label) - cmd.offset - 1; + IF ABS(diff) <= 512 THEN + cmd(JMP).short := TRUE; + shorted := TRUE + END + END; + cmd := cmd.next(ANYCODE) + END + + UNTIL ~shorted; + + IF offset * 2 > 10000H - IntVectorSize THEN + ERRORS.Error(203) + END; + + adr := CodeAdr; + cmd := CodeList.first(ANYCODE); + WHILE cmd # NIL DO + CASE cmd OF + |LABEL: + + |JMP: IF ~cmd.short THEN + CASE cmd.cc OF + |opJNE: cc := opJEQ + |opJEQ: cc := opJNE + |opJNC: cc := opJC + |opJC: cc := opJNC + |opJGE: cc := opJL + |opJL: cc := opJGE + |opJMP: cc := opJMP + END; + + IF cc # opJMP THEN + PutWord(cc + 2, adr) (* jcc L *) + END; + + PutWord(4030H, adr); (* MOV @PC+, PC *) + PutWord(LabelOffs(cmd.label) * 2, adr) + (* L: *) + ELSE + diff := LabelOffs(cmd.label) - cmd.offset - 1; + ASSERT((-512 <= diff) & (diff <= 511)); + PutWord(cmd.cc + diff MOD 1024, adr) + END + + |CALL: PutWord(12B0H, adr); (* CALL @PC+ *) + PutWord(LabelOffs(cmd.label) * 2, adr) + + |WORD: PutWord(cmd.val, adr) + + END; + cmd := cmd.next(ANYCODE) + END + + RETURN adr - CodeAdr +END Fixup; + + +PROCEDURE Push (reg: INTEGER); +BEGIN + Op1(opPUSH, reg, sREG); + IncStk +END Push; + + +PROCEDURE Pop (reg: INTEGER); +BEGIN + Op2(opMOV, incr(SP), reg); + DEC(StkCnt) +END Pop; + + +PROCEDURE Test (reg: INTEGER); +BEGIN + Op2(opCMP, imm(0), reg) +END Test; + + +PROCEDURE Clear (reg: INTEGER); +BEGIN + Op2(opMOV, imm(0), reg) +END Clear; + + +PROCEDURE mov (dst, src: INTEGER); +BEGIN + MovRR(src, dst) +END mov; + + +PROCEDURE xchg (reg1, reg2: INTEGER); +BEGIN + Push(reg1); + mov(reg1, reg2); + Pop(reg2) +END xchg; + + +PROCEDURE Reloc (section: INTEGER); +VAR + reloc: RELOC; + +BEGIN + NEW(reloc); + reloc.section := section; + reloc.WordPtr := CodeList.last(WORD); + LISTS.push(RelList, reloc) +END Reloc; + + +PROCEDURE CallRTL (proc, params: INTEGER); +BEGIN + IncStk; + DEC(StkCnt); + EmitCall(RTL.rtl[proc].label); + RTL.Used(proc); + IF params > 0 THEN + Op2(opADD, imm(params * 2), SP); + DEC(StkCnt, params) + END +END CallRTL; + + +PROCEDURE UnOp (VAR reg: INTEGER); +BEGIN + REG.UnOp(R, reg) +END UnOp; + + +PROCEDURE BinOp (VAR reg1, reg2: INTEGER); +BEGIN + REG.BinOp(R, reg1, reg2) +END BinOp; + + +PROCEDURE GetRegA; +BEGIN + ASSERT(REG.GetReg(R, ACC)) +END GetRegA; + + +PROCEDURE drop; +BEGIN + REG.Drop(R) +END drop; + + +PROCEDURE GetAnyReg (): INTEGER; + RETURN REG.GetAnyReg(R) +END GetAnyReg; + + +PROCEDURE PushAll (NumberOfParameters: INTEGER); +BEGIN + REG.PushAll(R); + DEC(R.pushed, NumberOfParameters) +END PushAll; + + +PROCEDURE PushAll_1; +BEGIN + REG.PushAll_1(R) +END PushAll_1; + + +PROCEDURE cond (op: INTEGER): INTEGER; +VAR + res: INTEGER; + +BEGIN + CASE op OF + |IL.opGT, IL.opGTC: res := jg + |IL.opGE, IL.opGEC: res := jge + |IL.opLT, IL.opLTC: res := jl + |IL.opLE, IL.opLEC: res := jle + |IL.opEQ, IL.opEQC: res := je + |IL.opNE, IL.opNEC: res := jne + END + + RETURN res +END cond; + + +PROCEDURE jcc (cc, label: INTEGER); +VAR + L: INTEGER; + +BEGIN + CASE cc OF + |jne: + EmitJmp(opJNE, label) + |je: + EmitJmp(opJEQ, label) + |jge: + EmitJmp(opJGE, label) + |jl: + EmitJmp(opJL, label) + |jle: + EmitJmp(opJL, label); + EmitJmp(opJEQ, label) + |jg: + L := NewLabel(); + EmitJmp(opJEQ, L); + EmitJmp(opJGE, label); + EmitLabel(L) + |jb: + EmitJmp(opJNC, label) + END +END jcc; + + +PROCEDURE setcc (cc, reg: INTEGER); +VAR + L: INTEGER; + +BEGIN + L := NewLabel(); + Op2(opMOV, imm(1), reg); + jcc(cc, L); + Clear(reg); + EmitLabel(L) +END setcc; + + +PROCEDURE Shift2 (op, reg, n: INTEGER); +VAR + reg2: INTEGER; + +BEGIN + IF n >= 8 THEN + CASE op OF + |IL.opASR2: Op1(opSWPB, reg, sREG); Op1(opSXT, reg, sREG) + |IL.opROR2: Op1(opSWPB, reg, sREG) + |IL.opLSL2: Op1(opSWPB, reg, sREG); Op2(opBIC, imm(255), reg) + |IL.opLSR2: Op2(opBIC, imm(255), reg); Op1(opSWPB, reg, sREG) + END; + DEC(n, 8) + END; + + IF (op = IL.opROR2) & (n > 0) THEN + reg2 := GetAnyReg(); + MovRR(reg, reg2) + ELSE + reg2 := -1 + END; + + WHILE n > 0 DO + CASE op OF + |IL.opASR2: Op1(opRRA, reg, sREG) + |IL.opROR2: Op1(opRRC, reg2, sREG); Op1(opRRC, reg, sREG) + |IL.opLSL2: Op2(opADD, reg * 256, reg) + |IL.opLSR2: Op2(opBIC, imm(1), SR); Op1(opRRC, reg, sREG) + END; + DEC(n) + END; + + IF reg2 # -1 THEN + drop + END + +END Shift2; + + +PROCEDURE Neg (reg: INTEGER); +BEGIN + Op2(opXOR, imm(-1), reg); + Op2(opADD, imm(1), reg) +END Neg; + + +PROCEDURE LocalOffset (offset: INTEGER): INTEGER; + RETURN (offset + StkCnt - ORD(offset > 0)) * 2 +END LocalOffset; + + +PROCEDURE LocalDst (offset: INTEGER): INTEGER; + RETURN dst_x(LocalOffset(offset), SP) +END LocalDst; + + +PROCEDURE LocalSrc (offset: INTEGER): INTEGER; + RETURN src_x(LocalOffset(offset), SP) +END LocalSrc; + + +PROCEDURE translate (chk_stk: BOOLEAN); +VAR + cmd, next: COMMAND; + + opcode, param1, param2, L, a, n, c1, c2: INTEGER; + + reg1, reg2: INTEGER; + + cc: INTEGER; + + word: WORD; + +BEGIN + cmd := IL.codes.commands.first(COMMAND); + + WHILE cmd # NIL DO + + param1 := cmd.param1; + param2 := cmd.param2; + + opcode := cmd.opcode; + + CASE opcode OF + |IL.opJMP: + EmitJmp(opJMP, param1) + + |IL.opCALL: + IncStk; + DEC(StkCnt); + EmitCall(param1) + + |IL.opCALLP: + IncStk; + DEC(StkCnt); + UnOp(reg1); + Op1(opCALL, reg1, sREG); + drop; + ASSERT(R.top = -1) + + |IL.opPRECALL: + PushAll(0) + + |IL.opLABEL: + EmitLabel(param1) + + |IL.opSADR_PARAM: + Op1(opPUSH, PC, sINCR); + IncStk; + EmitWord(param2); + Reloc(RDATA) + + |IL.opERR: + CallRTL(RTL._error, 2) + + |IL.opPUSHC: + PushImm(param2) + + |IL.opONERR: + DEC(StkCnt); + EmitWord(0C232H); (* BIC #8, SR; DINT *) + EmitWord(4303H); (* MOV R3, R3; NOP *) + PushImm(param2); + EmitJmp(opJMP, param1) + + |IL.opLEAVEC: + Pop(PC) + + |IL.opENTER: + ASSERT(R.top = -1); + EmitLabel(param1); + n := param2 MOD 65536; + param2 := param2 DIV 65536; + StkCnt := 0; + IF chk_stk THEN + L := NewLabel(); + Op2(opMOV, SP * 256, R4); + Op2(opSUB, HP * 256, R4); + Op2(opCMP, imm(StkReserve), R4); + word := CodeList.last(WORD); + jcc(jge, L); + DEC(StkCnt); + EmitWord(0C232H); (* BIC #8, SR; DINT *) + EmitWord(4303H); (* MOV R3, R3; NOP *) + PushImm(n); + EmitJmp(opJMP, cmd.param3); + EmitLabel(L) + END; + + IF param2 > 8 THEN + Op2(opMOV, imm(param2), R4); + L := NewLabel(); + EmitLabel(L); + Push(CG); + Op2(opSUB, imm(1), R4); + jcc(jne, L) + ELSE + FOR n := 1 TO param2 DO + Push(CG) + END + END; + StkCnt := param2; + MaxStkCnt := StkCnt + + |IL.opLEAVE, IL.opLEAVER: + ASSERT(param2 = 0); + IF opcode = IL.opLEAVER THEN + UnOp(reg1); + IF reg1 # ACC THEN + mov(ACC, reg1) + END; + drop + END; + ASSERT(R.top = -1); + ASSERT(StkCnt = param1); + IF chk_stk THEN + INC(word.val, MaxStkCnt * 2) + END; + IF param1 > 0 THEN + Op2(opADD, imm(param1 * 2), SP) + END; + Pop(PC) + + |IL.opRES: + ASSERT(R.top = -1); + GetRegA + + |IL.opCLEANUP: + IF param2 # 0 THEN + Op2(opADD, imm(param2 * 2), SP); + DEC(StkCnt, param2) + END + + |IL.opCONST: + next := cmd.next(COMMAND); + IF next.opcode = IL.opCONST THEN + c1 := param2; + c2 := next.param2; + next := next.next(COMMAND); + IF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN + Op2(opMOV + bw(next.opcode = IL.opSAVE8), imm(c1), dst_x(c2, SR)); + cmd := next + ELSE + Op2(opMOV, imm(param2), GetAnyReg()) + END + ELSIF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN + UnOp(reg1); + Op2(opMOV + bw(next.opcode = IL.opSAVE8), reg1 * 256, dst_x(param2, SR)); + drop; + cmd := next + ELSE + Op2(opMOV, imm(param2), GetAnyReg()) + END + + |IL.opSADR: + Op2(opMOV, incr(PC), GetAnyReg()); + EmitWord(param2); + Reloc(RDATA) + + |IL.opGADR: + Op2(opMOV, incr(PC), GetAnyReg()); + EmitWord(param2); + Reloc(RBSS) + + |IL.opLADR: + reg1 := GetAnyReg(); + n := LocalOffset(param2); + Op2(opMOV, SP * 256, reg1); + IF n # 0 THEN + Op2(opADD, imm(n), reg1) + END + + |IL.opLLOAD8: + Op2(opMOV + BW, LocalSrc(param2), GetAnyReg()) + + |IL.opLLOAD16, IL.opVADR: + Op2(opMOV, LocalSrc(param2), GetAnyReg()) + + |IL.opGLOAD8: + Op2(opMOV + BW, src_x(param2, SR), GetAnyReg()); + Reloc(RBSS) + + |IL.opGLOAD16: + Op2(opMOV, src_x(param2, SR), GetAnyReg()); + Reloc(RBSS) + + |IL.opLOAD8: + UnOp(reg1); + Op2(opMOV + BW, indir(reg1), reg1) + + |IL.opLOAD16: + UnOp(reg1); + Op2(opMOV, indir(reg1), reg1) + + |IL.opVLOAD8: + reg1 := GetAnyReg(); + Op2(opMOV, LocalSrc(param2), reg1); + Op2(opMOV + BW, indir(reg1), reg1) + + |IL.opVLOAD16: + reg1 := GetAnyReg(); + Op2(opMOV, LocalSrc(param2), reg1); + Op2(opMOV, indir(reg1), reg1) + + |IL.opSAVE, IL.opSAVE16: + BinOp(reg2, reg1); + Op2(opMOV, reg2 * 256, dst_x(0, reg1)); + drop; + drop + + |IL.opSAVE8: + BinOp(reg2, reg1); + Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1)); + drop; + drop + + |IL.opSAVE8C: + UnOp(reg1); + Op2(opMOV + BW, imm(param2), dst_x(0, reg1)); + drop + + |IL.opSAVE16C, IL.opSAVEC: + UnOp(reg1); + Op2(opMOV, imm(param2), dst_x(0, reg1)); + drop + + |IL.opUMINUS: + UnOp(reg1); + Neg(reg1) + + |IL.opADD: + BinOp(reg1, reg2); + Op2(opADD, reg2 * 256, reg1); + drop + + |IL.opADDC: + IF param2 # 0 THEN + UnOp(reg1); + Op2(opADD, imm(param2), reg1) + END + + |IL.opSUB: + BinOp(reg1, reg2); + Op2(opSUB, reg2 * 256, reg1); + drop + + |IL.opSUBR, IL.opSUBL: + UnOp(reg1); + IF param2 # 0 THEN + Op2(opSUB, imm(param2), reg1) + END; + IF opcode = IL.opSUBL THEN + Neg(reg1) + END + + |IL.opLADR_SAVEC: + Op2(opMOV, imm(param2), LocalDst(param1)) + + |IL.opLADR_SAVE: + UnOp(reg1); + Op2(opMOV, reg1 * 256, LocalDst(param2)); + drop + + |IL.opGADR_SAVEC: + Op2(opMOV, imm(param2), dst_x(param1, SR)); + Reloc(RBSS) + + |IL.opCONST_PARAM: + PushImm(param2) + + |IL.opPARAM: + IF param2 = 1 THEN + UnOp(reg1); + Push(reg1); + drop + ELSE + ASSERT(R.top + 1 <= param2); + PushAll(param2) + END + + |IL.opEQ..IL.opGE, + IL.opEQC..IL.opGEC: + + IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN + BinOp(reg1, reg2); + Op2(opCMP, reg2 * 256, reg1); + drop + ELSE + UnOp(reg1); + Op2(opCMP, imm(param2), reg1) + END; + + drop; + cc := cond(opcode); + next := cmd.next(COMMAND); + + IF next.opcode = IL.opJNZ THEN + jcc(cc, next.param1); + cmd := next + ELSIF next.opcode = IL.opJZ THEN + jcc(ORD(BITS(cc) / {0}), next.param1); + cmd := next + ELSE + setcc(cc, GetAnyReg()) + END + + |IL.opNOP, IL.opAND, IL.opOR: + + |IL.opCODE: + EmitWord(param2) + + |IL.opDROP: + UnOp(reg1); + drop + + |IL.opJNZ1: + UnOp(reg1); + Test(reg1); + jcc(jne, param1) + + |IL.opJG: + UnOp(reg1); + Test(reg1); + jcc(jg, param1) + + |IL.opJNZ: + UnOp(reg1); + Test(reg1); + jcc(jne, param1); + drop + + |IL.opJZ: + UnOp(reg1); + Test(reg1); + jcc(je, param1); + drop + + |IL.opNOT: + UnOp(reg1); + Test(reg1); + setcc(je, reg1) + + |IL.opORD: + UnOp(reg1); + Test(reg1); + setcc(jne, reg1) + + |IL.opGET: + BinOp(reg1, reg2); + drop; + drop; + Op2(opMOV + bw(param2 = 1), indir(reg1), dst_x(0, reg2)) + + |IL.opGETC: + UnOp(reg2); + drop; + Op2(opMOV + bw(param2 = 1), src_x(param1, SR), dst_x(0, reg2)) + + |IL.opCHKBYTE: + BinOp(reg1, reg2); + Op2(opCMP, imm(256), reg1); + jcc(jb, param1) + + |IL.opCHKIDX: + UnOp(reg1); + Op2(opCMP, imm(param2), reg1); + jcc(jb, param1) + + |IL.opCHKIDX2: + BinOp(reg1, reg2); + IF param2 # -1 THEN + Op2(opCMP, reg1 * 256, reg2); + jcc(jb, param1) + END; + INCL(R.regs, reg1); + DEC(R.top); + R.stk[R.top] := reg2 + + |IL.opINCC, IL.opINCCB: + UnOp(reg1); + Op2(opADD + bw(opcode = IL.opINCCB), imm(param2), dst_x(0, reg1)); + drop + + |IL.opDECCB: + UnOp(reg1); + Op2(opSUB + BW, imm(param2), dst_x(0, reg1)); + drop + + |IL.opINC, IL.opINCB: + BinOp(reg1, reg2); + Op2(opADD + bw(opcode = IL.opINCB), reg1 * 256, dst_x(0, reg2)); + drop; + drop + + |IL.opDEC, IL.opDECB: + BinOp(reg1, reg2); + Op2(opSUB + bw(opcode = IL.opDECB), reg1 * 256, dst_x(0, reg2)); + drop; + drop + + |IL.opLADR_INCC, IL.opLADR_INCCB: + Op2(opADD + bw(opcode = IL.opLADR_INCCB), imm(param2), LocalDst(param1)) + + |IL.opLADR_DECCB: + Op2(opSUB + BW, imm(param2), LocalDst(param1)) + + |IL.opLADR_INC, IL.opLADR_INCB: + UnOp(reg1); + Op2(opADD + bw(opcode = IL.opLADR_INCB), reg1 * 256, LocalDst(param2)); + drop + + |IL.opLADR_DEC, IL.opLADR_DECB: + UnOp(reg1); + Op2(opSUB + bw(opcode = IL.opLADR_DECB), reg1 * 256, LocalDst(param2)); + drop + + |IL.opPUSHT: + UnOp(reg1); + Op2(opMOV, src_x(-2, reg1), GetAnyReg()) + + |IL.opISREC: + PushAll(2); + PushImm(param2); + CallRTL(RTL._guardrec, 3); + GetRegA + + |IL.opIS: + PushAll(1); + PushImm(param2); + CallRTL(RTL._is, 2); + GetRegA + + |IL.opTYPEGR: + PushAll(1); + PushImm(param2); + CallRTL(RTL._guardrec, 2); + GetRegA + + |IL.opTYPEGP: + UnOp(reg1); + PushAll(0); + Push(reg1); + PushImm(param2); + CallRTL(RTL._guard, 2); + GetRegA + + |IL.opTYPEGD: + UnOp(reg1); + PushAll(0); + Op1(opPUSH, reg1, sIDX); + IncStk; + EmitWord(-2); + PushImm(param2); + CallRTL(RTL._guardrec, 2); + GetRegA + + |IL.opMULS: + BinOp(reg1, reg2); + Op2(opAND, reg2 * 256, reg1); + drop + + |IL.opMULSC: + UnOp(reg1); + Op2(opAND, imm(param2), reg1) + + |IL.opDIVS: + BinOp(reg1, reg2); + Op2(opXOR, reg2 * 256, reg1); + drop + + |IL.opDIVSC: + UnOp(reg1); + Op2(opXOR, imm(param2), reg1) + + |IL.opADDS: + BinOp(reg1, reg2); + Op2(opBIS, reg2 * 256, reg1); + drop + + |IL.opSUBS: + BinOp(reg1, reg2); + Op2(opBIC, reg2 * 256, reg1); + drop + + |IL.opADDSC: + UnOp(reg1); + Op2(opBIS, imm(param2), reg1) + + |IL.opSUBSL: + UnOp(reg1); + Op2(opXOR, imm(-1), reg1); + Op2(opAND, imm(param2), reg1) + + |IL.opSUBSR: + UnOp(reg1); + Op2(opBIC, imm(param2), reg1) + + |IL.opUMINS: + UnOp(reg1); + Op2(opXOR, imm(-1), reg1) + + |IL.opLENGTH: + PushAll(2); + CallRTL(RTL._length, 2); + GetRegA + + |IL.opMAX,IL.opMIN: + BinOp(reg1, reg2); + Op2(opCMP, reg2 * 256, reg1); + IF opcode = IL.opMIN THEN + cc := opJL + 1 + ELSE + cc := opJGE + 1 + END; + EmitWord(cc); (* jge/jl L *) + MovRR(reg2, reg1); + (* L: *) + drop + + |IL.opMAXC, IL.opMINC: + UnOp(reg1); + Op2(opCMP, imm(param2), reg1); + L := NewLabel(); + IF opcode = IL.opMINC THEN + cc := jl + ELSE + cc := jge + END; + jcc(cc, L); + Op2(opMOV, imm(param2), reg1); + EmitLabel(L) + + |IL.opSWITCH: + UnOp(reg1); + IF param2 = 0 THEN + reg2 := ACC + ELSE + reg2 := R5 + END; + IF reg1 # reg2 THEN + ASSERT(REG.GetReg(R, reg2)); + ASSERT(REG.Exchange(R, reg1, reg2)); + drop + END; + drop + + |IL.opENDSW: + + |IL.opCASEL: + Op2(opCMP, imm(param1), ACC); + jcc(jl, param2) + + |IL.opCASER: + Op2(opCMP, imm(param1), ACC); + jcc(jg, param2) + + |IL.opCASELR: + Op2(opCMP, imm(param1), ACC); + IF param2 = cmd.param3 THEN + jcc(jne, param2) + ELSE + jcc(jl, param2); + jcc(jg, cmd.param3) + END + + |IL.opSBOOL: + BinOp(reg2, reg1); + Test(reg2); + setcc(jne, reg2); + Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1)); + drop; + drop + + |IL.opSBOOLC: + UnOp(reg1); + Op2(opMOV + BW, imm(param2), dst_x(0, reg1)); + drop + + |IL.opEQS .. IL.opGES: + PushAll(4); + PushImm((opcode - IL.opEQS) * 12); + CallRTL(RTL._strcmp, 5); + GetRegA + + |IL.opLEN: + UnOp(reg1); + drop; + EXCL(R.regs, reg1); + + WHILE param2 > 0 DO + UnOp(reg2); + drop; + DEC(param2) + END; + + INCL(R.regs, reg1); + ASSERT(REG.GetReg(R, reg1)) + + |IL.opLSL, IL.opASR, IL.opROR, IL.opLSR: + PushAll(2); + CASE opcode OF + |IL.opLSL: CallRTL(RTL._lsl, 2) + |IL.opASR: CallRTL(RTL._asr, 2) + |IL.opROR: CallRTL(RTL._ror, 2) + |IL.opLSR: CallRTL(RTL._lsr, 2) + END; + GetRegA + + |IL.opLSL1, IL.opASR1, IL.opROR1, IL.opLSR1: + UnOp(reg1); + PushAll_1; + PushImm(param2); + Push(reg1); + drop; + CASE opcode OF + |IL.opLSL1: CallRTL(RTL._lsl, 2) + |IL.opASR1: CallRTL(RTL._asr, 2) + |IL.opROR1: CallRTL(RTL._ror, 2) + |IL.opLSR1: CallRTL(RTL._lsr, 2) + END; + GetRegA + + |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: + param2 := param2 MOD 16; + IF param2 # 0 THEN + UnOp(reg1); + Shift2(opcode, reg1, param2) + END + + |IL.opMUL: + PushAll(2); + CallRTL(RTL._mul, 2); + GetRegA + + |IL.opMULC: + UnOp(reg1); + + a := param2; + IF a > 1 THEN + n := UTILS.Log2(a) + ELSIF a < -1 THEN + n := UTILS.Log2(-a) + ELSE + n := -1 + END; + + IF a = 1 THEN + + ELSIF a = -1 THEN + Neg(reg1) + ELSIF a = 0 THEN + Clear(reg1) + ELSE + IF n > 0 THEN + IF a < 0 THEN + Neg(reg1) + END; + Shift2(IL.opLSL2, reg1, n) + ELSE + PushAll(1); + PushImm(a); + CallRTL(RTL._mul, 2); + GetRegA + END + END + + |IL.opDIV: + PushAll(2); + CallRTL(RTL._divmod, 2); + GetRegA + + |IL.opDIVR: + ASSERT(param2 > 0); + + IF param2 > 1 THEN + n := UTILS.Log2(param2); + IF n > 0 THEN + UnOp(reg1); + Shift2(IL.opASR2, reg1, n) + ELSE + PushAll(1); + PushImm(param2); + CallRTL(RTL._divmod, 2); + GetRegA + END + END + + |IL.opDIVL: + UnOp(reg1); + PushAll_1; + PushImm(param2); + Push(reg1); + drop; + CallRTL(RTL._divmod, 2); + GetRegA + + |IL.opMOD: + PushAll(2); + CallRTL(RTL._divmod, 2); + ASSERT(REG.GetReg(R, R5)) + + |IL.opMODR: + ASSERT(param2 > 0); + + IF param2 = 1 THEN + UnOp(reg1); + Clear(reg1) + ELSE + IF UTILS.Log2(param2) > 0 THEN + UnOp(reg1); + Op2(opAND, imm(param2 - 1), reg1) + ELSE + PushAll(1); + PushImm(param2); + CallRTL(RTL._divmod, 2); + ASSERT(REG.GetReg(R, R5)) + END + END + + |IL.opMODL: + UnOp(reg1); + PushAll_1; + PushImm(param2); + Push(reg1); + drop; + CallRTL(RTL._divmod, 2); + ASSERT(REG.GetReg(R, R5)) + + |IL.opCOPYS: + ASSERT(R.top = 3); + Push(R.stk[2]); + Push(R.stk[0]); + Op2(opCMP, R.stk[1] * 256, R.stk[3]); + EmitWord(3801H); (* JL L1 *) + MovRR(R.stk[1], R.stk[3]); + (* L1: *) + Push(R.stk[3]); + drop; + drop; + drop; + drop; + CallRTL(RTL._move, 3) + + |IL.opCOPY: + PushAll(2); + PushImm(param2); + CallRTL(RTL._move, 3) + + |IL.opMOVE: + PushAll(3); + CallRTL(RTL._move, 3) + + |IL.opCOPYA: + PushAll(4); + PushImm(param2); + CallRTL(RTL._arrcpy, 5); + GetRegA + + |IL.opROT: + PushAll(0); + MovRR(SP, ACC); + Push(ACC); + PushImm(param2); + CallRTL(RTL._rot, 2) + + |IL.opSAVES: + UnOp(reg1); + PushAll_1; + Op1(opPUSH, PC, sINCR); + IncStk; + EmitWord(param2); + Reloc(RDATA); + Push(reg1); + drop; + PushImm(param1); + CallRTL(RTL._move, 3) + + |IL.opCASET: + Push(R5); + Push(R5); + PushImm(param2); + CallRTL(RTL._guardrec, 2); + Pop(R5); + Test(ACC); + jcc(jne, param1) + + |IL.opCHR: + UnOp(reg1); + Op2(opAND, imm(255), reg1) + + |IL.opABS: + UnOp(reg1); + Test(reg1); + L := NewLabel(); + jcc(jge, L); + Neg(reg1); + EmitLabel(L) + + |IL.opEQB, IL.opNEB: + BinOp(reg1, reg2); + drop; + + Test(reg1); + L := NewLabel(); + jcc(je, L); + Op2(opMOV, imm(1), reg1); + EmitLabel(L); + + Test(reg2); + L := NewLabel(); + jcc(je, L); + Op2(opMOV, imm(1), reg2); + EmitLabel(L); + + Op2(opCMP, reg2 * 256, reg1); + IF opcode = IL.opEQB THEN + setcc(je, reg1) + ELSE + setcc(jne, reg1) + END + + |IL.opSAVEP: + UnOp(reg1); + Op2(opMOV, incr(PC), reg1 + dIDX); + EmitWord(param2); + Reloc(RCODE); + EmitWord(0); + drop + + |IL.opPUSHP: + Op2(opMOV, incr(PC), GetAnyReg()); + EmitWord(param2); + Reloc(RCODE) + + |IL.opEQP, IL.opNEP: + UnOp(reg1); + Op2(opCMP, incr(PC), reg1); + EmitWord(param1); + Reloc(RCODE); + drop; + reg1 := GetAnyReg(); + + IF opcode = IL.opEQP THEN + setcc(je, reg1) + ELSIF opcode = IL.opNEP THEN + setcc(jne, reg1) + END + + |IL.opVADR_PARAM: + reg1 := GetAnyReg(); + Op2(opMOV, LocalSrc(param2), reg1); + Push(reg1); + drop + + |IL.opNEW: + PushAll(1); + n := param2 + 2; + ASSERT(UTILS.Align(n, 2)); + PushImm(n); + PushImm(param1); + CallRTL(RTL._new, 3) + + |IL.opRSET: + PushAll(2); + CallRTL(RTL._set, 2); + GetRegA + + |IL.opRSETR: + PushAll(1); + PushImm(param2); + CallRTL(RTL._set, 2); + GetRegA + + |IL.opRSETL: + UnOp(reg1); + PushAll_1; + PushImm(param2); + Push(reg1); + drop; + CallRTL(RTL._set, 2); + GetRegA + + |IL.opRSET1: + PushAll(1); + CallRTL(RTL._set1, 1); + GetRegA + + |IL.opINCLC: + UnOp(reg1); + Op2(opBIS, imm(ORD({param2})), dst_x(0, reg1)); + drop + + |IL.opEXCLC: + UnOp(reg1); + Op2(opBIC, imm(ORD({param2})), dst_x(0, reg1)); + drop + + |IL.opIN: + PushAll(2); + CallRTL(RTL._in, 2); + GetRegA + + |IL.opINR: + PushAll(1); + PushImm(param2); + CallRTL(RTL._in, 2); + GetRegA + + |IL.opINL: + PushAll(1); + PushImm(param2); + CallRTL(RTL._in2, 2); + GetRegA + + |IL.opINCL: + PushAll(2); + CallRTL(RTL._incl, 2) + + |IL.opEXCL: + PushAll(2); + CallRTL(RTL._excl, 2) + + |IL.opLADR_INCL, IL.opLADR_EXCL: + PushAll(1); + MovRR(SP, ACC); + n := LocalOffset(param2); + IF n # 0 THEN + Op2(opADD, imm(n), ACC) + END; + Push(ACC); + IF opcode = IL.opLADR_INCL THEN + CallRTL(RTL._incl, 2) + ELSIF opcode = IL.opLADR_EXCL THEN + CallRTL(RTL._excl, 2) + END + + |IL.opLADR_INCLC: + Op2(opBIS, imm(ORD({param2})), LocalDst(param1)) + + |IL.opLADR_EXCLC: + Op2(opBIC, imm(ORD({param2})), LocalDst(param1)) + + END; + + cmd := cmd.next(COMMAND) + END; + + ASSERT(R.pushed = 0); + ASSERT(R.top = -1) +END translate; + + +PROCEDURE prolog; +VAR + i: INTEGER; + +BEGIN + RTL.Init(EmitLabel, EmitWord, EmitCall); + FOR i := 0 TO LEN(RTL.rtl) - 1 DO + RTL.Set(i, NewLabel()) + END; + + IV[LEN(IV) - 1] := NewLabel(); + EmitLabel(IV[LEN(IV) - 1]); + Op2(opMOV, incr(PC), SP); + EmitWord(0); + Op2(opMOV, incr(PC), HP); + EmitWord(0); + Op2(opMOV, imm(5A80H), dst_x(0120H, SR)); (* stop WDT *) + Op2(opMOV, imm(RTL.empty_proc), dst_x(0, SP)); + Op2(opMOV, imm(RTL.empty_proc), dst_x(2, SP)); +END prolog; + + +PROCEDURE epilog; +VAR + L1, i, n: INTEGER; + +BEGIN + Op2(opBIS, imm(10H), SR); (* CPUOFF *) + + L1 := NewLabel(); + FOR i := 0 TO LEN(IV) - 2 DO + IV[i] := NewLabel(); + EmitLabel(IV[i]); + PushImm(i); + IF i # LEN(IV) - 2 THEN + EmitJmp(opJMP, L1) + END + END; + + EmitLabel(L1); + + n := 0; + FOR i := 0 TO 15 DO + IF i IN R.regs THEN + Push(i); + INC(n) + END + END; + + MovRR(SP, R4); + Op2(opADD, imm(n * 2), R4); + + Push(R4); + Op1(opPUSH, R4, sINDIR); + Op1(opCALL, SR, sIDX); EmitWord(-RTL.VarSize); Reloc(RBSS); (* call int *) + Op2(opADD, imm(4), SP); + + FOR i := 15 TO 0 BY -1 DO + IF i IN R.regs THEN + Pop(i) + END + END; + + Op2(opADD, imm(2), SP); + Op1(opRETI, 0, 0); + + RTL.Gen +END epilog; + + +PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); +VAR + i, adr, heap, stack, TextSize, TypesSize, bits, n, val: INTEGER; + + Code, Data, Bss: RECORD address, size: INTEGER END; + + ram, rom: INTEGER; + + reloc: RELOC; + +BEGIN + IdxWords.src := NOWORD; + IdxWords.dst := NOWORD; + + ram := options.ram; + rom := options.rom; + + IF ODD(ram) THEN DEC(ram) END; + IF ODD(rom) THEN DEC(rom) END; + + ram := MIN(MAX(ram, minRAM), maxRAM); + rom := MIN(MAX(rom, minROM), maxROM); + + IF IL.codes.bss > ram - StkReserve - RTL.VarSize THEN + ERRORS.Error(204) + END; + + Labels := CHL.CreateIntList(); + FOR i := 1 TO IL.codes.lcount DO + CHL.PushInt(Labels, 0) + END; + + CodeList := LISTS.create(NIL); + RelList := LISTS.create(NIL); + REG.Init(R, Push, Pop, mov, xchg, {R4, R5, R6, R7}); + + prolog; + translate(chkSTK IN options.checking); + epilog; + + TypesSize := CHL.Length(IL.codes.types) * 2; + Data.size := CHL.Length(IL.codes.data); + IF ODD(Data.size) THEN + CHL.PushByte(IL.codes.data, 0); + INC(Data.size) + END; + Code.size := Fixup(0, IntVectorSize + TypesSize + Data.size); + Code.address := 10000H - (IntVectorSize + TypesSize + Data.size + Code.size); + IF Code.address < 10000H - rom THEN + ERRORS.Error(203) + END; + Code.size := Fixup(Code.address, IntVectorSize + TypesSize + Data.size); + Data.address := Code.address + Code.size; + TextSize := Code.size + Data.size; + + IF Code.address + TextSize + MAX(IL.codes.dmin - Data.size, IntVectorSize + TypesSize) > 10000H THEN + ERRORS.Error(203) + END; + + stack := RTL.ram + ram; + Bss.size := IL.codes.bss + IL.codes.bss MOD 2; + DEC(stack, Bss.size); + Bss.address := stack; + DEC(stack, RTL.VarSize); + heap := RTL.ram; + ASSERT(stack - heap >= StkReserve); + adr := Code.address + 2; + PutWord(stack, adr); + adr := Code.address + 6; + PutWord(heap, adr); + + reloc := RelList.first(RELOC); + WHILE reloc # NIL DO + adr := reloc.WordPtr.offset * 2; + val := reloc.WordPtr.val; + CASE reloc.section OF + |RCODE: PutWord(LabelOffs(val) * 2, adr) + |RDATA: PutWord(val + Data.address, adr) + |RBSS: PutWord((val + Bss.address) MOD 65536, adr) + END; + reloc := reloc.next(RELOC) + END; + + adr := Data.address; + + FOR i := 0 TO Data.size - 1 DO + mem[adr] := CHL.GetByte(IL.codes.data, i); + INC(adr) + END; + + FOR i := TypesSize DIV 2 - 1 TO 0 BY -1 DO + PutWord(CHL.GetInt(IL.codes.types, i), adr) + END; + + FOR i := 0 TO 15 DO + PutWord((33 - i) * i, adr); + END; + + FOR n := 0 TO 15 DO + bits := ORD({0 .. n}); + FOR i := 0 TO 15 - n DO + PutWord(bits, adr); + bits := LSL(bits, 1) + END + END; + + PutWord(4130H, adr); (* RET *) + PutWord(stack, adr); + PutWord(0001H, adr); (* bsl signature (adr 0FFBEH) *) + + FOR i := 0 TO LEN(IV) - 1 DO + PutWord(LabelOffs(IV[i]) * 2, adr) + END; + + INC(TextSize, IntVectorSize + TypesSize + Code.address MOD 16); + INC(Bss.size, StkReserve + RTL.VarSize); + + WR.Create(outname); + HEX.Data(mem, Code.address - Code.address MOD 16, TextSize); + HEX.End; + WR.Close; + + C.Dashes; + C.String(" rom: "); C.Int(TextSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(TextSize * 100 DIV rom); C.StringLn("%)"); + C.Ln; + C.String(" ram: "); C.Int(Bss.size); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(Bss.size * 100 DIV ram); C.StringLn("%)") +END CodeGen; + + END MSP430. \ No newline at end of file diff --git a/programs/develop/oberon07/source/MSP430RTL.ob07 b/programs/develop/oberon07/source/MSP430RTL.ob07 index 66f0021d99..4ddfe5ac2c 100644 --- a/programs/develop/oberon07/source/MSP430RTL.ob07 +++ b/programs/develop/oberon07/source/MSP430RTL.ob07 @@ -1,671 +1,671 @@ -(* - BSD 2-Clause License - - Copyright (c) 2019-2021, Anton Krotov - All rights reserved. -*) - -MODULE MSP430RTL; - - -CONST - - _mul* = 0; - _divmod* = 1; - _lsl* = 2; - _asr* = 3; - _ror* = 4; - _lsr* = 5; - _in* = 6; - _in2* = 7; - _set1* = 8; - _incl* = 9; - _excl* = 10; - _move* = 11; - _set* = 12; - _arrcpy* = 13; - _rot* = 14; - _strcmp* = 15; - _error* = 16; - _is* = 17; - _guard* = 18; - _guardrec* = 19; - _length* = 20; - _new* = 21; - - - HP* = 15; - - LenIV* = 32; - - iv = 10000H - LenIV * 2; - bsl = iv - 2; - sp = bsl - 2; - empty_proc* = sp - 2; - bits = empty_proc - 272; - bits_offs = bits - 32; - DataSize* = iv - bits_offs; - types = bits_offs - 2; - - IntVectorSize* = LenIV * 2 + DataSize; - - VarSize* = 4; - - StkReserve* = 40; - - trap = 2; - - -TYPE - - EMITPROC = PROCEDURE (n: INTEGER); - - -VAR - - ram*: INTEGER; - - rtl*: ARRAY 22 OF - RECORD - label*: INTEGER; - used: BOOLEAN - END; - - Label, Word, Call: EMITPROC; - - -PROCEDURE Gen*; - - - PROCEDURE Word1 (word: INTEGER); - BEGIN - Word(word) - END Word1; - - - PROCEDURE Word2 (word1, word2: INTEGER); - BEGIN - Word1(word1); - Word1(word2) - END Word2; - - - PROCEDURE Word3 (word1, word2, word3: INTEGER); - BEGIN - Word1(word1); - Word1(word2); - Word1(word3) - END Word3; - - -BEGIN - (* _lsl (n, x: INTEGER): INTEGER *) - IF rtl[_lsl].used THEN - Label(rtl[_lsl].label); - Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) - Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) - Word2(0F035H, 15); (* AND #15, R5 *) - Word1(2400H + 3); (* JZ L1 *) - (* L2: *) - Word1(5404H); (* ADD R4, R4 *) - Word1(8315H); (* SUB #1, R5 *) - Word1(2000H + 400H - 3); (* JNZ L2 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _asr (n, x: INTEGER): INTEGER *) - IF rtl[_asr].used THEN - Label(rtl[_asr].label); - Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) - Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) - Word2(0F035H, 15); (* AND #15, R5 *) - Word1(2400H + 3); (* JZ L1 *) - (* L2: *) - Word1(1104H); (* RRA R4 *) - Word1(8315H); (* SUB #1, R5 *) - Word1(2000H + 400H - 3); (* JNZ L2 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _ror (n, x: INTEGER): INTEGER *) - IF rtl[_ror].used THEN - Label(rtl[_ror].label); - Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) - Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) - Word2(0F035H, 15); (* AND #15, R5 *) - Word1(2400H + 5); (* JZ L1 *) - Word1(4406H); (* MOV R4, R6 *) - (* L2: *) - Word1(1006H); (* RRC R6 *) - Word1(1004H); (* RRC R4 *) - Word1(8315H); (* SUB #1, R5 *) - Word1(2000H + 400H - 4); (* JNZ L2 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _lsr (n, x: INTEGER): INTEGER *) - IF rtl[_lsr].used THEN - Label(rtl[_lsr].label); - Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) - Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) - Word2(0F035H, 15); (* AND #15, R5 *) - Word1(2400H + 4); (* JZ L1 *) - (* L2: *) - Word1(0C312H); (* BIC #1, SR *) - Word1(1004H); (* RRC R4 *) - Word1(8315H); (* SUB #1, R5 *) - Word1(2000H + 400H - 4); (* JNZ L2 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _set (b, a: INTEGER): SET *) - IF rtl[_set].used THEN - Label(rtl[_set].label); - Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- b *) - Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- a *) - Word1(9504H); (* CMP R5, R4 *) - Word1(3800H + 24); (* JL L1 *) - Word2(9035H, 16); (* CMP #16, R5 *) - Word1(3400H + 21); (* JGE L1 *) - Word1(9304H); (* CMP #0, R4 *) - Word1(3800H + 19); (* JL L1 *) - Word2(9034H, 16); (* CMP #16, R4 *) - Word1(3800H + 2); (* JL L2 *) - Word2(4034H, 15); (* MOV #15, R4 *) - (* L2: *) - Word1(9305H); (* CMP #0, R5 *) - Word1(3400H + 1); (* JGE L3 *) - Word1(4305H); (* MOV #0, R5 *) - (* L3: *) - Word1(8504H); (* SUB R5, R4 *) - Word1(5404H); (* ADD R4, R4 *) - Word2(5034H, bits_offs); (* ADD bits_offs, R4 *) - Word1(4424H); (* MOV @R4, R4 *) - Word1(5505H); (* ADD R5, R5 *) - Word1(5405H); (* ADD R4, R5 *) - Word2(5035H, bits); (* ADD bits, R5 *) - Word1(4524H); (* MOV @R5, R4 *) - Word1(4130H); (* RET *) - (* L1: *) - Word1(4304H); (* MOV #0, R4 *) - Word1(4130H) (* RET *) - END; - - (* _set1 (a: INTEGER): SET *) - IF rtl[_set1].used THEN - Label(rtl[_set1].label); - Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- a *) - Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) - Word1(2000H + 5); (* JNZ L1 *) - Word1(5404H); (* ADD R4, R4 *) - Word2(5034H, bits); (* ADD bits, R4 *) - Word1(4424H); (* MOV @R4, R4 *) - Word1(4130H); (* RET *) - (* L1: *) - Word1(4304H); (* MOV #0, R4 *) - Word1(4130H) (* RET *) - END; - - (* _in2 (i, s: INTEGER): BOOLEAN *) - IF rtl[_in2].used THEN - Label(rtl[_in2].label); - Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- i *) - Word1(5404H); (* ADD R4, R4 *) - Word2(5034H, bits); (* ADD bits, R4 *) - Word1(4424H); (* MOV @R4, R4 *) - Word2(0F114H, 4); (* AND 4(SP), R4 *) - Word1(2400H + 1); (* JZ L1 *) - Word1(4314H); (* MOV #1, R4 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _in (s, i: INTEGER): BOOLEAN *) - IF rtl[_in].used THEN - Label(rtl[_in].label); - Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) - Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) - Word1(2000H + 9); (* JNZ L2 *) - Word1(5404H); (* ADD R4, R4 *) - Word2(5034H, bits); (* ADD bits, R4 *) - Word1(4424H); (* MOV @R4, R4 *) - Word2(0F114H, 2); (* AND 2(SP), R4 *) - Word1(2400H + 3); (* JZ L1 *) - Word1(4314H); (* MOV #1, R4 *) - Word1(4130H); (* RET *) - (* L2: *) - Word1(4304H); (* MOV #0, R4 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _incl (VAR s: SET; i: INTEGER) *) - IF rtl[_incl].used THEN - Label(rtl[_incl].label); - Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) - Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) - Word1(2000H + 8); (* JNZ L1 *) - Word1(5404H); (* ADD R4, R4 *) - Word2(5034H, bits); (* ADD bits, R4 *) - Word1(4424H); (* MOV @R4, R4 *) - Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- @s *) - Word2(0D485H, 0); (* BIS R4, 0(R5) *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _excl (VAR s: SET; i: INTEGER) *) - IF rtl[_excl].used THEN - Label(rtl[_excl].label); - Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) - Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) - Word1(2000H + 8); (* JNZ L1 *) - Word1(5404H); (* ADD R4, R4 *) - Word2(5034H, bits); (* ADD bits, R4 *) - Word1(4424H); (* MOV @R4, R4 *) - Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- @s *) - Word2(0C485H, 0); (* BIC R4, 0(R5) *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _rot (len, adr: INTEGER) *) - IF rtl[_rot].used THEN - Label(rtl[_rot].label); - Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- len *) - Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- adr *) - Word1(8314H); (* SUB #1, R4 *) - Word1(5404H); (* ADD R4, R4 *) - Word1(1225H); (* PUSH @R5 *) - Word1(4406H); (* MOV R4, R6 *) - (* L1: *) - Word3(4595H, 2, 0); (* MOV 2(R5), 0(R5) *) - Word1(5325H); (* ADD #2, R5 *) - Word1(8326H); (* SUB #2, R6 *) - Word1(2000H + 400H - 6); (* JNZ L1 *) - Word2(41B5H, 0); (* MOV @SP+, 0(R5) *) - Word1(4130H) (* RET *) - END; - - (* _divmod (b, a: INTEGER): INTEGER (* res -> R4, mod -> R5 *) *) - IF rtl[_divmod].used THEN - Label(rtl[_divmod].label); - Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- a *) - Word1(4304H); (* MOV #0, R4 *) - (* L1: *) - Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- b *) - Word1(9605H); (* CMP R6, R5 *) - Word1(3800H + 17); (* JL L3 *) - Word1(4327H); (* MOV #2, R7 *) - Word1(5606H); (* ADD R6, R6 *) - (* L4: *) - Word1(9306H); (* CMP #0, R6 *) - Word1(2400H + 6); (* JZ L2 *) - Word1(3800H + 5); (* JL L2 *) - Word1(9605H); (* CMP R6, R5 *) - Word1(3800H + 3); (* JL L2 *) - Word1(5606H); (* ADD R6, R6 *) - Word1(5707H); (* ADD R7, R7 *) - Word1(3C00H + 400H - 8); (* JMP L4 *) - (* L2: *) - Word1(0C312H); (* BIC #1, SR *) - Word1(1006H); (* RRC R6 *) - Word1(0C312H); (* BIC #1, SR *) - Word1(1007H); (* RRC R7 *) - Word1(8605H); (* SUB R6, R5 *) - Word1(5704H); (* ADD R7, R4 *) - Word1(3C00H + 400H - 21); (* JMP L1 *) - (* L3: *) - (*----------- (a < 0) --------------*) - (* L1: *) - Word1(9305H); (* CMP #0, R5 *) - Word1(3400H + 23); (* JGE L3 *) - Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- b *) - Word1(4327H); (* MOV #2, R7 *) - Word1(5606H); (* ADD R6, R6 *) - Word1(0E335H); (* XOR #-1, R5 *) - Word1(5315H); (* ADD #1, R5 *) - (* L4: *) - Word1(9306H); (* CMP #0, R6 *) - Word1(2400H + 6); (* JZ L2 *) - Word1(3800H + 5); (* JL L2 *) - Word1(9605H); (* CMP R6, R5 *) - Word1(3800H + 3); (* JL L2 *) - Word1(5606H); (* ADD R6, R6 *) - Word1(5707H); (* ADD R7, R7 *) - Word1(3C00H + 400H - 8); (* JMP L4 *) - (* L2: *) - Word1(0E335H); (* XOR #-1, R5 *) - Word1(5315H); (* ADD #1, R5 *) - Word1(0C312H); (* BIC #1, SR *) - Word1(1006H); (* RRC R6 *) - Word1(0C312H); (* BIC #1, SR *) - Word1(1007H); (* RRC R7 *) - Word1(5605H); (* ADD R6, R5 *) - Word1(8704H); (* SUB R7, R4 *) - Word1(3C00H + 400H - 25); (* JMP L1 *) - (* L3: *) - Word1(4130H) (* RET *) - END; - - (* _mul (a, b: INTEGER): INTEGER *) - IF rtl[_mul].used THEN - Label(rtl[_mul].label); - Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- a *) - Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- b *) - Word1(4304H); (* MOV #0, R4; res := 0 *) - Word1(9306H); (* CMP #0, R6 *) - Word1(2400H + 7); (* JZ L1 *) - (* L2: *) - Word1(0B316H); (* BIT #1, R6 *) - Word1(2400H + 1); (* JZ L3 *) - Word1(5504H); (* ADD R5, R4 *) - (* L3: *) - Word1(5505H); (* ADD R5, R5 *) - Word1(0C312H); (* BIC #1, SR *) - Word1(1006H); (* RRC R6 *) - Word1(2000H + 400H - 7); (* JNZ L2 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _error (modNum, modName, err, line: INTEGER) *) - IF rtl[_error].used THEN - Label(rtl[_error].label); - Word1(5321H); (* ADD #2, SP *) - Word1(4134H); (* POP R4; R4 <- modNum *) - Word1(4135H); (* POP R5; R5 <- modName *) - Word1(4136H); (* POP R6; R6 <- err *) - Word1(4137H); (* POP R7; R7 <- line *) - Word2(4211H, sp); (* MOV sp(SR), SP *) - Word1(1207H); (* PUSH R7 *) - Word1(1206H); (* PUSH R6 *) - Word1(1205H); (* PUSH R5 *) - Word1(1204H); (* PUSH R4 *) - Word2(4214H, sp); (* MOV sp(SR), R4 *) - Word2(1294H, trap); (* CALL trap(R4) *) - Word2(04032H, 0F0H) (* MOV CPUOFF+OSCOFF+SCG0+SCG1, SR *) - END; - - (* _new (t, size: INTEGER; VAR ptr: INTEGER) *) - IF rtl[_new].used THEN - Label(rtl[_new].label); - Word1(1202H); (* PUSH SR *) - Word1(4302H); (* MOV #0, SR *) - Word1(4303H); (* NOP *) - Word1(4104H); (* MOV SP, R4 *) - Word2(8034H, StkReserve); (* SUB #StkReserve, R4 *) - Word1(4005H + 100H * HP); (* MOV HP, R5 *) - Word2(5115H, 6); (* ADD 6(SP), R5 *) - Word1(9504H); (* CMP R5, R4 *) - Word2(4114H, 8); (* MOV 8(SP), R4 *) - Word1(3800H + 12); (* JL L1 *) - Word3(4190H + HP, 4, 0); (* MOV 4(SP), 0(HP) *) - Word1(5320H + HP); (* ADD #2, HP *) - Word2(4084H + 100H * HP, 0); (* MOV HP, 0(R4) *) - (* L3 *) - Word2(4380H + HP, 0); (* MOV #0, 0(HP) *) - Word1(5320H + HP); (* ADD #2, HP *) - Word1(9500H + HP); (* CMP R5, HP *) - Word1(3800H + 400H - 5); (* JL L3 *) - Word1(3C00H + 2); (* JMP L2 *) - (* L1 *) - Word2(4384H, 0); (* MOV #0, 0(R4) *) - (* L2 *) - Word1(1300H) (* RETI *) - END; - - (* _guardrec (t0, t1: INTEGER): INTEGER *) - IF rtl[_guardrec].used THEN - Label(rtl[_guardrec].label); - Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- t0 *) - Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- t1 *) - Word2(4036H, types); (* MOV #types, R6 *) - (* L3: *) - Word1(9305H); (* CMP #0, R5 *) - Word1(2400H + 8); (* JZ L1 *) - Word1(9405H); (* CMP R4, R5 *) - Word1(2400H + 10); (* JZ L2 *) - Word1(5505H); (* ADD R5, R5 *) - Word1(0E335H); (* XOR #-1, R5 *) - Word1(5315H); (* ADD #1, R5 *) - Word1(5605H); (* ADD R6, R5 *) - Word1(4525H); (* MOV @R5, R5 *) - Word1(3C00H + 400H - 10); (* JMP L3 *) - (* L1: *) - Word1(9405H); (* CMP R4, R5 *) - Word1(2400H + 2); (* JZ L2 *) - Word1(4304H); (* MOV #0, R4 *) - Word1(4130H); (* RET *) - (* L2: *) - Word1(4314H); (* MOV #1, R4 *) - Word1(4130H) (* RET *) - END; - - (* _is (t, p: INTEGER): INTEGER *) - IF rtl[_is].used THEN - Label(rtl[_is].label); - Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- p *) - Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- t *) - Word1(9304H); (* TST R4 *) - Word1(2400H + 2); (* JZ L *) - Word2(4414H, -2); (* MOV -2(R4), R4 *) - (* L: *) - Word1(1204H); (* PUSH R4 *) - Word1(1205H); (* PUSH R5 *) - Call(rtl[_guardrec].label); (* CALL _guardrec *) - Word1(5221H); (* ADD #4, SP *) - Word1(4130H) (* RET *) - END; - - (* _guard (t, p: INTEGER): INTEGER *) - IF rtl[_guard].used THEN - Label(rtl[_guard].label); - Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- p *) - Word1(4314H); (* MOV #1, R4 *) - Word1(4525H); (* MOV @R5, R5 *) - Word1(9305H); (* TST R5 *) - Word1(2400H + 9); (* JZ L *) - Word2(4515H, -2); (* MOV -2(R5), R5 *) - Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- t *) - Word1(1205H); (* PUSH R5 *) - Word1(1204H); (* PUSH R4 *) - Call(rtl[_guardrec].label); (* CALL _guardrec *) - Word1(5221H); (* ADD #4, SP *) - (* L: *) - Word1(4130H) (* RET *) - END; - - (* _move (bytes, dest, source: INTEGER) *) - IF rtl[_move].used THEN - Label(rtl[_move].label); - Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- bytes *) - Word2(4117H, 4); (* MOV 4(SP), R7; R7 <- dest *) - Word2(4115H, 6); (* MOV 6(SP), R5; R5 <- source *) - Word1(9306H); (* CMP #0, R6 *) - Word1(3800H + 6); (* JL L1 *) - Word1(2400H + 5); (* JZ L1 *) - (* L2: *) - Word2(45F7H, 0); (* MOV.B @R5+, 0(R7) *) - Word1(5317H); (* ADD #1, R7 *) - Word1(8316H); (* SUB #1, R6 *) - Word1(2000H + 400H - 5); (* JNZ L2 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _arrcpy (base_size, len_dst, dst, len_src, src: INTEGER) *) - IF rtl[_arrcpy].used THEN - Label(rtl[_arrcpy].label); - Word3(9191H, 8, 4); (* CMP 8(SP), 4(SP) *) - Word1(3800H + 18); (* JL L1 *) - Word2(1211H, 12); (* PUSH 12(SP) *) - Word2(1211H, 10); (* PUSH 10(SP) *) - Word2(1211H, 14); (* PUSH 14(SP) *) - Word2(1211H, 10); (* PUSH 10(SP) *) - Call(rtl[_mul].label); (* CALL _mul *) - Word1(5221H); (* ADD #4, SP *) - Word1(1204H); (* PUSH R4 *) - Call(rtl[_move].label); (* CALL _move *) - Word2(5031H, 6); (* ADD #6, SP *) - Word1(4314H); (* MOV #1, R4 *) - Word1(4130H); (* RET *) - (* L1 *) - Word1(4304H); (* MOV #0, R4 *) - Word1(4130H) (* RET *) - END; - - (* _length (len, str: INTEGER): INTEGER *) - IF rtl[_length].used THEN - Label(rtl[_length].label); - Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- len *) - Word2(4117H, 4); (* MOV 4(SP), R7; R7 <- str *) - Word1(4304H); (* MOV #0, R4; res := 0 *) - (* L2: *) - Word1(4775H); (* MOV.B @R7+, R5 *) - Word1(9305H); (* CMP #0, R5 *) - Word1(2400H + 3); (* JZ L1 *) - Word1(5314H); (* ADD #1, R4 *) - Word1(8316H); (* SUB #1, R6 *) - Word1(2000H + 400H - 6); (* JNZ L2 *) - (* L1: *) - Word1(4130H) (* RET *) - END; - - (* _strcmp (op, len2, str2, len1, str1: INTEGER): BOOLEAN *) - IF rtl[_strcmp].used THEN - Label(rtl[_strcmp].label); - Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- len2 *) - Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- len1 *) - Word1(9607H); (* CMP R6, R7 *) - Word1(3400H + 1); (* JGE L5 *) - Word1(4706H); (* MOV R7, R6 *) - (* L5: *) - Word1(1206H); (* PUSH R6 *) - Word2(4116H, 12); (* MOV 12(SP), R6; R6 <- str1 *) - Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- str2 *) - (* L3: *) - Word2(9381H, 0); (* CMP #0, 0(SP) *) - Word1(2400H + 11); (* JZ L1 *) - Word1(4674H); (* MOV.B @R6+, R4 *) - Word1(4775H); (* MOV.B @R7+, R5 *) - Word2(8391H, 0); (* SUB #1, 0(SP) *) - Word1(9405H); (* CMP R4, R5 *) - Word1(2400H + 2); (* JZ L2 *) - Word1(8504H); (* SUB R5, R4 *) - Word1(3C00H + 5); (* JMP L4 *) - (* L2: *) - Word1(9304H); (* CMP #0, R4 *) - Word1(2000H + 400H - 13); (* JNZ L3 *) - Word1(3C00H + 2); (* JMP L4 *) - (* L1: *) - Word2(4034H, 8000H); (* MOV #8000H, R4 *) - (* L4: *) - Word1(5321H); (* ADD #2, SP *) - - Word2(9034H, 8000H); (* CMP #8000H, R4 *) - Word1(2000H + 18); (* JNZ L6 *) - Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- len2 *) - Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- len1 *) - Word1(9607H); (* CMP R6, R7 *) - Word1(2400H + 11); (* JZ L7 *) - Word1(3800H + 4); (* JL L8 *) - Word2(5116H, 10); (* ADD 10(SP), R6 *) - Word1(4664H); (* MOV.B @R6, R4 *) - Word1(3C00H + 7); (* JMP L6 *) - (* L8: *) - Word2(5117H, 6); (* ADD 6(SP), R7 *) - Word1(4764H); (* MOV.B @R7, R4 *) - Word1(0E334H); (* XOR #-1, R4 *) - Word1(5314H); (* ADD #1, R4 *) - Word1(3C00H + 1); (* JMP L6 *) - (* L7: *) - Word1(4304H); (* MOV #0, R4 *) - (* L6: *) - - Word2(5110H, 2); (* ADD 2(SP), PC; PC <- PC + op *) - - Word1(9304H); (* CMP #0, R4 *) - Word1(4314H); (* MOV #1, R4 *) - Word1(2400H + 1); (* JZ L *) - Word1(4304H); (* MOV #0, R4 *) - (* L *) - Word1(4130H); (* RET *) - Word1(4303H); (* NOP *) - - Word1(9304H); (* CMP #0, R4 *) - Word1(4314H); (* MOV #1, R4 *) - Word1(2000H + 1); (* JNZ L *) - Word1(4304H); (* MOV #0, R4 *) - (* L *) - Word1(4130H); (* RET *) - Word1(4303H); (* NOP *) - - Word1(9304H); (* CMP #0, R4 *) - Word1(4314H); (* MOV #1, R4 *) - Word1(3800H + 1); (* JL L *) - Word1(4304H); (* MOV #0, R4 *) - (* L *) - Word1(4130H); (* RET *) - Word1(4303H); (* NOP *) - - Word1(9304H); (* CMP #0, R4 *) - Word1(4314H); (* MOV #1, R4 *) - Word1(3800H + 2); (* JL L *) - Word1(2400H + 1); (* JZ L *) - Word1(4304H); (* MOV #0, R4 *) - (* L *) - Word1(4130H); (* RET *) - - Word1(9304H); (* CMP #0, R4 *) - Word1(4304H); (* MOV #0, R4 *) - Word1(3800H + 2); (* JL L *) - Word1(2400H + 1); (* JZ L *) - Word1(4314H); (* MOV #1, R4 *) - (* L *) - Word1(4130H); (* RET *) - - Word1(9304H); (* CMP #0, R4 *) - Word1(4314H); (* MOV #1, R4 *) - Word1(3400H + 1); (* JGE L *) - Word1(4304H); (* MOV #0, R4 *) - (* L *) - Word1(4130H) (* RET *) - END - -END Gen; - - -PROCEDURE Set* (idx, label: INTEGER); -BEGIN - rtl[idx].label := label; - rtl[idx].used := FALSE -END Set; - - -PROCEDURE Used* (idx: INTEGER); -BEGIN - rtl[idx].used := TRUE; - IF (idx = _guard) OR (idx = _is) THEN - rtl[_guardrec].used := TRUE - ELSIF idx = _arrcpy THEN - rtl[_move].used := TRUE; - rtl[_mul].used := TRUE - END -END Used; - - -PROCEDURE Init* (pLabel, pWord, pCall: EMITPROC); -BEGIN - Label := pLabel; - Word := pWord; - Call := pCall; - ram := 200H; -END Init; - - +(* + BSD 2-Clause License + + Copyright (c) 2019-2021, Anton Krotov + All rights reserved. +*) + +MODULE MSP430RTL; + + +CONST + + _mul* = 0; + _divmod* = 1; + _lsl* = 2; + _asr* = 3; + _ror* = 4; + _lsr* = 5; + _in* = 6; + _in2* = 7; + _set1* = 8; + _incl* = 9; + _excl* = 10; + _move* = 11; + _set* = 12; + _arrcpy* = 13; + _rot* = 14; + _strcmp* = 15; + _error* = 16; + _is* = 17; + _guard* = 18; + _guardrec* = 19; + _length* = 20; + _new* = 21; + + + HP* = 15; + + LenIV* = 32; + + iv = 10000H - LenIV * 2; + bsl = iv - 2; + sp = bsl - 2; + empty_proc* = sp - 2; + bits = empty_proc - 272; + bits_offs = bits - 32; + DataSize* = iv - bits_offs; + types = bits_offs - 2; + + IntVectorSize* = LenIV * 2 + DataSize; + + VarSize* = 4; + + StkReserve* = 40; + + trap = 2; + + +TYPE + + EMITPROC = PROCEDURE (n: INTEGER); + + +VAR + + ram*: INTEGER; + + rtl*: ARRAY 22 OF + RECORD + label*: INTEGER; + used: BOOLEAN + END; + + Label, Word, Call: EMITPROC; + + +PROCEDURE Gen*; + + + PROCEDURE Word1 (word: INTEGER); + BEGIN + Word(word) + END Word1; + + + PROCEDURE Word2 (word1, word2: INTEGER); + BEGIN + Word1(word1); + Word1(word2) + END Word2; + + + PROCEDURE Word3 (word1, word2, word3: INTEGER); + BEGIN + Word1(word1); + Word1(word2); + Word1(word3) + END Word3; + + +BEGIN + (* _lsl (n, x: INTEGER): INTEGER *) + IF rtl[_lsl].used THEN + Label(rtl[_lsl].label); + Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) + Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) + Word2(0F035H, 15); (* AND #15, R5 *) + Word1(2400H + 3); (* JZ L1 *) + (* L2: *) + Word1(5404H); (* ADD R4, R4 *) + Word1(8315H); (* SUB #1, R5 *) + Word1(2000H + 400H - 3); (* JNZ L2 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _asr (n, x: INTEGER): INTEGER *) + IF rtl[_asr].used THEN + Label(rtl[_asr].label); + Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) + Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) + Word2(0F035H, 15); (* AND #15, R5 *) + Word1(2400H + 3); (* JZ L1 *) + (* L2: *) + Word1(1104H); (* RRA R4 *) + Word1(8315H); (* SUB #1, R5 *) + Word1(2000H + 400H - 3); (* JNZ L2 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _ror (n, x: INTEGER): INTEGER *) + IF rtl[_ror].used THEN + Label(rtl[_ror].label); + Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) + Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) + Word2(0F035H, 15); (* AND #15, R5 *) + Word1(2400H + 5); (* JZ L1 *) + Word1(4406H); (* MOV R4, R6 *) + (* L2: *) + Word1(1006H); (* RRC R6 *) + Word1(1004H); (* RRC R4 *) + Word1(8315H); (* SUB #1, R5 *) + Word1(2000H + 400H - 4); (* JNZ L2 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _lsr (n, x: INTEGER): INTEGER *) + IF rtl[_lsr].used THEN + Label(rtl[_lsr].label); + Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) + Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) + Word2(0F035H, 15); (* AND #15, R5 *) + Word1(2400H + 4); (* JZ L1 *) + (* L2: *) + Word1(0C312H); (* BIC #1, SR *) + Word1(1004H); (* RRC R4 *) + Word1(8315H); (* SUB #1, R5 *) + Word1(2000H + 400H - 4); (* JNZ L2 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _set (b, a: INTEGER): SET *) + IF rtl[_set].used THEN + Label(rtl[_set].label); + Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- b *) + Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- a *) + Word1(9504H); (* CMP R5, R4 *) + Word1(3800H + 24); (* JL L1 *) + Word2(9035H, 16); (* CMP #16, R5 *) + Word1(3400H + 21); (* JGE L1 *) + Word1(9304H); (* CMP #0, R4 *) + Word1(3800H + 19); (* JL L1 *) + Word2(9034H, 16); (* CMP #16, R4 *) + Word1(3800H + 2); (* JL L2 *) + Word2(4034H, 15); (* MOV #15, R4 *) + (* L2: *) + Word1(9305H); (* CMP #0, R5 *) + Word1(3400H + 1); (* JGE L3 *) + Word1(4305H); (* MOV #0, R5 *) + (* L3: *) + Word1(8504H); (* SUB R5, R4 *) + Word1(5404H); (* ADD R4, R4 *) + Word2(5034H, bits_offs); (* ADD bits_offs, R4 *) + Word1(4424H); (* MOV @R4, R4 *) + Word1(5505H); (* ADD R5, R5 *) + Word1(5405H); (* ADD R4, R5 *) + Word2(5035H, bits); (* ADD bits, R5 *) + Word1(4524H); (* MOV @R5, R4 *) + Word1(4130H); (* RET *) + (* L1: *) + Word1(4304H); (* MOV #0, R4 *) + Word1(4130H) (* RET *) + END; + + (* _set1 (a: INTEGER): SET *) + IF rtl[_set1].used THEN + Label(rtl[_set1].label); + Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- a *) + Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) + Word1(2000H + 5); (* JNZ L1 *) + Word1(5404H); (* ADD R4, R4 *) + Word2(5034H, bits); (* ADD bits, R4 *) + Word1(4424H); (* MOV @R4, R4 *) + Word1(4130H); (* RET *) + (* L1: *) + Word1(4304H); (* MOV #0, R4 *) + Word1(4130H) (* RET *) + END; + + (* _in2 (i, s: INTEGER): BOOLEAN *) + IF rtl[_in2].used THEN + Label(rtl[_in2].label); + Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- i *) + Word1(5404H); (* ADD R4, R4 *) + Word2(5034H, bits); (* ADD bits, R4 *) + Word1(4424H); (* MOV @R4, R4 *) + Word2(0F114H, 4); (* AND 4(SP), R4 *) + Word1(2400H + 1); (* JZ L1 *) + Word1(4314H); (* MOV #1, R4 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _in (s, i: INTEGER): BOOLEAN *) + IF rtl[_in].used THEN + Label(rtl[_in].label); + Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) + Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) + Word1(2000H + 9); (* JNZ L2 *) + Word1(5404H); (* ADD R4, R4 *) + Word2(5034H, bits); (* ADD bits, R4 *) + Word1(4424H); (* MOV @R4, R4 *) + Word2(0F114H, 2); (* AND 2(SP), R4 *) + Word1(2400H + 3); (* JZ L1 *) + Word1(4314H); (* MOV #1, R4 *) + Word1(4130H); (* RET *) + (* L2: *) + Word1(4304H); (* MOV #0, R4 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _incl (VAR s: SET; i: INTEGER) *) + IF rtl[_incl].used THEN + Label(rtl[_incl].label); + Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) + Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) + Word1(2000H + 8); (* JNZ L1 *) + Word1(5404H); (* ADD R4, R4 *) + Word2(5034H, bits); (* ADD bits, R4 *) + Word1(4424H); (* MOV @R4, R4 *) + Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- @s *) + Word2(0D485H, 0); (* BIS R4, 0(R5) *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _excl (VAR s: SET; i: INTEGER) *) + IF rtl[_excl].used THEN + Label(rtl[_excl].label); + Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) + Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) + Word1(2000H + 8); (* JNZ L1 *) + Word1(5404H); (* ADD R4, R4 *) + Word2(5034H, bits); (* ADD bits, R4 *) + Word1(4424H); (* MOV @R4, R4 *) + Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- @s *) + Word2(0C485H, 0); (* BIC R4, 0(R5) *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _rot (len, adr: INTEGER) *) + IF rtl[_rot].used THEN + Label(rtl[_rot].label); + Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- len *) + Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- adr *) + Word1(8314H); (* SUB #1, R4 *) + Word1(5404H); (* ADD R4, R4 *) + Word1(1225H); (* PUSH @R5 *) + Word1(4406H); (* MOV R4, R6 *) + (* L1: *) + Word3(4595H, 2, 0); (* MOV 2(R5), 0(R5) *) + Word1(5325H); (* ADD #2, R5 *) + Word1(8326H); (* SUB #2, R6 *) + Word1(2000H + 400H - 6); (* JNZ L1 *) + Word2(41B5H, 0); (* MOV @SP+, 0(R5) *) + Word1(4130H) (* RET *) + END; + + (* _divmod (b, a: INTEGER): INTEGER (* res -> R4, mod -> R5 *) *) + IF rtl[_divmod].used THEN + Label(rtl[_divmod].label); + Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- a *) + Word1(4304H); (* MOV #0, R4 *) + (* L1: *) + Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- b *) + Word1(9605H); (* CMP R6, R5 *) + Word1(3800H + 17); (* JL L3 *) + Word1(4327H); (* MOV #2, R7 *) + Word1(5606H); (* ADD R6, R6 *) + (* L4: *) + Word1(9306H); (* CMP #0, R6 *) + Word1(2400H + 6); (* JZ L2 *) + Word1(3800H + 5); (* JL L2 *) + Word1(9605H); (* CMP R6, R5 *) + Word1(3800H + 3); (* JL L2 *) + Word1(5606H); (* ADD R6, R6 *) + Word1(5707H); (* ADD R7, R7 *) + Word1(3C00H + 400H - 8); (* JMP L4 *) + (* L2: *) + Word1(0C312H); (* BIC #1, SR *) + Word1(1006H); (* RRC R6 *) + Word1(0C312H); (* BIC #1, SR *) + Word1(1007H); (* RRC R7 *) + Word1(8605H); (* SUB R6, R5 *) + Word1(5704H); (* ADD R7, R4 *) + Word1(3C00H + 400H - 21); (* JMP L1 *) + (* L3: *) + (*----------- (a < 0) --------------*) + (* L1: *) + Word1(9305H); (* CMP #0, R5 *) + Word1(3400H + 23); (* JGE L3 *) + Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- b *) + Word1(4327H); (* MOV #2, R7 *) + Word1(5606H); (* ADD R6, R6 *) + Word1(0E335H); (* XOR #-1, R5 *) + Word1(5315H); (* ADD #1, R5 *) + (* L4: *) + Word1(9306H); (* CMP #0, R6 *) + Word1(2400H + 6); (* JZ L2 *) + Word1(3800H + 5); (* JL L2 *) + Word1(9605H); (* CMP R6, R5 *) + Word1(3800H + 3); (* JL L2 *) + Word1(5606H); (* ADD R6, R6 *) + Word1(5707H); (* ADD R7, R7 *) + Word1(3C00H + 400H - 8); (* JMP L4 *) + (* L2: *) + Word1(0E335H); (* XOR #-1, R5 *) + Word1(5315H); (* ADD #1, R5 *) + Word1(0C312H); (* BIC #1, SR *) + Word1(1006H); (* RRC R6 *) + Word1(0C312H); (* BIC #1, SR *) + Word1(1007H); (* RRC R7 *) + Word1(5605H); (* ADD R6, R5 *) + Word1(8704H); (* SUB R7, R4 *) + Word1(3C00H + 400H - 25); (* JMP L1 *) + (* L3: *) + Word1(4130H) (* RET *) + END; + + (* _mul (a, b: INTEGER): INTEGER *) + IF rtl[_mul].used THEN + Label(rtl[_mul].label); + Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- a *) + Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- b *) + Word1(4304H); (* MOV #0, R4; res := 0 *) + Word1(9306H); (* CMP #0, R6 *) + Word1(2400H + 7); (* JZ L1 *) + (* L2: *) + Word1(0B316H); (* BIT #1, R6 *) + Word1(2400H + 1); (* JZ L3 *) + Word1(5504H); (* ADD R5, R4 *) + (* L3: *) + Word1(5505H); (* ADD R5, R5 *) + Word1(0C312H); (* BIC #1, SR *) + Word1(1006H); (* RRC R6 *) + Word1(2000H + 400H - 7); (* JNZ L2 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _error (modNum, modName, err, line: INTEGER) *) + IF rtl[_error].used THEN + Label(rtl[_error].label); + Word1(5321H); (* ADD #2, SP *) + Word1(4134H); (* POP R4; R4 <- modNum *) + Word1(4135H); (* POP R5; R5 <- modName *) + Word1(4136H); (* POP R6; R6 <- err *) + Word1(4137H); (* POP R7; R7 <- line *) + Word2(4211H, sp); (* MOV sp(SR), SP *) + Word1(1207H); (* PUSH R7 *) + Word1(1206H); (* PUSH R6 *) + Word1(1205H); (* PUSH R5 *) + Word1(1204H); (* PUSH R4 *) + Word2(4214H, sp); (* MOV sp(SR), R4 *) + Word2(1294H, trap); (* CALL trap(R4) *) + Word2(04032H, 0F0H) (* MOV CPUOFF+OSCOFF+SCG0+SCG1, SR *) + END; + + (* _new (t, size: INTEGER; VAR ptr: INTEGER) *) + IF rtl[_new].used THEN + Label(rtl[_new].label); + Word1(1202H); (* PUSH SR *) + Word1(4302H); (* MOV #0, SR *) + Word1(4303H); (* NOP *) + Word1(4104H); (* MOV SP, R4 *) + Word2(8034H, StkReserve); (* SUB #StkReserve, R4 *) + Word1(4005H + 100H * HP); (* MOV HP, R5 *) + Word2(5115H, 6); (* ADD 6(SP), R5 *) + Word1(9504H); (* CMP R5, R4 *) + Word2(4114H, 8); (* MOV 8(SP), R4 *) + Word1(3800H + 12); (* JL L1 *) + Word3(4190H + HP, 4, 0); (* MOV 4(SP), 0(HP) *) + Word1(5320H + HP); (* ADD #2, HP *) + Word2(4084H + 100H * HP, 0); (* MOV HP, 0(R4) *) + (* L3 *) + Word2(4380H + HP, 0); (* MOV #0, 0(HP) *) + Word1(5320H + HP); (* ADD #2, HP *) + Word1(9500H + HP); (* CMP R5, HP *) + Word1(3800H + 400H - 5); (* JL L3 *) + Word1(3C00H + 2); (* JMP L2 *) + (* L1 *) + Word2(4384H, 0); (* MOV #0, 0(R4) *) + (* L2 *) + Word1(1300H) (* RETI *) + END; + + (* _guardrec (t0, t1: INTEGER): INTEGER *) + IF rtl[_guardrec].used THEN + Label(rtl[_guardrec].label); + Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- t0 *) + Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- t1 *) + Word2(4036H, types); (* MOV #types, R6 *) + (* L3: *) + Word1(9305H); (* CMP #0, R5 *) + Word1(2400H + 8); (* JZ L1 *) + Word1(9405H); (* CMP R4, R5 *) + Word1(2400H + 10); (* JZ L2 *) + Word1(5505H); (* ADD R5, R5 *) + Word1(0E335H); (* XOR #-1, R5 *) + Word1(5315H); (* ADD #1, R5 *) + Word1(5605H); (* ADD R6, R5 *) + Word1(4525H); (* MOV @R5, R5 *) + Word1(3C00H + 400H - 10); (* JMP L3 *) + (* L1: *) + Word1(9405H); (* CMP R4, R5 *) + Word1(2400H + 2); (* JZ L2 *) + Word1(4304H); (* MOV #0, R4 *) + Word1(4130H); (* RET *) + (* L2: *) + Word1(4314H); (* MOV #1, R4 *) + Word1(4130H) (* RET *) + END; + + (* _is (t, p: INTEGER): INTEGER *) + IF rtl[_is].used THEN + Label(rtl[_is].label); + Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- p *) + Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- t *) + Word1(9304H); (* TST R4 *) + Word1(2400H + 2); (* JZ L *) + Word2(4414H, -2); (* MOV -2(R4), R4 *) + (* L: *) + Word1(1204H); (* PUSH R4 *) + Word1(1205H); (* PUSH R5 *) + Call(rtl[_guardrec].label); (* CALL _guardrec *) + Word1(5221H); (* ADD #4, SP *) + Word1(4130H) (* RET *) + END; + + (* _guard (t, p: INTEGER): INTEGER *) + IF rtl[_guard].used THEN + Label(rtl[_guard].label); + Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- p *) + Word1(4314H); (* MOV #1, R4 *) + Word1(4525H); (* MOV @R5, R5 *) + Word1(9305H); (* TST R5 *) + Word1(2400H + 9); (* JZ L *) + Word2(4515H, -2); (* MOV -2(R5), R5 *) + Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- t *) + Word1(1205H); (* PUSH R5 *) + Word1(1204H); (* PUSH R4 *) + Call(rtl[_guardrec].label); (* CALL _guardrec *) + Word1(5221H); (* ADD #4, SP *) + (* L: *) + Word1(4130H) (* RET *) + END; + + (* _move (bytes, dest, source: INTEGER) *) + IF rtl[_move].used THEN + Label(rtl[_move].label); + Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- bytes *) + Word2(4117H, 4); (* MOV 4(SP), R7; R7 <- dest *) + Word2(4115H, 6); (* MOV 6(SP), R5; R5 <- source *) + Word1(9306H); (* CMP #0, R6 *) + Word1(3800H + 6); (* JL L1 *) + Word1(2400H + 5); (* JZ L1 *) + (* L2: *) + Word2(45F7H, 0); (* MOV.B @R5+, 0(R7) *) + Word1(5317H); (* ADD #1, R7 *) + Word1(8316H); (* SUB #1, R6 *) + Word1(2000H + 400H - 5); (* JNZ L2 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _arrcpy (base_size, len_dst, dst, len_src, src: INTEGER) *) + IF rtl[_arrcpy].used THEN + Label(rtl[_arrcpy].label); + Word3(9191H, 8, 4); (* CMP 8(SP), 4(SP) *) + Word1(3800H + 18); (* JL L1 *) + Word2(1211H, 12); (* PUSH 12(SP) *) + Word2(1211H, 10); (* PUSH 10(SP) *) + Word2(1211H, 14); (* PUSH 14(SP) *) + Word2(1211H, 10); (* PUSH 10(SP) *) + Call(rtl[_mul].label); (* CALL _mul *) + Word1(5221H); (* ADD #4, SP *) + Word1(1204H); (* PUSH R4 *) + Call(rtl[_move].label); (* CALL _move *) + Word2(5031H, 6); (* ADD #6, SP *) + Word1(4314H); (* MOV #1, R4 *) + Word1(4130H); (* RET *) + (* L1 *) + Word1(4304H); (* MOV #0, R4 *) + Word1(4130H) (* RET *) + END; + + (* _length (len, str: INTEGER): INTEGER *) + IF rtl[_length].used THEN + Label(rtl[_length].label); + Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- len *) + Word2(4117H, 4); (* MOV 4(SP), R7; R7 <- str *) + Word1(4304H); (* MOV #0, R4; res := 0 *) + (* L2: *) + Word1(4775H); (* MOV.B @R7+, R5 *) + Word1(9305H); (* CMP #0, R5 *) + Word1(2400H + 3); (* JZ L1 *) + Word1(5314H); (* ADD #1, R4 *) + Word1(8316H); (* SUB #1, R6 *) + Word1(2000H + 400H - 6); (* JNZ L2 *) + (* L1: *) + Word1(4130H) (* RET *) + END; + + (* _strcmp (op, len2, str2, len1, str1: INTEGER): BOOLEAN *) + IF rtl[_strcmp].used THEN + Label(rtl[_strcmp].label); + Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- len2 *) + Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- len1 *) + Word1(9607H); (* CMP R6, R7 *) + Word1(3400H + 1); (* JGE L5 *) + Word1(4706H); (* MOV R7, R6 *) + (* L5: *) + Word1(1206H); (* PUSH R6 *) + Word2(4116H, 12); (* MOV 12(SP), R6; R6 <- str1 *) + Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- str2 *) + (* L3: *) + Word2(9381H, 0); (* CMP #0, 0(SP) *) + Word1(2400H + 11); (* JZ L1 *) + Word1(4674H); (* MOV.B @R6+, R4 *) + Word1(4775H); (* MOV.B @R7+, R5 *) + Word2(8391H, 0); (* SUB #1, 0(SP) *) + Word1(9405H); (* CMP R4, R5 *) + Word1(2400H + 2); (* JZ L2 *) + Word1(8504H); (* SUB R5, R4 *) + Word1(3C00H + 5); (* JMP L4 *) + (* L2: *) + Word1(9304H); (* CMP #0, R4 *) + Word1(2000H + 400H - 13); (* JNZ L3 *) + Word1(3C00H + 2); (* JMP L4 *) + (* L1: *) + Word2(4034H, 8000H); (* MOV #8000H, R4 *) + (* L4: *) + Word1(5321H); (* ADD #2, SP *) + + Word2(9034H, 8000H); (* CMP #8000H, R4 *) + Word1(2000H + 18); (* JNZ L6 *) + Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- len2 *) + Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- len1 *) + Word1(9607H); (* CMP R6, R7 *) + Word1(2400H + 11); (* JZ L7 *) + Word1(3800H + 4); (* JL L8 *) + Word2(5116H, 10); (* ADD 10(SP), R6 *) + Word1(4664H); (* MOV.B @R6, R4 *) + Word1(3C00H + 7); (* JMP L6 *) + (* L8: *) + Word2(5117H, 6); (* ADD 6(SP), R7 *) + Word1(4764H); (* MOV.B @R7, R4 *) + Word1(0E334H); (* XOR #-1, R4 *) + Word1(5314H); (* ADD #1, R4 *) + Word1(3C00H + 1); (* JMP L6 *) + (* L7: *) + Word1(4304H); (* MOV #0, R4 *) + (* L6: *) + + Word2(5110H, 2); (* ADD 2(SP), PC; PC <- PC + op *) + + Word1(9304H); (* CMP #0, R4 *) + Word1(4314H); (* MOV #1, R4 *) + Word1(2400H + 1); (* JZ L *) + Word1(4304H); (* MOV #0, R4 *) + (* L *) + Word1(4130H); (* RET *) + Word1(4303H); (* NOP *) + + Word1(9304H); (* CMP #0, R4 *) + Word1(4314H); (* MOV #1, R4 *) + Word1(2000H + 1); (* JNZ L *) + Word1(4304H); (* MOV #0, R4 *) + (* L *) + Word1(4130H); (* RET *) + Word1(4303H); (* NOP *) + + Word1(9304H); (* CMP #0, R4 *) + Word1(4314H); (* MOV #1, R4 *) + Word1(3800H + 1); (* JL L *) + Word1(4304H); (* MOV #0, R4 *) + (* L *) + Word1(4130H); (* RET *) + Word1(4303H); (* NOP *) + + Word1(9304H); (* CMP #0, R4 *) + Word1(4314H); (* MOV #1, R4 *) + Word1(3800H + 2); (* JL L *) + Word1(2400H + 1); (* JZ L *) + Word1(4304H); (* MOV #0, R4 *) + (* L *) + Word1(4130H); (* RET *) + + Word1(9304H); (* CMP #0, R4 *) + Word1(4304H); (* MOV #0, R4 *) + Word1(3800H + 2); (* JL L *) + Word1(2400H + 1); (* JZ L *) + Word1(4314H); (* MOV #1, R4 *) + (* L *) + Word1(4130H); (* RET *) + + Word1(9304H); (* CMP #0, R4 *) + Word1(4314H); (* MOV #1, R4 *) + Word1(3400H + 1); (* JGE L *) + Word1(4304H); (* MOV #0, R4 *) + (* L *) + Word1(4130H) (* RET *) + END + +END Gen; + + +PROCEDURE Set* (idx, label: INTEGER); +BEGIN + rtl[idx].label := label; + rtl[idx].used := FALSE +END Set; + + +PROCEDURE Used* (idx: INTEGER); +BEGIN + rtl[idx].used := TRUE; + IF (idx = _guard) OR (idx = _is) THEN + rtl[_guardrec].used := TRUE + ELSIF idx = _arrcpy THEN + rtl[_move].used := TRUE; + rtl[_mul].used := TRUE + END +END Used; + + +PROCEDURE Init* (pLabel, pWord, pCall: EMITPROC); +BEGIN + Label := pLabel; + Word := pWord; + Call := pCall; + ram := 200H; +END Init; + + END MSP430RTL. \ No newline at end of file diff --git a/programs/develop/oberon07/source/PROG.ob07 b/programs/develop/oberon07/source/PROG.ob07 index f2e3b6c46d..3374779cf9 100644 --- a/programs/develop/oberon07/source/PROG.ob07 +++ b/programs/develop/oberon07/source/PROG.ob07 @@ -71,7 +71,7 @@ TYPE OPTIONS* = RECORD - version*, stack*, ram*, rom*: INTEGER; + version*, stack*, ram*, rom*, tab*: INTEGER; pic*, lower*: BOOLEAN; checking*: SET diff --git a/programs/develop/oberon07/source/RVMxI.ob07 b/programs/develop/oberon07/source/RVMxI.ob07 index d9630221c8..e2d0139910 100644 --- a/programs/develop/oberon07/source/RVMxI.ob07 +++ b/programs/develop/oberon07/source/RVMxI.ob07 @@ -1,1428 +1,1428 @@ -(* - BSD 2-Clause License - - Copyright (c) 2020-2021, Anton Krotov - All rights reserved. -*) - -MODULE RVMxI; - -IMPORT - - PROG, WR := WRITER, IL, CHL := CHUNKLISTS, REG, UTILS, STRINGS, ERRORS, TARGETS; - - -CONST - - LTypes = 0; - LStrings = 1; - LGlobal = 2; - LHeap = 3; - LStack = 4; - - numGPRs = 3; - - R0 = 0; R1 = 1; - BP = 3; SP = 4; - - ACC = R0; - - GPRs = {0 .. 2} + {5 .. numGPRs + 1}; - - opSTOP = 0; opRET = 1; opENTER = 2; opNEG = 3; opNOT = 4; opNOP = 5; - opXCHG = 6; opLDB = 7; opLDH = 8; opLDW = 9; opPUSH = 10; opPUSHC = 11; - opPOP = 12; opLABEL = 13; opLEA = 14; opLLA = 15; - opLDD = 16; (* 17, 18 *) - opJMP = 19; opCALL = 20; opCALLI = 21; - - opMOV = 22; opMUL = 24; opADD = 26; opSUB = 28; opDIV = 30; opMOD = 32; - opSTB = 34; opSTH = 36; opSTW = 38; opSTD = 40; (* 42, 44 *) - opAND = 46; opOR = 48; opXOR = 50; opASR = 52; opLSR = 54; - opLSL = 56; opROR = 58; (* 60, 62 *) opCMP = 64; - - opMOVC = 23; opMULC = 25; opADDC = 27; opSUBC = 29; opDIVC = 31; opMODC = 33; - opSTBC = 35; opSTHC = 37; opSTWC = 39; opSTDC = 41; (* 43, 45 *) - opANDC = 47; opORC = 49; opXORC = 51; opASRC = 53; opLSRC = 55; - opLSLC = 57; opRORC = 59; (* 61, 63 *) opCMPC = 65; - - opBIT = 66; opSYSCALL = 67; opJBT = 68; opADDRC = 69; - - opJEQ = 70; opJNE = 71; opJLT = 72; opJGE = 73; opJGT = 74; opJLE = 75; - opSEQ = 76; opSNE = 77; opSLT = 78; opSGE = 79; opSGT = 80; opSLE = 81; - - -VAR - - R: REG.REGS; count, szWord: INTEGER; - - ldr, str: PROCEDURE (r1, r2: INTEGER); - - -PROCEDURE OutByte (n: BYTE); -BEGIN - WR.WriteByte(n); - INC(count) -END OutByte; - - -PROCEDURE OutInt (n: INTEGER); -BEGIN - IF szWord = 8 THEN - WR.Write64LE(n); - INC(count, 8) - ELSE (* szWord = 4 *) - WR.Write32LE(n); - INC(count, 4) - END -END OutInt; - - -PROCEDURE Emit (op, par1, par2: INTEGER); -BEGIN - OutInt(op); - OutInt(par1); - OutInt(par2) -END Emit; - - -PROCEDURE drop; -BEGIN - REG.Drop(R) -END drop; - - -PROCEDURE GetAnyReg (): INTEGER; - RETURN REG.GetAnyReg(R) -END GetAnyReg; - - -PROCEDURE GetAcc; -BEGIN - ASSERT(REG.GetReg(R, ACC)) -END GetAcc; - - -PROCEDURE UnOp (VAR r: INTEGER); -BEGIN - REG.UnOp(R, r) -END UnOp; - - -PROCEDURE BinOp (VAR r1, r2: INTEGER); -BEGIN - REG.BinOp(R, r1, r2) -END BinOp; - - -PROCEDURE PushAll (NumberOfParameters: INTEGER); -BEGIN - REG.PushAll(R); - DEC(R.pushed, NumberOfParameters) -END PushAll; - - -PROCEDURE push (r: INTEGER); -BEGIN - Emit(opPUSH, r, 0) -END push; - - -PROCEDURE pop (r: INTEGER); -BEGIN - Emit(opPOP, r, 0) -END pop; - - -PROCEDURE mov (r1, r2: INTEGER); -BEGIN - Emit(opMOV, r1, r2) -END mov; - - -PROCEDURE xchg (r1, r2: INTEGER); -BEGIN - Emit(opXCHG, r1, r2) -END xchg; - - -PROCEDURE addrc (r, c: INTEGER); -BEGIN - Emit(opADDC, r, c) -END addrc; - - -PROCEDURE subrc (r, c: INTEGER); -BEGIN - Emit(opSUBC, r, c) -END subrc; - - -PROCEDURE movrc (r, c: INTEGER); -BEGIN - Emit(opMOVC, r, c) -END movrc; - - -PROCEDURE pushc (c: INTEGER); -BEGIN - Emit(opPUSHC, c, 0) -END pushc; - - -PROCEDURE add (r1, r2: INTEGER); -BEGIN - Emit(opADD, r1, r2) -END add; - - -PROCEDURE sub (r1, r2: INTEGER); -BEGIN - Emit(opSUB, r1, r2) -END sub; - - -PROCEDURE ldr64 (r1, r2: INTEGER); -BEGIN - Emit(opLDD, r2 * 256 + r1, 0) -END ldr64; - - -PROCEDURE ldr32 (r1, r2: INTEGER); -BEGIN - Emit(opLDW, r2 * 256 + r1, 0) -END ldr32; - - -PROCEDURE ldr16 (r1, r2: INTEGER); -BEGIN - Emit(opLDH, r2 * 256 + r1, 0) -END ldr16; - - -PROCEDURE ldr8 (r1, r2: INTEGER); -BEGIN - Emit(opLDB, r2 * 256 + r1, 0) -END ldr8; - - -PROCEDURE str64 (r1, r2: INTEGER); -BEGIN - Emit(opSTD, r1 * 256 + r2, 0) -END str64; - - -PROCEDURE str32 (r1, r2: INTEGER); -BEGIN - Emit(opSTW, r1 * 256 + r2, 0) -END str32; - - -PROCEDURE str16 (r1, r2: INTEGER); -BEGIN - Emit(opSTH, r1 * 256 + r2, 0) -END str16; - - -PROCEDURE str8 (r1, r2: INTEGER); -BEGIN - Emit(opSTB, r1 * 256 + r2, 0) -END str8; - - -PROCEDURE GlobalAdr (r, offset: INTEGER); -BEGIN - Emit(opLEA, r + 256 * LGlobal, offset) -END GlobalAdr; - - -PROCEDURE StrAdr (r, offset: INTEGER); -BEGIN - Emit(opLEA, r + 256 * LStrings, offset) -END StrAdr; - - -PROCEDURE ProcAdr (r, label: INTEGER); -BEGIN - Emit(opLLA, r, label) -END ProcAdr; - - -PROCEDURE jnz (r, label: INTEGER); -BEGIN - Emit(opCMPC, r, 0); - Emit(opJNE, label, 0) -END jnz; - - -PROCEDURE CallRTL (proc, par: INTEGER); -BEGIN - Emit(opCALL, IL.codes.rtl[proc], 0); - addrc(SP, par * szWord) -END CallRTL; - - -PROCEDURE jcc (cc: INTEGER): INTEGER; -BEGIN - CASE cc OF - |IL.opEQ, IL.opEQC: cc := opJEQ - |IL.opNE, IL.opNEC: cc := opJNE - |IL.opLT, IL.opLTC: cc := opJLT - |IL.opLE, IL.opLEC: cc := opJLE - |IL.opGT, IL.opGTC: cc := opJGT - |IL.opGE, IL.opGEC: cc := opJGE - END - RETURN cc -END jcc; - - -PROCEDURE shift1 (op, param: INTEGER); -VAR - r1, r2: INTEGER; - -BEGIN - r2 := GetAnyReg(); - Emit(opMOVC, r2, param); - BinOp(r1, r2); - Emit(op, r2, r1); - mov(r1, r2); - drop -END shift1; - - -PROCEDURE shift (op: INTEGER); -VAR - r1, r2: INTEGER; - -BEGIN - BinOp(r1, r2); - Emit(op, r1, r2); - drop -END shift; - - -PROCEDURE translate (szWord: INTEGER); -VAR - cmd, next: IL.COMMAND; - - opcode, param1, param2, r1, r2, r3, - a, b, label, opLD, opST, opSTC: INTEGER; - -BEGIN - IF szWord = 8 THEN - opLD := opLDD; - opST := opSTD; - opSTC := opSTDC - ELSE - opLD := opLDW; - opST := opSTW; - opSTC := opSTWC - END; - - cmd := IL.codes.commands.first(IL.COMMAND); - - WHILE cmd # NIL DO - - param1 := cmd.param1; - param2 := cmd.param2; - opcode := cmd.opcode; - - CASE opcode OF - - |IL.opJMP: - Emit(opJMP, param1, 0) - - |IL.opLABEL: - Emit(opLABEL, param1, 0) - - |IL.opCALL: - Emit(opCALL, param1, 0) - - |IL.opCALLP: - UnOp(r1); - Emit(opCALLI, r1, 0); - drop; - ASSERT(R.top = -1) - - |IL.opPUSHC: - pushc(param2) - - |IL.opCLEANUP: - IF param2 # 0 THEN - addrc(SP, param2 * szWord) - END - - |IL.opNOP, IL.opAND, IL.opOR: - - |IL.opSADR: - StrAdr(GetAnyReg(), param2) - - |IL.opGADR: - GlobalAdr(GetAnyReg(), param2) - - |IL.opLADR: - param2 := param2 * szWord; - next := cmd.next(IL.COMMAND); - IF ((next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVEF)) & (szWord = 8) OR (next.opcode = IL.opSAVE64) THEN - UnOp(r1); - Emit(opSTD, BP * 256 + r1, param2); - drop; - cmd := next - ELSIF ((next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVEF)) & (szWord = 4) OR (next.opcode = IL.opSAVE32) THEN - UnOp(r1); - Emit(opSTW, BP * 256 + r1, param2); - drop; - cmd := next - ELSIF next.opcode = IL.opSAVE16 THEN - UnOp(r1); - Emit(opSTH, BP * 256 + r1, param2); - drop; - cmd := next - ELSIF next.opcode = IL.opSAVE8 THEN - UnOp(r1); - Emit(opSTB, BP * 256 + r1, param2); - drop; - cmd := next - ELSE - Emit(opADDRC, BP * 256 + GetAnyReg(), param2) - END - - |IL.opPARAM: - IF param2 = 1 THEN - UnOp(r1); - push(r1); - drop - ELSE - ASSERT(R.top + 1 <= param2); - PushAll(param2) - END - - |IL.opONERR: - pushc(param2); - Emit(opJMP, param1, 0) - - |IL.opPRECALL: - PushAll(0) - - |IL.opRES, IL.opRESF: - ASSERT(R.top = -1); - GetAcc - - |IL.opENTER: - ASSERT(R.top = -1); - Emit(opLABEL, param1, 0); - Emit(opENTER, param2, 0) - - |IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: - IF opcode # IL.opLEAVE THEN - UnOp(r1); - IF r1 # ACC THEN - mov(ACC, r1) - END; - drop - END; - - ASSERT(R.top = -1); - - IF param1 > 0 THEN - mov(SP, BP) - END; - - pop(BP); - - Emit(opRET, 0, 0) - - |IL.opLEAVEC: - Emit(opRET, 0, 0) - - |IL.opCONST: - next := cmd.next(IL.COMMAND); - IF (next.opcode = IL.opPARAM) & (next.param2 = 1) THEN - pushc(param2); - cmd := next - ELSE - movrc(GetAnyReg(), param2) - END - - |IL.opDROP: - UnOp(r1); - drop - - |IL.opSAVEC: - UnOp(r1); - Emit(opSTC, r1, param2); - drop - - |IL.opSAVE8C: - UnOp(r1); - Emit(opSTBC, r1, param2 MOD 256); - drop - - |IL.opSAVE16C: - UnOp(r1); - Emit(opSTHC, r1, param2 MOD 65536); - drop - - |IL.opSAVE, IL.opSAVEF: - BinOp(r2, r1); - str(r1, r2); - drop; - drop - - |IL.opSAVE32: - BinOp(r2, r1); - str32(r1, r2); - drop; - drop - - |IL.opSAVE64: - BinOp(r2, r1); - str64(r1, r2); - drop; - drop - - |IL.opSAVEFI: - BinOp(r2, r1); - str(r2, r1); - drop; - drop - - |IL.opSAVE8: - BinOp(r2, r1); - str8(r1, r2); - drop; - drop - - |IL.opSAVE16: - BinOp(r2, r1); - str16(r1, r2); - drop; - drop - - |IL.opGLOAD32: - r1 := GetAnyReg(); - GlobalAdr(r1, param2); - ldr32(r1, r1) - - |IL.opGLOAD64: - r1 := GetAnyReg(); - GlobalAdr(r1, param2); - ldr64(r1, r1) - - |IL.opVADR: - Emit(opLD, BP * 256 + GetAnyReg(), param2 * szWord) - - |IL.opLLOAD32: - Emit(opLDW, BP * 256 + GetAnyReg(), param2 * szWord) - - |IL.opLLOAD64: - Emit(opLDD, BP * 256 + GetAnyReg(), param2 * szWord) - - |IL.opVLOAD32: - r1 := GetAnyReg(); - Emit(opLD, BP * 256 + r1, param2 * szWord); - ldr32(r1, r1) - - |IL.opVLOAD64: - r1 := GetAnyReg(); - Emit(opLDD, BP * 256 + r1, param2 * szWord); - ldr64(r1, r1) - - |IL.opGLOAD16: - r1 := GetAnyReg(); - GlobalAdr(r1, param2); - ldr16(r1, r1) - - |IL.opLLOAD16: - Emit(opLDH, BP * 256 + GetAnyReg(), param2 * szWord) - - |IL.opVLOAD16: - r1 := GetAnyReg(); - Emit(opLD, BP * 256 + r1, param2 * szWord); - ldr16(r1, r1) - - |IL.opGLOAD8: - r1 := GetAnyReg(); - GlobalAdr(r1, param2); - ldr8(r1, r1) - - |IL.opLLOAD8: - Emit(opLDB, BP * 256 + GetAnyReg(), param2 * szWord) - - |IL.opVLOAD8: - r1 := GetAnyReg(); - Emit(opLD, BP * 256 + r1, param2 * szWord); - ldr8(r1, r1) - - |IL.opLOAD8: - UnOp(r1); - ldr8(r1, r1) - - |IL.opLOAD16: - UnOp(r1); - ldr16(r1, r1) - - |IL.opLOAD32: - UnOp(r1); - ldr32(r1, r1) - - |IL.opLOAD64: - UnOp(r1); - ldr64(r1, r1) - - |IL.opLOADF: - UnOp(r1); - ldr(r1, r1) - - |IL.opUMINUS: - UnOp(r1); - Emit(opNEG, r1, 0) - - |IL.opADD: - BinOp(r1, r2); - add(r1, r2); - drop - - |IL.opSUB: - BinOp(r1, r2); - sub(r1, r2); - drop - - |IL.opADDC: - UnOp(r1); - next := cmd.next(IL.COMMAND); - CASE next.opcode OF - |IL.opLOADF: - Emit(opLD, r1 * 256 + r1, param2); - cmd := next - |IL.opLOAD64: - Emit(opLDD, r1 * 256 + r1, param2); - cmd := next - |IL.opLOAD32: - Emit(opLDW, r1 * 256 + r1, param2); - cmd := next - |IL.opLOAD16: - Emit(opLDH, r1 * 256 + r1, param2); - cmd := next - |IL.opLOAD8: - Emit(opLDB, r1 * 256 + r1, param2); - cmd := next - ELSE - addrc(r1, param2) - END - - |IL.opSUBR: - UnOp(r1); - subrc(r1, param2) - - |IL.opSUBL: - UnOp(r1); - subrc(r1, param2); - Emit(opNEG, r1, 0) - - |IL.opMULC: - UnOp(r1); - Emit(opMULC, r1, param2) - - |IL.opMUL: - BinOp(r1, r2); - Emit(opMUL, r1, r2); - drop - - |IL.opDIV: - BinOp(r1, r2); - Emit(opDIV, r1, r2); - drop - - |IL.opMOD: - BinOp(r1, r2); - Emit(opMOD, r1, r2); - drop - - |IL.opDIVR: - UnOp(r1); - Emit(opDIVC, r1, param2) - - |IL.opMODR: - UnOp(r1); - Emit(opMODC, r1, param2) - - |IL.opDIVL: - UnOp(r1); - r2 := GetAnyReg(); - movrc(r2, param2); - Emit(opDIV, r2, r1); - mov(r1, r2); - drop - - |IL.opMODL: - UnOp(r1); - r2 := GetAnyReg(); - movrc(r2, param2); - Emit(opMOD, r2, r1); - mov(r1, r2); - drop - - |IL.opEQ .. IL.opGE, IL.opEQC .. IL.opGEC: - IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN - BinOp(r1, r2); - Emit(opCMP, r1, r2); - drop - ELSE - UnOp(r1); - Emit(opCMPC, r1, param2) - END; - next := cmd.next(IL.COMMAND); - IF next.opcode = IL.opJZ THEN - Emit(ORD(BITS(jcc(opcode)) / {0}), next.param1, 0); - cmd := next; - drop - ELSIF next.opcode = IL.opJNZ THEN - Emit(jcc(opcode), next.param1, 0); - cmd := next; - drop - ELSE - Emit(jcc(opcode) + 6, r1, 0) - END - - |IL.opJNZ1: - UnOp(r1); - jnz(r1, param1) - - |IL.opJG: - UnOp(r1); - Emit(opCMPC, r1, 0); - Emit(opJGT, param1, 0) - - |IL.opJNZ: - UnOp(r1); - jnz(r1, param1); - drop - - |IL.opJZ: - UnOp(r1); - Emit(opCMPC, r1, 0); - Emit(opJEQ, param1, 0); - drop - - |IL.opMULS: - BinOp(r1, r2); - Emit(opAND, r1, r2); - drop - - |IL.opMULSC: - UnOp(r1); - Emit(opANDC, r1, param2) - - |IL.opDIVS: - BinOp(r1, r2); - Emit(opXOR, r1, r2); - drop - - |IL.opDIVSC: - UnOp(r1); - Emit(opXORC, r1, param2) - - |IL.opADDS: - BinOp(r1, r2); - Emit(opOR, r1, r2); - drop - - |IL.opSUBS: - BinOp(r1, r2); - Emit(opNOT, r2, 0); - Emit(opAND, r1, r2); - drop - - |IL.opADDSC: - UnOp(r1); - Emit(opORC, r1, param2) - - |IL.opSUBSL: - UnOp(r1); - Emit(opNOT, r1, 0); - Emit(opANDC, r1, param2) - - |IL.opSUBSR: - UnOp(r1); - Emit(opANDC, r1, ORD(-BITS(param2))) - - |IL.opUMINS: - UnOp(r1); - Emit(opNOT, r1, 0) - - |IL.opASR: - shift(opASR) - - |IL.opLSL: - shift(opLSL) - - |IL.opROR: - shift(opROR) - - |IL.opLSR: - shift(opLSR) - - |IL.opASR1: - shift1(opASR, param2) - - |IL.opLSL1: - shift1(opLSL, param2) - - |IL.opROR1: - shift1(opROR, param2) - - |IL.opLSR1: - shift1(opLSR, param2) - - |IL.opASR2: - UnOp(r1); - Emit(opASRC, r1, param2 MOD (szWord * 8)) - - |IL.opLSL2: - UnOp(r1); - Emit(opLSLC, r1, param2 MOD (szWord * 8)) - - |IL.opROR2: - UnOp(r1); - Emit(opRORC, r1, param2 MOD (szWord * 8)) - - |IL.opLSR2: - UnOp(r1); - Emit(opLSRC, r1, param2 MOD (szWord * 8)) - - |IL.opCHR: - UnOp(r1); - Emit(opANDC, r1, 255) - - |IL.opWCHR: - UnOp(r1); - Emit(opANDC, r1, 65535) - - |IL.opABS: - UnOp(r1); - Emit(opCMPC, r1, 0); - label := IL.NewLabel(); - Emit(opJGE, label, 0); - Emit(opNEG, r1, 0); - Emit(opLABEL, label, 0) - - |IL.opLEN: - UnOp(r1); - drop; - EXCL(R.regs, r1); - - WHILE param2 > 0 DO - UnOp(r2); - drop; - DEC(param2) - END; - - INCL(R.regs, r1); - ASSERT(REG.GetReg(R, r1)) - - |IL.opSWITCH: - UnOp(r1); - IF param2 = 0 THEN - r2 := ACC - ELSE - r2 := R1 - END; - IF r1 # r2 THEN - ASSERT(REG.GetReg(R, r2)); - ASSERT(REG.Exchange(R, r1, r2)); - drop - END; - drop - - |IL.opENDSW: - - |IL.opCASEL: - Emit(opCMPC, ACC, param1); - Emit(opJLT, param2, 0) - - |IL.opCASER: - Emit(opCMPC, ACC, param1); - Emit(opJGT, param2, 0) - - |IL.opCASELR: - Emit(opCMPC, ACC, param1); - IF param2 = cmd.param3 THEN - Emit(opJNE, param2, 0) - ELSE - Emit(opJLT, param2, 0); - Emit(opJGT, cmd.param3, 0) - END - - |IL.opSBOOL: - BinOp(r2, r1); - Emit(opCMPC, r2, 0); - Emit(opSNE, r2, 0); - str8(r1, r2); - drop; - drop - - |IL.opSBOOLC: - UnOp(r1); - Emit(opSTBC, r1, ORD(param2 # 0)); - drop - - |IL.opINCC: - UnOp(r1); - r2 := GetAnyReg(); - ldr(r2, r1); - addrc(r2, param2); - str(r1, r2); - drop; - drop - - |IL.opINCCB, IL.opDECCB: - IF opcode = IL.opDECCB THEN - param2 := -param2 - END; - UnOp(r1); - r2 := GetAnyReg(); - ldr8(r2, r1); - addrc(r2, param2); - str8(r1, r2); - drop; - drop - - |IL.opINCB, IL.opDECB: - BinOp(r2, r1); - r3 := GetAnyReg(); - ldr8(r3, r1); - IF opcode = IL.opINCB THEN - add(r3, r2) - ELSE - sub(r3, r2) - END; - str8(r1, r3); - drop; - drop; - drop - - |IL.opINC, IL.opDEC: - BinOp(r2, r1); - r3 := GetAnyReg(); - ldr(r3, r1); - IF opcode = IL.opINC THEN - add(r3, r2) - ELSE - sub(r3, r2) - END; - str(r1, r3); - drop; - drop; - drop - - |IL.opINCL, IL.opEXCL: - BinOp(r2, r1); - Emit(opBIT, r2, r2); - r3 := GetAnyReg(); - ldr(r3, r1); - IF opcode = IL.opINCL THEN - Emit(opOR, r3, r2) - ELSE - Emit(opNOT, r2, 0); - Emit(opAND, r3, r2) - END; - str(r1, r3); - drop; - drop; - drop - - |IL.opINCLC, IL.opEXCLC: - UnOp(r1); - r2 := GetAnyReg(); - ldr(r2, r1); - IF opcode = IL.opINCLC THEN - Emit(opORC, r2, ORD({param2})) - ELSE - Emit(opANDC, r2, ORD(-{param2})) - END; - str(r1, r2); - drop; - drop - - |IL.opEQB, IL.opNEB: - BinOp(r1, r2); - Emit(opCMPC, r1, 0); - Emit(opSNE, r1, 0); - Emit(opCMPC, r2, 0); - Emit(opSNE, r2, 0); - Emit(opCMP, r1, r2); - IF opcode = IL.opEQB THEN - Emit(opSEQ, r1, 0) - ELSE - Emit(opSNE, r1, 0) - END; - drop - - |IL.opCHKBYTE: - BinOp(r1, r2); - Emit(opCMPC, r1, 256); - Emit(opJBT, param1, 0) - - |IL.opCHKIDX: - UnOp(r1); - Emit(opCMPC, r1, param2); - Emit(opJBT, param1, 0) - - |IL.opCHKIDX2: - BinOp(r1, r2); - IF param2 # -1 THEN - Emit(opCMP, r2, r1); - Emit(opJBT, param1, 0) - END; - INCL(R.regs, r1); - DEC(R.top); - R.stk[R.top] := r2 - - |IL.opEQP, IL.opNEP: - ProcAdr(GetAnyReg(), param1); - BinOp(r1, r2); - Emit(opCMP, r1, r2); - IF opcode = IL.opEQP THEN - Emit(opSEQ, r1, 0) - ELSE - Emit(opSNE, r1, 0) - END; - drop - - |IL.opSAVEP: - UnOp(r1); - r2 := GetAnyReg(); - ProcAdr(r2, param2); - str(r1, r2); - drop; - drop - - |IL.opPUSHP: - ProcAdr(GetAnyReg(), param2) - - |IL.opPUSHT: - UnOp(r1); - Emit(opLD, r1 * 256 + GetAnyReg(), -szWord) - - |IL.opGET, IL.opGETC: - IF opcode = IL.opGET THEN - BinOp(r1, r2) - ELSIF opcode = IL.opGETC THEN - UnOp(r2); - r1 := GetAnyReg(); - movrc(r1, param1) - END; - drop; - drop; - - CASE param2 OF - |1: ldr8(r1, r1); str8(r2, r1) - |2: ldr16(r1, r1); str16(r2, r1) - |4: ldr32(r1, r1); str32(r2, r1) - |8: ldr64(r1, r1); str64(r2, r1) - END - - |IL.opNOT: - UnOp(r1); - Emit(opCMPC, r1, 0); - Emit(opSEQ, r1, 0) - - |IL.opORD: - UnOp(r1); - Emit(opCMPC, r1, 0); - Emit(opSNE, r1, 0) - - |IL.opMIN, IL.opMAX: - BinOp(r1, r2); - Emit(opCMP, r1, r2); - label := IL.NewLabel(); - IF opcode = IL.opMIN THEN - Emit(opJLE, label, 0) - ELSE - Emit(opJGE, label, 0) - END; - Emit(opMOV, r1, r2); - Emit(opLABEL, label, 0); - drop - - |IL.opMINC, IL.opMAXC: - UnOp(r1); - Emit(opCMPC, r1, param2); - label := IL.NewLabel(); - IF opcode = IL.opMINC THEN - Emit(opJLE, label, 0) - ELSE - Emit(opJGE, label, 0) - END; - Emit(opMOVC, r1, param2); - Emit(opLABEL, label, 0) - - |IL.opIN: - BinOp(r1, r2); - Emit(opBIT, r1, r1); - Emit(opAND, r1, r2); - Emit(opCMPC, r1, 0); - Emit(opSNE, r1, 0); - drop - - |IL.opINL: - UnOp(r1); - Emit(opANDC, r1, ORD({param2})); - Emit(opCMPC, r1, 0); - Emit(opSNE, r1, 0) - - |IL.opINR: - UnOp(r1); - Emit(opBIT, r1, r1); - Emit(opANDC, r1, param2); - Emit(opCMPC, r1, 0); - Emit(opSNE, r1, 0) - - |IL.opERR: - CallRTL(IL._error, 4) - - |IL.opEQS .. IL.opGES: - PushAll(4); - pushc(opcode - IL.opEQS); - CallRTL(IL._strcmp, 5); - GetAcc - - |IL.opEQSW .. IL.opGESW: - PushAll(4); - pushc(opcode - IL.opEQSW); - CallRTL(IL._strcmpw, 5); - GetAcc - - |IL.opCOPY: - PushAll(2); - pushc(param2); - CallRTL(IL._move, 3) - - |IL.opMOVE: - PushAll(3); - CallRTL(IL._move, 3) - - |IL.opCOPYA: - PushAll(4); - pushc(param2); - CallRTL(IL._arrcpy, 5); - GetAcc - - |IL.opCOPYS: - PushAll(4); - pushc(param2); - CallRTL(IL._strcpy, 5) - - |IL.opROT: - PushAll(0); - mov(ACC, SP); - push(ACC); - pushc(param2); - CallRTL(IL._rot, 2) - - |IL.opLENGTH: - PushAll(2); - CallRTL(IL._length, 2); - GetAcc - - |IL.opLENGTHW: - PushAll(2); - CallRTL(IL._lengthw, 2); - GetAcc - - |IL.opSAVES: - UnOp(r2); - REG.PushAll_1(R); - r1 := GetAnyReg(); - StrAdr(r1, param2); - push(r1); - drop; - push(r2); - drop; - pushc(param1); - CallRTL(IL._move, 3) - - |IL.opRSET: - PushAll(2); - CallRTL(IL._set, 2); - GetAcc - - |IL.opRSETR: - PushAll(1); - pushc(param2); - CallRTL(IL._set, 2); - GetAcc - - |IL.opRSETL: - UnOp(r1); - REG.PushAll_1(R); - pushc(param2); - push(r1); - drop; - CallRTL(IL._set, 2); - GetAcc - - |IL.opRSET1: - PushAll(1); - CallRTL(IL._set1, 1); - GetAcc - - |IL.opNEW: - PushAll(1); - INC(param2, szWord); - ASSERT(UTILS.Align(param2, szWord)); - pushc(param2); - pushc(param1); - CallRTL(IL._new, 3) - - |IL.opTYPEGP: - UnOp(r1); - PushAll(0); - push(r1); - pushc(param2); - CallRTL(IL._guard, 2); - GetAcc - - |IL.opIS: - PushAll(1); - pushc(param2); - CallRTL(IL._is, 2); - GetAcc - - |IL.opISREC: - PushAll(2); - pushc(param2); - CallRTL(IL._guardrec, 3); - GetAcc - - |IL.opTYPEGR: - PushAll(1); - pushc(param2); - CallRTL(IL._guardrec, 2); - GetAcc - - |IL.opTYPEGD: - UnOp(r1); - PushAll(0); - subrc(r1, szWord); - ldr(r1, r1); - push(r1); - pushc(param2); - CallRTL(IL._guardrec, 2); - GetAcc - - |IL.opCASET: - push(R1); - push(R1); - pushc(param2); - CallRTL(IL._guardrec, 2); - pop(R1); - jnz(ACC, param1) - - |IL.opCONSTF: - IF szWord = 8 THEN - movrc(GetAnyReg(), UTILS.splitf(cmd.float, a, b)) - ELSE (* szWord = 4 *) - movrc(GetAnyReg(), UTILS.d2s(cmd.float)) - END - - |IL.opMULF: - PushAll(2); - CallRTL(IL._fmul, 2); - GetAcc - - |IL.opDIVF: - PushAll(2); - CallRTL(IL._fdiv, 2); - GetAcc - - |IL.opDIVFI: - PushAll(2); - CallRTL(IL._fdivi, 2); - GetAcc - - |IL.opADDF: - PushAll(2); - CallRTL(IL._fadd, 2); - GetAcc - - |IL.opSUBFI: - PushAll(2); - CallRTL(IL._fsubi, 2); - GetAcc - - |IL.opSUBF: - PushAll(2); - CallRTL(IL._fsub, 2); - GetAcc - - |IL.opEQF..IL.opGEF: - PushAll(2); - pushc(opcode - IL.opEQF); - CallRTL(IL._fcmp, 3); - GetAcc - - |IL.opFLOOR: - PushAll(1); - CallRTL(IL._floor, 1); - GetAcc - - |IL.opFLT: - PushAll(1); - CallRTL(IL._flt, 1); - GetAcc - - |IL.opUMINF: - UnOp(r1); - Emit(opRORC, r1, -1); - Emit(opXORC, r1, 1); - Emit(opRORC, r1, 1) - - |IL.opFABS: - UnOp(r1); - Emit(opLSLC, r1, 1); - Emit(opLSRC, r1, 1) - - |IL.opINF: - r1 := GetAnyReg(); - Emit(opMOVC, r1, 1); - Emit(opRORC, r1, 1); - Emit(opASRC, r1, 7 + 3 * ORD(szWord = 8)); - Emit(opLSRC, r1, 1) - - |IL.opPUSHF: - UnOp(r1); - push(r1); - drop - - |IL.opPACK: - PushAll(2); - CallRTL(IL._pack, 2) - - |IL.opPACKC: - PushAll(1); - pushc(param2); - CallRTL(IL._pack, 2) - - |IL.opUNPK: - PushAll(2); - CallRTL(IL._unpk, 2) - - |IL.opCODE: - OutInt(param2) - - |IL.opLADR_SAVE: - UnOp(r1); - Emit(opST, BP * 256 + r1, param2 * szWord); - drop - - |IL.opLADR_INCC: - r1 := GetAnyReg(); - Emit(opLD, BP * 256 + r1, param1 * szWord); - Emit(opADDC, r1, param2); - Emit(opST, BP * 256 + r1, param1 * szWord); - drop - - END; - - cmd := cmd.next(IL.COMMAND) - END; - - ASSERT(R.pushed = 0); - ASSERT(R.top = -1) -END translate; - - -PROCEDURE prolog; -BEGIN - Emit(opLEA, SP + LStack * 256, 0); - Emit(opLEA, ACC + LTypes * 256, 0); - push(ACC); - Emit(opLEA, ACC + LHeap * 256, 0); - push(ACC); - pushc(CHL.Length(IL.codes.types)); - CallRTL(IL._init, 3) -END prolog; - - -PROCEDURE epilog (ram, szWord: INTEGER); -VAR - tcount, dcount, i, offTypes, offStrings, - szData, szGlobal, szHeapStack: INTEGER; - -BEGIN - Emit(opSTOP, 0, 0); - - offTypes := count; - - tcount := CHL.Length(IL.codes.types); - FOR i := 0 TO tcount - 1 DO - OutInt(CHL.GetInt(IL.codes.types, i)) - END; - - offStrings := count; - dcount := CHL.Length(IL.codes.data); - FOR i := 0 TO dcount - 1 DO - OutByte(CHL.GetByte(IL.codes.data, i)) - END; - - IF dcount MOD szWord # 0 THEN - i := szWord - dcount MOD szWord; - WHILE i > 0 DO - OutByte(0); - DEC(i) - END - END; - - szData := count - offTypes; - szGlobal := (IL.codes.bss DIV szWord + 1) * szWord; - szHeapStack := ram - szData - szGlobal; - - OutInt(offTypes); - OutInt(offStrings); - OutInt(szGlobal DIV szWord); - OutInt(szHeapStack DIV szWord); - FOR i := 1 TO 8 DO - OutInt(0) - END -END epilog; - - -PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); -CONST - minRAM = 32*1024; - maxRAM = 256*1024; - -VAR - szData, szRAM: INTEGER; - -BEGIN - szWord := TARGETS.WordSize; - IF szWord = 8 THEN - ldr := ldr64; - str := str64 - ELSE - ldr := ldr32; - str := str32 - END; - szData := (CHL.Length(IL.codes.types) + CHL.Length(IL.codes.data) DIV szWord + IL.codes.bss DIV szWord + 2) * szWord; - szRAM := MIN(MAX(options.ram, minRAM), maxRAM) * 1024; - - IF szRAM - szData < 1024*1024 THEN - ERRORS.Error(208) - END; - - count := 0; - WR.Create(outname); - - REG.Init(R, push, pop, mov, xchg, GPRs); - - prolog; - translate(szWord); - epilog(szRAM, szWord); - - WR.Close -END CodeGen; - - +(* + BSD 2-Clause License + + Copyright (c) 2020-2021, Anton Krotov + All rights reserved. +*) + +MODULE RVMxI; + +IMPORT + + PROG, WR := WRITER, IL, CHL := CHUNKLISTS, REG, UTILS, STRINGS, ERRORS, TARGETS; + + +CONST + + LTypes = 0; + LStrings = 1; + LGlobal = 2; + LHeap = 3; + LStack = 4; + + numGPRs = 3; + + R0 = 0; R1 = 1; + BP = 3; SP = 4; + + ACC = R0; + + GPRs = {0 .. 2} + {5 .. numGPRs + 1}; + + opSTOP = 0; opRET = 1; opENTER = 2; opNEG = 3; opNOT = 4; opNOP = 5; + opXCHG = 6; opLDB = 7; opLDH = 8; opLDW = 9; opPUSH = 10; opPUSHC = 11; + opPOP = 12; opLABEL = 13; opLEA = 14; opLLA = 15; + opLDD = 16; (* 17, 18 *) + opJMP = 19; opCALL = 20; opCALLI = 21; + + opMOV = 22; opMUL = 24; opADD = 26; opSUB = 28; opDIV = 30; opMOD = 32; + opSTB = 34; opSTH = 36; opSTW = 38; opSTD = 40; (* 42, 44 *) + opAND = 46; opOR = 48; opXOR = 50; opASR = 52; opLSR = 54; + opLSL = 56; opROR = 58; (* 60, 62 *) opCMP = 64; + + opMOVC = 23; opMULC = 25; opADDC = 27; opSUBC = 29; opDIVC = 31; opMODC = 33; + opSTBC = 35; opSTHC = 37; opSTWC = 39; opSTDC = 41; (* 43, 45 *) + opANDC = 47; opORC = 49; opXORC = 51; opASRC = 53; opLSRC = 55; + opLSLC = 57; opRORC = 59; (* 61, 63 *) opCMPC = 65; + + opBIT = 66; opSYSCALL = 67; opJBT = 68; opADDRC = 69; + + opJEQ = 70; opJNE = 71; opJLT = 72; opJGE = 73; opJGT = 74; opJLE = 75; + opSEQ = 76; opSNE = 77; opSLT = 78; opSGE = 79; opSGT = 80; opSLE = 81; + + +VAR + + R: REG.REGS; count, szWord: INTEGER; + + ldr, str: PROCEDURE (r1, r2: INTEGER); + + +PROCEDURE OutByte (n: BYTE); +BEGIN + WR.WriteByte(n); + INC(count) +END OutByte; + + +PROCEDURE OutInt (n: INTEGER); +BEGIN + IF szWord = 8 THEN + WR.Write64LE(n); + INC(count, 8) + ELSE (* szWord = 4 *) + WR.Write32LE(n); + INC(count, 4) + END +END OutInt; + + +PROCEDURE Emit (op, par1, par2: INTEGER); +BEGIN + OutInt(op); + OutInt(par1); + OutInt(par2) +END Emit; + + +PROCEDURE drop; +BEGIN + REG.Drop(R) +END drop; + + +PROCEDURE GetAnyReg (): INTEGER; + RETURN REG.GetAnyReg(R) +END GetAnyReg; + + +PROCEDURE GetAcc; +BEGIN + ASSERT(REG.GetReg(R, ACC)) +END GetAcc; + + +PROCEDURE UnOp (VAR r: INTEGER); +BEGIN + REG.UnOp(R, r) +END UnOp; + + +PROCEDURE BinOp (VAR r1, r2: INTEGER); +BEGIN + REG.BinOp(R, r1, r2) +END BinOp; + + +PROCEDURE PushAll (NumberOfParameters: INTEGER); +BEGIN + REG.PushAll(R); + DEC(R.pushed, NumberOfParameters) +END PushAll; + + +PROCEDURE push (r: INTEGER); +BEGIN + Emit(opPUSH, r, 0) +END push; + + +PROCEDURE pop (r: INTEGER); +BEGIN + Emit(opPOP, r, 0) +END pop; + + +PROCEDURE mov (r1, r2: INTEGER); +BEGIN + Emit(opMOV, r1, r2) +END mov; + + +PROCEDURE xchg (r1, r2: INTEGER); +BEGIN + Emit(opXCHG, r1, r2) +END xchg; + + +PROCEDURE addrc (r, c: INTEGER); +BEGIN + Emit(opADDC, r, c) +END addrc; + + +PROCEDURE subrc (r, c: INTEGER); +BEGIN + Emit(opSUBC, r, c) +END subrc; + + +PROCEDURE movrc (r, c: INTEGER); +BEGIN + Emit(opMOVC, r, c) +END movrc; + + +PROCEDURE pushc (c: INTEGER); +BEGIN + Emit(opPUSHC, c, 0) +END pushc; + + +PROCEDURE add (r1, r2: INTEGER); +BEGIN + Emit(opADD, r1, r2) +END add; + + +PROCEDURE sub (r1, r2: INTEGER); +BEGIN + Emit(opSUB, r1, r2) +END sub; + + +PROCEDURE ldr64 (r1, r2: INTEGER); +BEGIN + Emit(opLDD, r2 * 256 + r1, 0) +END ldr64; + + +PROCEDURE ldr32 (r1, r2: INTEGER); +BEGIN + Emit(opLDW, r2 * 256 + r1, 0) +END ldr32; + + +PROCEDURE ldr16 (r1, r2: INTEGER); +BEGIN + Emit(opLDH, r2 * 256 + r1, 0) +END ldr16; + + +PROCEDURE ldr8 (r1, r2: INTEGER); +BEGIN + Emit(opLDB, r2 * 256 + r1, 0) +END ldr8; + + +PROCEDURE str64 (r1, r2: INTEGER); +BEGIN + Emit(opSTD, r1 * 256 + r2, 0) +END str64; + + +PROCEDURE str32 (r1, r2: INTEGER); +BEGIN + Emit(opSTW, r1 * 256 + r2, 0) +END str32; + + +PROCEDURE str16 (r1, r2: INTEGER); +BEGIN + Emit(opSTH, r1 * 256 + r2, 0) +END str16; + + +PROCEDURE str8 (r1, r2: INTEGER); +BEGIN + Emit(opSTB, r1 * 256 + r2, 0) +END str8; + + +PROCEDURE GlobalAdr (r, offset: INTEGER); +BEGIN + Emit(opLEA, r + 256 * LGlobal, offset) +END GlobalAdr; + + +PROCEDURE StrAdr (r, offset: INTEGER); +BEGIN + Emit(opLEA, r + 256 * LStrings, offset) +END StrAdr; + + +PROCEDURE ProcAdr (r, label: INTEGER); +BEGIN + Emit(opLLA, r, label) +END ProcAdr; + + +PROCEDURE jnz (r, label: INTEGER); +BEGIN + Emit(opCMPC, r, 0); + Emit(opJNE, label, 0) +END jnz; + + +PROCEDURE CallRTL (proc, par: INTEGER); +BEGIN + Emit(opCALL, IL.codes.rtl[proc], 0); + addrc(SP, par * szWord) +END CallRTL; + + +PROCEDURE jcc (cc: INTEGER): INTEGER; +BEGIN + CASE cc OF + |IL.opEQ, IL.opEQC: cc := opJEQ + |IL.opNE, IL.opNEC: cc := opJNE + |IL.opLT, IL.opLTC: cc := opJLT + |IL.opLE, IL.opLEC: cc := opJLE + |IL.opGT, IL.opGTC: cc := opJGT + |IL.opGE, IL.opGEC: cc := opJGE + END + RETURN cc +END jcc; + + +PROCEDURE shift1 (op, param: INTEGER); +VAR + r1, r2: INTEGER; + +BEGIN + r2 := GetAnyReg(); + Emit(opMOVC, r2, param); + BinOp(r1, r2); + Emit(op, r2, r1); + mov(r1, r2); + drop +END shift1; + + +PROCEDURE shift (op: INTEGER); +VAR + r1, r2: INTEGER; + +BEGIN + BinOp(r1, r2); + Emit(op, r1, r2); + drop +END shift; + + +PROCEDURE translate (szWord: INTEGER); +VAR + cmd, next: IL.COMMAND; + + opcode, param1, param2, r1, r2, r3, + a, b, label, opLD, opST, opSTC: INTEGER; + +BEGIN + IF szWord = 8 THEN + opLD := opLDD; + opST := opSTD; + opSTC := opSTDC + ELSE + opLD := opLDW; + opST := opSTW; + opSTC := opSTWC + END; + + cmd := IL.codes.commands.first(IL.COMMAND); + + WHILE cmd # NIL DO + + param1 := cmd.param1; + param2 := cmd.param2; + opcode := cmd.opcode; + + CASE opcode OF + + |IL.opJMP: + Emit(opJMP, param1, 0) + + |IL.opLABEL: + Emit(opLABEL, param1, 0) + + |IL.opCALL: + Emit(opCALL, param1, 0) + + |IL.opCALLP: + UnOp(r1); + Emit(opCALLI, r1, 0); + drop; + ASSERT(R.top = -1) + + |IL.opPUSHC: + pushc(param2) + + |IL.opCLEANUP: + IF param2 # 0 THEN + addrc(SP, param2 * szWord) + END + + |IL.opNOP, IL.opAND, IL.opOR: + + |IL.opSADR: + StrAdr(GetAnyReg(), param2) + + |IL.opGADR: + GlobalAdr(GetAnyReg(), param2) + + |IL.opLADR: + param2 := param2 * szWord; + next := cmd.next(IL.COMMAND); + IF ((next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVEF)) & (szWord = 8) OR (next.opcode = IL.opSAVE64) THEN + UnOp(r1); + Emit(opSTD, BP * 256 + r1, param2); + drop; + cmd := next + ELSIF ((next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVEF)) & (szWord = 4) OR (next.opcode = IL.opSAVE32) THEN + UnOp(r1); + Emit(opSTW, BP * 256 + r1, param2); + drop; + cmd := next + ELSIF next.opcode = IL.opSAVE16 THEN + UnOp(r1); + Emit(opSTH, BP * 256 + r1, param2); + drop; + cmd := next + ELSIF next.opcode = IL.opSAVE8 THEN + UnOp(r1); + Emit(opSTB, BP * 256 + r1, param2); + drop; + cmd := next + ELSE + Emit(opADDRC, BP * 256 + GetAnyReg(), param2) + END + + |IL.opPARAM: + IF param2 = 1 THEN + UnOp(r1); + push(r1); + drop + ELSE + ASSERT(R.top + 1 <= param2); + PushAll(param2) + END + + |IL.opONERR: + pushc(param2); + Emit(opJMP, param1, 0) + + |IL.opPRECALL: + PushAll(0) + + |IL.opRES, IL.opRESF: + ASSERT(R.top = -1); + GetAcc + + |IL.opENTER: + ASSERT(R.top = -1); + Emit(opLABEL, param1, 0); + Emit(opENTER, param2, 0) + + |IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: + IF opcode # IL.opLEAVE THEN + UnOp(r1); + IF r1 # ACC THEN + mov(ACC, r1) + END; + drop + END; + + ASSERT(R.top = -1); + + IF param1 > 0 THEN + mov(SP, BP) + END; + + pop(BP); + + Emit(opRET, 0, 0) + + |IL.opLEAVEC: + Emit(opRET, 0, 0) + + |IL.opCONST: + next := cmd.next(IL.COMMAND); + IF (next.opcode = IL.opPARAM) & (next.param2 = 1) THEN + pushc(param2); + cmd := next + ELSE + movrc(GetAnyReg(), param2) + END + + |IL.opDROP: + UnOp(r1); + drop + + |IL.opSAVEC: + UnOp(r1); + Emit(opSTC, r1, param2); + drop + + |IL.opSAVE8C: + UnOp(r1); + Emit(opSTBC, r1, param2 MOD 256); + drop + + |IL.opSAVE16C: + UnOp(r1); + Emit(opSTHC, r1, param2 MOD 65536); + drop + + |IL.opSAVE, IL.opSAVEF: + BinOp(r2, r1); + str(r1, r2); + drop; + drop + + |IL.opSAVE32: + BinOp(r2, r1); + str32(r1, r2); + drop; + drop + + |IL.opSAVE64: + BinOp(r2, r1); + str64(r1, r2); + drop; + drop + + |IL.opSAVEFI: + BinOp(r2, r1); + str(r2, r1); + drop; + drop + + |IL.opSAVE8: + BinOp(r2, r1); + str8(r1, r2); + drop; + drop + + |IL.opSAVE16: + BinOp(r2, r1); + str16(r1, r2); + drop; + drop + + |IL.opGLOAD32: + r1 := GetAnyReg(); + GlobalAdr(r1, param2); + ldr32(r1, r1) + + |IL.opGLOAD64: + r1 := GetAnyReg(); + GlobalAdr(r1, param2); + ldr64(r1, r1) + + |IL.opVADR: + Emit(opLD, BP * 256 + GetAnyReg(), param2 * szWord) + + |IL.opLLOAD32: + Emit(opLDW, BP * 256 + GetAnyReg(), param2 * szWord) + + |IL.opLLOAD64: + Emit(opLDD, BP * 256 + GetAnyReg(), param2 * szWord) + + |IL.opVLOAD32: + r1 := GetAnyReg(); + Emit(opLD, BP * 256 + r1, param2 * szWord); + ldr32(r1, r1) + + |IL.opVLOAD64: + r1 := GetAnyReg(); + Emit(opLDD, BP * 256 + r1, param2 * szWord); + ldr64(r1, r1) + + |IL.opGLOAD16: + r1 := GetAnyReg(); + GlobalAdr(r1, param2); + ldr16(r1, r1) + + |IL.opLLOAD16: + Emit(opLDH, BP * 256 + GetAnyReg(), param2 * szWord) + + |IL.opVLOAD16: + r1 := GetAnyReg(); + Emit(opLD, BP * 256 + r1, param2 * szWord); + ldr16(r1, r1) + + |IL.opGLOAD8: + r1 := GetAnyReg(); + GlobalAdr(r1, param2); + ldr8(r1, r1) + + |IL.opLLOAD8: + Emit(opLDB, BP * 256 + GetAnyReg(), param2 * szWord) + + |IL.opVLOAD8: + r1 := GetAnyReg(); + Emit(opLD, BP * 256 + r1, param2 * szWord); + ldr8(r1, r1) + + |IL.opLOAD8: + UnOp(r1); + ldr8(r1, r1) + + |IL.opLOAD16: + UnOp(r1); + ldr16(r1, r1) + + |IL.opLOAD32: + UnOp(r1); + ldr32(r1, r1) + + |IL.opLOAD64: + UnOp(r1); + ldr64(r1, r1) + + |IL.opLOADF: + UnOp(r1); + ldr(r1, r1) + + |IL.opUMINUS: + UnOp(r1); + Emit(opNEG, r1, 0) + + |IL.opADD: + BinOp(r1, r2); + add(r1, r2); + drop + + |IL.opSUB: + BinOp(r1, r2); + sub(r1, r2); + drop + + |IL.opADDC: + UnOp(r1); + next := cmd.next(IL.COMMAND); + CASE next.opcode OF + |IL.opLOADF: + Emit(opLD, r1 * 256 + r1, param2); + cmd := next + |IL.opLOAD64: + Emit(opLDD, r1 * 256 + r1, param2); + cmd := next + |IL.opLOAD32: + Emit(opLDW, r1 * 256 + r1, param2); + cmd := next + |IL.opLOAD16: + Emit(opLDH, r1 * 256 + r1, param2); + cmd := next + |IL.opLOAD8: + Emit(opLDB, r1 * 256 + r1, param2); + cmd := next + ELSE + addrc(r1, param2) + END + + |IL.opSUBR: + UnOp(r1); + subrc(r1, param2) + + |IL.opSUBL: + UnOp(r1); + subrc(r1, param2); + Emit(opNEG, r1, 0) + + |IL.opMULC: + UnOp(r1); + Emit(opMULC, r1, param2) + + |IL.opMUL: + BinOp(r1, r2); + Emit(opMUL, r1, r2); + drop + + |IL.opDIV: + BinOp(r1, r2); + Emit(opDIV, r1, r2); + drop + + |IL.opMOD: + BinOp(r1, r2); + Emit(opMOD, r1, r2); + drop + + |IL.opDIVR: + UnOp(r1); + Emit(opDIVC, r1, param2) + + |IL.opMODR: + UnOp(r1); + Emit(opMODC, r1, param2) + + |IL.opDIVL: + UnOp(r1); + r2 := GetAnyReg(); + movrc(r2, param2); + Emit(opDIV, r2, r1); + mov(r1, r2); + drop + + |IL.opMODL: + UnOp(r1); + r2 := GetAnyReg(); + movrc(r2, param2); + Emit(opMOD, r2, r1); + mov(r1, r2); + drop + + |IL.opEQ .. IL.opGE, IL.opEQC .. IL.opGEC: + IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN + BinOp(r1, r2); + Emit(opCMP, r1, r2); + drop + ELSE + UnOp(r1); + Emit(opCMPC, r1, param2) + END; + next := cmd.next(IL.COMMAND); + IF next.opcode = IL.opJZ THEN + Emit(ORD(BITS(jcc(opcode)) / {0}), next.param1, 0); + cmd := next; + drop + ELSIF next.opcode = IL.opJNZ THEN + Emit(jcc(opcode), next.param1, 0); + cmd := next; + drop + ELSE + Emit(jcc(opcode) + 6, r1, 0) + END + + |IL.opJNZ1: + UnOp(r1); + jnz(r1, param1) + + |IL.opJG: + UnOp(r1); + Emit(opCMPC, r1, 0); + Emit(opJGT, param1, 0) + + |IL.opJNZ: + UnOp(r1); + jnz(r1, param1); + drop + + |IL.opJZ: + UnOp(r1); + Emit(opCMPC, r1, 0); + Emit(opJEQ, param1, 0); + drop + + |IL.opMULS: + BinOp(r1, r2); + Emit(opAND, r1, r2); + drop + + |IL.opMULSC: + UnOp(r1); + Emit(opANDC, r1, param2) + + |IL.opDIVS: + BinOp(r1, r2); + Emit(opXOR, r1, r2); + drop + + |IL.opDIVSC: + UnOp(r1); + Emit(opXORC, r1, param2) + + |IL.opADDS: + BinOp(r1, r2); + Emit(opOR, r1, r2); + drop + + |IL.opSUBS: + BinOp(r1, r2); + Emit(opNOT, r2, 0); + Emit(opAND, r1, r2); + drop + + |IL.opADDSC: + UnOp(r1); + Emit(opORC, r1, param2) + + |IL.opSUBSL: + UnOp(r1); + Emit(opNOT, r1, 0); + Emit(opANDC, r1, param2) + + |IL.opSUBSR: + UnOp(r1); + Emit(opANDC, r1, ORD(-BITS(param2))) + + |IL.opUMINS: + UnOp(r1); + Emit(opNOT, r1, 0) + + |IL.opASR: + shift(opASR) + + |IL.opLSL: + shift(opLSL) + + |IL.opROR: + shift(opROR) + + |IL.opLSR: + shift(opLSR) + + |IL.opASR1: + shift1(opASR, param2) + + |IL.opLSL1: + shift1(opLSL, param2) + + |IL.opROR1: + shift1(opROR, param2) + + |IL.opLSR1: + shift1(opLSR, param2) + + |IL.opASR2: + UnOp(r1); + Emit(opASRC, r1, param2 MOD (szWord * 8)) + + |IL.opLSL2: + UnOp(r1); + Emit(opLSLC, r1, param2 MOD (szWord * 8)) + + |IL.opROR2: + UnOp(r1); + Emit(opRORC, r1, param2 MOD (szWord * 8)) + + |IL.opLSR2: + UnOp(r1); + Emit(opLSRC, r1, param2 MOD (szWord * 8)) + + |IL.opCHR: + UnOp(r1); + Emit(opANDC, r1, 255) + + |IL.opWCHR: + UnOp(r1); + Emit(opANDC, r1, 65535) + + |IL.opABS: + UnOp(r1); + Emit(opCMPC, r1, 0); + label := IL.NewLabel(); + Emit(opJGE, label, 0); + Emit(opNEG, r1, 0); + Emit(opLABEL, label, 0) + + |IL.opLEN: + UnOp(r1); + drop; + EXCL(R.regs, r1); + + WHILE param2 > 0 DO + UnOp(r2); + drop; + DEC(param2) + END; + + INCL(R.regs, r1); + ASSERT(REG.GetReg(R, r1)) + + |IL.opSWITCH: + UnOp(r1); + IF param2 = 0 THEN + r2 := ACC + ELSE + r2 := R1 + END; + IF r1 # r2 THEN + ASSERT(REG.GetReg(R, r2)); + ASSERT(REG.Exchange(R, r1, r2)); + drop + END; + drop + + |IL.opENDSW: + + |IL.opCASEL: + Emit(opCMPC, ACC, param1); + Emit(opJLT, param2, 0) + + |IL.opCASER: + Emit(opCMPC, ACC, param1); + Emit(opJGT, param2, 0) + + |IL.opCASELR: + Emit(opCMPC, ACC, param1); + IF param2 = cmd.param3 THEN + Emit(opJNE, param2, 0) + ELSE + Emit(opJLT, param2, 0); + Emit(opJGT, cmd.param3, 0) + END + + |IL.opSBOOL: + BinOp(r2, r1); + Emit(opCMPC, r2, 0); + Emit(opSNE, r2, 0); + str8(r1, r2); + drop; + drop + + |IL.opSBOOLC: + UnOp(r1); + Emit(opSTBC, r1, ORD(param2 # 0)); + drop + + |IL.opINCC: + UnOp(r1); + r2 := GetAnyReg(); + ldr(r2, r1); + addrc(r2, param2); + str(r1, r2); + drop; + drop + + |IL.opINCCB, IL.opDECCB: + IF opcode = IL.opDECCB THEN + param2 := -param2 + END; + UnOp(r1); + r2 := GetAnyReg(); + ldr8(r2, r1); + addrc(r2, param2); + str8(r1, r2); + drop; + drop + + |IL.opINCB, IL.opDECB: + BinOp(r2, r1); + r3 := GetAnyReg(); + ldr8(r3, r1); + IF opcode = IL.opINCB THEN + add(r3, r2) + ELSE + sub(r3, r2) + END; + str8(r1, r3); + drop; + drop; + drop + + |IL.opINC, IL.opDEC: + BinOp(r2, r1); + r3 := GetAnyReg(); + ldr(r3, r1); + IF opcode = IL.opINC THEN + add(r3, r2) + ELSE + sub(r3, r2) + END; + str(r1, r3); + drop; + drop; + drop + + |IL.opINCL, IL.opEXCL: + BinOp(r2, r1); + Emit(opBIT, r2, r2); + r3 := GetAnyReg(); + ldr(r3, r1); + IF opcode = IL.opINCL THEN + Emit(opOR, r3, r2) + ELSE + Emit(opNOT, r2, 0); + Emit(opAND, r3, r2) + END; + str(r1, r3); + drop; + drop; + drop + + |IL.opINCLC, IL.opEXCLC: + UnOp(r1); + r2 := GetAnyReg(); + ldr(r2, r1); + IF opcode = IL.opINCLC THEN + Emit(opORC, r2, ORD({param2})) + ELSE + Emit(opANDC, r2, ORD(-{param2})) + END; + str(r1, r2); + drop; + drop + + |IL.opEQB, IL.opNEB: + BinOp(r1, r2); + Emit(opCMPC, r1, 0); + Emit(opSNE, r1, 0); + Emit(opCMPC, r2, 0); + Emit(opSNE, r2, 0); + Emit(opCMP, r1, r2); + IF opcode = IL.opEQB THEN + Emit(opSEQ, r1, 0) + ELSE + Emit(opSNE, r1, 0) + END; + drop + + |IL.opCHKBYTE: + BinOp(r1, r2); + Emit(opCMPC, r1, 256); + Emit(opJBT, param1, 0) + + |IL.opCHKIDX: + UnOp(r1); + Emit(opCMPC, r1, param2); + Emit(opJBT, param1, 0) + + |IL.opCHKIDX2: + BinOp(r1, r2); + IF param2 # -1 THEN + Emit(opCMP, r2, r1); + Emit(opJBT, param1, 0) + END; + INCL(R.regs, r1); + DEC(R.top); + R.stk[R.top] := r2 + + |IL.opEQP, IL.opNEP: + ProcAdr(GetAnyReg(), param1); + BinOp(r1, r2); + Emit(opCMP, r1, r2); + IF opcode = IL.opEQP THEN + Emit(opSEQ, r1, 0) + ELSE + Emit(opSNE, r1, 0) + END; + drop + + |IL.opSAVEP: + UnOp(r1); + r2 := GetAnyReg(); + ProcAdr(r2, param2); + str(r1, r2); + drop; + drop + + |IL.opPUSHP: + ProcAdr(GetAnyReg(), param2) + + |IL.opPUSHT: + UnOp(r1); + Emit(opLD, r1 * 256 + GetAnyReg(), -szWord) + + |IL.opGET, IL.opGETC: + IF opcode = IL.opGET THEN + BinOp(r1, r2) + ELSIF opcode = IL.opGETC THEN + UnOp(r2); + r1 := GetAnyReg(); + movrc(r1, param1) + END; + drop; + drop; + + CASE param2 OF + |1: ldr8(r1, r1); str8(r2, r1) + |2: ldr16(r1, r1); str16(r2, r1) + |4: ldr32(r1, r1); str32(r2, r1) + |8: ldr64(r1, r1); str64(r2, r1) + END + + |IL.opNOT: + UnOp(r1); + Emit(opCMPC, r1, 0); + Emit(opSEQ, r1, 0) + + |IL.opORD: + UnOp(r1); + Emit(opCMPC, r1, 0); + Emit(opSNE, r1, 0) + + |IL.opMIN, IL.opMAX: + BinOp(r1, r2); + Emit(opCMP, r1, r2); + label := IL.NewLabel(); + IF opcode = IL.opMIN THEN + Emit(opJLE, label, 0) + ELSE + Emit(opJGE, label, 0) + END; + Emit(opMOV, r1, r2); + Emit(opLABEL, label, 0); + drop + + |IL.opMINC, IL.opMAXC: + UnOp(r1); + Emit(opCMPC, r1, param2); + label := IL.NewLabel(); + IF opcode = IL.opMINC THEN + Emit(opJLE, label, 0) + ELSE + Emit(opJGE, label, 0) + END; + Emit(opMOVC, r1, param2); + Emit(opLABEL, label, 0) + + |IL.opIN: + BinOp(r1, r2); + Emit(opBIT, r1, r1); + Emit(opAND, r1, r2); + Emit(opCMPC, r1, 0); + Emit(opSNE, r1, 0); + drop + + |IL.opINL: + UnOp(r1); + Emit(opANDC, r1, ORD({param2})); + Emit(opCMPC, r1, 0); + Emit(opSNE, r1, 0) + + |IL.opINR: + UnOp(r1); + Emit(opBIT, r1, r1); + Emit(opANDC, r1, param2); + Emit(opCMPC, r1, 0); + Emit(opSNE, r1, 0) + + |IL.opERR: + CallRTL(IL._error, 4) + + |IL.opEQS .. IL.opGES: + PushAll(4); + pushc(opcode - IL.opEQS); + CallRTL(IL._strcmp, 5); + GetAcc + + |IL.opEQSW .. IL.opGESW: + PushAll(4); + pushc(opcode - IL.opEQSW); + CallRTL(IL._strcmpw, 5); + GetAcc + + |IL.opCOPY: + PushAll(2); + pushc(param2); + CallRTL(IL._move, 3) + + |IL.opMOVE: + PushAll(3); + CallRTL(IL._move, 3) + + |IL.opCOPYA: + PushAll(4); + pushc(param2); + CallRTL(IL._arrcpy, 5); + GetAcc + + |IL.opCOPYS: + PushAll(4); + pushc(param2); + CallRTL(IL._strcpy, 5) + + |IL.opROT: + PushAll(0); + mov(ACC, SP); + push(ACC); + pushc(param2); + CallRTL(IL._rot, 2) + + |IL.opLENGTH: + PushAll(2); + CallRTL(IL._length, 2); + GetAcc + + |IL.opLENGTHW: + PushAll(2); + CallRTL(IL._lengthw, 2); + GetAcc + + |IL.opSAVES: + UnOp(r2); + REG.PushAll_1(R); + r1 := GetAnyReg(); + StrAdr(r1, param2); + push(r1); + drop; + push(r2); + drop; + pushc(param1); + CallRTL(IL._move, 3) + + |IL.opRSET: + PushAll(2); + CallRTL(IL._set, 2); + GetAcc + + |IL.opRSETR: + PushAll(1); + pushc(param2); + CallRTL(IL._set, 2); + GetAcc + + |IL.opRSETL: + UnOp(r1); + REG.PushAll_1(R); + pushc(param2); + push(r1); + drop; + CallRTL(IL._set, 2); + GetAcc + + |IL.opRSET1: + PushAll(1); + CallRTL(IL._set1, 1); + GetAcc + + |IL.opNEW: + PushAll(1); + INC(param2, szWord); + ASSERT(UTILS.Align(param2, szWord)); + pushc(param2); + pushc(param1); + CallRTL(IL._new, 3) + + |IL.opTYPEGP: + UnOp(r1); + PushAll(0); + push(r1); + pushc(param2); + CallRTL(IL._guard, 2); + GetAcc + + |IL.opIS: + PushAll(1); + pushc(param2); + CallRTL(IL._is, 2); + GetAcc + + |IL.opISREC: + PushAll(2); + pushc(param2); + CallRTL(IL._guardrec, 3); + GetAcc + + |IL.opTYPEGR: + PushAll(1); + pushc(param2); + CallRTL(IL._guardrec, 2); + GetAcc + + |IL.opTYPEGD: + UnOp(r1); + PushAll(0); + subrc(r1, szWord); + ldr(r1, r1); + push(r1); + pushc(param2); + CallRTL(IL._guardrec, 2); + GetAcc + + |IL.opCASET: + push(R1); + push(R1); + pushc(param2); + CallRTL(IL._guardrec, 2); + pop(R1); + jnz(ACC, param1) + + |IL.opCONSTF: + IF szWord = 8 THEN + movrc(GetAnyReg(), UTILS.splitf(cmd.float, a, b)) + ELSE (* szWord = 4 *) + movrc(GetAnyReg(), UTILS.d2s(cmd.float)) + END + + |IL.opMULF: + PushAll(2); + CallRTL(IL._fmul, 2); + GetAcc + + |IL.opDIVF: + PushAll(2); + CallRTL(IL._fdiv, 2); + GetAcc + + |IL.opDIVFI: + PushAll(2); + CallRTL(IL._fdivi, 2); + GetAcc + + |IL.opADDF: + PushAll(2); + CallRTL(IL._fadd, 2); + GetAcc + + |IL.opSUBFI: + PushAll(2); + CallRTL(IL._fsubi, 2); + GetAcc + + |IL.opSUBF: + PushAll(2); + CallRTL(IL._fsub, 2); + GetAcc + + |IL.opEQF..IL.opGEF: + PushAll(2); + pushc(opcode - IL.opEQF); + CallRTL(IL._fcmp, 3); + GetAcc + + |IL.opFLOOR: + PushAll(1); + CallRTL(IL._floor, 1); + GetAcc + + |IL.opFLT: + PushAll(1); + CallRTL(IL._flt, 1); + GetAcc + + |IL.opUMINF: + UnOp(r1); + Emit(opRORC, r1, -1); + Emit(opXORC, r1, 1); + Emit(opRORC, r1, 1) + + |IL.opFABS: + UnOp(r1); + Emit(opLSLC, r1, 1); + Emit(opLSRC, r1, 1) + + |IL.opINF: + r1 := GetAnyReg(); + Emit(opMOVC, r1, 1); + Emit(opRORC, r1, 1); + Emit(opASRC, r1, 7 + 3 * ORD(szWord = 8)); + Emit(opLSRC, r1, 1) + + |IL.opPUSHF: + UnOp(r1); + push(r1); + drop + + |IL.opPACK: + PushAll(2); + CallRTL(IL._pack, 2) + + |IL.opPACKC: + PushAll(1); + pushc(param2); + CallRTL(IL._pack, 2) + + |IL.opUNPK: + PushAll(2); + CallRTL(IL._unpk, 2) + + |IL.opCODE: + OutInt(param2) + + |IL.opLADR_SAVE: + UnOp(r1); + Emit(opST, BP * 256 + r1, param2 * szWord); + drop + + |IL.opLADR_INCC: + r1 := GetAnyReg(); + Emit(opLD, BP * 256 + r1, param1 * szWord); + Emit(opADDC, r1, param2); + Emit(opST, BP * 256 + r1, param1 * szWord); + drop + + END; + + cmd := cmd.next(IL.COMMAND) + END; + + ASSERT(R.pushed = 0); + ASSERT(R.top = -1) +END translate; + + +PROCEDURE prolog; +BEGIN + Emit(opLEA, SP + LStack * 256, 0); + Emit(opLEA, ACC + LTypes * 256, 0); + push(ACC); + Emit(opLEA, ACC + LHeap * 256, 0); + push(ACC); + pushc(CHL.Length(IL.codes.types)); + CallRTL(IL._init, 3) +END prolog; + + +PROCEDURE epilog (ram, szWord: INTEGER); +VAR + tcount, dcount, i, offTypes, offStrings, + szData, szGlobal, szHeapStack: INTEGER; + +BEGIN + Emit(opSTOP, 0, 0); + + offTypes := count; + + tcount := CHL.Length(IL.codes.types); + FOR i := 0 TO tcount - 1 DO + OutInt(CHL.GetInt(IL.codes.types, i)) + END; + + offStrings := count; + dcount := CHL.Length(IL.codes.data); + FOR i := 0 TO dcount - 1 DO + OutByte(CHL.GetByte(IL.codes.data, i)) + END; + + IF dcount MOD szWord # 0 THEN + i := szWord - dcount MOD szWord; + WHILE i > 0 DO + OutByte(0); + DEC(i) + END + END; + + szData := count - offTypes; + szGlobal := (IL.codes.bss DIV szWord + 1) * szWord; + szHeapStack := ram - szData - szGlobal; + + OutInt(offTypes); + OutInt(offStrings); + OutInt(szGlobal DIV szWord); + OutInt(szHeapStack DIV szWord); + FOR i := 1 TO 8 DO + OutInt(0) + END +END epilog; + + +PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); +CONST + minRAM = 32*1024; + maxRAM = 256*1024; + +VAR + szData, szRAM: INTEGER; + +BEGIN + szWord := TARGETS.WordSize; + IF szWord = 8 THEN + ldr := ldr64; + str := str64 + ELSE + ldr := ldr32; + str := str32 + END; + szData := (CHL.Length(IL.codes.types) + CHL.Length(IL.codes.data) DIV szWord + IL.codes.bss DIV szWord + 2) * szWord; + szRAM := MIN(MAX(options.ram, minRAM), maxRAM) * 1024; + + IF szRAM - szData < 1024*1024 THEN + ERRORS.Error(208) + END; + + count := 0; + WR.Create(outname); + + REG.Init(R, push, pop, mov, xchg, GPRs); + + prolog; + translate(szWord); + epilog(szRAM, szWord); + + WR.Close +END CodeGen; + + END RVMxI. \ No newline at end of file diff --git a/programs/develop/oberon07/source/TARGETS.ob07 b/programs/develop/oberon07/source/TARGETS.ob07 index 0b87e5838d..a9006e944d 100644 --- a/programs/develop/oberon07/source/TARGETS.ob07 +++ b/programs/develop/oberon07/source/TARGETS.ob07 @@ -1,153 +1,153 @@ -(* - BSD 2-Clause License - - Copyright (c) 2019-2021, Anton Krotov - All rights reserved. -*) - -MODULE TARGETS; - -IMPORT UTILS; - - -CONST - - MSP430* = 0; - Win32C* = 1; - Win32GUI* = 2; - Win32DLL* = 3; - KolibriOS* = 4; - KolibriOSDLL* = 5; - Win64C* = 6; - Win64GUI* = 7; - Win64DLL* = 8; - Linux32* = 9; - Linux32SO* = 10; - Linux64* = 11; - Linux64SO* = 12; - STM32CM3* = 13; - RVM32I* = 14; - RVM64I* = 15; - - cpuX86* = 0; cpuAMD64* = 1; cpuMSP430* = 2; cpuTHUMB* = 3; - cpuRVM32I* = 4; cpuRVM64I* = 5; - - osNONE* = 0; osWIN32* = 1; osWIN64* = 2; - osLINUX32* = 3; osLINUX64* = 4; osKOS* = 5; - - noDISPOSE = {MSP430, STM32CM3, RVM32I, RVM64I}; - - noRTL = {MSP430}; - - libRVM32I = "RVMxI" + UTILS.slash + "32"; - libRVM64I = "RVMxI" + UTILS.slash + "64"; - - -TYPE - - STRING = ARRAY 32 OF CHAR; - - TARGET = RECORD - - target, CPU, OS, RealSize: INTEGER; - ComLinePar*, LibDir, FileExt: STRING - - END; - - -VAR - - Targets*: ARRAY 16 OF TARGET; - - CPUs: ARRAY 6 OF - RECORD - BitDepth, InstrSize: INTEGER; - LittleEndian: BOOLEAN - END; - - target*, CPU*, BitDepth*, OS*, RealSize*, WordSize*, AdrSize*, InstrSize*: INTEGER; - ComLinePar*, LibDir*, FileExt*: STRING; - Import*, Dispose*, RTL*, Dll*, LittleEndian*: BOOLEAN; - - -PROCEDURE Enter (idx, CPU, RealSize, OS: INTEGER; ComLinePar, LibDir, FileExt: STRING); -BEGIN - Targets[idx].target := idx; - Targets[idx].CPU := CPU; - Targets[idx].RealSize := RealSize; - Targets[idx].OS := OS; - Targets[idx].ComLinePar := ComLinePar; - Targets[idx].LibDir := LibDir; - Targets[idx].FileExt := FileExt; -END Enter; - - -PROCEDURE Select* (ComLineParam: ARRAY OF CHAR): BOOLEAN; -VAR - i: INTEGER; - res: BOOLEAN; - -BEGIN - i := 0; - WHILE (i < LEN(Targets)) & (Targets[i].ComLinePar # ComLineParam) DO - INC(i) - END; - - res := i < LEN(Targets); - IF res THEN - target := Targets[i].target; - CPU := Targets[i].CPU; - BitDepth := CPUs[CPU].BitDepth; - InstrSize := CPUs[CPU].InstrSize; - LittleEndian := CPUs[CPU].LittleEndian; - RealSize := Targets[i].RealSize; - OS := Targets[i].OS; - ComLinePar := Targets[i].ComLinePar; - LibDir := Targets[i].LibDir; - FileExt := Targets[i].FileExt; - - Import := OS IN {osWIN32, osWIN64, osKOS}; - Dispose := ~(target IN noDISPOSE); - RTL := ~(target IN noRTL); - Dll := target IN {Linux32SO, Linux64SO, Win32DLL, Win64DLL, KolibriOSDLL}; - WordSize := BitDepth DIV 8; - AdrSize := WordSize - END - - RETURN res -END Select; - - -PROCEDURE EnterCPU (cpu, BitDepth, InstrSize: INTEGER; LittleEndian: BOOLEAN); -BEGIN - CPUs[cpu].BitDepth := BitDepth; - CPUs[cpu].InstrSize := InstrSize; - CPUs[cpu].LittleEndian := LittleEndian -END EnterCPU; - - -BEGIN - EnterCPU(cpuX86, 32, 1, TRUE); - EnterCPU(cpuAMD64, 64, 1, TRUE); - EnterCPU(cpuMSP430, 16, 2, TRUE); - EnterCPU(cpuTHUMB, 32, 2, TRUE); - EnterCPU(cpuRVM32I, 32, 4, TRUE); - EnterCPU(cpuRVM64I, 64, 8, TRUE); - - Enter( MSP430, cpuMSP430, 0, osNONE, "msp430", "MSP430", ".hex"); - Enter( Win32C, cpuX86, 8, osWIN32, "win32con", "Windows", ".exe"); - Enter( Win32GUI, cpuX86, 8, osWIN32, "win32gui", "Windows", ".exe"); - Enter( Win32DLL, cpuX86, 8, osWIN32, "win32dll", "Windows", ".dll"); - Enter( KolibriOS, cpuX86, 8, osKOS, "kosexe", "KolibriOS", ""); - Enter( KolibriOSDLL, cpuX86, 8, osKOS, "kosdll", "KolibriOS", ".obj"); - Enter( Win64C, cpuAMD64, 8, osWIN64, "win64con", "Windows", ".exe"); - Enter( Win64GUI, cpuAMD64, 8, osWIN64, "win64gui", "Windows", ".exe"); - Enter( Win64DLL, cpuAMD64, 8, osWIN64, "win64dll", "Windows", ".dll"); - Enter( Linux32, cpuX86, 8, osLINUX32, "linux32exe", "Linux", ""); - Enter( Linux32SO, cpuX86, 8, osLINUX32, "linux32so", "Linux", ".so"); - Enter( Linux64, cpuAMD64, 8, osLINUX64, "linux64exe", "Linux", ""); - Enter( Linux64SO, cpuAMD64, 8, osLINUX64, "linux64so", "Linux", ".so"); - Enter( STM32CM3, cpuTHUMB, 4, osNONE, "stm32cm3", "STM32CM3", ".hex"); - Enter( RVM32I, cpuRVM32I, 4, osNONE, "rvm32i", libRVM32I, ".bin"); - Enter( RVM64I, cpuRVM64I, 8, osNONE, "rvm64i", libRVM64I, ".bin"); +(* + BSD 2-Clause License + + Copyright (c) 2019-2021, Anton Krotov + All rights reserved. +*) + +MODULE TARGETS; + +IMPORT UTILS; + + +CONST + + MSP430* = 0; + Win32C* = 1; + Win32GUI* = 2; + Win32DLL* = 3; + KolibriOS* = 4; + KolibriOSDLL* = 5; + Win64C* = 6; + Win64GUI* = 7; + Win64DLL* = 8; + Linux32* = 9; + Linux32SO* = 10; + Linux64* = 11; + Linux64SO* = 12; + STM32CM3* = 13; + RVM32I* = 14; + RVM64I* = 15; + + cpuX86* = 0; cpuAMD64* = 1; cpuMSP430* = 2; cpuTHUMB* = 3; + cpuRVM32I* = 4; cpuRVM64I* = 5; + + osNONE* = 0; osWIN32* = 1; osWIN64* = 2; + osLINUX32* = 3; osLINUX64* = 4; osKOS* = 5; + + noDISPOSE = {MSP430, STM32CM3, RVM32I, RVM64I}; + + noRTL = {MSP430}; + + libRVM32I = "RVMxI" + UTILS.slash + "32"; + libRVM64I = "RVMxI" + UTILS.slash + "64"; + + +TYPE + + STRING = ARRAY 32 OF CHAR; + + TARGET = RECORD + + target, CPU, OS, RealSize: INTEGER; + ComLinePar*, LibDir, FileExt: STRING + + END; + + +VAR + + Targets*: ARRAY 16 OF TARGET; + + CPUs: ARRAY 6 OF + RECORD + BitDepth, InstrSize: INTEGER; + LittleEndian: BOOLEAN + END; + + target*, CPU*, BitDepth*, OS*, RealSize*, WordSize*, AdrSize*, InstrSize*: INTEGER; + ComLinePar*, LibDir*, FileExt*: STRING; + Import*, Dispose*, RTL*, Dll*, LittleEndian*: BOOLEAN; + + +PROCEDURE Enter (idx, CPU, RealSize, OS: INTEGER; ComLinePar, LibDir, FileExt: STRING); +BEGIN + Targets[idx].target := idx; + Targets[idx].CPU := CPU; + Targets[idx].RealSize := RealSize; + Targets[idx].OS := OS; + Targets[idx].ComLinePar := ComLinePar; + Targets[idx].LibDir := LibDir; + Targets[idx].FileExt := FileExt; +END Enter; + + +PROCEDURE Select* (ComLineParam: ARRAY OF CHAR): BOOLEAN; +VAR + i: INTEGER; + res: BOOLEAN; + +BEGIN + i := 0; + WHILE (i < LEN(Targets)) & (Targets[i].ComLinePar # ComLineParam) DO + INC(i) + END; + + res := i < LEN(Targets); + IF res THEN + target := Targets[i].target; + CPU := Targets[i].CPU; + BitDepth := CPUs[CPU].BitDepth; + InstrSize := CPUs[CPU].InstrSize; + LittleEndian := CPUs[CPU].LittleEndian; + RealSize := Targets[i].RealSize; + OS := Targets[i].OS; + ComLinePar := Targets[i].ComLinePar; + LibDir := Targets[i].LibDir; + FileExt := Targets[i].FileExt; + + Import := OS IN {osWIN32, osWIN64, osKOS}; + Dispose := ~(target IN noDISPOSE); + RTL := ~(target IN noRTL); + Dll := target IN {Linux32SO, Linux64SO, Win32DLL, Win64DLL, KolibriOSDLL}; + WordSize := BitDepth DIV 8; + AdrSize := WordSize + END + + RETURN res +END Select; + + +PROCEDURE EnterCPU (cpu, BitDepth, InstrSize: INTEGER; LittleEndian: BOOLEAN); +BEGIN + CPUs[cpu].BitDepth := BitDepth; + CPUs[cpu].InstrSize := InstrSize; + CPUs[cpu].LittleEndian := LittleEndian +END EnterCPU; + + +BEGIN + EnterCPU(cpuX86, 32, 1, TRUE); + EnterCPU(cpuAMD64, 64, 1, TRUE); + EnterCPU(cpuMSP430, 16, 2, TRUE); + EnterCPU(cpuTHUMB, 32, 2, TRUE); + EnterCPU(cpuRVM32I, 32, 4, TRUE); + EnterCPU(cpuRVM64I, 64, 8, TRUE); + + Enter( MSP430, cpuMSP430, 0, osNONE, "msp430", "MSP430", ".hex"); + Enter( Win32C, cpuX86, 8, osWIN32, "win32con", "Windows", ".exe"); + Enter( Win32GUI, cpuX86, 8, osWIN32, "win32gui", "Windows", ".exe"); + Enter( Win32DLL, cpuX86, 8, osWIN32, "win32dll", "Windows", ".dll"); + Enter( KolibriOS, cpuX86, 8, osKOS, "kosexe", "KolibriOS", ""); + Enter( KolibriOSDLL, cpuX86, 8, osKOS, "kosdll", "KolibriOS", ".obj"); + Enter( Win64C, cpuAMD64, 8, osWIN64, "win64con", "Windows", ".exe"); + Enter( Win64GUI, cpuAMD64, 8, osWIN64, "win64gui", "Windows", ".exe"); + Enter( Win64DLL, cpuAMD64, 8, osWIN64, "win64dll", "Windows", ".dll"); + Enter( Linux32, cpuX86, 8, osLINUX32, "linux32exe", "Linux", ""); + Enter( Linux32SO, cpuX86, 8, osLINUX32, "linux32so", "Linux", ".so"); + Enter( Linux64, cpuAMD64, 8, osLINUX64, "linux64exe", "Linux", ""); + Enter( Linux64SO, cpuAMD64, 8, osLINUX64, "linux64so", "Linux", ".so"); + Enter( STM32CM3, cpuTHUMB, 4, osNONE, "stm32cm3", "STM32CM3", ".hex"); + Enter( RVM32I, cpuRVM32I, 4, osNONE, "rvm32i", libRVM32I, ".bin"); + Enter( RVM64I, cpuRVM64I, 8, osNONE, "rvm64i", libRVM64I, ".bin"); END TARGETS. \ No newline at end of file diff --git a/programs/develop/oberon07/source/TEXTDRV.ob07 b/programs/develop/oberon07/source/TEXTDRV.ob07 index 7f2c416dd2..b7c2f6d7c3 100644 --- a/programs/develop/oberon07/source/TEXTDRV.ob07 +++ b/programs/develop/oberon07/source/TEXTDRV.ob07 @@ -1,7 +1,7 @@ (* BSD 2-Clause License - Copyright (c) 2018-2020, Anton Krotov + Copyright (c) 2018-2021, Anton Krotov All rights reserved. *) @@ -12,10 +12,12 @@ IMPORT FILES, C := COLLECTIONS; CONST - CR = 0DX; LF = 0AX; + CR = 0DX; LF = 0AX; HT = 9X; CHUNK = 1024 * 256; + defTabSize* = 4; + TYPE @@ -45,6 +47,7 @@ TYPE VAR texts: C.COLLECTION; + TabSize: INTEGER; PROCEDURE load (text: TEXT); @@ -91,8 +94,11 @@ BEGIN text.eol := FALSE END; text.CR := FALSE + ELSIF c = HT THEN + text.col := text.col + TabSize - text.col MOD TabSize; + text.eol := FALSE; + text.CR := FALSE ELSE - text.eol := FALSE; IF text.utf8 THEN IF ORD(c) DIV 64 # 2 THEN INC(text.col) @@ -100,7 +106,8 @@ BEGIN ELSE INC(text.col) END; - text.CR := FALSE + text.eol := FALSE; + text.CR := FALSE END END @@ -187,6 +194,17 @@ BEGIN END open; +PROCEDURE setTabSize* (n: INTEGER); BEGIN + IF (0 < n) & (n <= 64) THEN + TabSize := n + ELSE + TabSize := defTabSize + END +END setTabSize; + + +BEGIN + TabSize := defTabSize; texts := C.create() END TEXTDRV. \ No newline at end of file diff --git a/programs/develop/oberon07/source/THUMB.ob07 b/programs/develop/oberon07/source/THUMB.ob07 index f53cd57c84..90bbf086de 100644 --- a/programs/develop/oberon07/source/THUMB.ob07 +++ b/programs/develop/oberon07/source/THUMB.ob07 @@ -1,2466 +1,2466 @@ -(* - BSD 2-Clause License - - Copyright (c) 2019-2021, Anton Krotov - All rights reserved. -*) - -MODULE THUMB; - -IMPORT PROG, LISTS, CHL := CHUNKLISTS, BIN, REG, IL, C := CONSOLE, - UTILS, WR := WRITER, HEX, ERRORS, TARGETS; - - -CONST - - R0 = 0; R1 = 1; R2 = 2; R3 = 3; R4 = 4; - - SP = 13; LR = 14; PC = 15; - - ACC = R0; - - je = 0; jne = 1; jnb = 2; jb = 3; jge = 10; jl = 11; jg = 12; jle = 13; - - inf = 7F800000H; - - minROM* = 16; maxROM* = 65536; - minRAM* = 4; maxRAM* = 65536; - - maxIVT* = 1023; - - _THUMB2 = 0; _IT = 1; _SDIV = 2; _CBXZ = 3; - - CortexM0 = {}; - CortexM1 = {}; - CortexM3 = {_THUMB2, _IT, _SDIV, _CBXZ}; - CortexM23 = {_SDIV, _CBXZ}; - - -TYPE - - COMMAND = IL.COMMAND; - - ANYCODE = POINTER TO RECORD (LISTS.ITEM) - - offset: INTEGER - - END; - - CODE = POINTER TO RECORD (ANYCODE) - - code: INTEGER - - END; - - LABEL = POINTER TO RECORD (ANYCODE) - - label: INTEGER - - END; - - JUMP = POINTER TO RECORD (ANYCODE) - - label, diff, len, cond: INTEGER; - short: BOOLEAN - - END; - - JMP = POINTER TO RECORD (JUMP) - - END; - - JCC = POINTER TO RECORD (JUMP) - - END; - - CBXZ = POINTER TO RECORD (JUMP) - - reg: INTEGER - - END; - - CALL = POINTER TO RECORD (JUMP) - - END; - - RELOC = POINTER TO RECORD (ANYCODE) - - reg, rel, value: INTEGER - - END; - - RELOCCODE = ARRAY 7 OF INTEGER; - - -VAR - - R: REG.REGS; - - tcount: INTEGER; - - CodeList: LISTS.LIST; - - program: BIN.PROGRAM; - - StkCount: INTEGER; - - Target: RECORD - FlashAdr, - SRAMAdr, - IVTLen, - MinStack, - Reserved: INTEGER; - InstrSet: SET; - isNXP: BOOLEAN - END; - - IVT: ARRAY maxIVT + 1 OF INTEGER; - - sdivProc, trap, genTrap, entry, emptyProc, int0, genInt: INTEGER; - - -PROCEDURE Code (code: INTEGER); -VAR - c: CODE; - -BEGIN - NEW(c); - c.code := code; - LISTS.push(CodeList, c) -END Code; - - -PROCEDURE Label (label: INTEGER); -VAR - L: LABEL; - -BEGIN - NEW(L); - L.label := label; - LISTS.push(CodeList, L) -END Label; - - -PROCEDURE jcc (cond, label: INTEGER); -VAR - j: JCC; - -BEGIN - NEW(j); - j.label := label; - j.cond := cond; - j.short := FALSE; - j.len := 3; - LISTS.push(CodeList, j) -END jcc; - - -PROCEDURE cbxz (cond, reg, label: INTEGER); -VAR - j: CBXZ; - -BEGIN - NEW(j); - j.label := label; - j.cond := cond; - j.reg := reg; - j.short := FALSE; - j.len := 4; - LISTS.push(CodeList, j) -END cbxz; - - -PROCEDURE jmp (label: INTEGER); -VAR - j: JMP; - -BEGIN - NEW(j); - j.label := label; - j.short := FALSE; - j.len := 2; - LISTS.push(CodeList, j) -END jmp; - - -PROCEDURE call (label: INTEGER); -VAR - c: CALL; - -BEGIN - NEW(c); - c.label := label; - c.short := FALSE; - c.len := 2; - LISTS.push(CodeList, c) -END call; - - -PROCEDURE reloc (reg, rel, value: INTEGER); -VAR - r: RELOC; - -BEGIN - NEW(r); - r.reg := reg; - r.rel := rel; - r.value := value; - LISTS.push(CodeList, r) -END reloc; - - -PROCEDURE NewLabel (): INTEGER; -BEGIN - BIN.NewLabel(program) - RETURN IL.NewLabel() -END NewLabel; - - -PROCEDURE range (x, n: INTEGER): BOOLEAN; - RETURN (0 <= x) & (x < LSL(1, n)) -END range; - - -PROCEDURE srange (x, n: INTEGER): BOOLEAN; - RETURN (-LSL(1, n - 1) <= x) & (x < LSL(1, n - 1)) -END srange; - - -PROCEDURE gen1 (op, imm, rs, rd: INTEGER); -BEGIN - ASSERT(op IN {0..2}); - ASSERT(range(imm, 5)); - ASSERT(range(rs, 3)); - ASSERT(range(rd, 3)); - Code(LSL(op, 11) + LSL(imm, 6) + LSL(rs, 3) + rd) -END gen1; - - -PROCEDURE gen2 (i, op: BOOLEAN; imm, rs, rd: INTEGER); -BEGIN - ASSERT(range(imm, 3)); - ASSERT(range(rs, 3)); - ASSERT(range(rd, 3)); - Code(1800H + LSL(ORD(i), 10) + LSL(ORD(op), 9) + LSL(imm, 6) + LSL(rs, 3) + rd) -END gen2; - - -PROCEDURE gen3 (op, rd, imm: INTEGER); -BEGIN - ASSERT(range(op, 2)); - ASSERT(range(rd, 3)); - ASSERT(range(imm, 8)); - Code(2000H + LSL(op, 11) + LSL(rd, 8) + imm) -END gen3; - - -PROCEDURE gen4 (op, rs, rd: INTEGER); -BEGIN - ASSERT(range(op, 4)); - ASSERT(range(rs, 3)); - ASSERT(range(rd, 3)); - Code(4000H + LSL(op, 6) + LSL(rs, 3) + rd) -END gen4; - - -PROCEDURE gen5 (op: INTEGER; h1, h2: BOOLEAN; rs, rd: INTEGER); -BEGIN - ASSERT(range(op, 2)); - ASSERT(range(rs, 3)); - ASSERT(range(rd, 3)); - Code(4400H + LSL(op, 8) + LSL(ORD(h1), 7) + LSL(ORD(h2), 6) + LSL(rs, 3) + rd) -END gen5; - - -PROCEDURE gen7 (l, b: BOOLEAN; ro, rb, rd: INTEGER); -BEGIN - ASSERT(range(ro, 3)); - ASSERT(range(rb, 3)); - ASSERT(range(rd, 3)); - Code(5000H + LSL(ORD(l), 11) + LSL(ORD(b), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) -END gen7; - - -PROCEDURE gen8 (h, s: BOOLEAN; ro, rb, rd: INTEGER); -BEGIN - ASSERT(range(ro, 3)); - ASSERT(range(rb, 3)); - ASSERT(range(rd, 3)); - Code(5200H + LSL(ORD(h), 11) + LSL(ORD(s), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) -END gen8; - - -PROCEDURE gen9 (b, l: BOOLEAN; imm, rb, rd: INTEGER); -BEGIN - ASSERT(range(imm, 5)); - ASSERT(range(rb, 3)); - ASSERT(range(rd, 3)); - Code(6000H + LSL(ORD(b), 12) + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) -END gen9; - - -PROCEDURE gen10 (l: BOOLEAN; imm, rb, rd: INTEGER); -BEGIN - ASSERT(range(imm, 5)); - ASSERT(range(rb, 3)); - ASSERT(range(rd, 3)); - Code(8000H + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) -END gen10; - - -PROCEDURE gen11 (l: BOOLEAN; rd, imm: INTEGER); -BEGIN - ASSERT(range(rd, 3)); - ASSERT(range(imm, 8)); - Code(9000H + LSL(ORD(l), 11) + LSL(rd, 8) + imm) -END gen11; - - -PROCEDURE gen12 (sp: BOOLEAN; rd, imm: INTEGER); -BEGIN - ASSERT(range(rd, 3)); - ASSERT(range(imm, 8)); - Code(0A000H + LSL(ORD(sp), 11) + LSL(rd, 8) + imm) -END gen12; - - -PROCEDURE gen14 (l, r: BOOLEAN; rlist: SET); -VAR - i, n: INTEGER; - -BEGIN - ASSERT(range(ORD(rlist), 8)); - - n := ORD(r); - FOR i := 0 TO 7 DO - IF i IN rlist THEN - INC(n) - END - END; - - IF l THEN - n := -n - END; - - INC(StkCount, n); - - Code(0B400H + LSL(ORD(l), 11) + LSL(ORD(r), 8) + ORD(rlist)) -END gen14; - - -PROCEDURE split16 (imm16: INTEGER; VAR imm4, imm1, imm3, imm8: INTEGER); -BEGIN - ASSERT(range(imm16, 16)); - imm8 := imm16 MOD 256; - imm4 := LSR(imm16, 12); - imm3 := LSR(imm16, 8) MOD 8; - imm1 := LSR(imm16, 11) MOD 2; -END split16; - - -PROCEDURE LslImm (r, imm5: INTEGER); -BEGIN - gen1(0, imm5, r, r) -END LslImm; - - -PROCEDURE LsrImm (r, imm5: INTEGER); -BEGIN - gen1(1, imm5, r, r) -END LsrImm; - - -PROCEDURE AsrImm (r, imm5: INTEGER); -BEGIN - gen1(2, imm5, r, r) -END AsrImm; - - -PROCEDURE AddReg (rd, rs, rn: INTEGER); -BEGIN - gen2(FALSE, FALSE, rn, rs, rd) -END AddReg; - - -PROCEDURE SubReg (rd, rs, rn: INTEGER); -BEGIN - gen2(FALSE, TRUE, rn, rs, rd) -END SubReg; - - -PROCEDURE AddImm8 (rd, imm8: INTEGER); -BEGIN - IF imm8 # 0 THEN - gen3(2, rd, imm8) - END -END AddImm8; - - -PROCEDURE SubImm8 (rd, imm8: INTEGER); -BEGIN - IF imm8 # 0 THEN - gen3(3, rd, imm8) - END -END SubImm8; - - -PROCEDURE AddSubImm12 (r, imm12: INTEGER; sub: BOOLEAN); -VAR - imm4, imm1, imm3, imm8: INTEGER; - -BEGIN - split16(imm12, imm4, imm1, imm3, imm8); - Code(0F200H + LSL(imm1, 10) + r + 0A0H * ORD(sub)); (* addw/subw r, r, imm12 *) - Code(LSL(imm3, 12) + LSL(r, 8) + imm8) -END AddSubImm12; - - -PROCEDURE MovImm8 (rd, imm8: INTEGER); -BEGIN - gen3(0, rd, imm8) -END MovImm8; - - -PROCEDURE CmpImm8 (rd, imm8: INTEGER); -BEGIN - gen3(1, rd, imm8) -END CmpImm8; - - -PROCEDURE Neg (r: INTEGER); -BEGIN - gen4(9, r, r) -END Neg; - - -PROCEDURE Mul (rd, rs: INTEGER); -BEGIN - gen4(13, rs, rd) -END Mul; - - -PROCEDURE Str32 (rs, rb: INTEGER); -BEGIN - gen9(FALSE, FALSE, 0, rb, rs) -END Str32; - - -PROCEDURE Ldr32 (rd, rb: INTEGER); -BEGIN - gen9(FALSE, TRUE, 0, rb, rd) -END Ldr32; - - -PROCEDURE Str16 (rs, rb: INTEGER); -BEGIN - gen10(FALSE, 0, rb, rs) -END Str16; - - -PROCEDURE Ldr16 (rd, rb: INTEGER); -BEGIN - gen10(TRUE, 0, rb, rd) -END Ldr16; - - -PROCEDURE Str8 (rs, rb: INTEGER); -BEGIN - gen9(TRUE, FALSE, 0, rb, rs) -END Str8; - - -PROCEDURE Ldr8 (rd, rb: INTEGER); -BEGIN - gen9(TRUE, TRUE, 0, rb, rd) -END Ldr8; - - -PROCEDURE Cmp (r1, r2: INTEGER); -BEGIN - gen4(10, r2, r1) -END Cmp; - - -PROCEDURE Tst (r: INTEGER); -BEGIN - gen3(1, r, 0) (* cmp r, 0 *) -END Tst; - - -PROCEDURE LdrSp (r, offset: INTEGER); -BEGIN - gen11(TRUE, r, offset) -END LdrSp; - - -PROCEDURE MovImm32 (r, imm32: INTEGER); -BEGIN - MovImm8(r, LSR(imm32, 24) MOD 256); - LslImm(r, 8); - AddImm8(r, LSR(imm32, 16) MOD 256); - LslImm(r, 8); - AddImm8(r, LSR(imm32, 8) MOD 256); - LslImm(r, 8); - AddImm8(r, imm32 MOD 256) -END MovImm32; - - -PROCEDURE low (x: INTEGER): INTEGER; - RETURN x MOD 65536 -END low; - - -PROCEDURE high (x: INTEGER): INTEGER; - RETURN (x DIV 65536) MOD 65536 -END high; - - -PROCEDURE movwt (r, imm16, t: INTEGER); -VAR - imm1, imm3, imm4, imm8: INTEGER; - -BEGIN - ASSERT(range(r, 3)); - ASSERT(range(imm16, 16)); - ASSERT(range(t, 1)); - split16(imm16, imm4, imm1, imm3, imm8); - Code(0F240H + imm1 * 1024 + t * 128 + imm4); - Code(imm3 * 4096 + r * 256 + imm8); -END movwt; - - -PROCEDURE inv0 (cond: INTEGER): INTEGER; - RETURN ORD(BITS(cond) / {0}) -END inv0; - - -PROCEDURE fixup (CodeAdr, DataAdr, BssAdr: INTEGER); -VAR - code: ANYCODE; - count: INTEGER; - shorted: BOOLEAN; - jump: JUMP; - - reloc, i, diff, len: INTEGER; - - RelocCode: RELOCCODE; - - - PROCEDURE genjcc (cond, offset: INTEGER): INTEGER; - BEGIN - ASSERT(range(cond, 4)); - ASSERT(srange(offset, 8)) - RETURN 0D000H + cond * 256 + offset MOD 256 - END genjcc; - - - PROCEDURE genjmp (offset: INTEGER): INTEGER; - BEGIN - ASSERT(srange(offset, 11)) - RETURN 0E000H + offset MOD 2048 - END genjmp; - - - PROCEDURE movwt (r, imm16, t: INTEGER; VAR code: RELOCCODE); - VAR - imm1, imm3, imm4, imm8: INTEGER; - - BEGIN - split16(imm16, imm4, imm1, imm3, imm8); - code[t * 2] := 0F240H + imm1 * 1024 + t * 128 + imm4; - code[t * 2 + 1] := imm3 * 4096 + r * 256 + imm8 - END movwt; - - - PROCEDURE genmovimm32 (r, value: INTEGER; VAR code: RELOCCODE); - BEGIN - IF _THUMB2 IN Target.InstrSet THEN - movwt(r, low(value), 0, code); - movwt(r, high(value), 1, code) - ELSE - code[0] := 2000H + r * 256 + UTILS.Byte(value, 3); (* movs r, imm8 *) - code[1] := 0200H + r * 9; (* lsls r, 8 *) - code[2] := 3000H + r * 256 + UTILS.Byte(value, 2); (* adds r, imm8 *) - code[3] := code[1]; (* lsls r, 8 *) - code[4] := 3000H + r * 256 + UTILS.Byte(value, 1); (* adds r, imm8 *) - code[5] := code[1]; (* lsls r, 8 *) - code[6] := 3000H + r * 256 + UTILS.Byte(value, 0) (* adds r, imm8 *) - END - END genmovimm32; - - - PROCEDURE PutCode (code: INTEGER); - BEGIN - BIN.PutCode16LE(program, code) - END PutCode; - - - PROCEDURE genlongjmp (offset: INTEGER); - BEGIN - ASSERT(srange(offset, 22)); - PutCode(0F000H + ASR(offset, 11) MOD 2048); - PutCode(0F800H + offset MOD 2048) - END genlongjmp; - - - PROCEDURE genbc (code: JUMP); - BEGIN - CASE code.len OF - |1: PutCode(genjcc(code.cond, code.diff)) - |2: PutCode(genjcc(inv0(code.cond), 0)); - PutCode(genjmp(code.diff)) - |3: PutCode(genjcc(inv0(code.cond), 1)); - genlongjmp(code.diff) - END - END genbc; - - - PROCEDURE SetIV (idx, label, CodeAdr: INTEGER); - VAR - l, h: LISTS.ITEM; - - BEGIN - l := CodeList.first; - h := l.next; - WHILE idx > 0 DO - l := h.next; - h := l.next; - DEC(idx) - END; - label := BIN.GetLabel(program, label) * 2 + CodeAdr + 1; - l(CODE).code := low(label); - h(CODE).code := high(label) - END SetIV; - - -BEGIN - - REPEAT - - shorted := FALSE; - count := 0; - - code := CodeList.first(ANYCODE); - WHILE code # NIL DO - code.offset := count; - - CASE code OF - |CODE: INC(count) - |LABEL: BIN.SetLabel(program, code.label, count) - |JUMP: INC(count, code.len); code.offset := count + ORD(code.short) - |RELOC: INC(count, 7 - ORD(_THUMB2 IN Target.InstrSet) * 3 + code.rel MOD 2) - END; - - code := code.next(ANYCODE) - END; - - code := CodeList.first(ANYCODE); - WHILE code # NIL DO - - IF code IS JUMP THEN - jump := code(JUMP); - jump.diff := BIN.GetLabel(program, jump.label) - jump.offset; - len := jump.len; - diff := jump.diff; - CASE jump OF - |JMP: - IF (len = 2) & srange(diff, 11) THEN - len := 1 - END - - |JCC: - CASE len OF - |1: - |2: IF srange(diff, 8) THEN DEC(len) END - |3: IF srange(diff, 11) THEN DEC(len) END - END - - |CBXZ: - CASE len OF - |1: - |2: IF range(diff, 6) THEN DEC(len) END - |3: IF srange(diff, 8) THEN DEC(len) END - |4: IF srange(diff, 11) THEN DEC(len) END - END - - |CALL: - - END; - IF len # jump.len THEN - jump.len := len; - jump.short := TRUE; - shorted := TRUE - END - END; - - code := code.next(ANYCODE) - END - - UNTIL ~shorted; - - FOR i := 1 TO Target.IVTLen - 1 DO - SetIV(i, IVT[i], CodeAdr) - END; - - code := CodeList.first(ANYCODE); - WHILE code # NIL DO - - CASE code OF - - |CODE: BIN.PutCode16LE(program, code.code) - - |LABEL: - - |JMP: - IF code.len = 1 THEN - PutCode(genjmp(code.diff)) - ELSE - genlongjmp(code.diff) - END - - |JCC: genbc(code) - - |CBXZ: - IF code.len > 1 THEN - PutCode(2800H + code.reg * 256); (* cmp code.reg, 0 *) - DEC(code.len); - genbc(code) - ELSE - (* cb(n)z code.reg, L *) - PutCode(0B100H + 800H * ORD(code.cond = jne) + 200H * (code.diff DIV 32) + (code.diff MOD 32) * 8 + code.reg) - END - - |CALL: genlongjmp(code.diff) - - |RELOC: - CASE code.rel OF - |BIN.RCODE, BIN.PICCODE: reloc := BIN.GetLabel(program, code.value) * 2 + CodeAdr - |BIN.RDATA, BIN.PICDATA: reloc := code.value + DataAdr - |BIN.RBSS, BIN.PICBSS: reloc := code.value + BssAdr - END; - IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN - DEC(reloc, CodeAdr + 2 * (code.offset - 3 * ORD(_THUMB2 IN Target.InstrSet) + 9)) - END; - genmovimm32(code.reg, reloc, RelocCode); - FOR i := 0 TO 6 - 3 * ORD(_THUMB2 IN Target.InstrSet) DO - PutCode(RelocCode[i]) - END; - IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN - PutCode(4478H + code.reg) (* add code.reg, pc *) - END - END; - - code := code.next(ANYCODE) - END - -END fixup; - - -PROCEDURE push (r: INTEGER); -BEGIN - gen14(FALSE, FALSE, {r}) -END push; - - -PROCEDURE pop (r: INTEGER); -BEGIN - gen14(TRUE, FALSE, {r}) -END pop; - - -PROCEDURE mov (r1, r2: INTEGER); -BEGIN - IF (r1 < 8) & (r2 < 8) THEN - gen1(0, 0, r2, r1) - ELSE - gen5(2, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) - END -END mov; - - -PROCEDURE xchg (r1, r2: INTEGER); -BEGIN - push(r1); - mov(r1, r2); - pop(r2) -END xchg; - - -PROCEDURE drop; -BEGIN - REG.Drop(R) -END drop; - - -PROCEDURE GetAnyReg (): INTEGER; - RETURN REG.GetAnyReg(R) -END GetAnyReg; - - -PROCEDURE UnOp (VAR r: INTEGER); -BEGIN - REG.UnOp(R, r) -END UnOp; - - -PROCEDURE BinOp (VAR r1, r2: INTEGER); -BEGIN - REG.BinOp(R, r1, r2) -END BinOp; - - -PROCEDURE PushAll (NumberOfParameters: INTEGER); -BEGIN - REG.PushAll(R); - DEC(R.pushed, NumberOfParameters) -END PushAll; - - -PROCEDURE cond (op: INTEGER): INTEGER; -VAR - res: INTEGER; - -BEGIN - CASE op OF - |IL.opGT, IL.opGTC: res := jg - |IL.opGE, IL.opGEC: res := jge - |IL.opLT, IL.opLTC: res := jl - |IL.opLE, IL.opLEC: res := jle - |IL.opEQ, IL.opEQC: res := je - |IL.opNE, IL.opNEC: res := jne - END - - RETURN res -END cond; - - -PROCEDURE GetRegA; -BEGIN - ASSERT(REG.GetReg(R, ACC)) -END GetRegA; - - -PROCEDURE MovConst (r, c: INTEGER); -BEGIN - IF (0 <= c) & (c <= 255) THEN - MovImm8(r, c) - ELSIF (-255 <= c) & (c < 0) THEN - MovImm8(r, -c); - Neg(r) - ELSIF UTILS.Log2(c) >= 0 THEN - MovImm8(r, 1); - LslImm(r, UTILS.Log2(c)) - ELSIF c = UTILS.min32 THEN - MovImm8(r, 1); - LslImm(r, 31) - ELSE - IF _THUMB2 IN Target.InstrSet THEN - movwt(r, low(c), 0); - IF (c < 0) OR (c > 65535) THEN - movwt(r, high(c), 1) - END - ELSE - MovImm32(r, c) - END - END -END MovConst; - - -PROCEDURE CmpConst (r, c: INTEGER); -VAR - r2: INTEGER; - -BEGIN - IF (0 <= c) & (c <= 255) THEN - CmpImm8(r, c) - ELSE - r2 := GetAnyReg(); - ASSERT(r2 # r); - MovConst(r2, c); - Cmp(r, r2); - drop - END -END CmpConst; - - -PROCEDURE LocalOffset (offset: INTEGER): INTEGER; - RETURN offset + StkCount - ORD(offset > 0) -END LocalOffset; - - -PROCEDURE SetCC (cc, r: INTEGER); -VAR - L1, L2: INTEGER; - -BEGIN - IF _IT IN Target.InstrSet THEN - Code(0BF00H + cc * 16 + ((cc + 1) MOD 2) * 8 + 4); (* ite cc *) - MovConst(r, 1); - MovConst(r, 0) - ELSE - L1 := NewLabel(); - L2 := NewLabel(); - jcc(cc, L1); - MovConst(r, 0); - jmp(L2); - Label(L1); - MovConst(r, 1); - Label(L2) - END -END SetCC; - - -PROCEDURE PushConst (n: INTEGER); -VAR - r: INTEGER; - -BEGIN - r := GetAnyReg(); - MovConst(r, n); - push(r); - drop -END PushConst; - - -PROCEDURE AddConst (r, n: INTEGER); -VAR - r2: INTEGER; - -BEGIN - IF n # 0 THEN - IF (-255 <= n) & (n <= 255) THEN - IF n > 0 THEN - AddImm8(r, n) - ELSE - SubImm8(r, -n) - END - ELSIF (_THUMB2 IN Target.InstrSet) & (-4095 <= n) & (n <= 4095) THEN - AddSubImm12(r, ABS(n), n < 0) - ELSE - r2 := GetAnyReg(); - ASSERT(r2 # r); - IF n > 0 THEN - MovConst(r2, n); - AddReg(r, r, r2) - ELSE - MovConst(r2, -n); - SubReg(r, r, r2) - END; - drop - END - END -END AddConst; - - -PROCEDURE AddHH (r1, r2: INTEGER); -BEGIN - ASSERT((r1 >= 8) OR (r2 >= 8)); - gen5(0, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) -END AddHH; - - -PROCEDURE AddSP (n: INTEGER); -BEGIN - IF n > 0 THEN - IF n < 127 THEN - Code(0B000H + n) (* add sp, n*4 *) - ELSE - ASSERT(R2 IN R.regs); - MovConst(R2, n * 4); - AddHH(SP, R2) - END; - DEC(StkCount, n) - END -END AddSP; - - -PROCEDURE cbxz2 (c, r, label: INTEGER); -BEGIN - IF _CBXZ IN Target.InstrSet THEN - cbxz(c, r, label) - ELSE - Tst(r); - jcc(c, label) - END -END cbxz2; - - -PROCEDURE cbz (r, label: INTEGER); -BEGIN - cbxz2(je, r, label) -END cbz; - - -PROCEDURE cbnz (r, label: INTEGER); -BEGIN - cbxz2(jne, r, label) -END cbnz; - - -PROCEDURE Shift (op, r1, r2: INTEGER); -VAR - L: INTEGER; - -BEGIN - LslImm(r2, 27); - LsrImm(r2, 27); - L := NewLabel(); - cbz(r2, L); - CASE op OF - |IL.opLSL, IL.opLSL1: gen4(2, r2, r1) - |IL.opLSR, IL.opLSR1: gen4(3, r2, r1) - |IL.opASR, IL.opASR1: gen4(4, r2, r1) - |IL.opROR, IL.opROR1: gen4(7, r2, r1) - END; - Label(L) -END Shift; - - -PROCEDURE LocAdr (offs: INTEGER); -VAR - r1, n: INTEGER; - -BEGIN - r1 := GetAnyReg(); - n := LocalOffset(offs); - IF n <= 255 THEN - gen12(TRUE, r1, n) - ELSE - MovConst(r1, n * 4); - AddHH(r1, SP) - END -END LocAdr; - - -PROCEDURE CallRTL (proc, par: INTEGER); -BEGIN - call(IL.codes.rtl[proc]); - AddSP(par) -END CallRTL; - - -PROCEDURE divmod; -BEGIN - call(sdivProc); - AddSP(2) -END divmod; - - -PROCEDURE cpsid_i; -BEGIN - Code(0B672H) (* cpsid i *) -END cpsid_i; - - -PROCEDURE cpsie_i; -BEGIN - Code(0B662H) (* cpsie i *) -END cpsie_i; - - -PROCEDURE translate (pic, stroffs: INTEGER); -VAR - cmd, next: COMMAND; - opcode, param1, param2: INTEGER; - - r1, r2, r3: INTEGER; - - a, n, cc, L, L2: INTEGER; - -BEGIN - cmd := IL.codes.commands.first(COMMAND); - - WHILE cmd # NIL DO - - param1 := cmd.param1; - param2 := cmd.param2; - opcode := cmd.opcode; - - CASE opcode OF - - |IL.opJMP: - jmp(param1) - - |IL.opLABEL: - Label(param1) - - |IL.opHANDLER: - IF param2 = 0 THEN - int0 := param1 - ELSIF param2 = 1 THEN - trap := param1 - ELSE - IVT[param2] := param1 - END - - |IL.opCALL: - call(param1) - - |IL.opCALLP: - UnOp(r1); - AddImm8(r1, 1); (* Thumb mode *) - gen5(3, TRUE, FALSE, r1, 0); (* blx r1 *) - drop; - ASSERT(R.top = -1) - - |IL.opENTER: - ASSERT(R.top = -1); - - Label(param1); - - gen14(FALSE, TRUE, {}); (* push {lr} *) - - n := param2; - IF n >= 5 THEN - MovConst(ACC, 0); - MovConst(R2, n); - L := NewLabel(); - Label(L); - push(ACC); - SubImm8(R2, 1); - Tst(R2); - jcc(jne, L) - ELSIF n > 0 THEN - MovConst(ACC, 0); - WHILE n > 0 DO - push(ACC); - DEC(n) - END - END; - StkCount := param2 - - |IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: - IF opcode # IL.opLEAVE THEN - UnOp(r1); - IF r1 # ACC THEN - mov(ACC, r1) - END; - drop - END; - - ASSERT(R.top = -1); - ASSERT(StkCount = param1); - - AddSP(param1); - gen14(TRUE, TRUE, {}) (* pop {pc} *) - - |IL.opLEAVEC: - gen5(3, FALSE, TRUE, 6, 0) (* bx lr *) - - |IL.opPRECALL: - PushAll(0) - - |IL.opPARAM: - n := param2; - IF n = 1 THEN - UnOp(r1); - push(r1); - drop - ELSE - ASSERT(R.top + 1 <= n); - PushAll(n) - END - - |IL.opCLEANUP: - AddSP(param2) - - |IL.opRES, IL.opRESF: - ASSERT(R.top = -1); - GetRegA - - |IL.opPUSHC: - PushConst(param2) - - |IL.opONERR: - cpsid_i; - MovConst(R0, param2); - push(R0); - DEC(StkCount); - jmp(param1) - - |IL.opERR: - call(genTrap) - - |IL.opNOP, IL.opAND, IL.opOR: - - |IL.opSADR: - reloc(GetAnyReg(), BIN.RDATA + pic, stroffs + param2) - - |IL.opGADR: - reloc(GetAnyReg(), BIN.RBSS + pic, param2) - - |IL.opLADR: - LocAdr(param2) - - |IL.opGLOAD32: - r1 := GetAnyReg(); - reloc(r1, BIN.RBSS + pic, param2); - Ldr32(r1, r1) - - |IL.opGLOAD16: - r1 := GetAnyReg(); - reloc(r1, BIN.RBSS + pic, param2); - Ldr16(r1, r1) - - |IL.opGLOAD8: - r1 := GetAnyReg(); - reloc(r1, BIN.RBSS + pic, param2); - Ldr8(r1, r1) - - |IL.opLADR_SAVE: - UnOp(r1); - n := LocalOffset(param2); - IF n <= 255 THEN - gen11(FALSE, r1, n) (* str r1, [sp, n*4] *) - ELSE - LocAdr(param2); - BinOp(r1, r2); - Str32(r1, r2); - drop - END; - drop - - |IL.opLADR_INCC: - n := LocalOffset(param1); - IF n <= 255 THEN - r1 := GetAnyReg(); - LdrSp(r1, n); - AddConst(r1, param2); - gen11(FALSE, r1, n) (* str r1, [sp, n*4] *) - ELSE - LocAdr(param1); - r1 := GetAnyReg(); - BinOp(r2, r1); - Ldr32(r1, r2); - AddConst(r1, param2); - BinOp(r2, r1); - Str32(r1, r2); - drop - END; - drop - - |IL.opLLOAD32, IL.opVADR, IL.opVLOAD32: - r1 := GetAnyReg(); - n := LocalOffset(param2); - IF n <= 255 THEN - LdrSp(r1, n) - ELSE - drop; - LocAdr(param2); - UnOp(r1); - Ldr32(r1, r1) - END; - IF opcode = IL.opVLOAD32 THEN - Ldr32(r1, r1) - END - - |IL.opLLOAD16: - LocAdr(param2); - UnOp(r1); - Ldr16(r1, r1) - - |IL.opLLOAD8: - LocAdr(param2); - UnOp(r1); - Ldr8(r1, r1) - - |IL.opLOAD32, IL.opLOADF: - UnOp(r1); - Ldr32(r1, r1) - - |IL.opLOAD16: - UnOp(r1); - Ldr16(r1, r1) - - |IL.opLOAD8: - UnOp(r1); - Ldr8(r1, r1) - - |IL.opVLOAD16: - LocAdr(param2); - UnOp(r1); - Ldr32(r1, r1); - Ldr16(r1, r1) - - |IL.opVLOAD8: - LocAdr(param2); - UnOp(r1); - Ldr32(r1, r1); - Ldr8(r1, r1) - - |IL.opSBOOL: - BinOp(r2, r1); - Tst(r2); - SetCC(jne, r2); - Str8(r2, r1); - drop; - drop - - |IL.opSBOOLC: - UnOp(r1); - r2 := GetAnyReg(); - MovConst(r2, ORD(param2 # 0)); - Str8(r2, r1); - drop; - drop - - |IL.opSAVEC: - UnOp(r1); - r2 := GetAnyReg(); - MovConst(r2, param2); - Str32(r2, r1); - drop; - drop - - |IL.opSAVE16C: - UnOp(r1); - r2 := GetAnyReg(); - MovConst(r2, low(param2)); - Str16(r2, r1); - drop; - drop - - |IL.opSAVE8C: - UnOp(r1); - r2 := GetAnyReg(); - MovConst(r2, param2 MOD 256); - Str8(r2, r1); - drop; - drop - - |IL.opSAVE, IL.opSAVE32, IL.opSAVEF: - BinOp(r2, r1); - Str32(r2, r1); - drop; - drop - - |IL.opSAVEFI: - BinOp(r2, r1); - Str32(r1, r2); - drop; - drop - - |IL.opSAVE16: - BinOp(r2, r1); - Str16(r2, r1); - drop; - drop - - |IL.opSAVE8: - BinOp(r2, r1); - Str8(r2, r1); - drop; - drop - - |IL.opSAVEP: - UnOp(r1); - r2 := GetAnyReg(); - reloc(r2, BIN.RCODE + pic, param2); - Str32(r2, r1); - drop; - drop - - |IL.opPUSHP: - reloc(GetAnyReg(), BIN.RCODE + pic, param2) - - |IL.opEQB, IL.opNEB: - BinOp(r1, r2); - drop; - - L := NewLabel(); - cbz(r1, L); - MovConst(r1, 1); - Label(L); - - L := NewLabel(); - cbz(r2, L); - MovConst(r2, 1); - Label(L); - - Cmp(r1, r2); - IF opcode = IL.opEQB THEN - SetCC(je, r1) - ELSE - SetCC(jne, r1) - END - - |IL.opDROP: - UnOp(r1); - drop - - |IL.opJNZ1: - UnOp(r1); - cbnz(r1, param1) - - |IL.opJG: - UnOp(r1); - Tst(r1); - jcc(jg, param1) - - |IL.opJNZ: - UnOp(r1); - cbnz(r1, param1); - drop - - |IL.opJZ: - UnOp(r1); - cbz(r1, param1); - drop - - |IL.opSWITCH: - UnOp(r1); - IF param2 = 0 THEN - r2 := ACC - ELSE - r2 := R2 - END; - IF r1 # r2 THEN - ASSERT(REG.GetReg(R, r2)); - ASSERT(REG.Exchange(R, r1, r2)); - drop - END; - drop - - |IL.opENDSW: - - |IL.opCASEL: - GetRegA; - CmpConst(ACC, param1); - jcc(jl, param2); - drop - - |IL.opCASER: - GetRegA; - CmpConst(ACC, param1); - jcc(jg, param2); - drop - - |IL.opCASELR: - GetRegA; - CmpConst(ACC, param1); - IF param2 = cmd.param3 THEN - jcc(jne, param2) - ELSE - jcc(jl, param2); - jcc(jg, cmd.param3) - END; - drop - - |IL.opCODE: - Code(param2) - - |IL.opEQ..IL.opGE, - IL.opEQC..IL.opGEC: - IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN - BinOp(r1, r2); - Cmp(r1, r2); - drop - ELSE - UnOp(r1); - CmpConst(r1, param2) - END; - - drop; - cc := cond(opcode); - next := cmd.next(COMMAND); - - IF next.opcode = IL.opJNZ THEN - jcc(cc, next.param1); - cmd := next - ELSIF next.opcode = IL.opJZ THEN - jcc(inv0(cc), next.param1); - cmd := next - ELSE - SetCC(cc, GetAnyReg()) - END - - |IL.opINCC: - UnOp(r1); - r2 := GetAnyReg(); - Ldr32(r2, r1); - AddConst(r2, param2); - Str32(r2, r1); - drop; - drop - - |IL.opINCCB, IL.opDECCB: - IF opcode = IL.opDECCB THEN - param2 := -param2 - END; - UnOp(r1); - r2 := GetAnyReg(); - Ldr8(r2, r1); - AddConst(r2, param2); - Str8(r2, r1); - drop; - drop - - |IL.opUMINUS: - UnOp(r1); - Neg(r1) - - |IL.opADD: - BinOp(r1, r2); - CASE cmd.next(COMMAND).opcode OF - |IL.opLOAD32, IL.opLOADF: - gen7(TRUE, FALSE, r2, r1, r1); (* ldr r1, [r1, r2] *) - cmd := cmd.next(COMMAND) - |IL.opLOAD8: - gen7(TRUE, TRUE, r2, r1, r1); (* ldrb r1, [r1, r2] *) - cmd := cmd.next(COMMAND) - |IL.opLOAD16: - gen8(TRUE, FALSE, r2, r1, r1); (* ldrh r1, [r1, r2] *) - cmd := cmd.next(COMMAND) - ELSE - AddReg(r1, r1, r2) - END; - drop - - |IL.opADDC: - UnOp(r1); - AddConst(r1, param2) - - |IL.opSUB: - BinOp(r1, r2); - SubReg(r1, r1, r2); - drop - - |IL.opSUBL, IL.opSUBR: - UnOp(r1); - AddConst(r1, -param2); - IF opcode = IL.opSUBL THEN - Neg(r1) - END - - |IL.opMUL: - BinOp(r1, r2); - Mul(r1, r2); - drop - - |IL.opMULC: - UnOp(r1); - - a := param2; - IF a > 1 THEN - n := UTILS.Log2(a) - ELSIF a < -1 THEN - n := UTILS.Log2(-a) - ELSE - n := -1 - END; - - IF a = 1 THEN - - ELSIF a = -1 THEN - Neg(r1) - ELSIF a = 0 THEN - MovConst(r1, 0) - ELSE - IF n > 0 THEN - IF a < 0 THEN - Neg(r1) - END; - LslImm(r1, n) - ELSE - r2 := GetAnyReg(); - MovConst(r2, a); - Mul(r1, r2); - drop - END - END - - |IL.opABS: - UnOp(r1); - Tst(r1); - L := NewLabel(); - jcc(jge, L); - Neg(r1); - Label(L) - - |IL.opNOT: - UnOp(r1); - Tst(r1); - SetCC(je, r1) - - |IL.opORD: - UnOp(r1); - Tst(r1); - SetCC(jne, r1) - - |IL.opCHR: - UnOp(r1); - Code(0B2C0H + r1 * 9) (* uxtb r1, r1 *) - - |IL.opWCHR: - UnOp(r1); - Code(0B280H + r1 * 9) (* uxth r1, r1 *) - - |IL.opASR, IL.opROR, IL.opLSL, IL.opLSR: - BinOp(r1, r2); - Shift(opcode, r1, r2); - drop - - |IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1: - MovConst(GetAnyReg(), param2); - BinOp(r2, r1); - Shift(opcode, r1, r2); - INCL(R.regs, r2); - DEC(R.top); - R.stk[R.top] := r1 - - |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: - n := param2 MOD 32; - IF n # 0 THEN - UnOp(r1); - CASE opcode OF - |IL.opASR2: AsrImm(r1, n) - |IL.opROR2: r2 := GetAnyReg(); MovConst(r2, n); Shift(IL.opROR, r1, r2); drop - |IL.opLSL2: LslImm(r1, n) - |IL.opLSR2: LsrImm(r1, n) - END - END - - |IL.opCHKBYTE: - BinOp(r1, r2); - CmpConst(r1, 256); - jcc(jb, param1) - - |IL.opCHKIDX: - UnOp(r1); - CmpConst(r1, param2); - jcc(jb, param1) - - |IL.opCHKIDX2: - BinOp(r1, r2); - IF param2 # -1 THEN - Cmp(r2, r1); - jcc(jb, param1) - END; - INCL(R.regs, r1); - DEC(R.top); - R.stk[R.top] := r2 - - |IL.opLEN: - n := param2; - UnOp(r1); - drop; - EXCL(R.regs, r1); - - WHILE n > 0 DO - UnOp(r2); - drop; - DEC(n) - END; - - INCL(R.regs, r1); - ASSERT(REG.GetReg(R, r1)) - - |IL.opINF: - MovConst(GetAnyReg(), inf) - - |IL.opPUSHF: - UnOp(r1); - push(r1); - drop - - |IL.opCONST: - MovConst(GetAnyReg(), param2) - - |IL.opEQP, IL.opNEP: - reloc(GetAnyReg(), BIN.RCODE + pic, param1); - BinOp(r1, r2); - Cmp(r1, r2); - drop; - IF opcode = IL.opEQP THEN - SetCC(je, r1) - ELSE - SetCC(jne, r1) - END - - |IL.opPUSHT: - UnOp(r1); - r2 := GetAnyReg(); - mov(r2, r1); - SubImm8(r2, 4); - Ldr32(r2, r2) - - |IL.opGET, IL.opGETC: - IF opcode = IL.opGET THEN - BinOp(r1, r2) - ELSIF opcode = IL.opGETC THEN - UnOp(r2); - r1 := GetAnyReg(); - MovConst(r1, param1) - END; - drop; - drop; - - CASE param2 OF - |1: Ldr8(r1, r1); Str8(r1, r2) - |2: Ldr16(r1, r1); Str16(r1, r2) - |4: Ldr32(r1, r1); Str32(r1, r2) - END - - |IL.opINC, IL.opDEC: - BinOp(r2, r1); - r3 := GetAnyReg(); - Ldr32(r3, r1); - IF opcode = IL.opINC THEN - AddReg(r3, r3, r2) - ELSE - SubReg(r3, r3, r2) - END; - Str32(r3, r1); - drop; - drop; - drop - - |IL.opINCB, IL.opDECB: - BinOp(r2, r1); - r3 := GetAnyReg(); - Ldr8(r3, r1); - IF opcode = IL.opINCB THEN - AddReg(r3, r3, r2) - ELSE - SubReg(r3, r3, r2) - END; - Str8(r3, r1); - drop; - drop; - drop - - |IL.opMIN, IL.opMAX: - BinOp(r1, r2); - Cmp(r1, r2); - L := NewLabel(); - IF opcode = IL.opMIN THEN - cc := jle - ELSE - cc := jge - END; - jcc(cc, L); - mov(r1, r2); - Label(L); - drop - - |IL.opMINC, IL.opMAXC: - UnOp(r1); - CmpConst(r1, param2); - L := NewLabel(); - IF opcode = IL.opMINC THEN - cc := jle - ELSE - cc := jge - END; - jcc(cc, L); - MovConst(r1, param2); - Label(L) - - |IL.opMULS: - BinOp(r1, r2); - gen4(0, r2, r1); (* ands r1, r2 *) - drop - - |IL.opMULSC: - MovConst(GetAnyReg(), param2); - BinOp(r1, r2); - gen4(0, r2, r1); (* ands r1, r2 *) - drop - - |IL.opDIVS: - BinOp(r1, r2); - gen4(1, r2, r1); (* eors r1, r2 *) - drop - - |IL.opDIVSC: - MovConst(GetAnyReg(), param2); - BinOp(r1, r2); - gen4(1, r2, r1); (* eors r1, r2 *) - drop - - |IL.opADDS: - BinOp(r1, r2); - gen4(12, r2, r1); (* orrs r1, r2 *) - drop - - |IL.opSUBS: - BinOp(r1, r2); - gen4(14, r2, r1); (* bics r1, r2 *) - drop - - |IL.opADDSC: - MovConst(GetAnyReg(), param2); - BinOp(r1, r2); - gen4(12, r2, r1); (* orrs r1, r2 *) - drop - - |IL.opSUBSL: - MovConst(GetAnyReg(), param2); - BinOp(r1, r2); - gen4(14, r1, r2); (* bics r2, r1 *) - INCL(R.regs, r1); - DEC(R.top); - R.stk[R.top] := r2 - - |IL.opSUBSR: - MovConst(GetAnyReg(), param2); - BinOp(r1, r2); - gen4(14, r2, r1); (* bics r1, r2 *) - drop - - |IL.opUMINS: - UnOp(r1); - gen4(15, r1, r1) (* mvns r1, r1 *) - - |IL.opINCL, IL.opEXCL: - BinOp(r1, r2); - r3 := GetAnyReg(); - MovConst(r3, 1); - CmpConst(r1, 32); - L := NewLabel(); - jcc(jnb, L); - gen4(2, r1, r3); (* lsls r3, r1 *) - Ldr32(r1, r2); - IF opcode = IL.opINCL THEN - gen4(12, r3, r1) (* orrs r1, r3 *) - ELSE - gen4(14, r3, r1) (* bics r1, r3 *) - END; - Str32(r1, r2); - Label(L); - drop; - drop; - drop - - |IL.opINCLC, IL.opEXCLC: - UnOp(r2); - r1 := GetAnyReg(); - r3 := GetAnyReg(); - MovConst(r3, 1); - LslImm(r3, param2); - Ldr32(r1, r2); - IF opcode = IL.opINCLC THEN - gen4(12, r3, r1) (* orrs r1, r3 *) - ELSE - gen4(14, r3, r1) (* bics r1, r3 *) - END; - Str32(r1, r2); - drop; - drop; - drop - - |IL.opLENGTH: - PushAll(2); - CallRTL(IL._length, 2); - GetRegA - - |IL.opLENGTHW: - PushAll(2); - CallRTL(IL._lengthw, 2); - GetRegA - - |IL.opSAVES: - UnOp(r2); - REG.PushAll_1(R); - r1 := GetAnyReg(); - reloc(r1, BIN.RDATA + pic, stroffs + param2); - push(r1); - drop; - push(r2); - drop; - PushConst(param1); - CallRTL(IL._move, 3) - - |IL.opEQS .. IL.opGES: - PushAll(4); - PushConst(opcode - IL.opEQS); - CallRTL(IL._strcmp, 5); - GetRegA - - |IL.opEQSW .. IL.opGESW: - PushAll(4); - PushConst(opcode - IL.opEQSW); - CallRTL(IL._strcmpw, 5); - GetRegA - - |IL.opCOPY: - PushAll(2); - PushConst(param2); - CallRTL(IL._move, 3) - - |IL.opMOVE: - PushAll(3); - CallRTL(IL._move, 3) - - |IL.opCOPYA: - PushAll(4); - PushConst(param2); - CallRTL(IL._arrcpy, 5); - GetRegA - - |IL.opCOPYS: - PushAll(4); - PushConst(param2); - CallRTL(IL._strcpy, 5) - - |IL.opDIV: - PushAll(2); - divmod; - GetRegA - - |IL.opDIVL: - UnOp(r1); - REG.PushAll_1(R); - PushConst(param2); - push(r1); - drop; - divmod; - GetRegA - - |IL.opDIVR: - n := UTILS.Log2(param2); - IF n > 0 THEN - UnOp(r1); - AsrImm(r1, n) - ELSIF n < 0 THEN - PushAll(1); - PushConst(param2); - divmod; - GetRegA - END - - |IL.opMOD: - PushAll(2); - divmod; - mov(R0, R1); - GetRegA - - |IL.opMODR: - n := UTILS.Log2(param2); - IF n > 0 THEN - UnOp(r1); - IF n = 8 THEN - Code(0B2C0H + r1 * 9) (* uxtb r1, r1 *) - ELSIF n = 16 THEN - Code(0B280H + r1 * 9) (* uxth r1, r1 *) - ELSE - LslImm(r1, 32 - n); - LsrImm(r1, 32 - n) - END - ELSIF n < 0 THEN - PushAll(1); - PushConst(param2); - divmod; - mov(R0, R1); - GetRegA - ELSE - UnOp(r1); - MovConst(r1, 0) - END - - |IL.opMODL: - UnOp(r1); - REG.PushAll_1(R); - PushConst(param2); - push(r1); - drop; - divmod; - mov(R0, R1); - GetRegA - - |IL.opIN, IL.opINR: - IF opcode = IL.opINR THEN - r2 := GetAnyReg(); - MovConst(r2, param2) - END; - L := NewLabel(); - L2 := NewLabel(); - BinOp(r1, r2); - r3 := GetAnyReg(); - CmpConst(r1, 32); - jcc(jb, L); - MovConst(r1, 0); - jmp(L2); - Label(L); - MovConst(r3, 1); - Shift(IL.opLSL, r3, r1); - gen4(0, r3, r2); (* ands r2, r3 *) - SetCC(jne, r1); - Label(L2); - drop; - drop - - |IL.opINL: - UnOp(r1); - r2 := GetAnyReg(); - MovConst(r2, LSL(1, param2)); - gen4(0, r2, r1); (* ands r1, r2 *) - SetCC(jne, r1); - drop - - |IL.opRSET: - PushAll(2); - CallRTL(IL._set, 2); - GetRegA - - |IL.opRSETR: - PushAll(1); - PushConst(param2); - CallRTL(IL._set, 2); - GetRegA - - |IL.opRSETL: - UnOp(r1); - REG.PushAll_1(R); - PushConst(param2); - push(r1); - drop; - CallRTL(IL._set, 2); - GetRegA - - |IL.opRSET1: - PushAll(1); - CallRTL(IL._set1, 1); - GetRegA - - |IL.opCONSTF: - MovConst(GetAnyReg(), UTILS.d2s(cmd.float)) - - |IL.opMULF: - PushAll(2); - CallRTL(IL._fmul, 2); - GetRegA - - |IL.opDIVF: - PushAll(2); - CallRTL(IL._fdiv, 2); - GetRegA - - |IL.opDIVFI: - PushAll(2); - CallRTL(IL._fdivi, 2); - GetRegA - - |IL.opADDF: - PushAll(2); - CallRTL(IL._fadd, 2); - GetRegA - - |IL.opSUBFI: - PushAll(2); - CallRTL(IL._fsubi, 2); - GetRegA - - |IL.opSUBF: - PushAll(2); - CallRTL(IL._fsub, 2); - GetRegA - - |IL.opEQF..IL.opGEF: - PushAll(2); - PushConst(opcode - IL.opEQF); - CallRTL(IL._fcmp, 3); - GetRegA - - |IL.opFLOOR: - PushAll(1); - CallRTL(IL._floor, 1); - GetRegA - - |IL.opFLT: - PushAll(1); - CallRTL(IL._flt, 1); - GetRegA - - |IL.opUMINF: - UnOp(r1); - r2 := GetAnyReg(); - MovConst(r2, 1); - LslImm(r2, 31); - gen4(1, r2, r1); (* eors r1, r2 *) - drop - - |IL.opFABS: - UnOp(r1); - r2 := GetAnyReg(); - MovConst(r2, 1); - LslImm(r2, 31); - gen4(14, r2, r1); (* bics r1, r2 *) - drop - - |IL.opNEW: - cpsid_i; - PushAll(1); - n := param2 + 4; - ASSERT(UTILS.Align(n, 4)); - PushConst(n); - PushConst(param1); - CallRTL(IL._new, 3); - cpsie_i - - |IL.opTYPEGP: - UnOp(r1); - PushAll(0); - push(r1); - PushConst(param2); - CallRTL(IL._guard, 2); - GetRegA - - |IL.opIS: - PushAll(1); - PushConst(param2); - CallRTL(IL._is, 2); - GetRegA - - |IL.opISREC: - PushAll(2); - PushConst(param2); - CallRTL(IL._guardrec, 3); - GetRegA - - |IL.opTYPEGR: - PushAll(1); - PushConst(param2); - CallRTL(IL._guardrec, 2); - GetRegA - - |IL.opTYPEGD: - UnOp(r1); - PushAll(0); - SubImm8(r1, 4); - Ldr32(r1, r1); - push(r1); - PushConst(param2); - CallRTL(IL._guardrec, 2); - GetRegA - - |IL.opCASET: - push(R2); - push(R2); - PushConst(param2); - CallRTL(IL._guardrec, 2); - pop(R2); - cbnz(ACC, param1) - - |IL.opROT: - PushAll(0); - mov(R2, SP); - push(R2); - PushConst(param2); - CallRTL(IL._rot, 2) - - |IL.opPACK: - PushAll(2); - CallRTL(IL._pack, 2) - - |IL.opPACKC: - PushAll(1); - PushConst(param2); - CallRTL(IL._pack, 2) - - |IL.opUNPK: - PushAll(2); - CallRTL(IL._unpk, 2) - - END; - - cmd := cmd.next(COMMAND) - END; - - ASSERT(R.pushed = 0); - ASSERT(R.top = -1) -END translate; - - -PROCEDURE prolog (GlobSize, tcount, pic, sp, ivt_len: INTEGER); -VAR - r1, r2, i, dcount: INTEGER; - -BEGIN - entry := NewLabel(); - emptyProc := NewLabel(); - genInt := NewLabel(); - genTrap := NewLabel(); - sdivProc := NewLabel(); - - trap := emptyProc; - int0 := emptyProc; - - IVT[0] := sp; - IVT[1] := entry; - FOR i := 2 TO ivt_len - 1 DO - IVT[i] := genInt - END; - - FOR i := 0 TO ivt_len - 1 DO - Code(low(IVT[i])); - Code(high(IVT[i])) - END; - - Label(entry); - cpsie_i; - - r1 := GetAnyReg(); - r2 := GetAnyReg(); - reloc(r1, BIN.RDATA + pic, 0); - - FOR i := 0 TO tcount - 1 DO - MovConst(r2, CHL.GetInt(IL.codes.types, i)); - Str32(r2, r1); - AddImm8(r1, 4) - END; - - dcount := CHL.Length(IL.codes.data); - FOR i := 0 TO dcount - 1 BY 4 DO - MovConst(r2, BIN.get32le(IL.codes.data, i)); - Str32(r2, r1); - AddImm8(r1, 4) - END; - - drop; - drop; - - r1 := GetAnyReg(); - MovConst(r1, sp); - mov(SP, r1); - reloc(r1, BIN.RDATA + pic, 0); - push(r1); - reloc(r1, BIN.RBSS + pic, 0); - r2 := GetAnyReg(); - MovConst(r2, GlobSize); - AddReg(r1, r1, r2); - drop; - push(r1); - drop; - PushConst(tcount); - CallRTL(IL._init, 3) -END prolog; - - -PROCEDURE epilog; -VAR - L1, L2, L3, L4: INTEGER; - -BEGIN - (* L2: *) - Code(0E7FEH); (* b L2 *) - - Label(genInt); - Code(0F3EFH); Code(08005H); (* mrs r0, ipsr *) - gen14(FALSE, TRUE, {R0}); (* push {lr, r0} *) - call(int0); - gen14(TRUE, TRUE, {R0}); (* pop {pc, r0} *) - - Label(emptyProc); - Code(04770H); (* bx lr *) - - Label(genTrap); - call(trap); - call(entry); - - Label(sdivProc); - IF _SDIV IN Target.InstrSet THEN - Code(09800H); (* ldr r0, [sp] *) - Code(09901H); (* ldr r1, [sp, 4] *) - Code(0FB91H); (* sdiv r2, r1, r0 *) - Code(0F2F0H); - Code(00013H); (* movs r3, r2 *) - Code(04343H); (* muls r3, r0, r3 *) - Code(01AC9H); (* subs r1, r1, r3 *) - Code(0DA01H); (* bge L *) - Code(01809H); (* adds r1, r1, r0 *) - Code(03A01H); (* subs r2, 1 *) - (* L: *) - Code(00010H); (* movs r0, r2 *) - Code(04770H); (* bx lr *) - ELSE - (* a / b; a >= 0 *) - L1 := NewLabel(); - L2 := NewLabel(); - L3 := NewLabel(); - L4 := NewLabel(); - - LdrSp(R1, 1); - LdrSp(R2, 0); - MovConst(R0, 0); - push(R4); - - Label(L4); - Cmp(R1, R2); - jcc(jl, L1); - MovConst(R3, 2); - mov(R4, R2); - LslImm(R4, 1); - Label(L3); - Cmp(R1, R4); - jcc(jl, L2); - CmpConst(R4, 0); - jcc(jle, L2); - LslImm(R4, 1); - LslImm(R3, 1); - jmp(L3); - Label(L2); - LsrImm(R4, 1); - LsrImm(R3, 1); - SubReg(R1, R1, R4); - AddReg(R0, R0, R3); - jmp(L4); - Label(L1); - - (* a / b; a < 0 *) - L1 := NewLabel(); - L2 := NewLabel(); - L3 := NewLabel(); - L4 := NewLabel(); - - Label(L4); - CmpConst(R1, 0); - jcc(jge, L1); - MovConst(R3, 2); - mov(R4, R2); - LslImm(R4, 1); - Neg(R1); - Label(L3); - Cmp(R1, R4); - jcc(jl, L2); - CmpConst(R4, 0); - jcc(jle, L2); - LslImm(R4, 1); - LslImm(R3, 1); - jmp(L3); - Label(L2); - Neg(R1); - LsrImm(R4, 1); - LsrImm(R3, 1); - AddReg(R1, R1, R4); - SubReg(R0, R0, R3); - jmp(L4); - Label(L1); - - pop(R4); - Code(04770H); (* bx lr *) - END - -END epilog; - - -PROCEDURE SetTarget (FlashStart, SRAMStart: INTEGER; InstrSet: SET; isNXP: BOOLEAN); -BEGIN - Target.FlashAdr := FlashStart; - Target.SRAMAdr := SRAMStart; - Target.InstrSet := InstrSet; - Target.isNXP := isNXP; - - Target.IVTLen := 256; (* >= 192 *) - Target.Reserved := 0; - Target.MinStack := 512; -END SetTarget; - - -PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); -VAR - opt: PROG.OPTIONS; - - ram, rom, i, j: INTEGER; - - DataAdr, BssAdr, DataSize, BssSize, CodeSize: INTEGER; - -BEGIN - ram := MIN(MAX(options.ram, minRAM), maxRAM) * 1024; - rom := MIN(MAX(options.rom, minROM), maxROM) * 1024; - - IF target = TARGETS.STM32CM3 THEN - SetTarget(08000000H, 20000000H, CortexM3, FALSE) - END; - - tcount := CHL.Length(IL.codes.types); - - opt := options; - CodeList := LISTS.create(NIL); - - program := BIN.create(IL.codes.lcount); - - REG.Init(R, push, pop, mov, xchg, {R0, R1, R2, R3}); - - StkCount := 0; - - DataAdr := Target.SRAMAdr + Target.Reserved; - DataSize := CHL.Length(IL.codes.data) + tcount * 4 + Target.Reserved; - WHILE DataSize MOD 4 # 0 DO - CHL.PushByte(IL.codes.data, 0); - INC(DataSize) - END; - BssAdr := DataAdr + DataSize - Target.Reserved; - - IL.set_bss(MAX(IL.codes.bss, MAX(IL.codes.dmin - CHL.Length(IL.codes.data), 4))); - - BssSize := IL.codes.bss; - ASSERT(UTILS.Align(BssSize, 4)); - - prolog(BssSize, tcount, ORD(opt.pic), Target.SRAMAdr + ram, Target.IVTLen); - translate(ORD(opt.pic), tcount * 4); - epilog; - - fixup(Target.FlashAdr, DataAdr, BssAdr); - - INC(DataSize, BssSize); - CodeSize := CHL.Length(program.code); - - IF CodeSize > rom THEN - ERRORS.Error(203) - END; - - IF DataSize > ram - Target.MinStack THEN - ERRORS.Error(204) - END; - - IF Target.isNXP THEN - BIN.put32le(program.code, 2FCH, 0H); (* code read protection (CRP) *) - (* NXP checksum *) - j := 0; - FOR i := 0 TO 6 DO - INC(j, BIN.get32le(program.code, i * 4)) - END; - BIN.put32le(program.code, 1CH, -j) - END; - - WR.Create(outname); - - HEX.Data2(program.code, 0, CodeSize, high(Target.FlashAdr)); - HEX.End; - - WR.Close; - - C.Dashes; - C.String( " rom: "); C.Int(CodeSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(CodeSize * 100 DIV rom); C.StringLn("%)"); - C.Ln; - C.String( " ram: "); C.Int(DataSize); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(DataSize * 100 DIV ram); C.StringLn("%)") -END CodeGen; - - -PROCEDURE SetIV* (idx: INTEGER): BOOLEAN; -VAR - res: BOOLEAN; - -BEGIN - res := IVT[idx] = 0; - IVT[idx] := 1 - - RETURN res -END SetIV; - - -PROCEDURE init; -VAR - i: INTEGER; - -BEGIN - FOR i := 0 TO LEN(IVT) - 1 DO - IVT[i] := 0 - END -END init; - - -BEGIN - init +(* + BSD 2-Clause License + + Copyright (c) 2019-2021, Anton Krotov + All rights reserved. +*) + +MODULE THUMB; + +IMPORT PROG, LISTS, CHL := CHUNKLISTS, BIN, REG, IL, C := CONSOLE, + UTILS, WR := WRITER, HEX, ERRORS, TARGETS; + + +CONST + + R0 = 0; R1 = 1; R2 = 2; R3 = 3; R4 = 4; + + SP = 13; LR = 14; PC = 15; + + ACC = R0; + + je = 0; jne = 1; jnb = 2; jb = 3; jge = 10; jl = 11; jg = 12; jle = 13; + + inf = 7F800000H; + + minROM* = 16; maxROM* = 65536; + minRAM* = 4; maxRAM* = 65536; + + maxIVT* = 1023; + + _THUMB2 = 0; _IT = 1; _SDIV = 2; _CBXZ = 3; + + CortexM0 = {}; + CortexM1 = {}; + CortexM3 = {_THUMB2, _IT, _SDIV, _CBXZ}; + CortexM23 = {_SDIV, _CBXZ}; + + +TYPE + + COMMAND = IL.COMMAND; + + ANYCODE = POINTER TO RECORD (LISTS.ITEM) + + offset: INTEGER + + END; + + CODE = POINTER TO RECORD (ANYCODE) + + code: INTEGER + + END; + + LABEL = POINTER TO RECORD (ANYCODE) + + label: INTEGER + + END; + + JUMP = POINTER TO RECORD (ANYCODE) + + label, diff, len, cond: INTEGER; + short: BOOLEAN + + END; + + JMP = POINTER TO RECORD (JUMP) + + END; + + JCC = POINTER TO RECORD (JUMP) + + END; + + CBXZ = POINTER TO RECORD (JUMP) + + reg: INTEGER + + END; + + CALL = POINTER TO RECORD (JUMP) + + END; + + RELOC = POINTER TO RECORD (ANYCODE) + + reg, rel, value: INTEGER + + END; + + RELOCCODE = ARRAY 7 OF INTEGER; + + +VAR + + R: REG.REGS; + + tcount: INTEGER; + + CodeList: LISTS.LIST; + + program: BIN.PROGRAM; + + StkCount: INTEGER; + + Target: RECORD + FlashAdr, + SRAMAdr, + IVTLen, + MinStack, + Reserved: INTEGER; + InstrSet: SET; + isNXP: BOOLEAN + END; + + IVT: ARRAY maxIVT + 1 OF INTEGER; + + sdivProc, trap, genTrap, entry, emptyProc, int0, genInt: INTEGER; + + +PROCEDURE Code (code: INTEGER); +VAR + c: CODE; + +BEGIN + NEW(c); + c.code := code; + LISTS.push(CodeList, c) +END Code; + + +PROCEDURE Label (label: INTEGER); +VAR + L: LABEL; + +BEGIN + NEW(L); + L.label := label; + LISTS.push(CodeList, L) +END Label; + + +PROCEDURE jcc (cond, label: INTEGER); +VAR + j: JCC; + +BEGIN + NEW(j); + j.label := label; + j.cond := cond; + j.short := FALSE; + j.len := 3; + LISTS.push(CodeList, j) +END jcc; + + +PROCEDURE cbxz (cond, reg, label: INTEGER); +VAR + j: CBXZ; + +BEGIN + NEW(j); + j.label := label; + j.cond := cond; + j.reg := reg; + j.short := FALSE; + j.len := 4; + LISTS.push(CodeList, j) +END cbxz; + + +PROCEDURE jmp (label: INTEGER); +VAR + j: JMP; + +BEGIN + NEW(j); + j.label := label; + j.short := FALSE; + j.len := 2; + LISTS.push(CodeList, j) +END jmp; + + +PROCEDURE call (label: INTEGER); +VAR + c: CALL; + +BEGIN + NEW(c); + c.label := label; + c.short := FALSE; + c.len := 2; + LISTS.push(CodeList, c) +END call; + + +PROCEDURE reloc (reg, rel, value: INTEGER); +VAR + r: RELOC; + +BEGIN + NEW(r); + r.reg := reg; + r.rel := rel; + r.value := value; + LISTS.push(CodeList, r) +END reloc; + + +PROCEDURE NewLabel (): INTEGER; +BEGIN + BIN.NewLabel(program) + RETURN IL.NewLabel() +END NewLabel; + + +PROCEDURE range (x, n: INTEGER): BOOLEAN; + RETURN (0 <= x) & (x < LSL(1, n)) +END range; + + +PROCEDURE srange (x, n: INTEGER): BOOLEAN; + RETURN (-LSL(1, n - 1) <= x) & (x < LSL(1, n - 1)) +END srange; + + +PROCEDURE gen1 (op, imm, rs, rd: INTEGER); +BEGIN + ASSERT(op IN {0..2}); + ASSERT(range(imm, 5)); + ASSERT(range(rs, 3)); + ASSERT(range(rd, 3)); + Code(LSL(op, 11) + LSL(imm, 6) + LSL(rs, 3) + rd) +END gen1; + + +PROCEDURE gen2 (i, op: BOOLEAN; imm, rs, rd: INTEGER); +BEGIN + ASSERT(range(imm, 3)); + ASSERT(range(rs, 3)); + ASSERT(range(rd, 3)); + Code(1800H + LSL(ORD(i), 10) + LSL(ORD(op), 9) + LSL(imm, 6) + LSL(rs, 3) + rd) +END gen2; + + +PROCEDURE gen3 (op, rd, imm: INTEGER); +BEGIN + ASSERT(range(op, 2)); + ASSERT(range(rd, 3)); + ASSERT(range(imm, 8)); + Code(2000H + LSL(op, 11) + LSL(rd, 8) + imm) +END gen3; + + +PROCEDURE gen4 (op, rs, rd: INTEGER); +BEGIN + ASSERT(range(op, 4)); + ASSERT(range(rs, 3)); + ASSERT(range(rd, 3)); + Code(4000H + LSL(op, 6) + LSL(rs, 3) + rd) +END gen4; + + +PROCEDURE gen5 (op: INTEGER; h1, h2: BOOLEAN; rs, rd: INTEGER); +BEGIN + ASSERT(range(op, 2)); + ASSERT(range(rs, 3)); + ASSERT(range(rd, 3)); + Code(4400H + LSL(op, 8) + LSL(ORD(h1), 7) + LSL(ORD(h2), 6) + LSL(rs, 3) + rd) +END gen5; + + +PROCEDURE gen7 (l, b: BOOLEAN; ro, rb, rd: INTEGER); +BEGIN + ASSERT(range(ro, 3)); + ASSERT(range(rb, 3)); + ASSERT(range(rd, 3)); + Code(5000H + LSL(ORD(l), 11) + LSL(ORD(b), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) +END gen7; + + +PROCEDURE gen8 (h, s: BOOLEAN; ro, rb, rd: INTEGER); +BEGIN + ASSERT(range(ro, 3)); + ASSERT(range(rb, 3)); + ASSERT(range(rd, 3)); + Code(5200H + LSL(ORD(h), 11) + LSL(ORD(s), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) +END gen8; + + +PROCEDURE gen9 (b, l: BOOLEAN; imm, rb, rd: INTEGER); +BEGIN + ASSERT(range(imm, 5)); + ASSERT(range(rb, 3)); + ASSERT(range(rd, 3)); + Code(6000H + LSL(ORD(b), 12) + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) +END gen9; + + +PROCEDURE gen10 (l: BOOLEAN; imm, rb, rd: INTEGER); +BEGIN + ASSERT(range(imm, 5)); + ASSERT(range(rb, 3)); + ASSERT(range(rd, 3)); + Code(8000H + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) +END gen10; + + +PROCEDURE gen11 (l: BOOLEAN; rd, imm: INTEGER); +BEGIN + ASSERT(range(rd, 3)); + ASSERT(range(imm, 8)); + Code(9000H + LSL(ORD(l), 11) + LSL(rd, 8) + imm) +END gen11; + + +PROCEDURE gen12 (sp: BOOLEAN; rd, imm: INTEGER); +BEGIN + ASSERT(range(rd, 3)); + ASSERT(range(imm, 8)); + Code(0A000H + LSL(ORD(sp), 11) + LSL(rd, 8) + imm) +END gen12; + + +PROCEDURE gen14 (l, r: BOOLEAN; rlist: SET); +VAR + i, n: INTEGER; + +BEGIN + ASSERT(range(ORD(rlist), 8)); + + n := ORD(r); + FOR i := 0 TO 7 DO + IF i IN rlist THEN + INC(n) + END + END; + + IF l THEN + n := -n + END; + + INC(StkCount, n); + + Code(0B400H + LSL(ORD(l), 11) + LSL(ORD(r), 8) + ORD(rlist)) +END gen14; + + +PROCEDURE split16 (imm16: INTEGER; VAR imm4, imm1, imm3, imm8: INTEGER); +BEGIN + ASSERT(range(imm16, 16)); + imm8 := imm16 MOD 256; + imm4 := LSR(imm16, 12); + imm3 := LSR(imm16, 8) MOD 8; + imm1 := LSR(imm16, 11) MOD 2; +END split16; + + +PROCEDURE LslImm (r, imm5: INTEGER); +BEGIN + gen1(0, imm5, r, r) +END LslImm; + + +PROCEDURE LsrImm (r, imm5: INTEGER); +BEGIN + gen1(1, imm5, r, r) +END LsrImm; + + +PROCEDURE AsrImm (r, imm5: INTEGER); +BEGIN + gen1(2, imm5, r, r) +END AsrImm; + + +PROCEDURE AddReg (rd, rs, rn: INTEGER); +BEGIN + gen2(FALSE, FALSE, rn, rs, rd) +END AddReg; + + +PROCEDURE SubReg (rd, rs, rn: INTEGER); +BEGIN + gen2(FALSE, TRUE, rn, rs, rd) +END SubReg; + + +PROCEDURE AddImm8 (rd, imm8: INTEGER); +BEGIN + IF imm8 # 0 THEN + gen3(2, rd, imm8) + END +END AddImm8; + + +PROCEDURE SubImm8 (rd, imm8: INTEGER); +BEGIN + IF imm8 # 0 THEN + gen3(3, rd, imm8) + END +END SubImm8; + + +PROCEDURE AddSubImm12 (r, imm12: INTEGER; sub: BOOLEAN); +VAR + imm4, imm1, imm3, imm8: INTEGER; + +BEGIN + split16(imm12, imm4, imm1, imm3, imm8); + Code(0F200H + LSL(imm1, 10) + r + 0A0H * ORD(sub)); (* addw/subw r, r, imm12 *) + Code(LSL(imm3, 12) + LSL(r, 8) + imm8) +END AddSubImm12; + + +PROCEDURE MovImm8 (rd, imm8: INTEGER); +BEGIN + gen3(0, rd, imm8) +END MovImm8; + + +PROCEDURE CmpImm8 (rd, imm8: INTEGER); +BEGIN + gen3(1, rd, imm8) +END CmpImm8; + + +PROCEDURE Neg (r: INTEGER); +BEGIN + gen4(9, r, r) +END Neg; + + +PROCEDURE Mul (rd, rs: INTEGER); +BEGIN + gen4(13, rs, rd) +END Mul; + + +PROCEDURE Str32 (rs, rb: INTEGER); +BEGIN + gen9(FALSE, FALSE, 0, rb, rs) +END Str32; + + +PROCEDURE Ldr32 (rd, rb: INTEGER); +BEGIN + gen9(FALSE, TRUE, 0, rb, rd) +END Ldr32; + + +PROCEDURE Str16 (rs, rb: INTEGER); +BEGIN + gen10(FALSE, 0, rb, rs) +END Str16; + + +PROCEDURE Ldr16 (rd, rb: INTEGER); +BEGIN + gen10(TRUE, 0, rb, rd) +END Ldr16; + + +PROCEDURE Str8 (rs, rb: INTEGER); +BEGIN + gen9(TRUE, FALSE, 0, rb, rs) +END Str8; + + +PROCEDURE Ldr8 (rd, rb: INTEGER); +BEGIN + gen9(TRUE, TRUE, 0, rb, rd) +END Ldr8; + + +PROCEDURE Cmp (r1, r2: INTEGER); +BEGIN + gen4(10, r2, r1) +END Cmp; + + +PROCEDURE Tst (r: INTEGER); +BEGIN + gen3(1, r, 0) (* cmp r, 0 *) +END Tst; + + +PROCEDURE LdrSp (r, offset: INTEGER); +BEGIN + gen11(TRUE, r, offset) +END LdrSp; + + +PROCEDURE MovImm32 (r, imm32: INTEGER); +BEGIN + MovImm8(r, LSR(imm32, 24) MOD 256); + LslImm(r, 8); + AddImm8(r, LSR(imm32, 16) MOD 256); + LslImm(r, 8); + AddImm8(r, LSR(imm32, 8) MOD 256); + LslImm(r, 8); + AddImm8(r, imm32 MOD 256) +END MovImm32; + + +PROCEDURE low (x: INTEGER): INTEGER; + RETURN x MOD 65536 +END low; + + +PROCEDURE high (x: INTEGER): INTEGER; + RETURN (x DIV 65536) MOD 65536 +END high; + + +PROCEDURE movwt (r, imm16, t: INTEGER); +VAR + imm1, imm3, imm4, imm8: INTEGER; + +BEGIN + ASSERT(range(r, 3)); + ASSERT(range(imm16, 16)); + ASSERT(range(t, 1)); + split16(imm16, imm4, imm1, imm3, imm8); + Code(0F240H + imm1 * 1024 + t * 128 + imm4); + Code(imm3 * 4096 + r * 256 + imm8); +END movwt; + + +PROCEDURE inv0 (cond: INTEGER): INTEGER; + RETURN ORD(BITS(cond) / {0}) +END inv0; + + +PROCEDURE fixup (CodeAdr, DataAdr, BssAdr: INTEGER); +VAR + code: ANYCODE; + count: INTEGER; + shorted: BOOLEAN; + jump: JUMP; + + reloc, i, diff, len: INTEGER; + + RelocCode: RELOCCODE; + + + PROCEDURE genjcc (cond, offset: INTEGER): INTEGER; + BEGIN + ASSERT(range(cond, 4)); + ASSERT(srange(offset, 8)) + RETURN 0D000H + cond * 256 + offset MOD 256 + END genjcc; + + + PROCEDURE genjmp (offset: INTEGER): INTEGER; + BEGIN + ASSERT(srange(offset, 11)) + RETURN 0E000H + offset MOD 2048 + END genjmp; + + + PROCEDURE movwt (r, imm16, t: INTEGER; VAR code: RELOCCODE); + VAR + imm1, imm3, imm4, imm8: INTEGER; + + BEGIN + split16(imm16, imm4, imm1, imm3, imm8); + code[t * 2] := 0F240H + imm1 * 1024 + t * 128 + imm4; + code[t * 2 + 1] := imm3 * 4096 + r * 256 + imm8 + END movwt; + + + PROCEDURE genmovimm32 (r, value: INTEGER; VAR code: RELOCCODE); + BEGIN + IF _THUMB2 IN Target.InstrSet THEN + movwt(r, low(value), 0, code); + movwt(r, high(value), 1, code) + ELSE + code[0] := 2000H + r * 256 + UTILS.Byte(value, 3); (* movs r, imm8 *) + code[1] := 0200H + r * 9; (* lsls r, 8 *) + code[2] := 3000H + r * 256 + UTILS.Byte(value, 2); (* adds r, imm8 *) + code[3] := code[1]; (* lsls r, 8 *) + code[4] := 3000H + r * 256 + UTILS.Byte(value, 1); (* adds r, imm8 *) + code[5] := code[1]; (* lsls r, 8 *) + code[6] := 3000H + r * 256 + UTILS.Byte(value, 0) (* adds r, imm8 *) + END + END genmovimm32; + + + PROCEDURE PutCode (code: INTEGER); + BEGIN + BIN.PutCode16LE(program, code) + END PutCode; + + + PROCEDURE genlongjmp (offset: INTEGER); + BEGIN + ASSERT(srange(offset, 22)); + PutCode(0F000H + ASR(offset, 11) MOD 2048); + PutCode(0F800H + offset MOD 2048) + END genlongjmp; + + + PROCEDURE genbc (code: JUMP); + BEGIN + CASE code.len OF + |1: PutCode(genjcc(code.cond, code.diff)) + |2: PutCode(genjcc(inv0(code.cond), 0)); + PutCode(genjmp(code.diff)) + |3: PutCode(genjcc(inv0(code.cond), 1)); + genlongjmp(code.diff) + END + END genbc; + + + PROCEDURE SetIV (idx, label, CodeAdr: INTEGER); + VAR + l, h: LISTS.ITEM; + + BEGIN + l := CodeList.first; + h := l.next; + WHILE idx > 0 DO + l := h.next; + h := l.next; + DEC(idx) + END; + label := BIN.GetLabel(program, label) * 2 + CodeAdr + 1; + l(CODE).code := low(label); + h(CODE).code := high(label) + END SetIV; + + +BEGIN + + REPEAT + + shorted := FALSE; + count := 0; + + code := CodeList.first(ANYCODE); + WHILE code # NIL DO + code.offset := count; + + CASE code OF + |CODE: INC(count) + |LABEL: BIN.SetLabel(program, code.label, count) + |JUMP: INC(count, code.len); code.offset := count + ORD(code.short) + |RELOC: INC(count, 7 - ORD(_THUMB2 IN Target.InstrSet) * 3 + code.rel MOD 2) + END; + + code := code.next(ANYCODE) + END; + + code := CodeList.first(ANYCODE); + WHILE code # NIL DO + + IF code IS JUMP THEN + jump := code(JUMP); + jump.diff := BIN.GetLabel(program, jump.label) - jump.offset; + len := jump.len; + diff := jump.diff; + CASE jump OF + |JMP: + IF (len = 2) & srange(diff, 11) THEN + len := 1 + END + + |JCC: + CASE len OF + |1: + |2: IF srange(diff, 8) THEN DEC(len) END + |3: IF srange(diff, 11) THEN DEC(len) END + END + + |CBXZ: + CASE len OF + |1: + |2: IF range(diff, 6) THEN DEC(len) END + |3: IF srange(diff, 8) THEN DEC(len) END + |4: IF srange(diff, 11) THEN DEC(len) END + END + + |CALL: + + END; + IF len # jump.len THEN + jump.len := len; + jump.short := TRUE; + shorted := TRUE + END + END; + + code := code.next(ANYCODE) + END + + UNTIL ~shorted; + + FOR i := 1 TO Target.IVTLen - 1 DO + SetIV(i, IVT[i], CodeAdr) + END; + + code := CodeList.first(ANYCODE); + WHILE code # NIL DO + + CASE code OF + + |CODE: BIN.PutCode16LE(program, code.code) + + |LABEL: + + |JMP: + IF code.len = 1 THEN + PutCode(genjmp(code.diff)) + ELSE + genlongjmp(code.diff) + END + + |JCC: genbc(code) + + |CBXZ: + IF code.len > 1 THEN + PutCode(2800H + code.reg * 256); (* cmp code.reg, 0 *) + DEC(code.len); + genbc(code) + ELSE + (* cb(n)z code.reg, L *) + PutCode(0B100H + 800H * ORD(code.cond = jne) + 200H * (code.diff DIV 32) + (code.diff MOD 32) * 8 + code.reg) + END + + |CALL: genlongjmp(code.diff) + + |RELOC: + CASE code.rel OF + |BIN.RCODE, BIN.PICCODE: reloc := BIN.GetLabel(program, code.value) * 2 + CodeAdr + |BIN.RDATA, BIN.PICDATA: reloc := code.value + DataAdr + |BIN.RBSS, BIN.PICBSS: reloc := code.value + BssAdr + END; + IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN + DEC(reloc, CodeAdr + 2 * (code.offset - 3 * ORD(_THUMB2 IN Target.InstrSet) + 9)) + END; + genmovimm32(code.reg, reloc, RelocCode); + FOR i := 0 TO 6 - 3 * ORD(_THUMB2 IN Target.InstrSet) DO + PutCode(RelocCode[i]) + END; + IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN + PutCode(4478H + code.reg) (* add code.reg, pc *) + END + END; + + code := code.next(ANYCODE) + END + +END fixup; + + +PROCEDURE push (r: INTEGER); +BEGIN + gen14(FALSE, FALSE, {r}) +END push; + + +PROCEDURE pop (r: INTEGER); +BEGIN + gen14(TRUE, FALSE, {r}) +END pop; + + +PROCEDURE mov (r1, r2: INTEGER); +BEGIN + IF (r1 < 8) & (r2 < 8) THEN + gen1(0, 0, r2, r1) + ELSE + gen5(2, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) + END +END mov; + + +PROCEDURE xchg (r1, r2: INTEGER); +BEGIN + push(r1); + mov(r1, r2); + pop(r2) +END xchg; + + +PROCEDURE drop; +BEGIN + REG.Drop(R) +END drop; + + +PROCEDURE GetAnyReg (): INTEGER; + RETURN REG.GetAnyReg(R) +END GetAnyReg; + + +PROCEDURE UnOp (VAR r: INTEGER); +BEGIN + REG.UnOp(R, r) +END UnOp; + + +PROCEDURE BinOp (VAR r1, r2: INTEGER); +BEGIN + REG.BinOp(R, r1, r2) +END BinOp; + + +PROCEDURE PushAll (NumberOfParameters: INTEGER); +BEGIN + REG.PushAll(R); + DEC(R.pushed, NumberOfParameters) +END PushAll; + + +PROCEDURE cond (op: INTEGER): INTEGER; +VAR + res: INTEGER; + +BEGIN + CASE op OF + |IL.opGT, IL.opGTC: res := jg + |IL.opGE, IL.opGEC: res := jge + |IL.opLT, IL.opLTC: res := jl + |IL.opLE, IL.opLEC: res := jle + |IL.opEQ, IL.opEQC: res := je + |IL.opNE, IL.opNEC: res := jne + END + + RETURN res +END cond; + + +PROCEDURE GetRegA; +BEGIN + ASSERT(REG.GetReg(R, ACC)) +END GetRegA; + + +PROCEDURE MovConst (r, c: INTEGER); +BEGIN + IF (0 <= c) & (c <= 255) THEN + MovImm8(r, c) + ELSIF (-255 <= c) & (c < 0) THEN + MovImm8(r, -c); + Neg(r) + ELSIF UTILS.Log2(c) >= 0 THEN + MovImm8(r, 1); + LslImm(r, UTILS.Log2(c)) + ELSIF c = UTILS.min32 THEN + MovImm8(r, 1); + LslImm(r, 31) + ELSE + IF _THUMB2 IN Target.InstrSet THEN + movwt(r, low(c), 0); + IF (c < 0) OR (c > 65535) THEN + movwt(r, high(c), 1) + END + ELSE + MovImm32(r, c) + END + END +END MovConst; + + +PROCEDURE CmpConst (r, c: INTEGER); +VAR + r2: INTEGER; + +BEGIN + IF (0 <= c) & (c <= 255) THEN + CmpImm8(r, c) + ELSE + r2 := GetAnyReg(); + ASSERT(r2 # r); + MovConst(r2, c); + Cmp(r, r2); + drop + END +END CmpConst; + + +PROCEDURE LocalOffset (offset: INTEGER): INTEGER; + RETURN offset + StkCount - ORD(offset > 0) +END LocalOffset; + + +PROCEDURE SetCC (cc, r: INTEGER); +VAR + L1, L2: INTEGER; + +BEGIN + IF _IT IN Target.InstrSet THEN + Code(0BF00H + cc * 16 + ((cc + 1) MOD 2) * 8 + 4); (* ite cc *) + MovConst(r, 1); + MovConst(r, 0) + ELSE + L1 := NewLabel(); + L2 := NewLabel(); + jcc(cc, L1); + MovConst(r, 0); + jmp(L2); + Label(L1); + MovConst(r, 1); + Label(L2) + END +END SetCC; + + +PROCEDURE PushConst (n: INTEGER); +VAR + r: INTEGER; + +BEGIN + r := GetAnyReg(); + MovConst(r, n); + push(r); + drop +END PushConst; + + +PROCEDURE AddConst (r, n: INTEGER); +VAR + r2: INTEGER; + +BEGIN + IF n # 0 THEN + IF (-255 <= n) & (n <= 255) THEN + IF n > 0 THEN + AddImm8(r, n) + ELSE + SubImm8(r, -n) + END + ELSIF (_THUMB2 IN Target.InstrSet) & (-4095 <= n) & (n <= 4095) THEN + AddSubImm12(r, ABS(n), n < 0) + ELSE + r2 := GetAnyReg(); + ASSERT(r2 # r); + IF n > 0 THEN + MovConst(r2, n); + AddReg(r, r, r2) + ELSE + MovConst(r2, -n); + SubReg(r, r, r2) + END; + drop + END + END +END AddConst; + + +PROCEDURE AddHH (r1, r2: INTEGER); +BEGIN + ASSERT((r1 >= 8) OR (r2 >= 8)); + gen5(0, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) +END AddHH; + + +PROCEDURE AddSP (n: INTEGER); +BEGIN + IF n > 0 THEN + IF n < 127 THEN + Code(0B000H + n) (* add sp, n*4 *) + ELSE + ASSERT(R2 IN R.regs); + MovConst(R2, n * 4); + AddHH(SP, R2) + END; + DEC(StkCount, n) + END +END AddSP; + + +PROCEDURE cbxz2 (c, r, label: INTEGER); +BEGIN + IF _CBXZ IN Target.InstrSet THEN + cbxz(c, r, label) + ELSE + Tst(r); + jcc(c, label) + END +END cbxz2; + + +PROCEDURE cbz (r, label: INTEGER); +BEGIN + cbxz2(je, r, label) +END cbz; + + +PROCEDURE cbnz (r, label: INTEGER); +BEGIN + cbxz2(jne, r, label) +END cbnz; + + +PROCEDURE Shift (op, r1, r2: INTEGER); +VAR + L: INTEGER; + +BEGIN + LslImm(r2, 27); + LsrImm(r2, 27); + L := NewLabel(); + cbz(r2, L); + CASE op OF + |IL.opLSL, IL.opLSL1: gen4(2, r2, r1) + |IL.opLSR, IL.opLSR1: gen4(3, r2, r1) + |IL.opASR, IL.opASR1: gen4(4, r2, r1) + |IL.opROR, IL.opROR1: gen4(7, r2, r1) + END; + Label(L) +END Shift; + + +PROCEDURE LocAdr (offs: INTEGER); +VAR + r1, n: INTEGER; + +BEGIN + r1 := GetAnyReg(); + n := LocalOffset(offs); + IF n <= 255 THEN + gen12(TRUE, r1, n) + ELSE + MovConst(r1, n * 4); + AddHH(r1, SP) + END +END LocAdr; + + +PROCEDURE CallRTL (proc, par: INTEGER); +BEGIN + call(IL.codes.rtl[proc]); + AddSP(par) +END CallRTL; + + +PROCEDURE divmod; +BEGIN + call(sdivProc); + AddSP(2) +END divmod; + + +PROCEDURE cpsid_i; +BEGIN + Code(0B672H) (* cpsid i *) +END cpsid_i; + + +PROCEDURE cpsie_i; +BEGIN + Code(0B662H) (* cpsie i *) +END cpsie_i; + + +PROCEDURE translate (pic, stroffs: INTEGER); +VAR + cmd, next: COMMAND; + opcode, param1, param2: INTEGER; + + r1, r2, r3: INTEGER; + + a, n, cc, L, L2: INTEGER; + +BEGIN + cmd := IL.codes.commands.first(COMMAND); + + WHILE cmd # NIL DO + + param1 := cmd.param1; + param2 := cmd.param2; + opcode := cmd.opcode; + + CASE opcode OF + + |IL.opJMP: + jmp(param1) + + |IL.opLABEL: + Label(param1) + + |IL.opHANDLER: + IF param2 = 0 THEN + int0 := param1 + ELSIF param2 = 1 THEN + trap := param1 + ELSE + IVT[param2] := param1 + END + + |IL.opCALL: + call(param1) + + |IL.opCALLP: + UnOp(r1); + AddImm8(r1, 1); (* Thumb mode *) + gen5(3, TRUE, FALSE, r1, 0); (* blx r1 *) + drop; + ASSERT(R.top = -1) + + |IL.opENTER: + ASSERT(R.top = -1); + + Label(param1); + + gen14(FALSE, TRUE, {}); (* push {lr} *) + + n := param2; + IF n >= 5 THEN + MovConst(ACC, 0); + MovConst(R2, n); + L := NewLabel(); + Label(L); + push(ACC); + SubImm8(R2, 1); + Tst(R2); + jcc(jne, L) + ELSIF n > 0 THEN + MovConst(ACC, 0); + WHILE n > 0 DO + push(ACC); + DEC(n) + END + END; + StkCount := param2 + + |IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: + IF opcode # IL.opLEAVE THEN + UnOp(r1); + IF r1 # ACC THEN + mov(ACC, r1) + END; + drop + END; + + ASSERT(R.top = -1); + ASSERT(StkCount = param1); + + AddSP(param1); + gen14(TRUE, TRUE, {}) (* pop {pc} *) + + |IL.opLEAVEC: + gen5(3, FALSE, TRUE, 6, 0) (* bx lr *) + + |IL.opPRECALL: + PushAll(0) + + |IL.opPARAM: + n := param2; + IF n = 1 THEN + UnOp(r1); + push(r1); + drop + ELSE + ASSERT(R.top + 1 <= n); + PushAll(n) + END + + |IL.opCLEANUP: + AddSP(param2) + + |IL.opRES, IL.opRESF: + ASSERT(R.top = -1); + GetRegA + + |IL.opPUSHC: + PushConst(param2) + + |IL.opONERR: + cpsid_i; + MovConst(R0, param2); + push(R0); + DEC(StkCount); + jmp(param1) + + |IL.opERR: + call(genTrap) + + |IL.opNOP, IL.opAND, IL.opOR: + + |IL.opSADR: + reloc(GetAnyReg(), BIN.RDATA + pic, stroffs + param2) + + |IL.opGADR: + reloc(GetAnyReg(), BIN.RBSS + pic, param2) + + |IL.opLADR: + LocAdr(param2) + + |IL.opGLOAD32: + r1 := GetAnyReg(); + reloc(r1, BIN.RBSS + pic, param2); + Ldr32(r1, r1) + + |IL.opGLOAD16: + r1 := GetAnyReg(); + reloc(r1, BIN.RBSS + pic, param2); + Ldr16(r1, r1) + + |IL.opGLOAD8: + r1 := GetAnyReg(); + reloc(r1, BIN.RBSS + pic, param2); + Ldr8(r1, r1) + + |IL.opLADR_SAVE: + UnOp(r1); + n := LocalOffset(param2); + IF n <= 255 THEN + gen11(FALSE, r1, n) (* str r1, [sp, n*4] *) + ELSE + LocAdr(param2); + BinOp(r1, r2); + Str32(r1, r2); + drop + END; + drop + + |IL.opLADR_INCC: + n := LocalOffset(param1); + IF n <= 255 THEN + r1 := GetAnyReg(); + LdrSp(r1, n); + AddConst(r1, param2); + gen11(FALSE, r1, n) (* str r1, [sp, n*4] *) + ELSE + LocAdr(param1); + r1 := GetAnyReg(); + BinOp(r2, r1); + Ldr32(r1, r2); + AddConst(r1, param2); + BinOp(r2, r1); + Str32(r1, r2); + drop + END; + drop + + |IL.opLLOAD32, IL.opVADR, IL.opVLOAD32: + r1 := GetAnyReg(); + n := LocalOffset(param2); + IF n <= 255 THEN + LdrSp(r1, n) + ELSE + drop; + LocAdr(param2); + UnOp(r1); + Ldr32(r1, r1) + END; + IF opcode = IL.opVLOAD32 THEN + Ldr32(r1, r1) + END + + |IL.opLLOAD16: + LocAdr(param2); + UnOp(r1); + Ldr16(r1, r1) + + |IL.opLLOAD8: + LocAdr(param2); + UnOp(r1); + Ldr8(r1, r1) + + |IL.opLOAD32, IL.opLOADF: + UnOp(r1); + Ldr32(r1, r1) + + |IL.opLOAD16: + UnOp(r1); + Ldr16(r1, r1) + + |IL.opLOAD8: + UnOp(r1); + Ldr8(r1, r1) + + |IL.opVLOAD16: + LocAdr(param2); + UnOp(r1); + Ldr32(r1, r1); + Ldr16(r1, r1) + + |IL.opVLOAD8: + LocAdr(param2); + UnOp(r1); + Ldr32(r1, r1); + Ldr8(r1, r1) + + |IL.opSBOOL: + BinOp(r2, r1); + Tst(r2); + SetCC(jne, r2); + Str8(r2, r1); + drop; + drop + + |IL.opSBOOLC: + UnOp(r1); + r2 := GetAnyReg(); + MovConst(r2, ORD(param2 # 0)); + Str8(r2, r1); + drop; + drop + + |IL.opSAVEC: + UnOp(r1); + r2 := GetAnyReg(); + MovConst(r2, param2); + Str32(r2, r1); + drop; + drop + + |IL.opSAVE16C: + UnOp(r1); + r2 := GetAnyReg(); + MovConst(r2, low(param2)); + Str16(r2, r1); + drop; + drop + + |IL.opSAVE8C: + UnOp(r1); + r2 := GetAnyReg(); + MovConst(r2, param2 MOD 256); + Str8(r2, r1); + drop; + drop + + |IL.opSAVE, IL.opSAVE32, IL.opSAVEF: + BinOp(r2, r1); + Str32(r2, r1); + drop; + drop + + |IL.opSAVEFI: + BinOp(r2, r1); + Str32(r1, r2); + drop; + drop + + |IL.opSAVE16: + BinOp(r2, r1); + Str16(r2, r1); + drop; + drop + + |IL.opSAVE8: + BinOp(r2, r1); + Str8(r2, r1); + drop; + drop + + |IL.opSAVEP: + UnOp(r1); + r2 := GetAnyReg(); + reloc(r2, BIN.RCODE + pic, param2); + Str32(r2, r1); + drop; + drop + + |IL.opPUSHP: + reloc(GetAnyReg(), BIN.RCODE + pic, param2) + + |IL.opEQB, IL.opNEB: + BinOp(r1, r2); + drop; + + L := NewLabel(); + cbz(r1, L); + MovConst(r1, 1); + Label(L); + + L := NewLabel(); + cbz(r2, L); + MovConst(r2, 1); + Label(L); + + Cmp(r1, r2); + IF opcode = IL.opEQB THEN + SetCC(je, r1) + ELSE + SetCC(jne, r1) + END + + |IL.opDROP: + UnOp(r1); + drop + + |IL.opJNZ1: + UnOp(r1); + cbnz(r1, param1) + + |IL.opJG: + UnOp(r1); + Tst(r1); + jcc(jg, param1) + + |IL.opJNZ: + UnOp(r1); + cbnz(r1, param1); + drop + + |IL.opJZ: + UnOp(r1); + cbz(r1, param1); + drop + + |IL.opSWITCH: + UnOp(r1); + IF param2 = 0 THEN + r2 := ACC + ELSE + r2 := R2 + END; + IF r1 # r2 THEN + ASSERT(REG.GetReg(R, r2)); + ASSERT(REG.Exchange(R, r1, r2)); + drop + END; + drop + + |IL.opENDSW: + + |IL.opCASEL: + GetRegA; + CmpConst(ACC, param1); + jcc(jl, param2); + drop + + |IL.opCASER: + GetRegA; + CmpConst(ACC, param1); + jcc(jg, param2); + drop + + |IL.opCASELR: + GetRegA; + CmpConst(ACC, param1); + IF param2 = cmd.param3 THEN + jcc(jne, param2) + ELSE + jcc(jl, param2); + jcc(jg, cmd.param3) + END; + drop + + |IL.opCODE: + Code(param2) + + |IL.opEQ..IL.opGE, + IL.opEQC..IL.opGEC: + IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN + BinOp(r1, r2); + Cmp(r1, r2); + drop + ELSE + UnOp(r1); + CmpConst(r1, param2) + END; + + drop; + cc := cond(opcode); + next := cmd.next(COMMAND); + + IF next.opcode = IL.opJNZ THEN + jcc(cc, next.param1); + cmd := next + ELSIF next.opcode = IL.opJZ THEN + jcc(inv0(cc), next.param1); + cmd := next + ELSE + SetCC(cc, GetAnyReg()) + END + + |IL.opINCC: + UnOp(r1); + r2 := GetAnyReg(); + Ldr32(r2, r1); + AddConst(r2, param2); + Str32(r2, r1); + drop; + drop + + |IL.opINCCB, IL.opDECCB: + IF opcode = IL.opDECCB THEN + param2 := -param2 + END; + UnOp(r1); + r2 := GetAnyReg(); + Ldr8(r2, r1); + AddConst(r2, param2); + Str8(r2, r1); + drop; + drop + + |IL.opUMINUS: + UnOp(r1); + Neg(r1) + + |IL.opADD: + BinOp(r1, r2); + CASE cmd.next(COMMAND).opcode OF + |IL.opLOAD32, IL.opLOADF: + gen7(TRUE, FALSE, r2, r1, r1); (* ldr r1, [r1, r2] *) + cmd := cmd.next(COMMAND) + |IL.opLOAD8: + gen7(TRUE, TRUE, r2, r1, r1); (* ldrb r1, [r1, r2] *) + cmd := cmd.next(COMMAND) + |IL.opLOAD16: + gen8(TRUE, FALSE, r2, r1, r1); (* ldrh r1, [r1, r2] *) + cmd := cmd.next(COMMAND) + ELSE + AddReg(r1, r1, r2) + END; + drop + + |IL.opADDC: + UnOp(r1); + AddConst(r1, param2) + + |IL.opSUB: + BinOp(r1, r2); + SubReg(r1, r1, r2); + drop + + |IL.opSUBL, IL.opSUBR: + UnOp(r1); + AddConst(r1, -param2); + IF opcode = IL.opSUBL THEN + Neg(r1) + END + + |IL.opMUL: + BinOp(r1, r2); + Mul(r1, r2); + drop + + |IL.opMULC: + UnOp(r1); + + a := param2; + IF a > 1 THEN + n := UTILS.Log2(a) + ELSIF a < -1 THEN + n := UTILS.Log2(-a) + ELSE + n := -1 + END; + + IF a = 1 THEN + + ELSIF a = -1 THEN + Neg(r1) + ELSIF a = 0 THEN + MovConst(r1, 0) + ELSE + IF n > 0 THEN + IF a < 0 THEN + Neg(r1) + END; + LslImm(r1, n) + ELSE + r2 := GetAnyReg(); + MovConst(r2, a); + Mul(r1, r2); + drop + END + END + + |IL.opABS: + UnOp(r1); + Tst(r1); + L := NewLabel(); + jcc(jge, L); + Neg(r1); + Label(L) + + |IL.opNOT: + UnOp(r1); + Tst(r1); + SetCC(je, r1) + + |IL.opORD: + UnOp(r1); + Tst(r1); + SetCC(jne, r1) + + |IL.opCHR: + UnOp(r1); + Code(0B2C0H + r1 * 9) (* uxtb r1, r1 *) + + |IL.opWCHR: + UnOp(r1); + Code(0B280H + r1 * 9) (* uxth r1, r1 *) + + |IL.opASR, IL.opROR, IL.opLSL, IL.opLSR: + BinOp(r1, r2); + Shift(opcode, r1, r2); + drop + + |IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1: + MovConst(GetAnyReg(), param2); + BinOp(r2, r1); + Shift(opcode, r1, r2); + INCL(R.regs, r2); + DEC(R.top); + R.stk[R.top] := r1 + + |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: + n := param2 MOD 32; + IF n # 0 THEN + UnOp(r1); + CASE opcode OF + |IL.opASR2: AsrImm(r1, n) + |IL.opROR2: r2 := GetAnyReg(); MovConst(r2, n); Shift(IL.opROR, r1, r2); drop + |IL.opLSL2: LslImm(r1, n) + |IL.opLSR2: LsrImm(r1, n) + END + END + + |IL.opCHKBYTE: + BinOp(r1, r2); + CmpConst(r1, 256); + jcc(jb, param1) + + |IL.opCHKIDX: + UnOp(r1); + CmpConst(r1, param2); + jcc(jb, param1) + + |IL.opCHKIDX2: + BinOp(r1, r2); + IF param2 # -1 THEN + Cmp(r2, r1); + jcc(jb, param1) + END; + INCL(R.regs, r1); + DEC(R.top); + R.stk[R.top] := r2 + + |IL.opLEN: + n := param2; + UnOp(r1); + drop; + EXCL(R.regs, r1); + + WHILE n > 0 DO + UnOp(r2); + drop; + DEC(n) + END; + + INCL(R.regs, r1); + ASSERT(REG.GetReg(R, r1)) + + |IL.opINF: + MovConst(GetAnyReg(), inf) + + |IL.opPUSHF: + UnOp(r1); + push(r1); + drop + + |IL.opCONST: + MovConst(GetAnyReg(), param2) + + |IL.opEQP, IL.opNEP: + reloc(GetAnyReg(), BIN.RCODE + pic, param1); + BinOp(r1, r2); + Cmp(r1, r2); + drop; + IF opcode = IL.opEQP THEN + SetCC(je, r1) + ELSE + SetCC(jne, r1) + END + + |IL.opPUSHT: + UnOp(r1); + r2 := GetAnyReg(); + mov(r2, r1); + SubImm8(r2, 4); + Ldr32(r2, r2) + + |IL.opGET, IL.opGETC: + IF opcode = IL.opGET THEN + BinOp(r1, r2) + ELSIF opcode = IL.opGETC THEN + UnOp(r2); + r1 := GetAnyReg(); + MovConst(r1, param1) + END; + drop; + drop; + + CASE param2 OF + |1: Ldr8(r1, r1); Str8(r1, r2) + |2: Ldr16(r1, r1); Str16(r1, r2) + |4: Ldr32(r1, r1); Str32(r1, r2) + END + + |IL.opINC, IL.opDEC: + BinOp(r2, r1); + r3 := GetAnyReg(); + Ldr32(r3, r1); + IF opcode = IL.opINC THEN + AddReg(r3, r3, r2) + ELSE + SubReg(r3, r3, r2) + END; + Str32(r3, r1); + drop; + drop; + drop + + |IL.opINCB, IL.opDECB: + BinOp(r2, r1); + r3 := GetAnyReg(); + Ldr8(r3, r1); + IF opcode = IL.opINCB THEN + AddReg(r3, r3, r2) + ELSE + SubReg(r3, r3, r2) + END; + Str8(r3, r1); + drop; + drop; + drop + + |IL.opMIN, IL.opMAX: + BinOp(r1, r2); + Cmp(r1, r2); + L := NewLabel(); + IF opcode = IL.opMIN THEN + cc := jle + ELSE + cc := jge + END; + jcc(cc, L); + mov(r1, r2); + Label(L); + drop + + |IL.opMINC, IL.opMAXC: + UnOp(r1); + CmpConst(r1, param2); + L := NewLabel(); + IF opcode = IL.opMINC THEN + cc := jle + ELSE + cc := jge + END; + jcc(cc, L); + MovConst(r1, param2); + Label(L) + + |IL.opMULS: + BinOp(r1, r2); + gen4(0, r2, r1); (* ands r1, r2 *) + drop + + |IL.opMULSC: + MovConst(GetAnyReg(), param2); + BinOp(r1, r2); + gen4(0, r2, r1); (* ands r1, r2 *) + drop + + |IL.opDIVS: + BinOp(r1, r2); + gen4(1, r2, r1); (* eors r1, r2 *) + drop + + |IL.opDIVSC: + MovConst(GetAnyReg(), param2); + BinOp(r1, r2); + gen4(1, r2, r1); (* eors r1, r2 *) + drop + + |IL.opADDS: + BinOp(r1, r2); + gen4(12, r2, r1); (* orrs r1, r2 *) + drop + + |IL.opSUBS: + BinOp(r1, r2); + gen4(14, r2, r1); (* bics r1, r2 *) + drop + + |IL.opADDSC: + MovConst(GetAnyReg(), param2); + BinOp(r1, r2); + gen4(12, r2, r1); (* orrs r1, r2 *) + drop + + |IL.opSUBSL: + MovConst(GetAnyReg(), param2); + BinOp(r1, r2); + gen4(14, r1, r2); (* bics r2, r1 *) + INCL(R.regs, r1); + DEC(R.top); + R.stk[R.top] := r2 + + |IL.opSUBSR: + MovConst(GetAnyReg(), param2); + BinOp(r1, r2); + gen4(14, r2, r1); (* bics r1, r2 *) + drop + + |IL.opUMINS: + UnOp(r1); + gen4(15, r1, r1) (* mvns r1, r1 *) + + |IL.opINCL, IL.opEXCL: + BinOp(r1, r2); + r3 := GetAnyReg(); + MovConst(r3, 1); + CmpConst(r1, 32); + L := NewLabel(); + jcc(jnb, L); + gen4(2, r1, r3); (* lsls r3, r1 *) + Ldr32(r1, r2); + IF opcode = IL.opINCL THEN + gen4(12, r3, r1) (* orrs r1, r3 *) + ELSE + gen4(14, r3, r1) (* bics r1, r3 *) + END; + Str32(r1, r2); + Label(L); + drop; + drop; + drop + + |IL.opINCLC, IL.opEXCLC: + UnOp(r2); + r1 := GetAnyReg(); + r3 := GetAnyReg(); + MovConst(r3, 1); + LslImm(r3, param2); + Ldr32(r1, r2); + IF opcode = IL.opINCLC THEN + gen4(12, r3, r1) (* orrs r1, r3 *) + ELSE + gen4(14, r3, r1) (* bics r1, r3 *) + END; + Str32(r1, r2); + drop; + drop; + drop + + |IL.opLENGTH: + PushAll(2); + CallRTL(IL._length, 2); + GetRegA + + |IL.opLENGTHW: + PushAll(2); + CallRTL(IL._lengthw, 2); + GetRegA + + |IL.opSAVES: + UnOp(r2); + REG.PushAll_1(R); + r1 := GetAnyReg(); + reloc(r1, BIN.RDATA + pic, stroffs + param2); + push(r1); + drop; + push(r2); + drop; + PushConst(param1); + CallRTL(IL._move, 3) + + |IL.opEQS .. IL.opGES: + PushAll(4); + PushConst(opcode - IL.opEQS); + CallRTL(IL._strcmp, 5); + GetRegA + + |IL.opEQSW .. IL.opGESW: + PushAll(4); + PushConst(opcode - IL.opEQSW); + CallRTL(IL._strcmpw, 5); + GetRegA + + |IL.opCOPY: + PushAll(2); + PushConst(param2); + CallRTL(IL._move, 3) + + |IL.opMOVE: + PushAll(3); + CallRTL(IL._move, 3) + + |IL.opCOPYA: + PushAll(4); + PushConst(param2); + CallRTL(IL._arrcpy, 5); + GetRegA + + |IL.opCOPYS: + PushAll(4); + PushConst(param2); + CallRTL(IL._strcpy, 5) + + |IL.opDIV: + PushAll(2); + divmod; + GetRegA + + |IL.opDIVL: + UnOp(r1); + REG.PushAll_1(R); + PushConst(param2); + push(r1); + drop; + divmod; + GetRegA + + |IL.opDIVR: + n := UTILS.Log2(param2); + IF n > 0 THEN + UnOp(r1); + AsrImm(r1, n) + ELSIF n < 0 THEN + PushAll(1); + PushConst(param2); + divmod; + GetRegA + END + + |IL.opMOD: + PushAll(2); + divmod; + mov(R0, R1); + GetRegA + + |IL.opMODR: + n := UTILS.Log2(param2); + IF n > 0 THEN + UnOp(r1); + IF n = 8 THEN + Code(0B2C0H + r1 * 9) (* uxtb r1, r1 *) + ELSIF n = 16 THEN + Code(0B280H + r1 * 9) (* uxth r1, r1 *) + ELSE + LslImm(r1, 32 - n); + LsrImm(r1, 32 - n) + END + ELSIF n < 0 THEN + PushAll(1); + PushConst(param2); + divmod; + mov(R0, R1); + GetRegA + ELSE + UnOp(r1); + MovConst(r1, 0) + END + + |IL.opMODL: + UnOp(r1); + REG.PushAll_1(R); + PushConst(param2); + push(r1); + drop; + divmod; + mov(R0, R1); + GetRegA + + |IL.opIN, IL.opINR: + IF opcode = IL.opINR THEN + r2 := GetAnyReg(); + MovConst(r2, param2) + END; + L := NewLabel(); + L2 := NewLabel(); + BinOp(r1, r2); + r3 := GetAnyReg(); + CmpConst(r1, 32); + jcc(jb, L); + MovConst(r1, 0); + jmp(L2); + Label(L); + MovConst(r3, 1); + Shift(IL.opLSL, r3, r1); + gen4(0, r3, r2); (* ands r2, r3 *) + SetCC(jne, r1); + Label(L2); + drop; + drop + + |IL.opINL: + UnOp(r1); + r2 := GetAnyReg(); + MovConst(r2, LSL(1, param2)); + gen4(0, r2, r1); (* ands r1, r2 *) + SetCC(jne, r1); + drop + + |IL.opRSET: + PushAll(2); + CallRTL(IL._set, 2); + GetRegA + + |IL.opRSETR: + PushAll(1); + PushConst(param2); + CallRTL(IL._set, 2); + GetRegA + + |IL.opRSETL: + UnOp(r1); + REG.PushAll_1(R); + PushConst(param2); + push(r1); + drop; + CallRTL(IL._set, 2); + GetRegA + + |IL.opRSET1: + PushAll(1); + CallRTL(IL._set1, 1); + GetRegA + + |IL.opCONSTF: + MovConst(GetAnyReg(), UTILS.d2s(cmd.float)) + + |IL.opMULF: + PushAll(2); + CallRTL(IL._fmul, 2); + GetRegA + + |IL.opDIVF: + PushAll(2); + CallRTL(IL._fdiv, 2); + GetRegA + + |IL.opDIVFI: + PushAll(2); + CallRTL(IL._fdivi, 2); + GetRegA + + |IL.opADDF: + PushAll(2); + CallRTL(IL._fadd, 2); + GetRegA + + |IL.opSUBFI: + PushAll(2); + CallRTL(IL._fsubi, 2); + GetRegA + + |IL.opSUBF: + PushAll(2); + CallRTL(IL._fsub, 2); + GetRegA + + |IL.opEQF..IL.opGEF: + PushAll(2); + PushConst(opcode - IL.opEQF); + CallRTL(IL._fcmp, 3); + GetRegA + + |IL.opFLOOR: + PushAll(1); + CallRTL(IL._floor, 1); + GetRegA + + |IL.opFLT: + PushAll(1); + CallRTL(IL._flt, 1); + GetRegA + + |IL.opUMINF: + UnOp(r1); + r2 := GetAnyReg(); + MovConst(r2, 1); + LslImm(r2, 31); + gen4(1, r2, r1); (* eors r1, r2 *) + drop + + |IL.opFABS: + UnOp(r1); + r2 := GetAnyReg(); + MovConst(r2, 1); + LslImm(r2, 31); + gen4(14, r2, r1); (* bics r1, r2 *) + drop + + |IL.opNEW: + cpsid_i; + PushAll(1); + n := param2 + 4; + ASSERT(UTILS.Align(n, 4)); + PushConst(n); + PushConst(param1); + CallRTL(IL._new, 3); + cpsie_i + + |IL.opTYPEGP: + UnOp(r1); + PushAll(0); + push(r1); + PushConst(param2); + CallRTL(IL._guard, 2); + GetRegA + + |IL.opIS: + PushAll(1); + PushConst(param2); + CallRTL(IL._is, 2); + GetRegA + + |IL.opISREC: + PushAll(2); + PushConst(param2); + CallRTL(IL._guardrec, 3); + GetRegA + + |IL.opTYPEGR: + PushAll(1); + PushConst(param2); + CallRTL(IL._guardrec, 2); + GetRegA + + |IL.opTYPEGD: + UnOp(r1); + PushAll(0); + SubImm8(r1, 4); + Ldr32(r1, r1); + push(r1); + PushConst(param2); + CallRTL(IL._guardrec, 2); + GetRegA + + |IL.opCASET: + push(R2); + push(R2); + PushConst(param2); + CallRTL(IL._guardrec, 2); + pop(R2); + cbnz(ACC, param1) + + |IL.opROT: + PushAll(0); + mov(R2, SP); + push(R2); + PushConst(param2); + CallRTL(IL._rot, 2) + + |IL.opPACK: + PushAll(2); + CallRTL(IL._pack, 2) + + |IL.opPACKC: + PushAll(1); + PushConst(param2); + CallRTL(IL._pack, 2) + + |IL.opUNPK: + PushAll(2); + CallRTL(IL._unpk, 2) + + END; + + cmd := cmd.next(COMMAND) + END; + + ASSERT(R.pushed = 0); + ASSERT(R.top = -1) +END translate; + + +PROCEDURE prolog (GlobSize, tcount, pic, sp, ivt_len: INTEGER); +VAR + r1, r2, i, dcount: INTEGER; + +BEGIN + entry := NewLabel(); + emptyProc := NewLabel(); + genInt := NewLabel(); + genTrap := NewLabel(); + sdivProc := NewLabel(); + + trap := emptyProc; + int0 := emptyProc; + + IVT[0] := sp; + IVT[1] := entry; + FOR i := 2 TO ivt_len - 1 DO + IVT[i] := genInt + END; + + FOR i := 0 TO ivt_len - 1 DO + Code(low(IVT[i])); + Code(high(IVT[i])) + END; + + Label(entry); + cpsie_i; + + r1 := GetAnyReg(); + r2 := GetAnyReg(); + reloc(r1, BIN.RDATA + pic, 0); + + FOR i := 0 TO tcount - 1 DO + MovConst(r2, CHL.GetInt(IL.codes.types, i)); + Str32(r2, r1); + AddImm8(r1, 4) + END; + + dcount := CHL.Length(IL.codes.data); + FOR i := 0 TO dcount - 1 BY 4 DO + MovConst(r2, BIN.get32le(IL.codes.data, i)); + Str32(r2, r1); + AddImm8(r1, 4) + END; + + drop; + drop; + + r1 := GetAnyReg(); + MovConst(r1, sp); + mov(SP, r1); + reloc(r1, BIN.RDATA + pic, 0); + push(r1); + reloc(r1, BIN.RBSS + pic, 0); + r2 := GetAnyReg(); + MovConst(r2, GlobSize); + AddReg(r1, r1, r2); + drop; + push(r1); + drop; + PushConst(tcount); + CallRTL(IL._init, 3) +END prolog; + + +PROCEDURE epilog; +VAR + L1, L2, L3, L4: INTEGER; + +BEGIN + (* L2: *) + Code(0E7FEH); (* b L2 *) + + Label(genInt); + Code(0F3EFH); Code(08005H); (* mrs r0, ipsr *) + gen14(FALSE, TRUE, {R0}); (* push {lr, r0} *) + call(int0); + gen14(TRUE, TRUE, {R0}); (* pop {pc, r0} *) + + Label(emptyProc); + Code(04770H); (* bx lr *) + + Label(genTrap); + call(trap); + call(entry); + + Label(sdivProc); + IF _SDIV IN Target.InstrSet THEN + Code(09800H); (* ldr r0, [sp] *) + Code(09901H); (* ldr r1, [sp, 4] *) + Code(0FB91H); (* sdiv r2, r1, r0 *) + Code(0F2F0H); + Code(00013H); (* movs r3, r2 *) + Code(04343H); (* muls r3, r0, r3 *) + Code(01AC9H); (* subs r1, r1, r3 *) + Code(0DA01H); (* bge L *) + Code(01809H); (* adds r1, r1, r0 *) + Code(03A01H); (* subs r2, 1 *) + (* L: *) + Code(00010H); (* movs r0, r2 *) + Code(04770H); (* bx lr *) + ELSE + (* a / b; a >= 0 *) + L1 := NewLabel(); + L2 := NewLabel(); + L3 := NewLabel(); + L4 := NewLabel(); + + LdrSp(R1, 1); + LdrSp(R2, 0); + MovConst(R0, 0); + push(R4); + + Label(L4); + Cmp(R1, R2); + jcc(jl, L1); + MovConst(R3, 2); + mov(R4, R2); + LslImm(R4, 1); + Label(L3); + Cmp(R1, R4); + jcc(jl, L2); + CmpConst(R4, 0); + jcc(jle, L2); + LslImm(R4, 1); + LslImm(R3, 1); + jmp(L3); + Label(L2); + LsrImm(R4, 1); + LsrImm(R3, 1); + SubReg(R1, R1, R4); + AddReg(R0, R0, R3); + jmp(L4); + Label(L1); + + (* a / b; a < 0 *) + L1 := NewLabel(); + L2 := NewLabel(); + L3 := NewLabel(); + L4 := NewLabel(); + + Label(L4); + CmpConst(R1, 0); + jcc(jge, L1); + MovConst(R3, 2); + mov(R4, R2); + LslImm(R4, 1); + Neg(R1); + Label(L3); + Cmp(R1, R4); + jcc(jl, L2); + CmpConst(R4, 0); + jcc(jle, L2); + LslImm(R4, 1); + LslImm(R3, 1); + jmp(L3); + Label(L2); + Neg(R1); + LsrImm(R4, 1); + LsrImm(R3, 1); + AddReg(R1, R1, R4); + SubReg(R0, R0, R3); + jmp(L4); + Label(L1); + + pop(R4); + Code(04770H); (* bx lr *) + END + +END epilog; + + +PROCEDURE SetTarget (FlashStart, SRAMStart: INTEGER; InstrSet: SET; isNXP: BOOLEAN); +BEGIN + Target.FlashAdr := FlashStart; + Target.SRAMAdr := SRAMStart; + Target.InstrSet := InstrSet; + Target.isNXP := isNXP; + + Target.IVTLen := 256; (* >= 192 *) + Target.Reserved := 0; + Target.MinStack := 512; +END SetTarget; + + +PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); +VAR + opt: PROG.OPTIONS; + + ram, rom, i, j: INTEGER; + + DataAdr, BssAdr, DataSize, BssSize, CodeSize: INTEGER; + +BEGIN + ram := MIN(MAX(options.ram, minRAM), maxRAM) * 1024; + rom := MIN(MAX(options.rom, minROM), maxROM) * 1024; + + IF target = TARGETS.STM32CM3 THEN + SetTarget(08000000H, 20000000H, CortexM3, FALSE) + END; + + tcount := CHL.Length(IL.codes.types); + + opt := options; + CodeList := LISTS.create(NIL); + + program := BIN.create(IL.codes.lcount); + + REG.Init(R, push, pop, mov, xchg, {R0, R1, R2, R3}); + + StkCount := 0; + + DataAdr := Target.SRAMAdr + Target.Reserved; + DataSize := CHL.Length(IL.codes.data) + tcount * 4 + Target.Reserved; + WHILE DataSize MOD 4 # 0 DO + CHL.PushByte(IL.codes.data, 0); + INC(DataSize) + END; + BssAdr := DataAdr + DataSize - Target.Reserved; + + IL.set_bss(MAX(IL.codes.bss, MAX(IL.codes.dmin - CHL.Length(IL.codes.data), 4))); + + BssSize := IL.codes.bss; + ASSERT(UTILS.Align(BssSize, 4)); + + prolog(BssSize, tcount, ORD(opt.pic), Target.SRAMAdr + ram, Target.IVTLen); + translate(ORD(opt.pic), tcount * 4); + epilog; + + fixup(Target.FlashAdr, DataAdr, BssAdr); + + INC(DataSize, BssSize); + CodeSize := CHL.Length(program.code); + + IF CodeSize > rom THEN + ERRORS.Error(203) + END; + + IF DataSize > ram - Target.MinStack THEN + ERRORS.Error(204) + END; + + IF Target.isNXP THEN + BIN.put32le(program.code, 2FCH, 0H); (* code read protection (CRP) *) + (* NXP checksum *) + j := 0; + FOR i := 0 TO 6 DO + INC(j, BIN.get32le(program.code, i * 4)) + END; + BIN.put32le(program.code, 1CH, -j) + END; + + WR.Create(outname); + + HEX.Data2(program.code, 0, CodeSize, high(Target.FlashAdr)); + HEX.End; + + WR.Close; + + C.Dashes; + C.String( " rom: "); C.Int(CodeSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(CodeSize * 100 DIV rom); C.StringLn("%)"); + C.Ln; + C.String( " ram: "); C.Int(DataSize); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(DataSize * 100 DIV ram); C.StringLn("%)") +END CodeGen; + + +PROCEDURE SetIV* (idx: INTEGER): BOOLEAN; +VAR + res: BOOLEAN; + +BEGIN + res := IVT[idx] = 0; + IVT[idx] := 1 + + RETURN res +END SetIV; + + +PROCEDURE init; +VAR + i: INTEGER; + +BEGIN + FOR i := 0 TO LEN(IVT) - 1 DO + IVT[i] := 0 + END +END init; + + +BEGIN + init END THUMB. \ No newline at end of file diff --git a/programs/develop/oberon07/source/UTILS.ob07 b/programs/develop/oberon07/source/UTILS.ob07 index d854e0639f..1261e8df52 100644 --- a/programs/develop/oberon07/source/UTILS.ob07 +++ b/programs/develop/oberon07/source/UTILS.ob07 @@ -23,8 +23,8 @@ CONST max32* = 2147483647; vMajor* = 1; - vMinor* = 52; - Date* = "07-may-2021"; + vMinor* = 53; + Date* = "26-aug-2021"; FILE_EXT* = ".ob07"; RTL_NAME* = "RTL";