Files
Sprinter-SDCC/libbgi/bgi256/_bgi_hspan_raw.c
T
snark13 38bfabb2ca libbgi: __preserves_regs(d,e) на raw-примитивы (контракт, без эффекта сейчас)
plot/read/hspan/vspan_raw читают D/E (y в DE), но не пишут — аннотация
задокументирована в _bgi.h.  Честное измерение (полная пересборка с/без,
diff всех .asm в common/ и bgi256/): кодогенерация SDCC 4.5 НЕ меняется —
вызывающие держат локали в IX-фрейме и перезагружают DE перед каждым
вызовом, спасений DE вокруг вызовов не было.  Оставлено как контракт на
будущее (изменение вызывающих/компилятора); при правке asm сверять
клоббер-лист.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:35:32 +03:00

87 lines
4.2 KiB
C
Raw 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.
/*
* _bgi_hspan_raw — горизонтальная линия len пикселей от (x,y), mode 0x81,
* через Fill-burst'ы акселератора (до 256 байт за выстрел).
*
* Это «сырой» leaf-примитив: максимально тонкий, БЕЗ клиппинга. Всю
* защиту берёт на себя вызывающий (см. ОГРАНИЧЕНИЯ). Проверенный путь:
* _bgi_fill_span (клиппит сам) и _bgi_lineseg (ортогональ) → сюда.
*
* ---- ОГРАНИЧЕНИЯ ВЫЗОВА (ответственность вызывающего) --------------
* - W3-скобка: вызывать ТОЛЬКО между _bgi_begin/_bgi_end (W3 замаплен
* на видеобанк; DI/EI вокруг каждого выстрела ставит сам сегмент).
* - Клиппинга НЕТ. Требуется 0 <= x и x+len <= 320 (иначе burst
* вылезет за строку и затрёт соседнюю видеопамять). Отрицательный x
* и x+len>320 НЕ обрезаются — координаты обязаны быть уже валидны.
* - Диапазон len: 1..320. len==0: safe-версия (с проверками) тихо
* вернётся; fast (GFX_NOCHECK) из-за конвенции акселератора (B=0 =
* «256») отрисует 256 точек. len<0 / len>320 — UB.
* - Встроенная проверка (если НЕ задан GFX_NOCHECK) отсекает лишь
* грубый выход за экран по одной координате: (unsigned)y>=256 и
* (unsigned)x>=320 → тихий возврат. Это НЕ клиппинг диапазона —
* частичного отрезка/правого края не режет.
*
* ---- ABI ----------------------------------------------------------
* __sdcccall(1): x→HL, y→DE(E=y), len→стек(4/5(ix)), color→стек(6(ix)),
* __naked → callee-pops 3 байта аргументов (len + color) вручную.
* Значения уходят в _gfx_hfill256_segment через регистры (HL=addr,
* C=color, B=len, E=y) — без глобального скретча; сегмент клоббер только
* A/F, поэтому HL/E переживают выстрел (см. _gfx_hfill256.c).
*
* ---- Логика двух burst'ов (len 257..320) --------------------------
* Сначала 256 точек на addr (B=0), затем inc h (addr+256) и хвост
* (len-256) точек. Усечение len до младшего байта само даёт (len-256)
* для 257..320; при len==256 младший байт 0 → одиночный burst «256».
*/
#include "../_bgi.h"
void _bgi_hspan_raw(int x, int y, int len, uint8_t color) __naked __preserves_regs(d,e)
{
__asm
.globl __gfx_addr_base
.globl __gfx_hfill256_segment
push ix
ld ix, #0
add ix, sp
#ifndef GFX_NOCHECK
ld a, d
or a, a
jr NZ, hs_ret ; (unsigned)y >= 256
ld a, l
sub a, #0x40
ld a, h
sbc a, #0x01
jr NC, hs_ret ; (unsigned)x >= 320
ld a, 4 (ix)
or a, 5 (ix)
jr Z, hs_ret ; len == 0 (иначе B=0 «256»)
#endif
ld c, l
ld b, h ; BC = x
ld hl, (__gfx_addr_base)
add hl, bc ; HL = base + x
ld a, 6 (ix)
ld c, a ; C = color
ld a, 5 (ix)
or a, a
jr Z, hs_single ; len < 256
ld a, 4 (ix)
or a, a
jr Z, hs_single ; len == 256 (B=0)
;; 257..320: два burst-a
ld b, #0 ; 256
call __gfx_hfill256_segment
inc h ; addr + 256
hs_single:
ld a, 4 (ix)
ld b, a ; B = len (0 если ==256)
call __gfx_hfill256_segment
hs_ret:
pop ix
pop hl
pop af
inc sp
jp (hl)
__endasm;
}