Files
snark13 9f8aa6fc28 libc: две версии библиотеки — sprinter.lib (fast) / sprinter_safe.lib
Симметрично libbgi (bgi256/bgi256_safe): fast = -DLIBC_NOCHECK,
дефолт sprinter-cc; safe линкуется по --safe (флаг уже существовал).

Под LIBC_NOCHECK вырезаны ТОЛЬКО параметр-валидации:
- fgetc/fputc: NULL-check в горячей asm-обёртке (~11Т на каждый байт);
- fgets/fputs/fread/fwrite: NULL ptr/fp и EBADF на неверное направление
  потока; ftell/fseek/ungetc/fclose: NULL fp; cputs: NULL s.
НЕ тронуты: критичный _fd_guard (9-й OPEN вешает DSS — в обеих
версиях), функциональная маршрутизация (консоль/направление/hold),
cold-path валидации (fopen/cbl_open/irq/settextmode — экономии ноль).

libc/Makefile — dual-build по образцу libbgi (build/fast + build/safe,
общий стейл-контроль).  Корневой Makefile: в TESTS добавлены bgitest,
bgi_img, accfill, cblstream — раньше не собирались корневым make и
выпадали из size-check при чистой пересборке.

Дельты fast vs старая (safe-семантика): filetest -481, fbench -384,
solidt -180, errno -71, остальные -3..-9; роста нет.  Проверено в MAME:
filetest fast и safe (--safe, sprinter_safe.lib) — прогоны идентичны.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 22:11:01 +03:00

84 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sprinter C-Compiler — правила проекта
Target-слой SDCC 4.5 (z80) для компьютера Sprinter Sp2000: crt0,
линковка, libc, mkexe. Общение и комментарии — на русском.
## Сборка и проверка
```
make # tools + lib + libbgi + все тесты (45) + examples
make -C libc # только libc → lib/sprinter.lib (fast) + sprinter_safe.lib
make -C libbgi # только BGI → lib/bgi256.lib (fast) + bgi256_safe.lib
make floppy # упаковать все .exe в mame/v306/IMG/mc.img
make size-check # размерный регресс: _CODE vs docs/size_baseline.tsv
make size-baseline # принять текущие размеры эталоном
```
Обе библиотеки собираются в двух вариантах: fast (дефолт; `-D*_NOCHECK`
параметр-валидации вырезаны) и safe (линкуется по `sprinter-cc --safe`).
Критичные гарды (напр. _fd_guard — 9-й OPEN вешает DSS) — в ОБОИХ.
Графика (BGI) — отдельная библиотека libbgi/ (см. ниже). Программа,
использующая graphics.h, собирается с `--gfx 256` (или `--gfx 16` в
Фазе 2): sprinter-cc подлинкует lib/bgi256.lib и добавит -I libbgi/include.
Одиночный тест: `cd tests/<имя> && make run` (пакует exe + EXTRA_DATA на
дискету и запускает MAME автоматически через `toolchain/mame_interactive.py`,
снимает скриншоты, выводит пути). Для сложных сценариев (диалог, несколько
шагов ввода) — прямой вызов:
`python3 toolchain/mame_interactive.py tests/<имя>/<имя>.exe --snap T1,T2 --timeout T`.
Скриншоты лежат в `mame/v306/snap_auto/sprinter/` (читаются инструментом Read).
Подробности: `docs/mame-autotest.md`.
После правок libc/libbgi: пересборка от чистого листа (`make -C libc clean`
/ `make -C libbgi clean`) не обязательна — stale .rel чистятся
автоматически; `make size-check` обязателен (рост _CODE без причины —
регрессия).
## Правила libc
- **1 публичная функция = 1 .c-модуль** (линкер тянет .rel целиком —
гранулярность файлов = гранулярность DCE). Никакой группировки
«используются вместе». Internal-хелперы — тоже по одному на модуль
(`_`-префикс); общие статики — в отдельные data-модули
(`_xxx_state.c`); internal-заголовки (`_file.h`, `_gfx.h`, …) —
рядом с исходниками, НЕ в libc/include.
- Имя файла = имя функции. libc/Makefile собирает wildcard'ом —
ничего регистрировать не надо.
- Комментарии — на русском; шапка модуля объясняет что/зачем + ABI.
- File-scope переменные НЕ инициализировать `= 0` (crt0 зануляет
_DATA; см. memory/sdcc_static_storage_gotcha).
- asm-связки между модулями: `call/jp _global` — ок; `jr/djnz` через
границу и fall-through — НЕЛЬЗЯ (docs/libc-split-asm-cases.md).
- Заголовки: сначала пробовать include_next-паттерн; полная замена
SDCC-заголовка обязана дублировать его контракт
(docs/libc-headers.md).
- Справочник API — docs/libc-reference.md (обновлять при добавлении
функций).
## ABI и платформа (кратко; детали в memory/)
- SDCC `__sdcccall(1)`: arg1 → HL (8-бит → A), arg2 → DE, остальные
на стеке (callee-pops в __naked); **возврат int/ptr в DE**, uint8 в A.
IX callee-saved (в __naked с IX — push/pop обязательны).
- ESTEX (rst #0x10): CF=1 — ошибка, код в A → `call __errno_set`;
все регистры клобберятся (IX сохранять); стек обязан быть в W2.
- BIOS (rst #0x08): строки/буферы в #4000-#BFFF.
- Квирки: ESTEX WRITE возвращает DE=0 на успехе (судить по CF/A);
лимит 8 файловых манипуляторов, 9-й OPEN ВЕШАЕТ DSS (_fd_guard);
ENV $46: A=0 = NOT FOUND.
- Перед обвинением компилятора/железа — подтвердить артефактом
(сгенерированный .asm в libc/build/ или libbgi/build/, дамп, репро) — см.
memory/defer_unexplained_quirks.
## Структура
- `libc/<area>/*.c` — модули libc (ядро, БЕЗ графики); `libc/include/` — публичные заголовки libc
- `libbgi/` — графика BGI (отдельная библиотека): `common/` — mode-agnostic (один исходник, .rel в обеих driver-библиотеках), `bgi256/` + `bgi16/` — mode-specific leaf'ы (реальные реализации, без обёрток); `include/` — graphics.h + gfx.h; `_bgi.h` — внутренний заголовок. Собирает `lib/bgi256.lib``bgi16.lib` в Фазе 2). Выбор режима линковкой: `--gfx 256` / `--gfx 16`.
- `runtime/` — crt0-семейство, heap, bank (bank.s собирается per-build)
- `bin/sprinter-cc` — обёртка компилятора; `toolchain/mkexe` — упаковщик
- `tests/` — по одному API/фиче; `examples/` — реальные приложения
- `docs/` — дизайн-доки; `docs/TODO.md` — roadmap
- `third_party/solid-c/` — нативный Sprinter C (референс, CP866;
их ABI несовместим — только как образец)