libc: сплит «1 функция = 1 модуль» — вся библиотека, wildcard-сборка

- bios/conio/env/errno/gfx/io/mem/mouse/stdio/stdlib/string/sys/time/
  video разложены по модулям: общие статики и helpers — в internal
  _-модулях (_conio.h/_mouse.h/_gfx.h/_palette.h/_atexit.h/_time.h)
- lib/Makefile: LIBC_C = wildcard libc/*/*.c — гранулярность файлов
  = гранулярность DCE линкера
- эффект _CODE: gfx_text 6986→2568 Б, gfx_mous −1745, gfx_demo/d16
  −542; ранее timedir −3270, ls −3098, stattest −2995
- комментарии оставшихся модулей переведены на русский; puts: убран
  мёртвый pchars; videomode_raw разложен на get/set
- docs/libc-split-asm-cases.md — правила asm-связок между модулями;
  docs/libc-roadmap.md — план этапа
- восстановлен examples/mdview/SAMPLE.MD (нужен make floppy)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 16:08:58 +03:00
parent 46553f4e07
commit 4a081501d8
237 changed files with 4830 additions and 3933 deletions
+33
View File
@@ -0,0 +1,33 @@
/*
* bios_clearwin — очистить окно (row, col, height, width) пробелами с
* атрибутом attr. BIOS LP_CLS_WIN ($89, rst 8): D=row, E=col,
* H=height, L=width, B=attr.
*/
#include <bios/text.h>
void bios_clearwin(uint8_t row, uint8_t col, uint8_t height, uint8_t width,
uint8_t attr) __naked
{
(void)row; (void)col; (void)height; (void)width; (void)attr;
__asm
;; rowA, colL, height/width/attr на стеке [SP+2..4].
ld iy, #2
add iy, sp
ld h, 0 (iy) ; H = height
ld c, 1 (iy) ; спрятать width (L пока держит col)
ld e, l ; E = col
ld d, a ; D = row
ld l, c ; L = width
ld b, 2 (iy) ; B = attr
push ix
ld c, #0x89
rst #0x08
pop ix
pop hl
inc sp
inc sp
inc sp ; съесть height + width + attr
jp (hl)
__endasm;
}
+35
View File
@@ -0,0 +1,35 @@
/*
* bios_clearwin_ch — залить окно (row, col, height, width) символом
* fillch с атрибутом attr. BIOS LP_CLS_WIN2 ($8D, rst 8): D=row,
* E=col, H=height, L=width, B=attr, A=fillch.
*/
#include <bios/text.h>
void bios_clearwin_ch(uint8_t row, uint8_t col, uint8_t height,
uint8_t width, uint8_t attr, char fillch) __naked
{
(void)row; (void)col; (void)height; (void)width; (void)attr; (void)fillch;
__asm
;; rowA, colL, height/width/attr/fillch на стеке [SP+2..5].
ld iy, #2
add iy, sp
ld d, a ; D = row (освободить A под fillch)
ld e, l ; E = col (освободить L под width)
ld h, 0 (iy) ; H = height
ld c, 1 (iy) ; спрятать width
ld b, 2 (iy) ; B = attr
ld a, 3 (iy) ; A = fillch
ld l, c ; L = width
push ix
ld c, #0x8D
rst #0x08
pop ix
pop hl
inc sp
inc sp
inc sp
inc sp ; съесть height + width + attr + fillch
jp (hl)
__endasm;
}
+20
View File
@@ -0,0 +1,20 @@
/*
* bios_fillattr — залить count позиций атрибутом attr (символы не
* трогаются) от текущего place. BIOS LP_PRINT_ATR ($83, rst 8):
* E=attr, B=count. Сохраняет HL и IX.
*/
#include <bios/text.h>
void bios_fillattr(uint8_t attr, uint8_t count) __naked
{
(void)attr; (void)count;
__asm
;; attrA, countL.
ld e, a
ld b, l
ld c, #0x83
rst #0x08
ret
__endasm;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* bios_fillchar — вывести символ ch count раз (атрибут не трогается)
* от текущего place. BIOS LP_PRINT_SYM ($82, rst 8): A=ch, B=count.
* Сохраняет HL и IX.
*/
#include <bios/text.h>
void bios_fillchar(char ch, uint8_t count) __naked
{
(void)ch; (void)count;
__asm
;; chA, countL.
ld b, l
ld c, #0x82
rst #0x08
ret
__endasm;
}
+26
View File
@@ -0,0 +1,26 @@
/*
* bios_fillcharattr — вывести символ ch с атрибутом attr count раз от
* текущего place. BIOS LP_PRINT_ALL ($81, rst 8): A=ch, E=attr,
* B=count. Сохраняет HL и IX — push/pop ix не нужен.
*
* SDCC __sdcccall(1): ch→A, attr→L, count на стеке [SP+2]; стековый
* байт съедает callee (inc sp), IY — скретч для чтения без порчи IX.
*/
#include <bios/text.h>
void bios_fillcharattr(char ch, uint8_t attr, uint8_t count) __naked
{
(void)ch; (void)attr; (void)count;
__asm
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = count
ld e, l ; E = attr
ld c, #0x81
rst #0x08
pop hl ; адрес возврата
inc sp ; съесть байт count
jp (hl)
__endasm;
}
+16
View File
@@ -0,0 +1,16 @@
/*
* bios_get_place — текущая позиция BIOS-вывода: (row << 8) | col.
* BIOS LP_GET_PLACE ($8E, rst 8) возвращает D=row, E=col — это уже
* конвенция возврата uint16_t (DE), перестановок не нужно.
*/
#include <bios/text.h>
uint16_t bios_get_place(void) __naked
{
__asm
ld c, #0x8E
rst #0x08
ret
__endasm;
}
+27
View File
@@ -0,0 +1,27 @@
/*
* bios_scrollwin — прокрутить экран от строки row на count строк.
* BIOS LP_SCROLL_UD ($8A, rst 8): B=dir (1=вверх, 2=вниз), D=row,
* E=count.
*/
#include <bios/text.h>
void bios_scrollwin(uint8_t dir, uint8_t row, uint8_t count) __naked
{
(void)dir; (void)row; (void)count;
__asm
;; dirA, rowL, count на стеке [SP+2].
ld iy, #2
add iy, sp
ld e, 0 (iy) ; E = count
ld d, l ; D = row
ld b, a ; B = dir
push ix
ld c, #0x8A
rst #0x08
pop ix
pop hl
inc sp
jp (hl)
__endasm;
}
+20
View File
@@ -0,0 +1,20 @@
/*
* bios_set_place — установить позицию вывода BIOS-текста (place).
* BIOS LP_SET_PLACE ($84, rst 8): D=row, E=col. Используется без
* push/pop ix (как gotoxy в conio — эмпирически безопасно).
*/
#include <bios/text.h>
void bios_set_place(uint8_t row, uint8_t col) __naked
{
(void)row; (void)col;
__asm
;; rowA, colL.
ld d, a
ld e, l
ld c, #0x84
rst #0x08
ret
__endasm;
}
+25
View File
@@ -0,0 +1,25 @@
/*
* bios_write — вывести len символов строки s (атрибут не трогается).
* BIOS LP_PRINT_LN2 ($86, rst 8): HL=s, B=len. Place продвигается.
* s должен лежать в #4000-#BFFF.
*/
#include <bios/text.h>
void bios_write(const char *s, uint8_t len) __naked
{
(void)s; (void)len;
__asm
;; sHL, len на стеке [SP+2].
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = len
push ix
ld c, #0x86
rst #0x08
pop ix
pop hl
inc sp
jp (hl)
__endasm;
}
+27
View File
@@ -0,0 +1,27 @@
/*
* bios_write_stop — вывести строку s до разделителя sep БЕЗ добивки
* (максимум maxlen символов, атрибут не трогается).
* BIOS LP_PRINT_LN6 ($8C, rst 8): HL=s, B=maxlen, D=sep.
*/
#include <bios/text.h>
void bios_write_stop(const char *s, uint8_t maxlen, char sep) __naked
{
(void)s; (void)maxlen; (void)sep;
__asm
;; sHL, maxlen/sep на стеке [SP+2..3].
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = maxlen
ld d, 1 (iy) ; D = sep
push ix
ld c, #0x8C
rst #0x08
pop ix
pop hl
inc sp
inc sp
jp (hl)
__endasm;
}
+27
View File
@@ -0,0 +1,27 @@
/*
* bios_write_until — вывести строку s до разделителя sep, ДОБИВ
* пробелами до len (атрибут не трогается). BIOS LP_PRINT_LN4 ($88,
* rst 8): HL=s, B=len, D=sep.
*/
#include <bios/text.h>
void bios_write_until(const char *s, uint8_t len, char sep) __naked
{
(void)s; (void)len; (void)sep;
__asm
;; sHL, len/sep на стеке [SP+2..3].
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = len
ld d, 1 (iy) ; D = sep
push ix
ld c, #0x88
rst #0x08
pop ix
pop hl
inc sp
inc sp
jp (hl)
__endasm;
}
+29
View File
@@ -0,0 +1,29 @@
/*
* bios_writeattr — вывести len символов строки s с атрибутом attr.
* BIOS LP_PRINT_LN ($85, rst 8): HL=s, B=len, E=attr. Place
* продвигается после печати. s должен лежать в #4000-#BFFF.
*
* SDCC __sdcccall(1): s→HL, len/attr на стеке [SP+2]/[SP+3];
* стековые байты съедает callee.
*/
#include <bios/text.h>
void bios_writeattr(const char *s, uint8_t len, uint8_t attr) __naked
{
(void)s; (void)len; (void)attr;
__asm
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = len
ld e, 1 (iy) ; E = attr
push ix
ld c, #0x85
rst #0x08
pop ix
pop hl ; адрес возврата
inc sp
inc sp ; съесть len + attr
jp (hl)
__endasm;
}
+30
View File
@@ -0,0 +1,30 @@
/*
* bios_writeattr_stop — вывести строку s с атрибутом attr до
* разделителя sep БЕЗ добивки пробелами (максимум maxlen символов).
* BIOS LP_PRINT_LN5 ($8B, rst 8): HL=s, B=maxlen, E=attr, D=sep.
*/
#include <bios/text.h>
void bios_writeattr_stop(const char *s, uint8_t maxlen, uint8_t attr,
char sep) __naked
{
(void)s; (void)maxlen; (void)attr; (void)sep;
__asm
;; sHL, maxlen/attr/sep на стеке [SP+2..4].
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = maxlen
ld e, 1 (iy) ; E = attr
ld d, 2 (iy) ; D = sep
push ix
ld c, #0x8B
rst #0x08
pop ix
pop hl
inc sp
inc sp
inc sp
jp (hl)
__endasm;
}
+29
View File
@@ -0,0 +1,29 @@
/*
* bios_writeattr_until — вывести строку s с атрибутом attr до
* разделителя sep, ДОБИВ пробелами до len. BIOS LP_PRINT_LN3 ($87,
* rst 8): HL=s, B=len, E=attr, D=sep.
*/
#include <bios/text.h>
void bios_writeattr_until(const char *s, uint8_t len, uint8_t attr, char sep) __naked
{
(void)s; (void)len; (void)attr; (void)sep;
__asm
;; sHL, len/attr/sep на стеке [SP+2..4].
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = len
ld e, 1 (iy) ; E = attr
ld d, 2 (iy) ; D = sep
push ix
ld c, #0x87
rst #0x08
pop ix
pop hl
inc sp
inc sp
inc sp ; съесть len + attr + sep
jp (hl)
__endasm;
}
-302
View File
@@ -1,302 +0,0 @@
/*
* text.c — wrappers for the Sprinter BIOS text-output calls (RST 8,
* 081h..08Eh "LP_*"). See <bios/text.h> for the full opcode -> name
* mapping and semantics.
*
* ABI recap (docs/converted/bios.txt):
* - 081h/082h/083h explicitly preserve HL and IX -> no push/pop ix
* needed, and the result is the smallest/fastest of the set.
* - 084h/08Eh (place get/set) are used without push/pop ix elsewhere
* in this libc (libc/conio/conio.c gotoxy/wherex/wherey via the same
* opcodes) — empirically safe, followed here too.
* - Everything else clobbers IX like any other BIOS/ESTEX call, so
* every RST 8 below is bracketed with push ix / pop ix.
*
* Stack-argument layout: SDCC __sdcccall(1) places the first 8-bit arg
* in A, the second (only if the first was also 8-bit) in L; every arg
* beyond that lands on the stack in left-to-right declaration order,
* starting at [SP+2] (right after the 2-byte return address) — verified
* empirically via `sdcc -S` for 2..6 uint8 args and for pointer+N uint8
* args. IY is used as a scratch index register to read those without
* disturbing IX (the caller's frame pointer).
*/
#include <bios/text.h>
void bios_fillcharattr(char ch, uint8_t attr, uint8_t count) __naked
{
(void)ch; (void)attr; (void)count;
__asm
;; ch->A, attr->L, count on stack at [SP+2].
;; LP_PRINT_ALL (081h): A=ch, E=attr, B=count. Preserves HL,IX.
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = count
ld e, l ; E = attr
ld c, #0x81
rst #0x08
pop hl ; return address
inc sp ; consume count byte
jp (hl)
__endasm;
}
void bios_fillchar(char ch, uint8_t count) __naked
{
(void)ch; (void)count;
__asm
;; ch->A, count->L. LP_PRINT_SYM (082h): A=ch, B=count.
;; Preserves HL,IX.
ld b, l
ld c, #0x82
rst #0x08
ret
__endasm;
}
void bios_fillattr(uint8_t attr, uint8_t count) __naked
{
(void)attr; (void)count;
__asm
;; attr->A, count->L. LP_PRINT_ATR (083h): E=attr, B=count.
;; Preserves HL,IX.
ld e, a
ld b, l
ld c, #0x83
rst #0x08
ret
__endasm;
}
void bios_set_place(uint8_t row, uint8_t col) __naked
{
(void)row; (void)col;
__asm
;; row->A, col->L. LP_SET_PLACE (084h): D=row, E=col.
ld d, a
ld e, l
ld c, #0x84
rst #0x08
ret
__endasm;
}
uint16_t bios_get_place(void) __naked
{
__asm
;; LP_GET_PLACE (08Eh): returns D=row, E=col already the
;; uint16_t return convention (DE); nothing left to rearrange.
ld c, #0x8E
rst #0x08
ret
__endasm;
}
void bios_writeattr(const char *s, uint8_t len, uint8_t attr) __naked
{
(void)s; (void)len; (void)attr;
__asm
;; s->HL, len/attr on stack at [SP+2]/[SP+3].
;; LP_PRINT_LN (085h): HL=s, B=len, E=attr.
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = len
ld e, 1 (iy) ; E = attr
push ix
ld c, #0x85
rst #0x08
pop ix
pop hl ; return address
inc sp
inc sp ; consume len + attr
jp (hl)
__endasm;
}
void bios_write(const char *s, uint8_t len) __naked
{
(void)s; (void)len;
__asm
;; s->HL, len on stack at [SP+2].
;; LP_PRINT_LN2 (086h): HL=s, B=len.
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = len
push ix
ld c, #0x86
rst #0x08
pop ix
pop hl
inc sp
jp (hl)
__endasm;
}
void bios_writeattr_until(const char *s, uint8_t len, uint8_t attr, char sep) __naked
{
(void)s; (void)len; (void)attr; (void)sep;
__asm
;; s->HL, len/attr/sep on stack at [SP+2..4].
;; LP_PRINT_LN3 (087h): HL=s, B=len, E=attr, D=sep.
;; Pads with spaces after sep up to len.
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = len
ld e, 1 (iy) ; E = attr
ld d, 2 (iy) ; D = sep
push ix
ld c, #0x87
rst #0x08
pop ix
pop hl
inc sp
inc sp
inc sp ; consume len + attr + sep
jp (hl)
__endasm;
}
void bios_write_until(const char *s, uint8_t len, char sep) __naked
{
(void)s; (void)len; (void)sep;
__asm
;; s->HL, len/sep on stack at [SP+2..3].
;; LP_PRINT_LN4 (088h): HL=s, B=len, D=sep. Pads with spaces.
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = len
ld d, 1 (iy) ; D = sep
push ix
ld c, #0x88
rst #0x08
pop ix
pop hl
inc sp
inc sp
jp (hl)
__endasm;
}
void bios_clearwin(uint8_t row, uint8_t col, uint8_t height, uint8_t width,
uint8_t attr) __naked
{
(void)row; (void)col; (void)height; (void)width; (void)attr;
__asm
;; row->A, col->L, height/width/attr on stack at [SP+2..4].
;; LP_CLS_WIN (089h): D=row, E=col, H=height, L=width, B=attr.
ld iy, #2
add iy, sp
ld h, 0 (iy) ; H = height
ld c, 1 (iy) ; stash width (L is still col for now)
ld e, l ; E = col
ld d, a ; D = row
ld l, c ; L = width
ld b, 2 (iy) ; B = attr
push ix
ld c, #0x89
rst #0x08
pop ix
pop hl
inc sp
inc sp
inc sp ; consume height + width + attr
jp (hl)
__endasm;
}
void bios_scrollwin(uint8_t dir, uint8_t row, uint8_t count) __naked
{
(void)dir; (void)row; (void)count;
__asm
;; dir->A, row->L, count on stack at [SP+2].
;; LP_SCROLL_UD (08Ah): B=dir(1 up/2 down), D=row, E=count.
ld iy, #2
add iy, sp
ld e, 0 (iy) ; E = count
ld d, l ; D = row
ld b, a ; B = dir
push ix
ld c, #0x8A
rst #0x08
pop ix
pop hl
inc sp
jp (hl)
__endasm;
}
void bios_writeattr_stop(const char *s, uint8_t maxlen, uint8_t attr,
char sep) __naked
{
(void)s; (void)maxlen; (void)attr; (void)sep;
__asm
;; s->HL, maxlen/attr/sep on stack at [SP+2..4].
;; LP_PRINT_LN5 (08Bh): HL=s, B=maxlen, E=attr, D=sep.
;; Stops at sep (no padding).
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = maxlen
ld e, 1 (iy) ; E = attr
ld d, 2 (iy) ; D = sep
push ix
ld c, #0x8B
rst #0x08
pop ix
pop hl
inc sp
inc sp
inc sp
jp (hl)
__endasm;
}
void bios_write_stop(const char *s, uint8_t maxlen, char sep) __naked
{
(void)s; (void)maxlen; (void)sep;
__asm
;; s->HL, maxlen/sep on stack at [SP+2..3].
;; LP_PRINT_LN6 (08Ch): HL=s, B=maxlen, D=sep. Stops at sep.
ld iy, #2
add iy, sp
ld b, 0 (iy) ; B = maxlen
ld d, 1 (iy) ; D = sep
push ix
ld c, #0x8C
rst #0x08
pop ix
pop hl
inc sp
inc sp
jp (hl)
__endasm;
}
void bios_clearwin_ch(uint8_t row, uint8_t col, uint8_t height,
uint8_t width, uint8_t attr, char fillch) __naked
{
(void)row; (void)col; (void)height; (void)width; (void)attr; (void)fillch;
__asm
;; row->A, col->L, height/width/attr/fillch on stack [SP+2..5].
;; LP_CLS_WIN2 (08Dh): D=row, E=col, H=height, L=width, B=attr,
;; A=fillch.
ld iy, #2
add iy, sp
ld d, a ; D = row (free A for fillch later)
ld e, l ; E = col (free L for width later)
ld h, 0 (iy) ; H = height
ld c, 1 (iy) ; stash width
ld b, 2 (iy) ; B = attr
ld a, 3 (iy) ; A = fillch
ld l, c ; L = width
push ix
ld c, #0x8D
rst #0x08
pop ix
pop hl
inc sp
inc sp
inc sp
inc sp ; consume height + width + attr + fillch
jp (hl)
__endasm;
}