9f8aa6fc28
Симметрично 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>
106 lines
3.7 KiB
C
106 lines
3.7 KiB
C
/*
|
||
* fgetc — прочитать один байт из потока (буферизованно, вариант B+).
|
||
*
|
||
* Горячий путь («в readahead-буфере есть байт») написан на asm —
|
||
* SDCC на эту цепочку проверок генерит ~90 инструкций с IX-фреймом,
|
||
* asm укладывается в ~30 без фрейма (замер fbench: ~176 мкс/байт
|
||
* у C-версии). Всё остальное — медленный C-путь fgetc_slow:
|
||
* hold-байт от ungetc, консольный getchar(), сброс накопленной
|
||
* записи, дозаполнение буфера read(fd, buf, BUFSIZ), fallback без
|
||
* буфера. Возвращает байт, EOF на конце файла (_F_EOF) или при
|
||
* ошибке (_F_ERROR).
|
||
*
|
||
* Раскладка FILE (см. stdio.h, байтовые смещения):
|
||
* +0 fd, +2 flags, +3 buf, +5 curp, +7 level, +9 hold
|
||
*/
|
||
|
||
#include <unistd.h>
|
||
#include <errno.h>
|
||
#include "_file.h"
|
||
|
||
/* Медленный путь; зовётся из asm-обёртки (метка _fgetc_slow видна в
|
||
* пределах этого модуля). */
|
||
static int fgetc_slow(FILE *fp)
|
||
{
|
||
#ifndef LIBC_NOCHECK
|
||
if (!fp) { errno = EBADF; return EOF; }
|
||
#endif
|
||
if (fp->hold != EOF) {
|
||
int c = fp->hold;
|
||
fp->hold = EOF;
|
||
return c;
|
||
}
|
||
if (fp->flags & _F_CONIN) {
|
||
return getchar();
|
||
}
|
||
if (!(fp->flags & _F_READ)) { errno = EBADF; return EOF; }
|
||
|
||
if (fp->flags & _F_DIROUT) {
|
||
if (_file_sync(fp)) return EOF; /* сброс накопленной записи */
|
||
}
|
||
if (fp->level == 0) {
|
||
uint8_t *b = _file_buf(fp);
|
||
if (!b) {
|
||
/* Небуферизованный fallback. */
|
||
uint8_t ch;
|
||
int r = read(fp->fd, &ch, 1);
|
||
if (r == 0) { fp->flags |= _F_EOF; return EOF; }
|
||
if (r < 0) { fp->flags |= _F_ERROR; return EOF; }
|
||
return (int)ch;
|
||
}
|
||
int r = read(fp->fd, b, BUFSIZ);
|
||
if (r == 0) { fp->flags |= _F_EOF; return EOF; }
|
||
if (r < 0) { fp->flags |= _F_ERROR; return EOF; }
|
||
fp->level = (uint16_t)r;
|
||
fp->curp = b;
|
||
}
|
||
fp->level--;
|
||
return (int)*fp->curp++;
|
||
}
|
||
|
||
int fgetc(FILE *fp) __naked
|
||
{
|
||
(void)fp;
|
||
(void)fgetc_slow; /* используется из asm */
|
||
__asm
|
||
;; HL = fp.
|
||
#ifndef LIBC_NOCHECK
|
||
ld a, h
|
||
or a, l
|
||
jr Z, _fg_slow ; NULL — C-путь выставит errno
|
||
#endif
|
||
push hl
|
||
pop iy ; IY = fp (IY — scratch в __sdcccall(1))
|
||
|
||
ld a, 7 (iy) ; level != 0 ?
|
||
or a, 8 (iy)
|
||
jr Z, _fg_slow ; буфер пуст/не наш режим
|
||
ld a, 2 (iy) ; flags
|
||
and a, #0x08 ; _F_DIROUT — буфер копит запись?
|
||
jr NZ, _fg_slow
|
||
ld a, 9 (iy) ; hold == EOF (0xFFFF)?
|
||
and a, 10 (iy)
|
||
inc a
|
||
jr NZ, _fg_slow ; есть отложенный ungetc-байт
|
||
|
||
;; --- горячий путь: level--, вернуть *curp++ ---
|
||
ld a, 7 (iy)
|
||
sub a, #1
|
||
ld 7 (iy), a
|
||
jr NC, _fg_nb
|
||
dec 8 (iy)
|
||
_fg_nb:
|
||
ld l, 5 (iy) ; HL = curp
|
||
ld h, 6 (iy)
|
||
ld e, (hl) ; E = байт
|
||
ld d, #0 ; zero-extend в int
|
||
inc hl
|
||
ld 5 (iy), l ; curp++
|
||
ld 6 (iy), h
|
||
ret
|
||
|
||
_fg_slow:
|
||
jp _fgetc_slow ; HL = fp уже на месте
|
||
__endasm;
|
||
}
|