GeneratorD7 (GEN00) uGEN00_a.pas unit uGEN00_a; interface type string255 = string[255]; { Основні процедури для користувача } {1} Procedure INITCompiler; {2} Function FINALCompiler: Boolean; { True – компіляція успішна; False – є помилки } {3} Procedure DB(e: Cardinal); { додати байт } {4} Procedure REM(s: string255); { ремарка } {5} Procedure DW(e: Cardinal); {6} Procedure SetAddrCompile(e: Cardinal); { встановити адресу для компіляції } {7} Procedure DD(e: Cardinal); {8} Procedure DQ(e: Int64); {9} Procedure FillChar(SizeData: Cardinal; e: Byte); {10} Procedure SetFileName(s: string255); {11} Procedure DString255(const s: string255); {12} Function GetAddrPosCompile: Longint; { остання позиція, в яку була компіляція } {13} Procedure FillDB(var arr: array of Byte; BeginPos, SizeData: Cardinal); {14} Function GetAddrMaxPosCompile: Longint; { максимальна позиція, яка була компілювана } { Службові процедури, які не впливають на компіляцію } function AnsiToOem(const s: string): string; procedure WritelnOEM(s: string255); implementation uses SysUtils; const RAMpastByte = 5000000; { остання можлива адреса } var RAM : array[0..RAMpastByte] of Byte; { пам'ять для компіляції } RAMcompile : array[0..RAMpastByte] of Byte; { 1 – була компіляція, 0 – не було } RAMposCompile : Longint = -1; { остання позиція, у яку була компіляція } RAMmaxposCompile : Longint = -1; { максимальна позиція, яка була компілювана } OutFileName : string255 = 'BOOT.bin'; { ---------------- Допоміжні процедури ---------------- } function AnsiToOem(const s: string): string; var i, code: Integer; begin Result := ''; for i := 1 to Length(s) do begin code := Ord(s[i]); case code of 0..127 : Result := Result + Chr(code); 192..239: Result := Result + Chr(code - 64); // А..п 240..255: Result := Result + Chr(code - 16); // р..я 168 : Result := Result + Chr(240); // Ё 184 : Result := Result + Chr(241); // ё { Українські літери (правильні OEM?коди) } 165 : Result := Result + Chr(248); // Ґ 170 : Result := Result + Chr(242); // Є 175 : Result := Result + Chr(244); // Ї 180 : Result := Result + Chr(249); // ґ 186 : Result := Result + Chr(243); // є 191 : Result := Result + Chr(245); // ї 178 : Result := Result + Chr($49); // І 179 : Result := Result + Chr($69); // і else Result := Result + '?'; end; end; end; procedure WritelnOEM(s: string255); begin Writeln(AnsiToOem(s)); end; procedure ClearRAMcompile; var c1: Cardinal; begin for c1 := 0 to RAMpastByte do RAMcompile[c1] := 0; end; procedure WriteFileRAM; var f : file; NumWritten : Integer; begin AssignFile(f, OutFileName); Rewrite(f, 1); try BlockWrite(f, RAM, RAMmaxposCompile + 1, NumWritten); finally CloseFile(f); end; end; { ---------------- Обробка помилок ---------------- } const GEN00TXTError: array[1..4] of string255 = ( {1} '* Неприпустима адреса компіляції.', {2} '* В адресу вже було компілювання.', {3} '* Відсутня ініціалізація програми.', {4} '* Відсутність коду в програмі.' ); const GEN00CodeComand: array[1..14] of string255 = ( 'INITCompiler', 'FINALCompiler', 'DB', 'REM', 'DW', 'SetAddrCompile', 'DD', 'DQ', 'FillChar', 'SetFileName', 'DString255', 'GetAddrPosCompile', 'FillDB', 'GetAddrMaxPosCompile' ); var fErrorGEN00 : Boolean = False; { прапор помилки } { Параметри помилки } CodeError : Cardinal = 0; { код помилки } ValueError : Cardinal = 0; { значення помилки } Command : Cardinal = 0; { номер команди } CurrentAddress : Longint = 0; { адреса, в якій виникла помилка } RemStrERR : string255 = ''; { останній коментар } MaxCompileAddress : Longint = 0; { максимальна адреса на момент помилки } procedure INITerrorGEN00; begin fErrorGEN00 := False; CodeError := 0; ValueError := 0; Command := 0; CurrentAddress := 0; RemStrERR := ''; MaxCompileAddress := 0; end; var RemStr: string255; { останній коментар } procedure Error(code,val,com:Cardinal); begin fErrorGEN00 := True; CodeError := code; ValueError := val; Command := com; CurrentAddress := RAMposCompile + 1; MaxCompileAddress := RAMmaxposCompile; RemStrERR := RemStr; WritelnOEM(''); WritelnOEM(''); WritelnOEM(''); WritelnOEM('GEN00:'); WritelnOEM('Код помилки (CodeError): ' + IntToStr(CodeError)); WritelnOEM('Значення помилки (ValueError): ' + IntToStr(ValueError) + ' ($' + IntToHex(ValueError, 8) + ')'); WritelnOEM('Номер команди (Command): ' + IntToStr(Command) + ' ( ' + GEN00CodeComand[Command] + ' )'); WritelnOEM('Адреса, в якій виникла помилка (CurrentAddress): ' + IntToStr(CurrentAddress) + ' ( $' + IntToHex(CurrentAddress, 8) + ' )'); WritelnOEM('Максимальна адреса компіляції (MaxCompileAddress): ' + IntToStr(MaxCompileAddress) + ' ( $' + IntToHex(MaxCompileAddress, 8) + ' )'); WritelnOEM('Останній коментар (RemStrERR): "' + RemStrERR + '"'); WritelnOEM('======================'); WritelnOEM('Помилка в процедурі: ' + GEN00CodeComand[Command]); WritelnOEM(GEN00TXTError[CodeError] + #13 + #10); WritelnOEM(''); WritelnOEM(''); WritelnOEM(''); Readln; end; { ---------------- Основні процедури ---------------- } var pINITCompiler: Boolean = False; { чи була ініціалізація } {1} Procedure INITCompiler; const NumberProc = 1; begin pINITCompiler := True; ClearRAMcompile; RAMposCompile := -1; RAMmaxposCompile := -1; INITerrorGEN00; end; {2} Function FINALCompiler: Boolean; const NumberProc = 2; begin if fErrorGEN00 then begin FINALCompiler := False; Exit; end; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then begin FINALCompiler := False; Exit; end; end; if RAMposCompile > RAMmaxposCompile then RAMmaxposCompile := RAMposCompile; if RAMmaxposCompile >= 0 then WriteFileRAM else begin Error(4, 0, NumberProc); if fErrorGEN00 then begin FINALCompiler := False; Exit; end; end; FINALCompiler := True; end; {3} Procedure DB(e: Cardinal); const NumberProc = 3; begin if fErrorGEN00 then Exit; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then Exit; end else if RAMposCompile + 1 > RAMpastByte then begin Error(1, 0, NumberProc); if fErrorGEN00 then Exit; end else if RAMcompile[RAMposCompile + 1] <> 0 then begin Error(2, e, NumberProc); if fErrorGEN00 then Exit; end else begin Inc(RAMposCompile); RAM[RAMposCompile] := e; RAMcompile[RAMposCompile] := 1; if RAMposCompile > RAMmaxposCompile then RAMmaxposCompile := RAMposCompile; end; end; {4} Procedure REM(s: string255); begin RemStr := s; end; {5} Procedure DW(e: Cardinal); const NumberProc = 5; SizeData = 2; var B_ : array[1..2] of Byte; W_ : Word absolute B_; c1 : Cardinal; begin if fErrorGEN00 then Exit; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then Exit; end else if RAMposCompile + SizeData > RAMpastByte then begin Error(1, 0, NumberProc); if fErrorGEN00 then Exit; end else begin W_ := e; for c1 := 1 to SizeData do begin Inc(RAMposCompile); if RAMcompile[RAMposCompile] <> 0 then begin Error(2, e, NumberProc); if fErrorGEN00 then Exit; end else begin RAM[RAMposCompile] := B_[c1]; RAMcompile[RAMposCompile] := 1; end; end; if RAMposCompile > RAMmaxposCompile then RAMmaxposCompile := RAMposCompile; end; end; {6} Procedure SetAddrCompile(e: Cardinal); const NumberProc = 6; begin if fErrorGEN00 then Exit; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then Exit; end else if e > RAMpastByte then begin Error(1, e, NumberProc); if fErrorGEN00 then Exit; end else if RAMcompile[e] <> 0 then begin Error(2, e, NumberProc); if fErrorGEN00 then Exit; end else RAMposCompile := e - 1; end; {7} Procedure DD(e: Cardinal); const NumberProc = 7; SizeData = 4; var B_ : array[1..4] of Byte; C_ : Cardinal absolute B_; c1 : Cardinal; begin if fErrorGEN00 then Exit; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then Exit; end else if RAMposCompile + SizeData > RAMpastByte then begin Error(1, 0, NumberProc); if fErrorGEN00 then Exit; end else begin C_ := e; for c1 := 1 to SizeData do begin Inc(RAMposCompile); if RAMcompile[RAMposCompile] <> 0 then begin Error(2, e, NumberProc); if fErrorGEN00 then Exit; end else begin RAM[RAMposCompile] := B_[c1]; RAMcompile[RAMposCompile] := 1; end; end; if RAMposCompile > RAMmaxposCompile then RAMmaxposCompile := RAMposCompile; end; end; {8} Procedure DQ(e: Int64); const NumberProc = 8; SizeData = 8; var B_ : array[1..8] of Byte; i64_: Int64 absolute B_; c1 : Cardinal; begin if fErrorGEN00 then Exit; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then Exit; end else if RAMposCompile + SizeData > RAMpastByte then begin Error(1, 0, NumberProc); if fErrorGEN00 then Exit; end else begin i64_ := e; for c1 := 1 to SizeData do begin Inc(RAMposCompile); if RAMcompile[RAMposCompile] <> 0 then begin Error(2, e, NumberProc); if fErrorGEN00 then Exit; end else begin RAM[RAMposCompile] := B_[c1]; RAMcompile[RAMposCompile] := 1; end; end; if RAMposCompile > RAMmaxposCompile then RAMmaxposCompile := RAMposCompile; end; end; {9} Procedure FillChar(SizeData: Cardinal; e: Byte); const NumberProc = 9; var c1: Cardinal; begin if fErrorGEN00 then Exit; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then Exit; end else if RAMposCompile + SizeData > RAMpastByte then begin Error(1, 0, NumberProc); if fErrorGEN00 then Exit; end else begin for c1 := 1 to SizeData do begin Inc(RAMposCompile); if RAMcompile[RAMposCompile] <> 0 then begin Error(2, e, NumberProc); if fErrorGEN00 then Exit; end else begin RAM[RAMposCompile] := e; RAMcompile[RAMposCompile] := 1; end; end; if RAMposCompile > RAMmaxposCompile then RAMmaxposCompile := RAMposCompile; end; end; {10} Procedure SetFileName(s: string255); begin OutFileName := s; end; {11} Procedure DString255(const s: string255); const NumberProc = 11; var SizeData: Cardinal; c1: Cardinal; begin SizeData := Length(s); if fErrorGEN00 then Exit; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then Exit; end else if RAMposCompile + SizeData > RAMpastByte then begin Error(1, 0, NumberProc); if fErrorGEN00 then Exit; end else begin for c1 := 1 to SizeData do begin Inc(RAMposCompile); if RAMcompile[RAMposCompile] <> 0 then begin Error(2, 0, NumberProc); if fErrorGEN00 then Exit; end else begin RAM[RAMposCompile] := Ord(s[c1]); RAMcompile[RAMposCompile] := 1; end; end; if RAMposCompile > RAMmaxposCompile then RAMmaxposCompile := RAMposCompile; end; end; {12} Function GetAddrPosCompile: Longint; begin Result := RAMposCompile; end; {13} Procedure FillDB(var arr: array of Byte; BeginPos, SizeData: Cardinal); const NumberProc = 13; var len: Cardinal; c1 : Cardinal; begin if fErrorGEN00 then Exit; if not pINITCompiler then begin Error(3, 0, NumberProc); if fErrorGEN00 then Exit; end else if RAMposCompile + SizeData > RAMpastByte then begin Error(1, 0, NumberProc); if fErrorGEN00 then Exit; end else begin len := Length(arr); if BeginPos = 0 then BeginPos := 1; if BeginPos > len then BeginPos := len; if BeginPos + SizeData > len then SizeData := len - BeginPos; BeginPos := BeginPos - 1; // перехід до 0?базового індексу for c1 := 1 to SizeData do begin Inc(RAMposCompile); if RAMcompile[RAMposCompile] <> 0 then begin Error(2, 0, NumberProc); if fErrorGEN00 then Exit; end else begin RAM[RAMposCompile] := arr[BeginPos + c1]; RAMcompile[RAMposCompile] := 1; end; end; if RAMposCompile > RAMmaxposCompile then RAMmaxposCompile := RAMposCompile; end; end; {14} Function GetAddrMaxPosCompile: Longint; begin Result := RAMmaxposCompile; end; end. uGEN00z.pas unit uGEN00z; interface uses uGEN00_a; type string255 = string[255]; { Основні процедури користувача } Procedure INITCompiler; Function FINALCompiler: Boolean; Procedure DB(e: Cardinal); Procedure DW(e: Cardinal); Procedure SetAddrCompile(e: Cardinal); Procedure DD(e: Cardinal); Procedure DQ(e: Int64); Procedure FillChar(SizeData: Cardinal; e: Byte); Procedure SetFileName(s: string255); Procedure DString255(const s: string255); Function GetAddrPosCompile: Longint; Procedure FillDB(var arr: array of Byte; BeginPos, SizeData: Cardinal); Function GetAddrMaxPosCompile: Longint; { Коментар (не впливає на код) } Procedure REM(s: string255); { Службові функції виводу } function AnsiToOem(const s: string255): string255; procedure WritelnOEM(s: string255); implementation Procedure INITCompiler; begin uGEN00_a.INITCompiler; end; Function FINALCompiler: Boolean; begin Result := uGEN00_a.FINALCompiler; end; Procedure DB(e: Cardinal); begin uGEN00_a.DB(e); end; Procedure DW(e: Cardinal); begin uGEN00_a.DW(e); end; Procedure SetAddrCompile(e: Cardinal); begin uGEN00_a.SetAddrCompile(e); end; Procedure DD(e: Cardinal); begin uGEN00_a.DD(e); end; Procedure DQ(e: Int64); begin uGEN00_a.DQ(e); end; Procedure FillChar(SizeData: Cardinal; e: Byte); begin uGEN00_a.FillChar(SizeData, e); end; Procedure SetFileName(s: string255); begin uGEN00_a.SetFileName(s); end; Procedure DString255(const s: string255); begin uGEN00_a.DString255(s); end; Function GetAddrPosCompile: Longint; begin Result := uGEN00_a.GetAddrPosCompile; end; Procedure FillDB(var arr: array of Byte; BeginPos, SizeData: Cardinal); begin uGEN00_a.FillDB(arr, BeginPos, SizeData); end; Function GetAddrMaxPosCompile: Longint; begin Result := uGEN00_a.GetAddrMaxPosCompile; end; Procedure REM(s: string255); begin uGEN00_a.REM(s); end; function AnsiToOem(const s: string255): string255; begin Result := uGEN00_a.AnsiToOem(s); end; procedure WritelnOEM(s: string255); begin uGEN00_a.WritelnOEM(s); end; end. GEN00.dpr program GEN00; {$APPTYPE CONSOLE} uses Windows, uGEN00_a in '_UNIT\uGEN00_a.pas', uGEN00z in '_UNIT\uGEN00z.pas'; { Приклад програми взятий з EnotVM32\BP4_001\Examples\deepseek\03 Cycle\ ; Програма від https://chat.deepseek.com/ ; Цикл: вивід чисел від 1 до 9 ; Використовується лічильник, умовний перехід `GOTOsrLess` та ; вивід через `WritelnYA`. ; ; format binary as 'bin' ; include 'Macros.asm' ; ; MOVrv D, 1 ; D = лічильник = 1 ; MOVrv E, 10 ; E = межа = 10 ; ; loop_start: ; MOVrr YA, D ; YA = лічильник ; WritelnYA ; WritelnYA ; INCr D ; D++ ; CMPrr D, E ; CMP1=D, CMP2=E ; GOTOsaLess loop_start ; якщо D < E, повторити ; ; Readln0 ; Натиснути "Enter" для продовження. ; EndProgram ; ставиться наприкінці програми. } var loop_start: Cardinal; procedure ProgramEnot; begin INITCompiler; DB($01); DB($03); DD($00000001); // MOVrv D, 1 DB($01); DB($04); DD($0000000A); // MOVrv E, 10 loop_start := GetAddrPosCompile + 1; DB($02); DB($E8); DB($03); // MOVrr YA, D DB($2A); DW($0008); // WritelnYA DB($21); DB($03); // INCr D DB($29); DB($03); DB($04); // CMPrr D, E DB($13); DD(loop_start); // GOTOsaLess loop_start DB($2A); DW($0004); // Readln0 DB($2A); DW($000A); // EndProgram FINALCompiler; WinExec('EnotVM32.EXE', SW_ShowMaximized); end; begin ProgramEnot; end. uGEN00_a.txt 2. Документація модуля `uGEN00_a` (генератор рівня 0) Призначення ----------- `uGEN00_a` – низькорівневий бінарний генератор для проєкту EnotVM32. Він дозволяє побайтово формувати образ програми (`BOOT.bin`) безпосередньо в пам’яті, контролюючи адресацію та уникаючи перезапису. Усі байти зберігаються в масиві `RAM[0..RAMpastByte]`. Додатковий масив `RAMcompile` позначає, які адреси вже були зайняті компіляцією – це запобігає випадковому подвійному запису в ту саму комірку. Основні процедури (API) ------------------------ | Процедура/Функція | Опис | |-------------------|------| | `INITCompiler` | Ініціалізує пам’ять, очищує прапори помилок. Обов’язково викликати першою. | | `FINALCompiler: Boolean` | Завершує компіляцію, записує буфер у файл `BOOT.bin`. Повертає `True` при успіху. | | `DB(e: Cardinal)` | Додає 1 байт. | | `DW(e: Cardinal)` | Додає 2 байти (Word, little-endian). | | `DD(e: Cardinal)` | Додає 4 байти (Cardinal, little-endian). | | `DQ(e: Int64)` | Додає 8 байт (Int64, little-endian). | | `FillChar(SizeData: Cardinal; e: Byte)` | Заповнює `SizeData` байт значенням `e`. | | `DString255(const s: string255)` | Записує символи рядка (без нуль-термінатора) як послідовність байт. | | `FillDB(var arr: array of Byte; BeginPos, SizeData: Cardinal)` | Копіює `SizeData` байт із масиву `arr`, починаючи з елемента `BeginPos` (1-базова індексація). | | `SetAddrCompile(e: Cardinal)` | Встановлює поточну адресу компіляції в `e`. Наступний виклик `DB`/`DW`/… запише дані за цією адресою. | | `GetAddrPosCompile: Longint` | Поточна позиція запису (остання зайнята адреса). | | `GetAddrMaxPosCompile: Longint` | Максимальна адреса, яка була використана (для визначення довжини файлу). | | `SetFileName(s: string255)` | Змінює ім’я вихідного файлу (за замовчуванням `BOOT.bin`). | | `REM(s: string255)` | Запам’ятовує коментар (використовується у повідомленнях про помилки). | Коди помилок ------------- Якщо `FINALCompiler` повертає `False`, на консоль виводиться детальний звіт: | CodeError | Повідомлення | |-----------|--------------| | 1 | Неприпустима адреса компіляції. | | 2 | В адресу вже було компілювання. | | 3 | Відсутня ініціалізація програми (не викликано `INITCompiler`). | | 4 | Відсутність коду в програмі. | Помилки супроводжуються номером команди, значенням, адресою та останнім коментарем, що допомагає швидко знайти джерело проблеми. Допоміжні функції для виводу в консоль --------------------------------------- - `AnsiToOem(const s: string): string` – перекодовує рядок з Windows?1251 у OEM (CP866) для коректного відображення кирилиці у консолі. - `WritelnOEM(s: string255)` – виводить рядок із автоматичним перекодуванням. uGEN00z.txt Модулі uGENXXz є експортом усіх процедур модулю XX, які можуть бути використані користувачем, в інших модулях або ж у файлі .dpr. Достатньо підключити один файл uGENXXz.pas, і усі доступні можливості інших файлів модулю uGENXX будуть доступні. Примітка. При використанні в файлах .dpr, він повинен підключатись останнім uGEN00z in '_UNIT\uGEN00z.pas'; в файлах модулів .pas, він повинен підключатись єдиним. Саме цей модуль uGEN00z.pas може підійти для використовувати в генерації BIN-файлів, або чогось подібного. Процедури, доступні в модулі uGEN00z.pas: {Основні процедури для користувача} {1} Procedure INITCompiler; {2} Function FINALCompiler: Boolean; {3} Procedure DB(e: Cardinal); {4} Procedure REM(s: string255); {5} Procedure DW(e: Cardinal); {6} Procedure SetAddrCompile(e: Cardinal); {7} Procedure DD(e: Cardinal); {8} Procedure DQ(e: Int64); {9} Procedure FillChar(SizeData: Cardinal; e: Byte); {10} Procedure SetFileName(s: string255); {11} Procedure DString255(const s: string255); {12} Function GetAddrPosCompile: Longint; {13} Procedure FillDB(var arr: array of Byte; BeginPos, SizeData: Cardinal); {14} Function GetAddrMaxPosCompile: Longint; {Службові процедури та функції, які не впливають на компіляцію} function AnsiToOem(const s: string): string; procedure WritelnOEM(s: string255);