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
+25 -24
View File
@@ -1,18 +1,18 @@
/*
* lseek — 32-bit file position via ESTEX MOVE_FP ($15).
* lseek — 32-битная позиция файла через ESTEX MOVE_FP ($15).
*
* ESTEX MOVE_FP: A=handle, B=whence (0=SET, 1=CUR, 2=END),
* HL=offset high16, IX=offset low16
* HL:IX = new absolute position, CF=err
* возврат: HL:IX = новая абсолютная позиция, CF=err
*
* SDCC __sdcccall(1) on z80 for `long lseek(int fd, long offset, int whence)`:
* - fd HL (1st 16-bit arg in register)
* - offset → stack as two 16-bit words (low first, then high)
* - whence → stack (top after offset)
* - 32-bit return: DE = low16, HL = high16
* - caller-pops (caller-side `pop af; pop af; pop af` after the call)
* SDCC __sdcccall(1) на z80 для `long lseek(int fd, long offset, int whence)`:
* - fd HL (первый 16-битный аргумент в регистре)
* - offset — на стеке двумя 16-битными словами (сначала low, потом high)
* - whence — на стеке (выше offset)
* - 32-битный возврат: DE = low16, HL = high16
* - стек чистит вызывающий (`pop af; pop af; pop af` после call)
*
* IX is saved (caller frame pointer).
* IX сохраняется (frame pointer вызывающего).
*/
#include <unistd.h>
@@ -21,21 +21,21 @@ long lseek(int fd, long offset, int whence) __naked
{
(void)fd; (void)offset; (void)whence;
__asm
push ix ; save caller-side IX
;; Layout after push:
;; SP+0..1 = saved IX
;; SP+2..3 = ret addr
push ix ; сохранить IX вызывающего
;; Раскладка после push:
;; SP+0..1 = сохранённый IX
;; SP+2..3 = адрес возврата
;; SP+4..5 = offset low16
;; SP+6..7 = offset high16
;; SP+8..9 = whence
ld a, l ; A = fd low byte (was in HL)
ld a, l ; A = младший байт fd (был в HL)
;; Walk through 5 consecutive stack bytes via HL cheaper than
;; IY-indexed because `ld r,(hl); inc hl` (2B/13T per byte) beats
;; `ld r, n(iy)` (3B/19T) for sequential reads.
;; 5 последовательных байтов стека читаем через HL дешевле,
;; чем IY-индексация: `ld r,(hl); inc hl` (2Б/13Т на байт)
;; против `ld r, n(iy)` (3Б/19Т) при последовательном чтении.
ld hl, #4
add hl, sp ; HL offset_low
add hl, sp ; HL указывает на offset_low
ld e, (hl)
inc hl
@@ -47,18 +47,19 @@ long lseek(int fd, long offset, int whence) __naked
inc hl
ld d, (hl) ; DE = offset_high
inc hl
ld b, (hl) ; B = whence (low byte)
ex de, hl ; HL = offset_high (ESTEX wants it here)
ld b, (hl) ; B = whence (младший байт)
ex de, hl ; HL = offset_high (ESTEX ждёт его тут)
ld c, #0x15 ; ESTEX MOVE_FP
rst #0x10
jr c, _lseek_err
;; Returns HL:IX = new position. Convert to SDCC long return (DE:HL).
;; Вернулось HL:IX = новая позиция. Приводим к long-возврату
;; SDCC (DE:HL).
push ix
pop de ; DE = low16 (was IX)
;; HL already has high16
pop ix ; restore caller-side IX
pop de ; DE = low16 (был IX)
;; HL уже содержит high16
pop ix ; восстановить IX вызывающего
ret
_lseek_err: