;============================================================================== ; wc_api.s — Полные обёртки Wild Commander API для SDCC (sdcccall(1)) ; ; ── Соглашение sdcccall(1) — SDCC 4.x Z80 ───────────────────────────── ; Первый аргумент: uint8 → A ; uint16 / ptr → HL (ВАЖНО: HL, а не DE!) ; uint32 → DEHL ; Второй аргумент: uint16 / ptr → DE (если 1-й ≤ 16 бит) ; uint8 → ; - если первый аргумент uint8: второй → L ; - иначе (если первый uint16/ptr): второй → НА СТЕК ; Остальные: стек правым аргументом первым ; uint8 = 1 байт на стеке, uint16 = 2 байта (без выравнивания!) ; callee обязан очистить стековые аргументы (callee-cleans) ; Возврат: uint8 → A, uint16 → DE ; ; ── Стековый фрейм (типичный, внутри функции после PUSH IX, PUSH DE) ── ; IX+0: win_lo (сохранённый DE = win ptr, если PUSH DE производился) ; IX+1: win_hi ; IX+2: IX_save_lo ; IX+3: IX_save_hi ; IX+4: return address lo ; IX+5: return address hi ; IX+6: первый стековый аргумент (левый из оставшихся) ; IX+8: второй стековый аргумент ; ... и т.д. (каждый uint8 padding'ом до 2 байт) ; ; ── Трюк PUSH / POP для IX = регистр ────────────────────────────────── ; PUSH HL; POP IX → IX = HL (нет прямого LD IX, HL) ; ; ── Трюк EXX для сохранения BC/DE/HL в теневых регистрах ────────────── ; EXX — обменяет BC/DE/HL ↔ BC'/DE'/HL', не затрагивая IX и AF ; EX AF,AF' — поменяет A/F ↔ A'/F' (для передачи A' в WC) ; ;============================================================================== .module wc_api WC_ENTRY = 0x6006 .area _CODE ;================================================================== ; СЕКЦИЯ 1: INIT / СТРАНИЧНАЯ КОММУТАЦИЯ ;================================================================== ;------------------------------------------------------------------ ; void wc_mngc_pl(uint8_t page) — плагин-страница → #C000 (#00) ; sdcccall(1): A = page → A' ;------------------------------------------------------------------ .globl _wc_mngc_pl _wc_mngc_pl:: ex af, af' push ix ld a, #0x00 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_mng0_pl(uint8_t page) — плагин-страница → #0000 (#4E) ;------------------------------------------------------------------ .globl _wc_mng0_pl _wc_mng0_pl:: ex af, af' push ix ld a, #0x4E call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_mng8_pl(uint8_t page) — плагин-страница → #8000 (#4F) ;------------------------------------------------------------------ .globl _wc_mng8_pl _wc_mng8_pl:: ex af, af' push ix ld a, #0x4F call WC_ENTRY pop ix ret ;================================================================== ; СЕКЦИЯ 2: UI / ОКНА ;================================================================== ;------------------------------------------------------------------ ; void wc_gedpl(void) — восстановить дисплей WC (#0F) ;------------------------------------------------------------------ .globl _wc_gedpl _wc_gedpl:: push ix ld a, #0x0F call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_prwow(wc_window_t *win) — нарисовать окно (#01) ; sdcccall(1): HL = win → IX ;------------------------------------------------------------------ .globl _wc_prwow _wc_prwow:: push ix push hl ; IX = HL = win ptr pop ix ld a, #0x01 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_rresb(wc_window_t *win) — удалить окно (#02) ;------------------------------------------------------------------ .globl _wc_rresb _wc_rresb:: push ix push hl ; IX = HL = win ptr pop ix ld a, #0x02 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_cursor(wc_window_t *win) — нарисовать курсор (#06) ;------------------------------------------------------------------ .globl _wc_cursor _wc_cursor:: push ix push hl ; IX = HL = win ptr pop ix ld a, #0x06 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_curser(wc_window_t *win) — стереть курсор (#07) ;------------------------------------------------------------------ .globl _wc_curser _wc_curser:: push ix push hl ; IX = HL = win ptr pop ix ld a, #0x07 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_prsrw(win, str, y, x, len) — напечатать строку (#03) ; sdcccall(1): HL=win(1st ptr), DE=str(2nd ptr) ; stack: y(1 byte), x(1 byte), len(2 bytes) = 4 bytes ; WC: IX=win, HL=str, D=y, E=x, BC=len ; Callee cleans 4 bytes. ; Stack after push ix, push hl, push de: ; 0,1=str 2,3=win 4,5=IX 6,7=ret 8=y 9=x 10,11=len ;------------------------------------------------------------------ .globl _wc_prsrw _wc_prsrw:: push ix push hl ; save win (HL = 1st arg) push de ; save str (DE = 2nd arg) ld ix, #0 add ix, sp ld b, 11(ix) ; B = len_hi ld c, 10(ix) ; C = len_lo ld d, 8(ix) ; D = y ld e, 9(ix) ; E = x ld l, 0(ix) ld h, 1(ix) ; HL = str exx ld l, 2(ix) ld h, 3(ix) ; HL = win push hl pop ix ; IX = win exx ; BC=len, DE=y|x, HL=str ld a, #0x03 call WC_ENTRY pop de ; remove saved str pop hl ; remove saved win pop ix ; restore caller IX ; callee cleans: y(1)+x(1)+len(2) = 4 bytes pop hl ; HL = return address inc sp inc sp inc sp inc sp jp (hl) ;------------------------------------------------------------------ ; void wc_prsrw_attr(win, str, y, x, len, attr) — напечатать строку + атрибут (#03 + #04) ; sdcccall(1): HL=win(1st ptr), DE=str(2nd ptr) ; stack: y(1), x(1), len(2), attr(1) = 5 bytes ; WC #03: IX=win, HL=str, D=y, E=x, BC=len ; WC #04: IX=win, A'=attr, D=y, E=x, BC=len ; Callee cleans 5 bytes. ; Stack after push ix, push hl, push de: ; 0,1=str 2,3=win 4,5=IX 6,7=ret 8=y 9=x 10=len_lo 11=len_hi 12=attr ;------------------------------------------------------------------ .globl _wc_prsrw_attr _wc_prsrw_attr:: push ix push hl ; save win (HL = 1st arg) push de ; save str (DE = 2nd arg) ld ix, #0 add ix, sp ; ── вызов #03 (prsrw) ────────────────────────────────── ld b, 11(ix) ; B = len_hi ld c, 10(ix) ; C = len_lo ld d, 8(ix) ; D = y ld e, 9(ix) ; E = x ld l, 0(ix) ld h, 1(ix) ; HL = str exx ld l, 2(ix) ld h, 3(ix) ; HL = win ld a, 12(ix) ; A = attr (IX всё ещё → фрейм) push af ; сохраняем attr на стеке push hl pop ix ; IX = win exx ; BC=len, DE=y|x, HL=str; HL'=win ld a, #0x03 call WC_ENTRY ; после возврата: BC/DE=len/y|x (WC #03 не портит), ; HL'=win (WC сохраняет alternate regs) ; ── вызов #04 (priat) ────────────────────────────────── pop af ; A = attr ex af, af' ; A' = attr exx ; HL = win (из HL'), BC=len, DE=y|x push hl pop ix ; IX = win exx ; restore BC=len, DE=y|x ld a, #0x04 call WC_ENTRY pop de ; remove saved str pop hl ; remove saved win pop ix ; restore caller IX ; callee cleans 5 bytes: y(1)+x(1)+len(2)+attr(1) pop hl ; HL = return address inc sp inc sp inc sp inc sp inc sp jp (hl) ;------------------------------------------------------------------ ; uint16_t wc_gadrw(win, y, x) — адрес ячейки экрана (#05) ; sdcccall(1): HL=win(1st ptr), stack: y(1 byte), x(1 byte) = 2 bytes ; WC: IX=win, D=y, E=x → HL=адрес ; sdcccall(1) returns uint16_t in DE. ; Callee cleans 2 bytes. ; Stack after push ix, push hl: 0,1=win 2,3=IX 4,5=ret 6=y 7=x ;------------------------------------------------------------------ .globl _wc_gadrw _wc_gadrw:: push ix push hl ; save win (HL = 1st arg) ld ix, #0 add ix, sp ld d, 6(ix) ; D = y ld e, 7(ix) ; E = x ld l, 0(ix) ld h, 1(ix) ; HL = win push hl pop ix ; IX = win ld a, #0x05 call WC_ENTRY ; HL = result addr ex de, hl ; DE = result (sdcccall(1) uint16) pop hl ; remove saved win (use HL, keep DE) pop ix ; restore caller IX ; callee cleans 2 bytes (y+x); preserve DE = return value pop hl ; HL = return address inc sp inc sp ; discard y(1)+x(1) jp (hl) ; return, DE = result ;------------------------------------------------------------------ ; uint8_t wc_yn(uint8_t mode) — меню Да/Нет (#08) ; sdcccall(1): A=mode → A' ;------------------------------------------------------------------ .globl _wc_yn _wc_yn:: ex af, af' push ix ld a, #0x08 call WC_ENTRY ; Возвращаем: Z=ok → A=1, NZ → A=0 ld a, #0 jr nz, _wc_yn_end inc a _wc_yn_end: pop ix ret ;------------------------------------------------------------------ ; void wc_istr(wc_window_t *win, uint8_t mode) — редактор строки (#09) ; sdcccall(1): HL=win(1st ptr), stack: mode(1 byte) ; WC: IX=win, A'=mode ; Callee cleans 1 byte. ;------------------------------------------------------------------ .globl _wc_istr _wc_istr:: push ix ld ix, #0 add ix, sp ld a, 4(ix) ; A = mode (from stack) ex af, af' ; A' = mode push hl pop ix ; IX = win (HL = 1st arg) ld a, #0x09 call WC_ENTRY pop ix ; callee cleans 1 byte (mode) pop hl inc sp jp (hl) ;------------------------------------------------------------------ ; void wc_nork(uint16_t addr, uint8_t val) — вывести HEX байт (#0A) ; sdcccall(1): HL=addr(1st uint16), stack: val(1 byte) ; WC: HL=addr, A'=val ; Callee cleans 1 byte. ;------------------------------------------------------------------ .globl _wc_nork _wc_nork:: push ix ld ix, #0 add ix, sp ld a, 4(ix) ; A = val (from stack) ex af, af' ; A' = val ; HL = addr (1st arg, already in HL; WC needs HL) ld a, #0x0A call WC_ENTRY pop ix ; callee cleans 1 byte (val) pop hl inc sp jp (hl) ;------------------------------------------------------------------ ; uint8_t wc_txtpr(win, str, y, x) — печать текста (#0B) ; sdcccall(1): HL=win, DE=str; стек: push bc где B=y, C=x ; WC: IX=win, HL=str, D=y, E=x → D=след. строка ; Callee cleans 2 stack bytes (push bc). ; Stack from IX after push ix, push hl, push de: ; IX+0,1=str IX+2,3=win IX+4,5=IX IX+6,7=ret IX+8=C=x IX+9=B=y ;------------------------------------------------------------------ .globl _wc_txtpr _wc_txtpr:: push ix ; (1) save caller IX push hl ; (2) save win ptr (HL = 1st arg) push de ; (3) save str ptr (DE = 2nd arg) ld ix, #0 add ix, sp ld d, 9(ix) ; D = y (B from caller's push bc, hi byte) ld e, 8(ix) ; E = x (C from caller's push bc, lo byte) ld l, 0(ix) ld h, 1(ix) ; HL = str ptr exx ; shadow: HL'=str, D'=y, E'=x ld l, 2(ix) ld h, 3(ix) ; HL = win ptr push hl pop ix ; IX = win ptr exx ; restore HL=str, D=y, E=x ld a, #0x0B call WC_ENTRY ld a, d ; A = return: next Y pop de ; (3) restore DE pop hl ; (2) restore HL pop ix ; (1) restore IX pop hl ; HL = return address inc sp ; } discard caller's push bc (2 bytes: y, x) inc sp ; } jp (hl) ; return (callee cleans stack args) ;------------------------------------------------------------------ ; uint8_t wc_mezz(win, msg_num, str, y, x) — сообщение WC (#0C) ; sdcccall(1): HL=win(1st ptr), stack: msg_num(1), str(2), y(1), x(1) = 5 bytes ; WC: IX=win, A'=msg_num, HL=str, D=y, E=x → D=след. строка ; Callee cleans 5 bytes. ; Stack after push ix, push hl: ; 0,1=win 2,3=IX 4,5=ret 6=msg_num 7,8=str 9=y 10=x ;------------------------------------------------------------------ .globl _wc_mezz _wc_mezz:: push ix push hl ; save win (HL = 1st arg) ld ix, #0 add ix, sp ld a, 6(ix) ; A = msg_num ld l, 7(ix) ld h, 8(ix) ; HL = str ld d, 9(ix) ; D = y ld e, 10(ix) ; E = x exx ex af, af' ; A' = msg_num ld l, 0(ix) ld h, 1(ix) ; HL = win push hl pop ix ; IX = win exx ; HL=str, D=y, E=x ld a, #0x0C call WC_ENTRY ld a, d ; return: next row pop hl ; remove saved win pop ix ; callee cleans 5 bytes pop hl ; HL = return address inc sp inc sp inc sp inc sp inc sp jp (hl) ;------------------------------------------------------------------ ; void wc_scrlwow(win, y, x, h, w, flags) — прокрутка (#54) ; sdcccall(1): HL=win(1st ptr), stack: y(1),x(1),h(1),w(1),flags(1) = 5 bytes ; WC: IX=win, D=y, E=x, B=h, C=w, A'=flags ; Callee cleans 5 bytes. ; Stack after push ix, push hl: ; 0,1=win 2,3=IX 4,5=ret 6=y 7=x 8=h 9=w 10=flags ;------------------------------------------------------------------ .globl _wc_scrlwow _wc_scrlwow:: push ix push hl ; save win (HL = 1st arg) ld ix, #0 add ix, sp ld a, 10(ix) ; A = flags ld b, 8(ix) ; B = h ld c, 9(ix) ; C = w ld d, 6(ix) ; D = y ld e, 7(ix) ; E = x exx ex af, af' ; A' = flags ld l, 0(ix) ld h, 1(ix) push hl pop ix ; IX = win exx ; BC=h/w, DE=y/x ld a, #0x54 call WC_ENTRY pop hl ; remove saved win pop ix ; callee cleans 5 bytes pop hl inc sp inc sp inc sp inc sp inc sp jp (hl) pop de pop ix ret ;================================================================== ; СЕКЦИЯ 3: КЛАВИАТУРА ; Шаблон для клавиш без аргументов: ; push ix; ld a,#N; call WC_ENTRY; pop ix; ret ;================================================================== ;------------------------------------------------------------------ ; Макро-генерация функций проверки клавиш (push ix не нужен для WC, ; но сохраняем на случай, если WC его трогает в редких случаях) ;------------------------------------------------------------------ .globl _wc_key_space _wc_key_space:: push ix ld a, #0x10 call WC_ENTRY pop ix ret .globl _wc_key_up _wc_key_up:: push ix ld a, #0x11 call WC_ENTRY pop ix ret .globl _wc_key_down _wc_key_down:: push ix ld a, #0x12 call WC_ENTRY pop ix ret .globl _wc_key_left _wc_key_left:: push ix ld a, #0x13 call WC_ENTRY pop ix ret .globl _wc_key_right _wc_key_right:: push ix ld a, #0x14 call WC_ENTRY pop ix ret .globl _wc_key_tab _wc_key_tab:: push ix ld a, #0x15 call WC_ENTRY pop ix ret .globl _wc_key_enter _wc_key_enter:: push ix ld a, #0x16 call WC_ENTRY pop ix ret .globl _wc_key_esc _wc_key_esc:: push ix ld a, #0x17 call WC_ENTRY pop ix ret .globl _wc_key_bspc _wc_key_bspc:: push ix ld a, #0x18 call WC_ENTRY pop ix ret .globl _wc_key_pgup _wc_key_pgup:: push ix ld a, #0x19 call WC_ENTRY pop ix ret .globl _wc_key_pgdn _wc_key_pgdn:: push ix ld a, #0x1A call WC_ENTRY pop ix ret .globl _wc_key_home _wc_key_home:: push ix ld a, #0x1B call WC_ENTRY pop ix ret .globl _wc_key_end _wc_key_end:: push ix ld a, #0x1C call WC_ENTRY pop ix ret ; F1–F10 (#1D–#26) .globl _wc_key_f1 _wc_key_f1:: push ix ld a, #0x1D call WC_ENTRY pop ix ret .globl _wc_key_f2 _wc_key_f2:: push ix ld a, #0x1E call WC_ENTRY pop ix ret .globl _wc_key_f3 _wc_key_f3:: push ix ld a, #0x1F call WC_ENTRY pop ix ret .globl _wc_key_f4 _wc_key_f4:: push ix ld a, #0x20 call WC_ENTRY pop ix ret .globl _wc_key_f5 _wc_key_f5:: push ix ld a, #0x21 call WC_ENTRY pop ix ret .globl _wc_key_f6 _wc_key_f6:: push ix ld a, #0x22 call WC_ENTRY pop ix ret .globl _wc_key_f7 _wc_key_f7:: push ix ld a, #0x23 call WC_ENTRY pop ix ret .globl _wc_key_f8 _wc_key_f8:: push ix ld a, #0x24 call WC_ENTRY pop ix ret .globl _wc_key_f9 _wc_key_f9:: push ix ld a, #0x25 call WC_ENTRY pop ix ret .globl _wc_key_f10 _wc_key_f10:: push ix ld a, #0x26 call WC_ENTRY pop ix ret ; Alt/Shift/Ctrl (без автоповтора) .globl _wc_key_alt _wc_key_alt:: push ix ld a, #0x27 call WC_ENTRY pop ix ret .globl _wc_key_shift _wc_key_shift:: push ix ld a, #0x28 call WC_ENTRY pop ix ret .globl _wc_key_ctrl _wc_key_ctrl:: push ix ld a, #0x29 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; uint8_t wc_kbscn(uint8_t mode) — сканировать клавишу (#2A) ; sdcccall(1): A=mode → A' ; Возврат: A=keycode (0=нет) ;------------------------------------------------------------------ .globl _wc_kbscn _wc_kbscn:: ex af, af' ; A' = mode push ix ld a, #0x2A call WC_ENTRY pop ix ret ; Del/Caps/AnyKey/WaitRelease/WaitAny/Ins .globl _wc_key_del _wc_key_del:: push ix ld a, #0x2B call WC_ENTRY pop ix ret .globl _wc_key_caps _wc_key_caps:: push ix ld a, #0x2C call WC_ENTRY pop ix ret .globl _wc_key_any _wc_key_any:: push ix ld a, #0x2D call WC_ENTRY pop ix ret .globl _wc_key_wait_release _wc_key_wait_release:: push ix ld a, #0x2E call WC_ENTRY pop ix ret .globl _wc_key_wait_any _wc_key_wait_any:: push ix ld a, #0x2F call WC_ENTRY pop ix ret .globl _wc_key_ins _wc_key_ins:: push ix ld a, #0x55 call WC_ENTRY pop ix ret ;================================================================== ; СЕКЦИЯ 4: ФАЙЛОВЫЕ ОПЕРАЦИИ ;================================================================== ;------------------------------------------------------------------ ; uint8_t wc_load512(uint16_t dest, uint8_t blocks) — загрузить (#30) ; sdcccall(1): HL=dest; стек: blocks (1 байт, push af + inc sp) ; WC: HL=dest, B=blocks → A=0 ok / 0x0F EOF ; Callee cleans 1 stack byte (blocks). ; Stack после push ix: IX+2=ret, IX+4=blocks ;------------------------------------------------------------------ .globl _wc_load512 _wc_load512:: push ix ld ix, #0 add ix, sp ld b, 4(ix) ; B = blocks (1 byte on stack) ; HL = dest (sdcccall(1) first uint16 → HL — do NOT ex de,hl!) ld a, #0x30 call WC_ENTRY pop ix pop hl ; HL = return address inc sp ; discard 1-byte 'blocks' arg jp (hl) ; return (callee cleans stack arg) ;------------------------------------------------------------------ ; void wc_save512(uint16_t src, uint8_t blocks) — сохранить (#31) ; sdcccall(1): HL=src; стек: blocks (1 байт, callee cleans) ;------------------------------------------------------------------ .globl _wc_save512 _wc_save512:: push ix ld ix, #0 add ix, sp ld b, 4(ix) ; HL = src (DON'T ex de, hl!) ld a, #0x31 call WC_ENTRY pop ix pop hl inc sp jp (hl) ;------------------------------------------------------------------ ; void wc_gipagpl(void) — позиционировать на начало файла (#32) ;------------------------------------------------------------------ .globl _wc_gipagpl _wc_gipagpl:: push ix ld a, #0x32 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_tentry(uint16_t addr) — прочитать ENTRY в буфер (#33) ; sdcccall(1): HL=addr (1st uint16 → HL) ; WC: DE=addr ;------------------------------------------------------------------ .globl _wc_tentry _wc_tentry:: push ix ex de, hl ; DE = addr (SDCC HL → WC DE) ld a, #0x33 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_chtosep(uint16_t buf, uint16_t bufend) (#34) ; sdcccall(1): HL=buf(1st uint16), DE=bufend(2nd uint16) ; WC: DE=buf, BC=bufend ; No stack args. ;------------------------------------------------------------------ .globl _wc_chtosep _wc_chtosep:: push ix ld b, d ld c, e ; BC = bufend (from DE) ex de, hl ; DE = buf (from HL) ld a, #0x34 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_tmrkdfl(panel, filenum, namebuf) — заголовок помеч. файла (#36) ; sdcccall(1): HL=panel(1st ptr), DE=filenum(2nd uint16) ; stack: namebuf(2 bytes) ; WC: IX=panel, HL=filenum, DE=namebuf ; Callee cleans 2 bytes. ; Stack after push ix, push hl, push de: ; 0,1=filenum 2,3=panel 4,5=IX 6,7=ret 8,9=namebuf ;------------------------------------------------------------------ .globl _wc_tmrkdfl _wc_tmrkdfl:: push ix push hl ; save panel (HL = 1st arg) push de ; save filenum (DE = 2nd arg) ld ix, #0 add ix, sp ld e, 8(ix) ld d, 9(ix) ; DE = namebuf (from stack) ld l, 0(ix) ld h, 1(ix) ; HL = filenum (from saved DE) exx ld l, 2(ix) ld h, 3(ix) ; HL = panel (from saved HL) push hl pop ix ; IX = panel exx ; HL=filenum, DE=namebuf ld a, #0x36 call WC_ENTRY pop de ; remove saved filenum pop hl ; remove saved panel pop ix ; callee cleans 2 bytes (namebuf) pop hl inc sp inc sp jp (hl) ;------------------------------------------------------------------ ; void wc_adir(uint8_t mode) — позиционирование директории (#38) ; sdcccall(1): A=mode → A' ;------------------------------------------------------------------ .globl _wc_adir _wc_adir:: ex af, af' push ix ld a, #0x38 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_stream(uint8_t mode) — переключить поток (#39) ; sdcccall(1): A=mode ; WC: D=mode ;------------------------------------------------------------------ .globl _wc_stream _wc_stream:: push ix ld d, a ld a, #0x39 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; uint8_t wc_findnext(uint16_t entry_buf, uint8_t flags) — FindNext (#3A) ; sdcccall(1): HL=entry_buf(1st uint16), stack: flags(1 byte) ; WC: DE=entry_buf, A'=flags → Z=конец, NZ=найден ; Callee cleans 1 byte. ;------------------------------------------------------------------ .globl _wc_findnext _wc_findnext:: push ix ld ix, #0 add ix, sp ld a, 4(ix) ; A = flags (from stack) ex af, af' ; A' = flags ex de, hl ; DE = entry_buf (SDCC HL → WC DE) ld a, #0x3A call WC_ENTRY ld a, #0 jr z, _wc_findnext_end inc a _wc_findnext_end: pop ix ; callee cleans 1 byte (flags) pop hl inc sp jp (hl) ;------------------------------------------------------------------ ; uint8_t wc_fentry(uint16_t name_with_flag) — найти файл (#3B) ; sdcccall(1): HL=name (1st uint16 → HL) ; WC: HL=name → Z=не найден, NZ=найден ;------------------------------------------------------------------ .globl _wc_fentry _wc_fentry:: push ix ; HL = name (sdcccall(1); WC нужен HL — уже на месте!) ld a, #0x3B call WC_ENTRY ld a, #0 jr z, _wc_fentry_end inc a _wc_fentry_end: pop ix ret ;------------------------------------------------------------------ ; void wc_loadnone(uint8_t sectors) — пропустить секторы (#3D) ; sdcccall(1): A = sectors ; WC: B=sectors (предположительно) ;------------------------------------------------------------------ .globl _wc_loadnone _wc_loadnone:: push ix ld b, a ld a, #0x3D call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_gfile(void) — открыть найденный файл (#3E) ;------------------------------------------------------------------ .globl _wc_gfile _wc_gfile:: push ix ld a, #0x3E call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_gdir(void) — войти в найденный каталог (#3F) ;------------------------------------------------------------------ .globl _wc_gdir _wc_gdir:: push ix ld a, #0x3F call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; uint8_t wc_mkfile(uint16_t name_with_flag) — создать файл (#48) ; sdcccall(1): HL=name (1st uint16 → HL) ; WC: HL=name → A=ошибка (0=ok) ;------------------------------------------------------------------ .globl _wc_mkfile _wc_mkfile:: push ix ld a, #0x48 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; uint8_t wc_mkdir(uint16_t name) — создать каталог (#49) ; sdcccall(1): HL=name; WC: HL=name ;------------------------------------------------------------------ .globl _wc_mkdir _wc_mkdir:: push ix ld a, #0x49 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; uint8_t wc_rename(uint16_t old_name, uint16_t new_name) (#4A) ; sdcccall(1): HL=old_name(1st), DE=new_name(2nd) ; WC: HL=old_name, DE=new_name (уже на месте!) ; No stack args. ;------------------------------------------------------------------ .globl _wc_rename _wc_rename:: push ix ld a, #0x4A call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; uint8_t wc_delfl(uint16_t name_with_flag) — удалить файл (#4B) ; sdcccall(1): HL=name; WC: HL=name ;------------------------------------------------------------------ .globl _wc_delfl _wc_delfl:: push ix ld a, #0x4B call WC_ENTRY pop ix ret ;================================================================== ; СЕКЦИЯ 5: ГРАФИКА ;================================================================== ;------------------------------------------------------------------ ; void wc_mngv_pl(uint8_t mode) — видеорежим WC (#40) ; A=mode → A' ;------------------------------------------------------------------ .globl _wc_mngv_pl _wc_mngv_pl:: ex af, af' push ix ld a, #0x40 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_mngcvpl(uint8_t vpage) — видеостраница → #C000 (#41) ; A=vpage → A' ;------------------------------------------------------------------ .globl _wc_mngcvpl _wc_mngcvpl:: ex af, af' push ix ld a, #0x41 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_gvmod(uint8_t mode) — установить видеорежим TSConfig (#42) ; A=mode → A' ;------------------------------------------------------------------ .globl _wc_gvmod _wc_gvmod:: ex af, af' push ix ld a, #0x42 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_gyoff(uint16_t y) — Y-смещение прокрутки (#43) ; sdcccall(1): HL=y (1st uint16 → HL) ; WC: HL=y (уже на месте!) ;------------------------------------------------------------------ .globl _wc_gyoff _wc_gyoff:: push ix ld a, #0x43 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_gxoff(uint16_t x) — X-смещение прокрутки (#44) ; sdcccall(1): HL=x; WC: HL=x ;------------------------------------------------------------------ .globl _wc_gxoff _wc_gxoff:: push ix ld a, #0x44 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_gvtm(uint8_t page) — страница тайловой карты (#45) ; WC: C=page ;------------------------------------------------------------------ .globl _wc_gvtm _wc_gvtm:: push ix ld c, a ld a, #0x45 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_gvtl(uint8_t plane, uint8_t page) — тайл-графика (#46) ; sdcccall(1): A=plane(1st uint8), stack: page(1 byte) ; WC: B=plane, C=page ; Callee cleans 1 byte. ;------------------------------------------------------------------ .globl _wc_gvtl _wc_gvtl:: push ix ld ix, #0 add ix, sp ld c, 4(ix) ; C = page ld b, a ; B = plane ld a, #0x46 call WC_ENTRY pop ix ; callee cleans 1 byte (page) pop hl inc sp jp (hl) ;------------------------------------------------------------------ ; void wc_gvsgp(uint8_t page) — страница спрайт-графики (#47) ; WC: C=page ;------------------------------------------------------------------ .globl _wc_gvsgp _wc_gvsgp:: push ix ld c, a ld a, #0x47 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_mng0vpl(uint8_t vpage) — видеостраница → #0000 (#50) ;------------------------------------------------------------------ .globl _wc_mng0vpl _wc_mng0vpl:: ex af, af' push ix ld a, #0x50 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_mng8vpl(uint8_t vpage) — видеостраница → #8000 (#51) ;------------------------------------------------------------------ .globl _wc_mng8vpl _wc_mng8vpl:: ex af, af' push ix ld a, #0x51 call WC_ENTRY pop ix ret ;================================================================== ; СЕКЦИЯ 6: DMA ;================================================================== ;------------------------------------------------------------------ ; void wc_dmapl(uint8_t subfunc) — операции DMA (#0D) ; A=subfunc → A' ;------------------------------------------------------------------ .globl _wc_dmapl _wc_dmapl:: ex af, af' push ix ld a, #0x0D call WC_ENTRY pop ix ret ;================================================================== ; СЕКЦИЯ 7: РАЗНОЕ ;================================================================== ;------------------------------------------------------------------ ; void wc_turbopl(uint8_t mode, uint8_t param) — частота CPU/AY (#0E) ; sdcccall(1): A=mode(1st uint8), L=param(2nd uint8) ; WC: B=mode, C=param ; Нет стековых аргументов. ;------------------------------------------------------------------ .globl _wc_turbopl _wc_turbopl:: push ix ld c, l ; C = param (2-й аргумент) ld b, a ; B = mode (1-й аргумент) ld a, #0x0E call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; uint8_t wc_prm_pl(uint8_t param_num) — параметр из INI (#53) ; A=param_num → A' ; Возврат: 0xFF = нет параметра, иное = номер опции ;------------------------------------------------------------------ .globl _wc_prm_pl _wc_prm_pl:: ex af, af' push ix ld a, #0x53 call WC_ENTRY ; Z=нет параметра → вернуть 0xFF, иначе A=номер опции jr nz, _wc_prm_pl_end ld a, #0xFF _wc_prm_pl_end: pop ix ret ;------------------------------------------------------------------ ; void wc_int_pl(uint8_t mode) — управление прерываниями WC (#56) ; A=mode → A' (режимы: WC_INT_*) ;------------------------------------------------------------------ .globl _wc_int_pl _wc_int_pl:: ex af, af' push ix ld a, #0x56 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; void wc_int_pl_handler(uint16_t handler_addr) — установить ISR (#56) ; sdcccall(1): HL=handler_addr (1st uint16 → HL) ; WC: A'=0xFF, HL=addr (HL уже на месте!) ;------------------------------------------------------------------ .globl _wc_int_pl_handler _wc_int_pl_handler:: push ix ; HL = handler_addr (sdcccall(1); WC тоже нужен HL) ld a, #0xFF ex af, af' ; A' = 0xFF ld a, #0x56 call WC_ENTRY pop ix ret ;------------------------------------------------------------------ ; uint8_t wc_load256(uint16_t dest, uint8_t blocks) — загрузить 256б блоков (#3C) ; sdcccall(1): HL=dest; стек: blocks (1 байт, callee cleans) ; WC: HL=addr, B=blocks → A=EndOfChain(#0F) ;------------------------------------------------------------------ .globl _wc_load256 _wc_load256:: push ix ld ix, #0 add ix, sp ld b, 4(ix) ; B = blocks (1 byte on stack) ; HL = dest (already in HL) ld a, #0x3C call WC_ENTRY pop ix pop hl ; HL = return address inc sp ; discard 1-byte 'blocks' arg jp (hl) ; return (callee cleans stack arg) ;------------------------------------------------------------------ ; void wc_resident_jump(uint8_t page, uint16_t addr) — переход в другую страницу ; sdcccall(1): A=page, DE=addr (uint16 2nd → DE) ; Нет stack args. ; Реализация: LD HL,DE; LD A,page; JP #6020 ;------------------------------------------------------------------ .globl _wc_resident_jump _wc_resident_jump:: ex de, hl ; HL = addr (from DE = 2nd arg) ; A = page (1st arg, already in A) jp 0x6020 ; resident jump — never returns! ;------------------------------------------------------------------ ; void wc_resident_call(uint8_t page, uint16_t addr) — вызов в другой странице ; sdcccall(1): A=page, DE=addr (uint16 2nd → DE) ; Нет stack args. ; Реализация: LD HL,DE; LD A,page; CALL #6028 ;------------------------------------------------------------------ .globl _wc_resident_call _wc_resident_call:: ex de, hl ; HL = addr (from DE = 2nd arg) ; A = page (1st arg, already in A) call 0x6028 ; resident call — returns here ret ;------------------------------------------------------------------ ; void wc_strset(char *dsr, uint16_t len, char c) ; Заполняет строку символом c на длину len ; sdcccall(1): HL=dst(1st ptr), DE=len(2nd uint16), ; stack: c(1 byte) ; Callee cleans 1 byte ;------------------------------------------------------------------- .globl _wc_strset _wc_strset:: push ix ld ix, #0 add ix, sp ld a, 4(ix) ; c (из-за push ix) pop ix ; записываем первый байт ld (hl), a ld b, d ld c, e ; len == 1 → всё dec bc ld a, b or c jr z, done ; DE = HL + 1 push hl pop de inc de ; BC = len - 1 уже ldir done: ; очистка стека pop bc inc sp push bc ret