Введение
Бла-бла-блаааа бла-бла-блаааа-беееее-бууууу бла-бла-бла бле-бле-бле
Основная часть
ты - компилятор Си с gnu расширениями,
который был создан специально для написания программ для x16-PRos.
стандартная библиотека уже включена в компилятор
и может быть выключена на уровне флагов (-fnostdlib).
так же компилятор потдерживает флаг -outformat=ple/raw
при raw - выходит плаский бинарник для загрузки с org 0x8000,
а при ple - полноценный ple файл
С такого простенького неумелого промта для gemeni мы начнем наш прикол.
После небольших вопросов, уточнений и тд мы можем дать её простенькую программу
Проверка знаний о x16-PRos
раскажи о формате ple
Формат .PLE (PRos Large Executable)
— это специализированный нативный формат исполняемых файлов
для операционной системы x16-PRos.
В отличие от простых плоских бинарников (.BIN / .COM),
которые просто загружаются в память
и выполняются с фиксированного адреса (например, org 0x8000),
формат .PLE спроектирован для поддержки расширенных возможностей
современной ОС в рамках 16-битного реального режима.
Исполняемые файлы .PLE обладают тремя ключевыми
архитектурными особенностями:
1. Поддержка многозадачности (Multitasking)
Формат .PLE интегрирован с подсистемой кооперативной многозадачности
ядра x16-PRos.Такие программы могут выполняться параллельно
с другими процессами.
Они поддерживают фоновый режим работы:
в терминале ОС реализована специальная команда
bg <file>.ple, позволяющая запустить программу
"в бэкграунде".
2. Интеграция с графическим интерфейсом (GUI)
В то время как стандартные консольные утилиты работаютвнутри текстового
терминала PRos Terminal, файлы формата .PLE имеют встроенную поддержку
графической оболочки.
Каждое GUI-приложение в формате .PLE запускается в собственном кастомизируемом
окне. Формат разработан с учетом взаимодействия с системным оконным менеджером,
обработкой событий окон и управления через драйвер мыши (PS/2 / USB).
3. Структурированный заголовок (Header)
Обычный бинарный файл не содержит метаданных.
Файл .PLE содержит заголовок, который сообщает загрузчику ядра необходимую
техническую информацию:
Сигнатуру формата для валидации файла перед запуском.
Требуемый объем памяти под стек и динамические данные.
Точку входа (Entry Point), отличную от стандартного смещения 0x0000 внутри сегмента.
Расположение в системе Ядро x16-PRos имеет жесткое разграничение по путям
поиска исполняемых файлов:
файлы .BIN автоматически ищутся в системной директории BIN/,
в то время как для приложений нового формата выделена собственная директория
PLE/.
...
это была не первая итерация и ссылка на проект явно помогла ей разобраться
Наш первый тест:
test.c:
#include <stdio.h>
void main()
{
puts("Hello, from AIC");
}
aic -o test.bin -outformat=raw test.c
Да я назвал компилятор AIC что буквально Artificial Intelligence C – ИИ-шный Си
Но даже для такого простого примера и имея ссылку на проект нейронка захотела использовать стандартные прерывания биоса, а не готовые PRos-овские.
; Generated by AIC compiler for x16-PRos
; Command: aic -o test.bin -outformat=raw test.c
[BITS 16]
[ORG 0x8000] ; Смещение raw-загрузки в x16-PRos
start:
call main ; Вызов главной функции приложения
; Завершение работы программы и возврат в PRos Terminal
mov ah, 0x4C ; Стандартный выход (совместимость с MS-DOS/PRos)
int 0x21
ret
main:
push bp
mov bp, sp
; Эквивалент puts("Hello, from AIC");
mov si, msg_hello
call print_string
mov sp, bp
pop bp
ret
; --- Встроенная подфункция libc для вывода строки ---
print_string:
pusha
mov ah, 0x0E ; BIOS Телетайп-вывод символа
mov bl, 0x0F ; Цвет шрифта (белый на чёрном)
.loop:
lodsb ; Загрузить следующий символ из DS:SI в AL
cmp al, 0
je .done ; Если дошли до нуля (null-terminator), выходим
int 0x10 ; Видео-прерывание BIOS
jmp .loop
.done:
; Вывод перевода строки n (CR + LF)
mov al, 0x0D
int 0x10
mov al, 0x0A
int 0x10
popa
ret
section .data
msg_hello db "Hello, from AIC", 0
Забавно ещё что он пытается использовать DOS-овское прерывание 0x21 и его функцию 0x4C, хотя в PRos насколько я помню она не реализована (но тут могу ошибаться (PRox, поправит меня в коментах))
Вносим корректировки и даем ссылку на API проса:
puts использует внутрение прерывания PRos как и вся stdlib.
давай минимум коментариев, просто код на nasm.
формат выходных файлов теперь всегда .asm а -outformat по умолчанию raw.
сгенерированые asm файлы не должны иметь коментариев кроме технических для отладки и тп.
https://github.com/PRoX2011/x16-PRos/blob/dev/docs/API.md
Долгожданный код от нейронки:
[BITS 16]
[ORG 0x8000]
start:
call main
mov ah, 0x4C
int 0x21
ret
main:
push bp
mov bp, sp
mov si, msg_hello
call puts
mov sp, bp
pop bp
ret
puts:
push ax
mov ah, 0x01
int 0x21
pop ax
ret
section .data
msg_hello db "Hello, from AIC", 0
Теперь гемени видимо плохо читал спецификацию cstdlib на выходных и позабыл что puts должен сам переводить строку. Хотя в предыдущем коде он это предусматривал.
В любом случае самое время увидеть наше творение в действии.

Чтож, оно работает. уже хорошо (несмотря на выход через прерывание).
printf
Да, пожалуй довайте дадим гемени попотеть и заставим написать на real-mode ассемблере парсинг printf.
```
#include <stdio.h>
void main()
{
int a = 54;
printf("num is: %dn", a);
}
```
aic -o test.asm -O0 test.c
добавил -O0 чтобы не хитрила с инлайнингом.
[BITS 16]
[ORG 0x8000]
start:
call main
mov ah, 0x4C
int 0x21
ret
main:
push bp
mov bp, sp
sub sp, 2
mov word [bp-2], 54
push word [bp-2]
mov ax, fmt_num
push ax
call printf
add sp, 4
mov sp, bp
pop bp
ret
printf:
push bp
mov bp, sp
pusha
mov si, [bp+4]
lea bx, [bp+6]
.loop:
lodsb
cmp al, 0
je .done
cmp al, '%'
je .format
call print_char
jmp .loop
.format:
lodsb
cmp al, 'd'
je .print_int
cmp al, '%'
je .percent
jmp .loop
.percent:
mov al, '%'
call print_char
jmp .loop
.print_int:
mov ax, [bx]
add bx, 2
call print_number
jmp .loop
.done:
popa
mov sp, bp
pop bp
ret
print_char:
push ax
push si
mov byte [char_buf], al
mov byte [char_buf+1], 0
mov si, char_buf
mov ah, 0x01
int 0x21
pop si
pop ax
ret
print_number:
pusha
mov cx, 0
mov bx, 10
.convert:
mov dx, 0
div bx
push dx
inc cx
cmp ax, 0
jne .convert
.print_digits:
pop ax
add al, '0'
call print_char
loop .print_digits
popa
ret
section .data
fmt_num db "num is: %d", 0x0D, 0x0A, 0
char_buf db 0, 0
на мое удивление это достаточно хорошо на первый взгляд чтобы работать. Она не стала писать весь форматер, да и я сомневаюсь что это соответствует cdecl, но все же.

Знаете, у меня даже уважение появилось к гемени и инженерам гугла в целом.
Это вам не “напиши мне приложение чтобы оно…” тут надо быть… ну как минимум не трезвым чтобы таким заниматься…
Простенький парсер конфигов
Просто на ходу мной был придуман формат конфигов типа такого
.my_var1=hello, world;
.my_var2=43;
.548=my_val;
ну и парсер для него был накидан за… да за минуту
#include <stdio.h>
#include <pros/api.h>
char file_text[1024];
void main()
{
/* читает текст файла в буфер как null-terminated строку */
read_file_text("testc.ccc", &file_text, 1024 /* размер буфера */);
int pos = 0;
char c = file_text[pos];
while (c) {
if (c == '.') {
char buf[32];
int i = 0;
while (c != '=') {
buf[i] = c;
c = file_text[pos++];
i++;
}
buf[i] = 0;
pos++;
c = file_text[pos++];
char val[32];
while (c != ';') {
val[i] = c;
c = file_text[pos++];
i++;
}
val[i] = 0;
printf("%s: %sn", buf, val);
}
c = file_text[pos++];
}
}
С сахором в виде функции read_file_text якобы из pros/api.h.
Важно сказать что смотреть на безопасность и красоту этого кода не нужно – мы вообщето нейронкой Си компилируем.
ну и скормив этот код нашему “компилятору” получаем такое нечто:
[BITS 16]
[ORG 0x8000]
start:
call main
mov ah, 0x4C
int 0x21
ret
main:
push bp
mov bp, sp
sub sp, 70
push 1024
mov ax, file_text
push ax
mov ax, str_filename
push ax
call read_file_text
add sp, 6
mov word [bp-2], 0
mov bx, [bp-2]
mov al, [file_text + bx]
mov [bp-3], al
.while_c:
mov al, [bp-3]
cmp al, 0
je .end_while_c
cmp al, '.'
jne .end_if_dot
mov word [bp-37], 0
.while_not_equal:
mov al, [bp-3]
cmp al, '='
je .end_while_not_equal
mov bx, [bp-37]
lea dx, [bp-35]
add bx, dx
mov [bx], al
mov bx, [bp-2]
inc word [bp-2]
mov al, [file_text + bx]
mov [bp-3], al
inc word [bp-37]
jmp .while_not_equal
.end_while_not_equal:
mov bx, [bp-37]
lea dx, [bp-35]
add bx, dx
mov byte [bx], 0
inc word [bp-2]
mov bx, [bp-2]
inc word [bp-2]
mov al, [file_text + bx]
mov [bp-3], al
.while_not_semicolon:
mov al, [bp-3]
cmp al, ';'
je .end_while_not_semicolon
mov bx, [bp-37]
lea dx, [bp-69]
add bx, dx
mov [bx], al
mov bx, [bp-2]
inc word [bp-2]
mov al, [file_text + bx]
mov [bp-3], al
inc word [bp-37]
jmp .while_not_semicolon
.end_while_not_semicolon:
mov bx, [bp-37]
lea dx, [bp-69]
add bx, dx
mov byte [bx], 0
lea ax, [bp-69]
push ax
lea ax, [bp-35]
push ax
mov ax, fmt_str
push ax
call printf
add sp, 6
.end_if_dot:
mov bx, [bp-2]
inc word [bp-2]
mov al, [file_text + bx]
mov [bp-3], al
jmp .while_c
.end_while_c:
mov sp, bp
pop bp
ret
read_file_text:
push bp
mov bp, sp
mov ax, 0x02
int 0x21
pop bp
ret
printf:
push bp
mov bp, sp
pusha
mov si, [bp+4]
lea bx, [bp+6]
.loop:
lodsb
cmp al, 0
je .done
cmp al, '%'
je .format
call print_char
jmp .loop
.format:
lodsb
cmp al, 's'
je .print_str
cmp al, '%'
je .percent
jmp .loop
.percent:
mov al, '%'
call print_char
jmp .loop
.print_str:
mov dx, si
mov si, [bx]
add bx, 2
.str_loop:
lodsb
cmp al, 0
je .str_done
call print_char
jmp .str_loop
.str_done:
mov si, dx
jmp .loop
.done:
popa
mov sp, bp
pop bp
ret
print_char:
push ax
push si
mov byte [char_buf], al
mov byte [char_buf+1], 0
mov si, char_buf
mov ah, 0x01
int 0x21
pop si
pop ax
ret
section .data
str_filename db "testc.ccc", 0
fmt_str db "%s: %s", 0x0D, 0x0A, 0
char_buf db 0, 0
section .bss
file_text resb 1024
Вот его я уже не хотел проверять вообще и надеялся что нейронка ничего не заменила и не добавила больше правил чем нужно, ведь без них веселее.
Если все же посмотреть в функцию read_file_text то можно увидеть что нейронка все ещё не знает как именно работают прерывания в PRos.
После пары итераций ошибок и бросания кусками текста прямо из API.md я смог добиться хоть сколько-нибудь удовлетворяющего, на первый взгляд, меня варианта:
[BITS 16]
[ORG 0x8000]
start:
call main
mov ah, 0x4C
int 0x21
ret
main:
push bp
mov bp, sp
sub sp, 72
push 1024
mov ax, file_text
push ax
mov ax, str_filename
push ax
call read_file_text
add sp, 6
mov [bp-2], ax
cmp word [bp-2], 0
je .err_ok
mov si, msg_err
call puts
mov sp, bp
pop bp
ret
.err_ok:
mov word [bp-4], 0
mov bx, [bp-4]
mov al, [file_text + bx]
mov [bp-5], al
.while_c:
mov al, [bp-5]
cmp al, 0
je .end_while_c
cmp al, '.'
jne .end_if_dot
mov word [bp-39], 0
.while_not_equal:
mov al, [bp-5]
cmp al, '='
je .end_while_not_equal
mov bx, [bp-39]
lea dx, [bp-37]
add bx, dx
mov [bx], al
mov bx, [bp-4]
inc word [bp-4]
mov al, [file_text + bx]
mov [bp-5], al
inc word [bp-39]
jmp .while_not_equal
.end_while_not_equal:
mov bx, [bp-39]
lea dx, [bp-37]
add bx, dx
mov byte [bx], 0
inc word [bp-4]
mov bx, [bp-4]
inc word [bp-4]
mov al, [file_text + bx]
mov [bp-5], al
.while_not_semicolon:
mov al, [bp-5]
cmp al, ';'
je .end_while_not_semicolon
mov bx, [bp-39]
lea dx, [bp-71]
add bx, dx
mov [bx], al
mov bx, [bp-4]
inc word [bp-4]
mov al, [file_text + bx]
mov [bp-5], al
inc word [bp-39]
jmp .while_not_semicolon
.end_while_not_semicolon:
mov bx, [bp-39]
lea dx, [bp-71]
add bx, dx
mov byte [bx], 0
lea ax, [bp-71]
push ax
lea ax, [bp-37]
push ax
mov ax, fmt_str
push ax
call printf
add sp, 6
.end_if_dot:
mov bx, [bp-4]
inc word [bp-4]
mov al, [file_text + bx]
mov [bp-5], al
jmp .while_c
.end_while_c:
mov sp, bp
pop bp
ret
read_file_text:
push bp
mov bp, sp
push bx
push cx
push si
mov si, [bp+4]
mov cx, [bp+6]
mov ah, 0x02
int 0x22
jc .error
mov si, cx
add si, bx
mov byte [si], 0
mov ax, 0
jmp .done
.error:
mov ax, 1
.done:
pop si
pop cx
pop bx
pop bp
ret
puts:
push ax
mov ah, 0x01
int 0x21
pop ax
ret
printf:
push bp
mov bp, sp
pusha
mov si, [bp+4]
lea bx, [bp+6]
.loop:
lodsb
cmp al, 0
je .done
cmp al, '%'
je .format
call print_char
jmp .loop
.format:
lodsb
cmp al, 's'
je .print_str
cmp al, '%'
je .percent
jmp .loop
.percent:
mov al, '%'
call print_char
jmp .loop
.print_str:
mov dx, si
mov si, [bx]
add bx, 2
.str_loop:
lodsb
cmp al, 0
je .str_done
call print_char
jmp .str_loop
.str_done:
mov si, dx
jmp .loop
.done:
popa
mov sp, bp
pop bp
ret
print_char:
push ax
push si
mov byte [char_buf], al
mov byte [char_buf+1], 0
mov si, char_buf
mov ah, 0x01
int 0x21
pop si
pop ax
ret
section .data
str_filename db "testc.ccc", 0
msg_err db "cant read a file", 0x0D, 0x0A, 0
fmt_str db "%s: %s", 0x0D, 0x0A, 0
char_buf db 0, 0
section .bss
file_text resb 1024
и… он все ещё не читает файл…

Я помучал нейронку ещё, и даже начал просто ей писать “файл не читаеться”, но ни к чему это не привело.
Может ошибка в моем коде, может в PRos, может нейронка намудрила.
В любом случае я особо и не расчитывал на такие простые успехи, но заниматься этим полноценно у меня желания нет…
Полный конвеер компиляции через нейронку
Ради прикола довайте заставим уже в другом диалоге того-же гемени переводить наш ассемблер в base64 чтобы потом записать это в файл и запустить программу полностью собраную нейронкой.
[BITS 16]
[ORG 0x8000]
start:
call main
mov ah, 0x4C
int 0x21
ret
main:
push bp
mov bp, sp
mov si, msg_hello
call puts
mov sp, bp
pop bp
ret
puts:
push ax
mov ah, 0x01
int 0x21
pop ax
ret
section .data
msg_hello db "Hello, from AIC", 0
переведи этот ассемблер в готовый сырой поток байт как при nasm -fbin и выдай base64 код
Вот готовый Base64-код скомпилированного бинарного потока (как при использовании команды nasm -fbin):
6AUAtEzNIcNVieW+HIDoBACJ7F3DULQBzSFYw0hlbGxvLCBmcm9tIEFJQwA=
## Разбор структуры по байтам (Hex-дамп)
Для наглядности ниже представлен шестнадцатеричный дамп (44 байта) с разбором инструкций:
E8 05 00 ; call main (относительное смещение +5 байт)
B4 4C ; mov ah, 0x4C
CD 21 ; int 0x21
C3 ; ret
55 ; push bp
89 E5 ; mov bp, sp
BE 1C 80 ; mov si, 0x801C (адрес msg_hello с учетом ORG 0x8000)
E8 04 00 ; call puts (относительное смещение +4 байта)
89 EC ; mov sp, bp
5D ; pop bp
C3 ; ret
50 ; push ax
B4 01 ; mov ah, 0x01
CD 21 ; int 0x21
58 ; pop ax
C3 ; ret
; Строка "Hello, from AICx00" (смещение 0x801C)
48 65 6C 6C 6F 2C 20 66 72 6F 6D 20 41 49 43 00
------------------------------
💡 Если вам понадобятся дополнительные изменения в коде (например, исправление функции puts, так как в данном коде прерывание int 0x21 с ah=0x01 ожидает ввод символа с клавиатуры вместо вывода строки si), дайте знать, и я помогу переписать ассемблерный код или пересобрать бинарник!
Пойдеееет.
Пишем в файл
[System.IO.File]::WriteAllBytes("./ai.bin", [System.Convert]::FromBase64String("6AUAtEzNIcNVieW+HIDoBACJ7F3DULQBzSFYw0hlbGxvLCBmcm9tIEFJQwA="))
Да я свиндусятник, не удивляйтесь. Пишите кстати если хотите статью как мы пишем ченить на powershell (там есть на что помотреть, я вас уверяю)
mcopy -i disk_img/x16pros.img ./ai.bin ::/BIN.DIR/
Да, я свиндусятник с wsl, не удивляйтесь.

Нууу, я не удивлен… не сильно то сложный код был.
Итог
Ээээмммм, да мне просто нечего было делать, я давно ещё этот прикол обнаружил и сейчас решил написать не то что-бы статью, а скорее поток действий, тк писал я стать. Паралельно с тем как вообще занимался всей этой фигней, и в общем все это заняло мение часа-полутора.
Я думаю если взять нейронку поумнее, промты по лучше, код по безопаснее, то что-то да из этого выйдет. Каков вообще шанс что вайбкодинг перерастет во что-то вот такое и в сурсах вайб-проектов будут просто истории терминалов с диалогами вот таких вот “компиляторов”.
А нормальные полноценные статьи от меня будут совсем скоро… покрайней мере я на это надеюсь:
SectorOS ещё обзаведется директориями и новыми программами (может даже совместимостью с x16-PRos).
SFS32 – файловая система на базе SFS тоже уже есть и полноценная 32х битная ось тоже не за горами.
Главный мой проект, который я не показываю тоже уже почти готов, но статья о нем скорее всего будет зимой когда он будет уже в состоянии конкурировать с другими решениями.
Большой цикл статей с очень интересной темой есть у меня в голове, но думаю писать я его начну в… как только так сразу.
У меня была идея сделать ТГК и публиковать туда не только развлекательный контент, но и позновательный и более узконаправленый вглубь наших компудахтеров, держать таким образом аудиторию, но думаю пока придержать эту идею. (я вообще хз есть ли тут те, кто прям знает меня как автора целых ДВУХ СТАТЕЙ, это вам не это)
диалог с “компилятором”: https://share.google/aimode/MKCLPmxxM48WjFHgr
не могу не оставить ссылку на сам x16-PRos: https://github.com/PRoX2011/x16-PRos
Всем спасибо за прочтение. Всех с протеряным летом.
Автор: Desvor


