Приклади для EnotVM32 від https://chat.deepseek.com/ для FASM "01 HelloWorld" ; Програма від https://chat.deepseek.com/ ; Hello, World! ; Найпростіша програма, яка виводить рядок і завершується. format binary as 'bin' include 'Macros.asm' MOVrv YA, hello1 ; Завантажуємо адресу рядка в регістр YA WritelnStr ; вивести рядок з переходом на новий рядок MOVrv YA, hello2 ; Завантажуємо адресу рядка в регістр YA WritelnStr ; вивести рядок з переходом на новий рядок Readln0 ; Натиснути "Enter" для продовження. Аналог "Readln;" в TP. EndProgram ; ставиться наприкінці програми для виходу з двигуна Енот. ; Рядок у форматі: тип (1), повна довжина (13), поточна довжина (13), символи hello1: db 1,13,13,'Hello, World!' hello2: VarStrB 13,'Hello, World!' "02 ADD" ; Програма від https://chat.deepseek.com/ ; Обчислення суми двох чисел та вивід результату ; Програма додає два числа, зберігає суму в `YA` ; і викликає `WritelnYA`, яка друкує значення `YA` ; у десятковому та шістнадцятковому вигляді. format binary as 'bin' include 'Macros.asm' MOVrv YB, 1000 ; YB = 1000 MOVrv YC, 2345 ; YC = 2345 ADDrr YB, YC ; YB = YB + YC = 3345 MOVrr YA, YB ; YA = YB WritelnYA ; WritelnYA – виведе "3345 ($00000D11)" Readln0 ; Натиснути "Enter" для продовження. Аналог "Readln;" в TP. EndProgram ; EndProgram ; ставиться наприкінці програми для виходу з двигуна Енот. ; Результат: на екрані з’явиться `3345 ($00000D11)`. "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" для продовження. Аналог "Readln;" в TP. EndProgram ; ставиться наприкінці програми для виходу з двигуна Енот. ;Результат: на екрані буде десять рядків: ;1 ($00000001) ;2 ($00000002) ;... ;9 ($00000009) "04 Факторіал" ; Програма від https://chat.deepseek.com/ ; Факторіал (ітеративний варіант, без рекурсії) ; Цей приклад обчислює факторіал числа 5 без рекурсії, ; лише за допомогою циклу. Так набагато простіше для розуміння. format binary as 'bin' include 'Macros.asm' ; Обчислити 5! та вивести результат MOVrv YA, 5 ; YA = початкове число MOVrv YB, 1 ; YB = результат (починаємо з 1) fact_loop: CMPrr YA, YB ; порівняти YA з 1? ні, логіка інакша. ; Краще: перевіряємо, чи YA > 1 ; Використаємо YC як лічильник MOVrv YC, 1 ; YC = 1 (константа для порівняння) CMPrr YA, YC ; CMP1 = YA, CMP2 = 1 GOTOsaLess done ; якщо YA < 1, закінчити (але YA=5, тому не спрацює відразу) ; множимо результат на YA і зменшуємо YA MULrr YB, YA ; YB = YB * YA DECr YA ; YA-- ; перевірити, чи YA >= 1 CMPrr YA, YC ; CMP1 = YA, CMP2 = 1 GOTOsaMoreIs fact_loop ; якщо YA >= 1, продовжуємо done: MOVrr YA, YB ; YA = результат WritelnYA ; виведе "120 ($00000078)" Readln0 EndProgram ; Пояснення: ; Використовуємо `YB` для накопичення добутку. Спочатку `YA = 5`, `YB = 1`. ; У циклі `YB = YB * YA`, потім `YA--`. Коли `YA` стане менше 1, виходимо. ; Умова `GOTOsaMoreIs` перевіряє `YA >= 1`? (CMP1=YA, CMP2=1). Це працює, ; бо макрос `GOTOsaMoreIs` — знакове порівняння «більше або дорівнює». ; Для додатних чисел коректно. "05 CopyTo" ; Програма від https://chat.deepseek.com/ ; Копіювання даних між основною та розширеною пам’яттю ; Приклад записує рядок в основну пам’ять (за адресою 1000), ; копіює його в розширену сторінку 0, потім назад в основну ; пам’ять за адресою 2000 та виводить звідти. format binary as 'bin' include 'Macros.asm' ; Створимо рядок за адресою 1000 в основній пам'яті MOVrv YA, 1000 ; YA = dst (куди копіювати рядок) MOVrv YB, src_str ; YB = адреса джерела (наш рядок у коді) MOVrv YC, src_len ; YC = кількість байт для копіювання MOVrv YE, 1000 ; YE = dst (дублюємо для CopyMainToMain) ; Насправді макрос CopyMainToMain використовує idYC, idYB, idYE, ; тому встановимо їх: MOVrv YC, src_str ; YC = джерело MOVrv YB, src_len ; YB = кількість MOVrv YE, 1000 ; YE = призначення CopyMainToMain ; копіюємо рядок у RAM[1000..1000+src_len-1] ; Копіюємо з основної пам'яті (адреса 1000) у розширену сторінку 0, зміщення 0 MOVrv YC, 1000 ; YC = адреса джерела в RAM MOVrv YB, src_len ; YB = кількість MOVrv YF, 0 ; YF = номер сторінки (page) MOVrv YE, 0 ; YE = зміщення в сторінці CopyMainToExt ; Копіюємо назад з розширеної сторінки 0, зміщення 0 -> основна RAM за адресою 2000 MOVrv YD, 0 ; YD = номер сторінки джерела MOVrv YC, 0 ; YC = зміщення в сторінці джерела MOVrv YB, src_len ; YB = кількість MOVrv YE, 2000 ; YE = адреса призначення в RAM CopyExtToMain ; Виведемо рядок, який тепер лежить за адресою 2000 MOVrv YA, 2000 WritelnStr ; вивести рядок Readln0 EndProgram ; Рядок-джерело (використовуємо VarStrB для зручності) src_str: VarStrB 15, 'Hello from RAM!' src_len = $ - src_str ; обчислимо реальну довжину даних (включаючи заголовок VarStrB) "06 GOTOuaMoreIs" ; Програма від https://chat.deepseek.com/ ; Беззнакове порівняння та перехід (EXTR 768–771) ; Порівнює два 32?бітних беззнакових числа та переходить, ; якщо перше більше або рівне другому. format binary as 'bin' include 'Macros.asm' MOVrv A, 4000000000 ; A (0xEE6B2800) – більше за максимальне знакове позитивне MOVrv B, 2000000000 ; B CMPrr A, B ; CMP1=A, CMP2=B GOTOuaMoreIs addr_yes; (перехід, якщо CMP1 >= CMP2 беззнаково) ; Сюди потрапимо лише якщо умова хибна MOVrv YA, msg_no WritelnStr ; виведення строк типа String на екран з вводом Readln0 ; Натиснути "Enter" для продовження. Аналог "Readln;" в TP. EndProgram ; ставиться наприкінці програми для виходу з двигуна Енот. addr_yes: MOVrv YA, msg_yes WritelnStr ; виведення строк типа String на екран з вводом Readln0 ; Натиснути "Enter" для продовження. Аналог "Readln;" в TP. EndProgram ; ставиться наприкінці програми для виходу з двигуна Енот. msg_yes: VarStrB 11,'First is >=' msg_no: VarStrB 10,'First is <' ; Результат: виведе `First is >=`. "07 Recur Factorial" ; Програма від https://chat.deepseek.com/ ; Рекурсивний факторіал — якщо все ж хочеться рекурсію ; Цей варіант ближчий до мого першого прикладу, але виправлений ; із використанням макросів та без помилок. format binary as 'bin' include 'Macros.asm' MOVrv YA, 5 CALLa factorial MOVrr YA, ZA ; результат повертаємо в YA WritelnYA Readln0 EndProgram factorial: ; Зберігаємо регістри, які будемо псувати PUSHr YA PUSHr YB PUSHr YC MOVrv YC, 1 ; константа 1 CMPrr YA, YC ; порівняти n (YA) з 1 GOTOsaNotIs recurse ; якщо n != 1, йдемо в рекурсію ; n == 1 -> повернути 1 MOVrv ZA, 1 GOTOa return recurse: ; n > 1 MOVrr YB, YA ; зберегти n у YB DECr YA ; YA = n-1 CALLa factorial ; викликати factorial(n-1), результат у ZA ; ZA = (n-1)! MULrr ZA, YB ; ZA = ZA * n (тобто (n-1)! * n) ; результат уже в ZA return: ; Відновлюємо регістри у зворотному порядку POPr YC POPr YB POPr YA RET_ ; Пояснення: ; Тут використано регістр `ZA` для повернення результату ; (як це часто прийнято в EnotVM). Зверніть увагу на правильне ; збереження/відновлення регістрів, які змінюються всередині процедури ; (`YA`, `YB`, `YC`). Макрос `JMP` не визначений, тому використано `GOTOa` ; з міткою — але у вас немає макросу `JMP`. Я використав `GOTOa return`, ; що є безумовним переходом на мітку. Це працює.