a6fe50e247
Проще исходного плана (docs/im2_isr_design.md обновлён): отдельный --memory im2 не понадобился. - <irq.h>: irq_install(handler) — вызов ~50 Гц только на КАДРОВЫХ прерываниях (клавиатура bit0:0x19 и CBL bit7:0xFE отфильтровываются); штатный обработчик DSS чейнится ВСЕГДА (SMC-jp, адрес из старой IM2-таблицы по регистру I) — клавиатура/SYSTIME/мышь живут - вектор-таблица: 513 Б BSS + runtime-выравнивание; Sprinter шлёт только вектор 0xFF, поэтому jp-заглушка лежит внутри самой таблицы по смещению H — без linker-областей и правок crt0 - трамплин: полный сейв обоих наборов+IX/IY вокруг user-handler'а (ex af,af' как .db 0x08 — апостроф ломает препроцессор SDCC) - tiny/big: работает (код в W2); small/huge: EINVAL по проверке адресов; irq_remove идемпотентен и висит на atexit (выход без снятия = I в памяти умершего процесса = крах шелла); old_I==0 → IM1 - tests/irqtest: тики за 3 с против time() (~50 Гц), живая клавиатура под handler'ом, остановка после remove, чистый выход - docs: im2_isr_design (статус+дельты), libc-reference (<irq.h>), TODO Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
206 lines
11 KiB
Markdown
206 lines
11 KiB
Markdown
# libc — справочник API (2026-07-06)
|
||
|
||
Сводка по заголовкам: сигнатура + одна строка + особенности ABI.
|
||
Детали дизайна: docs/libc-headers.md (контракт затенения SDCC),
|
||
docs/file-buffering-design.md (FILE*), docs/solid_c_compatibility.md.
|
||
|
||
Общие соглашения:
|
||
- ошибки: возврат -1/NULL/EOF + `errno` (код DSS as-is, см. errno.h);
|
||
- SDCC `__sdcccall(1)`: 1-й аргумент HL (8-битный — A), 2-й — DE,
|
||
остальные на стеке; **int/указатель возвращается в DE**;
|
||
- строки для BIOS-вызовов (rst 8) должны лежать в #4000–#BFFF;
|
||
- стек при любых ESTEX/BIOS-вызовах — в W2 (обеспечено crt0).
|
||
|
||
## <stdio.h> — полная замена SDCC (контракт: printf-семейство из z80.lib)
|
||
|
||
Из SDCC z80.lib: `printf sprintf vprintf vsprintf`.
|
||
|
||
Консоль (ESTEX, без атрибутов — быстрый путь; цветной вывод — conio):
|
||
| Сигнатура | Описание |
|
||
|---|---|
|
||
| `int putchar(int c)` | символ через PUTCHAR $5B; '\n'→CR LF |
|
||
| `int getchar(void)` | блокирующий WAITKEY $30, ASCII |
|
||
| `char puts(const char *s)` | строка + '\n' (посимвольно через putchar) |
|
||
| `char *gets(char *buf)` | строка с консоли, без контроля длины |
|
||
| `void dec8/dec16/dec32(v)` | десятичная печать без ведущих нулей |
|
||
| `void hex8/hex16/hex32(v)` | hex-печать фиксированной ширины |
|
||
|
||
FILE* (буферизованный, вариант B+ — единый ленивый буфер BUFSIZ=512
|
||
на чтение/запись с автопереключением; таблица `OPEN_MAX=8` слотов;
|
||
exit() сбрасывает всё через atexit; **ошибки записи отложенные —
|
||
проверять fclose**):
|
||
| Сигнатура | Описание |
|
||
|---|---|
|
||
| `FILE *fopen(path, mode)` | "r/w/a" + '+', 'b/t' игнорируются |
|
||
| `FILE *fdopen(fd, mode)` | завернуть готовый fd (закрывать fclose!) |
|
||
| `FILE *freopen(path, mode, fp)` | переоткрыть тот же FILE* |
|
||
| `int fclose(FILE*)` / `void fclosall(void)` | сброс+закрытие / все потоки |
|
||
| `int fflush(FILE*)` | сброс записи / откат readahead; NULL = все |
|
||
| `int fgetc/fputc(...)` | горячий путь на asm; getc/putc — макро-алиасы |
|
||
| `char *fgets(buf, n, fp)` | до '\n' (сохраняется); блочный LDI-сканер |
|
||
| `int fputs(s, fp)` | без '\n'; через fwrite |
|
||
| `size_t fread/fwrite(p, sz, n, fp)` | блоки ≥ 512 идут мимо буфера |
|
||
| `int ungetc(c, fp)` | 1 байт putback (и на stdin) |
|
||
| `int fseek(fp, off, whence)` / `long ftell(fp)` | ftell без побочных эффектов |
|
||
| `void rewind(fp)` | fseek(0) + сброс EOF/ERROR |
|
||
| `int fgetpos/fsetpos(fp, &pos)` | fpos_t = long |
|
||
| `int feof/ferror(fp)`, `void clearerr(fp)` | флаги потока |
|
||
| `int fprintf/vfprintf(fp, fmt, ...)` | vsprintf в статический буфер 256 |
|
||
| `int scanf/fscanf/sscanf(...)` | %d %u %x %o %c %s, `l`, ширина, %*, %% |
|
||
| `int rename(old, new)` | ESTEX RENAME $10 |
|
||
|
||
`stdin/stdout/stderr` — консольные псевдопотоки (fd 0/-1/-2), не
|
||
буферизуются; freopen на них меняет только FILE*-операции (printf
|
||
идёт в ESTEX напрямую).
|
||
|
||
## <stdlib.h> — include_next + добавки
|
||
|
||
Из SDCC: malloc/free/calloc/realloc (heap в W2), atoi/atol/strtol/
|
||
strtoul, rand/srand, qsort/bsearch, abs/labs, div/ldiv, exit-типы.
|
||
Наше: `int16_t min(a,b)`, `int16_t max(a,b)` (функции, как в Solid-C).
|
||
|
||
## <string.h> — include_next + добавки
|
||
|
||
Из SDCC: mem*/str* полностью. Наше: `char *strlwr/strupr(char *s)` —
|
||
in-place регистр, латиница + кириллица CP866.
|
||
|
||
## <time.h> — полная замена (struct tm в SDCC-ABI, __TIME_UNSIGNED=1)
|
||
|
||
| Сигнатура | Описание |
|
||
|---|---|
|
||
| `void getdatetime(datetime_t*)` | RTC как есть (ESTEX SYSTIME $21) |
|
||
| `int setdatetime(const datetime_t*)` | установка RTC ($22) |
|
||
| `time_t time(time_t*)` | Unix-эпоха из RTC |
|
||
| `mktime/gmtime/localtime/asctime/ctime` | POSIX поверх RTC (без TZ) |
|
||
|
||
`datetime_t`: day/month/year(полный)/hour/minute/second/dow (1=Вс).
|
||
|
||
## <unistd.h>, <fcntl.h> — fd-уровень (манипуляторы DSS)
|
||
|
||
| Сигнатура | Описание |
|
||
|---|---|
|
||
| `int open(path, flags)` | O_RDONLY/WRONLY/RDWR + O_CREAT/TRUNC/EXCL/APPEND (ESTEX $11/$0A/$0B) |
|
||
| `int creat(path, mode)` | open(W|CREAT|TRUNC); mode игнорируется |
|
||
| `int read/write(fd, buf, n)` | ESTEX $13/$14. **Квирк WRITE: DE-возврат ненадёжен, успех = CF=0&A=0** (см. memory/estex_write_de_quirk) |
|
||
| `int close(fd)` | ESTEX $12 |
|
||
| `long lseek(fd, off, whence)` | 32-битная позиция (MOVE_FP $15) |
|
||
| `int unlink(path)` | удалить (DELETE $0E) |
|
||
| `int isatty(fd)` | fd <= 0 (файловые манипуляторы DSS с 1) |
|
||
| `int mkdir/rmdir/chdir(path)` | ESTEX $1B/$1C/$1D |
|
||
| `char *getcwd(buf, size)` | буфер 256 байт, size игнорируется |
|
||
| `void sleep(seconds)` | 50 halt/с по кадровому IRQ |
|
||
|
||
**Лимит: 8 одновременных манипуляторов**; 9-й OPEN вешает DSS —
|
||
libc отказывает сама (EMFILE, предохранитель _fd_guard).
|
||
|
||
## <errno.h>
|
||
|
||
`errno` (int), коды = коды DSS (EOK..EUNKERR) + POSIX-имена
|
||
(ENOENT/EBADF/EMFILE/…) + алиасы Solid-C (EZERO/EINVFNC/ENOFILE/…).
|
||
`const char *strerror(int)`, `void perror(const char*)`.
|
||
|
||
## <dos.h> — DOS-слой Solid-C
|
||
|
||
| Сигнатура | Описание |
|
||
|---|---|
|
||
| `void getdate/gettime(&d)` | struct date/time (Turbo-C; ti_hund=0) |
|
||
| `int setdate/settime(&d)` | RMW полного datetime |
|
||
| `uint8_t getdisk(void)` | текущий диск, 0=A (ESTEX $02) |
|
||
| `int setdisk(uint8_t)` | смена диска; возврат = число дисков ($01) |
|
||
| `int absread/abswrite(disk, sect, cnt, buf)` | секторы ЛОГИЧЕСКОГО диска (BIOS $55/$56); буфер в #4000–#BFFF; abswrite минует ФС! |
|
||
|
||
## <dir.h>
|
||
|
||
`int ffirst(pattern, ffblk_t*, attrib)` / `int fnext(ffblk_t*)` —
|
||
поиск по шаблону (ESTEX $19/$1A). Квирк: "."/".." находятся только
|
||
итерацией "*.*" (memory/estex_ffirst_dotdot). FA_*-атрибуты.
|
||
|
||
## <sys/stat.h>
|
||
|
||
`int stat(path, struct stat*)` / `int fstat(fd, ...)` — st_mode
|
||
(S_ISREG/S_ISDIR), st_size, st_mtime (Unix-эпоха).
|
||
|
||
## <conio.h> — текстовый экран с атрибутами (Turbo-C стиль)
|
||
|
||
Клавиатура: `kbhit getch getche getkey` (+KEY_* коды позиций),
|
||
`char *cgets(buf)`.
|
||
Вывод с атрибутом: `putch cputs cprintf` (~10× медленнее stdio-пути;
|
||
'\n' НЕ транслируется — писать "\r\n").
|
||
Атрибуты: `textcolor textbackground textattr`, `set/get_text_attr`,
|
||
COLOR_*-enum, `COLOR(fg,bg)`, COLOR_BLINK; `set/get_putch_raw_mode`.
|
||
Экран: `clrscr clrscr_attr gotoxy home() wherex wherey wherexy scroll
|
||
wrchar rdchar`; режимы `gettextmode/settextmode` (0x02=40×32,
|
||
0x03=80×32).
|
||
Порты/IRQ: `inp outp enable() disable()`.
|
||
Текстовая палитра: `text_pal_load/set_color/get/get_color/reset`
|
||
(план 0..3 → страница BIOS 4..7).
|
||
|
||
## <bios/text.h> — быстрый BIOS-вывод (rst 8, place-based)
|
||
|
||
`bios_set_place/get_place`, `bios_write[attr][_until|_stop]`,
|
||
`bios_fillchar/fillattr/fillcharattr`, `bios_clearwin[_ch]`,
|
||
`bios_scrollwin`. Строка s — в #4000–#BFFF; place продвигается.
|
||
|
||
## <gfx.h> — графика (0x81: 320×256×256; 0x82: 640×256×16)
|
||
|
||
Setup: `gfx_init(mode,page)→prev`, `gfx_done(prev)`.
|
||
Страницы/банк: `gfx_set/get_visible_page`, `gfx_set/get_draw_page`
|
||
(double buffering), `gfx_set/get_bank` (0x50..0x5F, 0x58 = FF-
|
||
прозрачность), `gfx_wait_vsync()`.
|
||
Примитивы (суффикс _256 / _16): `clear putpixel hline vline line
|
||
rect fill_rect` — через акселератор (hline/vline burst до 256 байт;
|
||
в 0x82 vline через RMW). Координаты int, клиппинг по краям.
|
||
Текст: `gfx_putchar256/16, gfx_text256/16` (8×8, fg/bg; в 0x82 x —
|
||
чётный), `gfx_load_default_font`, `gfx_set_font(ptr)` (interleaved
|
||
font[row*256+char]).
|
||
Палитра: `gfx_pal_load/set/get/get_color/reset` (страницы 0..3).
|
||
|
||
## <irq.h> — user-ISR кадрового прерывания (IM 2)
|
||
|
||
| Сигнатура | Описание |
|
||
|---|---|
|
||
| `int irq_install(isr_t h)` | h зовётся ~50 Гц на кадровых прерываниях; DSS-обработчик чейнится всегда (клавиатура/SYSTIME/мышь живы). 0 / -1+errno (EBUSY повтор, EINVAL — код не в W2: только tiny/big) |
|
||
| `void irq_remove(void)` | вернуть таблицу DSS; идемпотентно; висит на atexit |
|
||
| `IRQ_DISABLE()/IRQ_ENABLE()` | di/ei — скобки для чтения shared-переменных из main |
|
||
|
||
Handler'у нельзя: ESTEX/BIOS-вызовы, gfx_*/своп окон, акселератор,
|
||
banked-функции; только volatile-глобалы и быстрая работа (<1 мс).
|
||
|
||
## <palette.h> — низкий уровень (BIOS $A4/$A6)
|
||
|
||
`pal_load pal_get pal_set_color pal_get_color` (страница 0..7,
|
||
записи B,G,R,0), `pal_reset(type)` / `pal_reset_at(type,page,graph)`;
|
||
PAL_GRAPH/PAL_SINCLAIR/PAL_CGA.
|
||
|
||
## <mouse.h> — драйвер RST 30h
|
||
|
||
`mouse_init show hide refresh read(mouse_state_t*) goto bounds_x/y
|
||
text_cursor load_cursor/get_cursor(mouse_cursor_t*) set_sensitivity
|
||
get_sensitivity_x/y video_mode_changed`. Sensitivity = делитель
|
||
(меньше = быстрее). Solid-C алиасы ms_* включены.
|
||
|
||
## <sprinter.h> — платформа
|
||
|
||
Константы портов (PORT_PAGE_W0..W3, PORT_RGADR, PORT_RGMOD), номера
|
||
всех ESTEX-функций (ESTEX_*), BIOS EMM ($C0..$C7); `__sfr`-доступ и
|
||
inline `sprinter_page_w0..w3(page)`; ENV: `getenv putenv sysenv`.
|
||
|
||
## <sprinter_mem.h> — EMM-страницы и банковый I/O
|
||
|
||
`mem_alloc_pages(n)→blk_id, mem_free_block, mem_get_page(blk,idx),
|
||
mem_info(&total,&free)` (реализации _bios/_estex; макро-выбор
|
||
MEM_MANAGE_MODE_*). HOME-резидентный доступ к чужим страницам:
|
||
`bank_load_byte/store_byte/read/write` (своп W3 внутри; *_w1 —
|
||
вариант через окно W1).
|
||
|
||
## <sprinter_exit.h>
|
||
|
||
`atexit` (LIFO, 8 слотов), `exit` (хендлеры+сброс FILE), `_exit`.
|
||
|
||
## <sprinter_compat.h> / <sprinter_solid.h>
|
||
|
||
Типы (BYTE/BOOL/WORD/uint/FD/f_point), TRUE/FALSE/OK/ERROR,
|
||
`setmem movmem` (порядок аргументов!), `strerr seek tell ltell
|
||
remove _ffirst _setargv abort()`, isascii. `<sprinter_solid.h>` —
|
||
зонтичный: один include для портирования Solid-C программ.
|