conio: switch cursor get/set to BIOS calls, rename text-mode accessors
_get_cursor/_set_cursor now use BIOS GetCursor/SetCursor (RST 8, 08Eh/084h) instead of ESTEX CURSOR/LOCATE; cursor position packed into a two_bytes union. get_videotextmode/set_videotextmode renamed to gettextmode/settextmode. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+129
-142
@@ -15,10 +15,18 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
/* Forward extern — definition is further down (after putch/cputs which
|
/* Forward extern — definition is further down (after putch/cputs which
|
||||||
* reference it from asm by linker-symbol name). */
|
* reference it from asm by linker-symbol name). */
|
||||||
extern int16_t g_text_attr;
|
static two_bytes g_text_attr = {0};
|
||||||
|
static uint8_t pc_ch = 0;
|
||||||
|
extern two_bytes pc_place = {0};
|
||||||
|
static uint8_t pc_raw_mode = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO - проверить - ф-ии 30h-33h (kbhit/getch/getche/getkey)
|
||||||
|
// не должны менять IX и им можно не делать push ix / pop ix
|
||||||
|
//
|
||||||
char kbhit(void) __naked
|
char kbhit(void) __naked
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
@@ -91,10 +99,6 @@ uint16_t getkey(void) __naked
|
|||||||
* caller to use "\r\n" explicitly. Stdio puts/putchar do translate.
|
* caller to use "\r\n" explicitly. Stdio puts/putchar do translate.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static uint8_t pc_ch = 0;
|
|
||||||
static uint8_t pc_attr = 0;
|
|
||||||
static uint8_t pc_row = 0;
|
|
||||||
static uint8_t pc_col = 0;
|
|
||||||
|
|
||||||
/* Controls how _raw_putch treats control characters (< 0x20):
|
/* Controls how _raw_putch treats control characters (< 0x20):
|
||||||
* 0 (default) — BS/TAB/LF/CR are interpreted (no glyph output);
|
* 0 (default) — BS/TAB/LF/CR are interpreted (no glyph output);
|
||||||
@@ -104,7 +108,6 @@ static uint8_t pc_col = 0;
|
|||||||
* Only takes effect on the WRCHAR (attr ≤ 0xFF) path. When
|
* Only takes effect on the WRCHAR (attr ≤ 0xFF) path. When
|
||||||
* g_text_attr is KEEP_EXIST_ATTR, ESTEX's own PUTCHAR/PCHARS handle
|
* g_text_attr is KEEP_EXIST_ATTR, ESTEX's own PUTCHAR/PCHARS handle
|
||||||
* cursor and control chars — pc_raw_mode is irrelevant. */
|
* cursor and control chars — pc_raw_mode is irrelevant. */
|
||||||
static uint8_t pc_raw_mode = 0;
|
|
||||||
|
|
||||||
void set_putch_raw_mode(uint8_t mode) { pc_raw_mode = mode; }
|
void set_putch_raw_mode(uint8_t mode) { pc_raw_mode = mode; }
|
||||||
uint8_t get_putch_raw_mode(void) { return pc_raw_mode; }
|
uint8_t get_putch_raw_mode(void) { return pc_raw_mode; }
|
||||||
@@ -115,14 +118,11 @@ uint8_t get_putch_raw_mode(void) { return pc_raw_mode; }
|
|||||||
static void _get_cursor(void) __naked
|
static void _get_cursor(void) __naked
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
push ix
|
; push ix
|
||||||
ld c, #0x53 ; ESTEX CURSOR
|
ld c, #0x8e ; BIOS GetCursor
|
||||||
rst #0x10
|
rst #0x08
|
||||||
ld a, d
|
ld (_pc_place), de
|
||||||
ld (_pc_row), a
|
; pop ix
|
||||||
ld a, e
|
|
||||||
ld (_pc_col), a
|
|
||||||
pop ix
|
|
||||||
ret
|
ret
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
@@ -131,14 +131,11 @@ static void _get_cursor(void) __naked
|
|||||||
static void _set_cursor(void) __naked
|
static void _set_cursor(void) __naked
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
push ix
|
; push ix
|
||||||
ld a, (_pc_row)
|
ld de, (_pc_place)
|
||||||
ld d, a
|
ld c, #0x84 ; BIOS SetCursor
|
||||||
ld a, (_pc_col)
|
rst #0x08
|
||||||
ld e, a
|
; pop ix
|
||||||
ld c, #0x52 ; ESTEX LOCATE
|
|
||||||
rst #0x10
|
|
||||||
pop ix
|
|
||||||
ret
|
ret
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
@@ -183,7 +180,7 @@ static char _bios_putchar(char ch) __naked
|
|||||||
* once before a sequence of _raw_putch calls and write it back once
|
* once before a sequence of _raw_putch calls and write it back once
|
||||||
* after, so we pay the BIOS overhead per OPERATION instead of per CHAR. */
|
* after, so we pay the BIOS overhead per OPERATION instead of per CHAR. */
|
||||||
/* Mode-0 worker: interprets BS/TAB/LF/CR, outputs other chars as glyphs. */
|
/* Mode-0 worker: interprets BS/TAB/LF/CR, outputs other chars as glyphs. */
|
||||||
static void _raw_putch_raw0(char ch, uint8_t attr) __naked
|
static void _putch_wrchar(char ch, uint8_t attr) __naked
|
||||||
{
|
{
|
||||||
(void)ch; (void)attr;
|
(void)ch; (void)attr;
|
||||||
__asm
|
__asm
|
||||||
@@ -191,6 +188,12 @@ static void _raw_putch_raw0(char ch, uint8_t attr) __naked
|
|||||||
;; Dispatch on control chars while A still holds ch (cp does not
|
;; Dispatch on control chars while A still holds ch (cp does not
|
||||||
;; modify A). B/C only get loaded on the output path so the
|
;; modify A). B/C only get loaded on the output path so the
|
||||||
;; ctrl-char paths are cheaper.
|
;; ctrl-char paths are cheaper.
|
||||||
|
|
||||||
|
;; ld c, a
|
||||||
|
;; ld a, (_pc_ch) ; A = ch (`ld a,(nn)` does not touch flags)
|
||||||
|
;; jr nz, _rp0_pri
|
||||||
|
|
||||||
|
;; ld a, c
|
||||||
cp #0x08
|
cp #0x08
|
||||||
jr z, _rp0_bs
|
jr z, _rp0_bs
|
||||||
cp #0x09
|
cp #0x09
|
||||||
@@ -201,18 +204,21 @@ static void _raw_putch_raw0(char ch, uint8_t attr) __naked
|
|||||||
jr z, _rp0_cr
|
jr z, _rp0_cr
|
||||||
;; Anything else (printable or unrecognised ctrl) → glyph.
|
;; Anything else (printable or unrecognised ctrl) → glyph.
|
||||||
|
|
||||||
|
_rp0_pri:
|
||||||
|
|
||||||
ld c, a ; C = ch (save before A is clobbered)
|
ld c, a ; C = ch (save before A is clobbered)
|
||||||
ld a, (_pc_row)
|
ld a, (_pc_place + 1)
|
||||||
cp #32
|
cp #32
|
||||||
ret nc ; off-screen bottom — silently skip
|
ret nc ; off-screen bottom — silently skip
|
||||||
ld d, a ; D = row (ESTEX WRCHAR convention)
|
ld d, a ; D = row (ESTEX WRCHAR convention)
|
||||||
ld a, (_pc_col)
|
ld a, (_pc_place)
|
||||||
cp #80
|
cp #80
|
||||||
ret nc ; off-screen right — silently skip
|
ret nc ; off-screen right — silently skip
|
||||||
ld e, a ; E = col
|
ld e, a ; E = col
|
||||||
inc a
|
inc a
|
||||||
ld (_pc_col), a ; pc_col++
|
ld (_pc_place), a ; pc_col++
|
||||||
|
|
||||||
|
_rp0_wr:
|
||||||
ld b, l ; B = attr
|
ld b, l ; B = attr
|
||||||
ld a, c ; A = ch
|
ld a, c ; A = ch
|
||||||
push ix
|
push ix
|
||||||
@@ -222,56 +228,61 @@ static void _raw_putch_raw0(char ch, uint8_t attr) __naked
|
|||||||
ret
|
ret
|
||||||
|
|
||||||
_rp0_bs:
|
_rp0_bs:
|
||||||
ld a, (_pc_col)
|
ld a, (_pc_place)
|
||||||
or a, a
|
or a, a
|
||||||
ret z ; already at col 0 — no change
|
ret z ; already at col 0 — no change
|
||||||
dec a
|
dec a
|
||||||
ld (_pc_col), a
|
ld (_pc_place), a
|
||||||
ret
|
ld e, a ; E = col
|
||||||
|
ld a, (_pc_place + 1)
|
||||||
|
ld d, a ; D = row (ESTEX WRCHAR convention)
|
||||||
|
ld c, #0x20
|
||||||
|
jr _rp0_wr
|
||||||
|
|
||||||
_rp0_tab:
|
_rp0_tab:
|
||||||
ld a, (_pc_col)
|
ld a, (_pc_place)
|
||||||
and #0xF8 ; floor to mult of 8
|
or #0x07 ; floor to mult of 8
|
||||||
add a, #8 ; → next mult of 8
|
inc a ; → next mult of 8
|
||||||
cp #80
|
cp #81 ; сравнить A с 81 (0x51)
|
||||||
jr c, _rp0_tab_store
|
jr c, _rp0_tab_skip ; если A < 81 (т.е. A ≤ 80), пропустить загрузку
|
||||||
ld a, #80 ; cap at off-screen right
|
ld a, #80 ; иначе A > 80 → установить A = 80
|
||||||
_rp0_tab_store:
|
_rp0_tab_skip:
|
||||||
ld (_pc_col), a
|
ld (_pc_place), a
|
||||||
ret
|
ret
|
||||||
|
|
||||||
_rp0_lf:
|
_rp0_lf:
|
||||||
ld a, (_pc_row)
|
ld a, (_pc_place + 1)
|
||||||
cp #32
|
cp #32
|
||||||
ret nc ; already at bottom edge
|
ret nc ; already at bottom edge
|
||||||
inc a
|
inc a
|
||||||
ld (_pc_row), a
|
ld (_pc_place + 1), a
|
||||||
ret
|
ret
|
||||||
|
|
||||||
_rp0_cr:
|
_rp0_cr:
|
||||||
xor a, a
|
xor a, a
|
||||||
ld (_pc_col), a
|
ld (_pc_place), a
|
||||||
ret
|
ret
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mode-1 worker: every byte goes through WRCHAR as a glyph. */
|
/* Mode-1 worker: every byte goes through WRCHAR as a glyph. */
|
||||||
static void _raw_putch_raw1(char ch, uint8_t attr) __naked
|
static void _putch_wrchar_raw(char ch, uint8_t attr) __naked
|
||||||
{
|
{
|
||||||
(void)ch; (void)attr;
|
(void)ch; (void)attr;
|
||||||
__asm
|
__asm
|
||||||
;; __sdcccall(1): ch in A, attr in L.
|
;; __sdcccall(1): ch in A, attr in L.
|
||||||
ld c, a ; C = ch (save)
|
ld c, a ; C = ch (save)
|
||||||
ld a, (_pc_row)
|
|
||||||
|
ld a, (_pc_place + 1)
|
||||||
cp #32
|
cp #32
|
||||||
ret nc ; off-screen bottom — silently skip
|
ret nc ; off-screen bottom — silently skip
|
||||||
ld d, a ; D = row
|
ld d, a ; D = row
|
||||||
ld a, (_pc_col)
|
ld a, (_pc_place)
|
||||||
cp #80
|
cp #80
|
||||||
ret nc ; off-screen right — silently skip
|
ret nc ; off-screen right — silently skip
|
||||||
ld e, a ; E = col
|
ld e, a ; E = col
|
||||||
inc a
|
inc a
|
||||||
ld (_pc_col), a ; pc_col++
|
ld (_pc_place), a ; pc_col++
|
||||||
|
|
||||||
ld b, l ; B = attr
|
ld b, l ; B = attr
|
||||||
ld a, c ; A = ch
|
ld a, c ; A = ch
|
||||||
@@ -283,18 +294,6 @@ static void _raw_putch_raw1(char ch, uint8_t attr) __naked
|
|||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PCHARS (no attr) — used by cputs when KEEP_EXIST_ATTR is in effect. */
|
|
||||||
static void _cputs_pchars(const char *s) __naked
|
|
||||||
{
|
|
||||||
(void)s;
|
|
||||||
__asm
|
|
||||||
push ix
|
|
||||||
ld c, #0x5C ; ESTEX PCHARS
|
|
||||||
rst #0x10
|
|
||||||
pop ix
|
|
||||||
ret
|
|
||||||
__endasm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- Public putch / cputs --------------------------------------- *
|
/* ---- Public putch / cputs --------------------------------------- *
|
||||||
*
|
*
|
||||||
@@ -306,6 +305,7 @@ static void _cputs_pchars(const char *s) __naked
|
|||||||
* folds the per-char CURSOR/LOCATE pair from the old design into a
|
* folds the per-char CURSOR/LOCATE pair from the old design into a
|
||||||
* single pair per operation. */
|
* single pair per operation. */
|
||||||
|
|
||||||
|
|
||||||
char putch(char ch) __naked
|
char putch(char ch) __naked
|
||||||
{
|
{
|
||||||
(void)ch;
|
(void)ch;
|
||||||
@@ -313,38 +313,26 @@ char putch(char ch) __naked
|
|||||||
;; A = ch on entry; char return → A.
|
;; A = ch on entry; char return → A.
|
||||||
ld (_pc_ch), a ; stash c (for both return and re-load)
|
ld (_pc_ch), a ; stash c (for both return and re-load)
|
||||||
|
|
||||||
;; KEEP_EXIST_ATTR? high byte of g_text_attr != 0
|
|
||||||
ld a, (_g_text_attr + 1)
|
|
||||||
or a, a
|
|
||||||
jr nz, _putch_fast
|
|
||||||
|
|
||||||
;; --- WRCHAR path: cursor → worker → cursor ---
|
|
||||||
call __get_cursor
|
|
||||||
|
|
||||||
;; Worker ABI (2 char/uint8 args): ch in A, attr in L.
|
|
||||||
ld a, (_g_text_attr) ; A = low byte = attr
|
ld a, (_g_text_attr) ; A = low byte = attr
|
||||||
ld l, a ; L = attr
|
ld l, a ; L = attr
|
||||||
|
|
||||||
ld a, (_pc_raw_mode)
|
ld a, (_pc_raw_mode)
|
||||||
or a, a ; Z = (mode == 0)
|
or a, a ; Z = (mode == 0)
|
||||||
ld a, (_pc_ch) ; A = ch (`ld a,(nn)` does not touch flags)
|
ld a, (_pc_ch) ; A = ch (`ld a,(nn)` does not touch flags)
|
||||||
jr nz, _putch_use_raw1
|
jr nz, _putch_use_raw
|
||||||
call __raw_putch_raw0
|
call __putch_wrchar
|
||||||
jr _putch_after_raw
|
jr _putch_after_raw
|
||||||
_putch_use_raw1:
|
_putch_use_raw:
|
||||||
call __raw_putch_raw1
|
call __putch_wrchar_raw
|
||||||
_putch_after_raw:
|
_putch_after_raw:
|
||||||
call __set_cursor
|
call __set_cursor
|
||||||
ld a, (_pc_ch) ; return value
|
ld a, (_pc_ch) ; return value
|
||||||
ret
|
ret
|
||||||
|
|
||||||
_putch_fast:
|
|
||||||
ld a, (_pc_ch)
|
|
||||||
call __bios_putchar ; __bios_putchar keeps AF
|
|
||||||
ret
|
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char cputs(const char *s) __naked
|
char cputs(const char *s) __naked
|
||||||
{
|
{
|
||||||
(void)s;
|
(void)s;
|
||||||
@@ -356,60 +344,48 @@ char cputs(const char *s) __naked
|
|||||||
or a, l
|
or a, l
|
||||||
ret z
|
ret z
|
||||||
|
|
||||||
;; IX is callee-saved under SDCC's z80 ABI. We use it as a
|
|
||||||
;; function pointer below (ld ix, #__raw_putch_raw0/1) so save
|
|
||||||
;; the caller's value up front and restore before every ret.
|
|
||||||
push ix
|
push ix
|
||||||
|
|
||||||
|
call __get_cursor
|
||||||
|
|
||||||
;; KEEP_EXIST_ATTR? high byte of g_text_attr != 0
|
;; KEEP_EXIST_ATTR? high byte of g_text_attr != 0
|
||||||
ld a, (_g_text_attr + 1)
|
ld a, (_g_text_attr + 1)
|
||||||
or a, a
|
or a, a
|
||||||
jr nz, _cputs_fast
|
jr nz, _cputs_fast
|
||||||
|
|
||||||
;; --- WRCHAR path: cursor → worker → cursor ---
|
|
||||||
call __get_cursor
|
|
||||||
|
|
||||||
;; Worker walks the string via DE; HL is used to carry attr in L
|
|
||||||
;; across iterations (RST 10 inside worker clobbers it, so we
|
|
||||||
;; push/pop hl around each call).
|
|
||||||
ex de, hl ; DE = s
|
|
||||||
ld a, (_g_text_attr) ; A = attr (low byte)
|
|
||||||
ld l, a ; L = attr (worker ABI: arg2 in L)
|
|
||||||
|
|
||||||
;; Pick worker once based on pc_raw_mode; IX = function pointer.
|
|
||||||
ld a, (_pc_raw_mode)
|
ld a, (_pc_raw_mode)
|
||||||
or a, a
|
or a, a
|
||||||
jr z, _cputs_use_raw0
|
jr nz, _cputs_bios
|
||||||
ld ix, #__raw_putch_raw1
|
|
||||||
jr _cputs_loop
|
|
||||||
_cputs_use_raw0:
|
|
||||||
ld ix, #__raw_putch_raw0
|
|
||||||
|
|
||||||
_cputs_loop:
|
push hl
|
||||||
ld a, (de)
|
|
||||||
or a, a
|
|
||||||
jr z, _cputs_loop_end
|
|
||||||
inc de
|
|
||||||
;; Z80 has no "call (ix)" — emulate via push-of-ret + jp (ix).
|
|
||||||
push de ; save string pointer
|
|
||||||
push hl ; save attr (in L)
|
|
||||||
ld de, #_cputs_after_worker
|
|
||||||
push de ; push return address
|
|
||||||
jp (ix) ; "call" worker
|
|
||||||
_cputs_after_worker:
|
|
||||||
pop hl
|
|
||||||
pop de
|
pop de
|
||||||
jr _cputs_loop
|
|
||||||
_cputs_loop_end:
|
|
||||||
|
|
||||||
call __set_cursor
|
_cputs_wrloop:
|
||||||
pop ix ; restore caller's IX
|
ld a, (_g_text_attr)
|
||||||
xor a, a ; return 0
|
ld l, a
|
||||||
ret
|
ld a, (de) ; загрузить байт
|
||||||
|
or a ; установить флаг Z, если A == 0
|
||||||
|
jr z, _cputs_ex ; завершить подпрограмму (конец строки)
|
||||||
|
push de
|
||||||
|
call __putch_wrchar ; вывести символ (A передаётся как аргумент)
|
||||||
|
pop de
|
||||||
|
inc de ; перейти к следующему байту
|
||||||
|
jr _cputs_wrloop ; повторить
|
||||||
|
|
||||||
|
_cputs_bios:
|
||||||
|
ld a, (_g_text_attr)
|
||||||
|
ld b, #0xFF
|
||||||
|
ld d, #0x0
|
||||||
|
ld e, a
|
||||||
|
ld c, #0x8B ; BIOS LP_PRINT_LN5
|
||||||
|
rst #0x08
|
||||||
|
jr _cputs_ex
|
||||||
_cputs_fast:
|
_cputs_fast:
|
||||||
call __cputs_pchars
|
ld c, #0x5C ; ESTEX PCHARS
|
||||||
pop ix ; restore caller's IX
|
rst #0x10
|
||||||
|
_cputs_ex:
|
||||||
|
call __set_cursor
|
||||||
|
pop ix ; restore callers IX
|
||||||
xor a, a ; return 0
|
xor a, a ; return 0
|
||||||
ret
|
ret
|
||||||
__endasm;
|
__endasm;
|
||||||
@@ -446,12 +422,15 @@ void gotoxy(uint8_t x, uint8_t y) __naked
|
|||||||
__asm
|
__asm
|
||||||
;; __sdcccall(1) 2 uint8 args: x in A, y in L.
|
;; __sdcccall(1) 2 uint8 args: x in A, y in L.
|
||||||
;; ESTEX LOCATE ($52) wants: D = row, E = col.
|
;; ESTEX LOCATE ($52) wants: D = row, E = col.
|
||||||
push ix
|
;; push ix
|
||||||
ld d, l ; D = row (y)
|
ld d, l ; D = row (y)
|
||||||
ld e, a ; E = col (x)
|
ld e, a ; E = col (x)
|
||||||
ld c, #0x52
|
ld (_pc_place), de
|
||||||
rst #0x10
|
ld c, #0x84 ; BIOS SetCursor
|
||||||
pop ix
|
rst #0x08
|
||||||
|
;; ld c, #0x52
|
||||||
|
;; rst #0x10
|
||||||
|
;; pop ix
|
||||||
ret
|
ret
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
@@ -460,11 +439,14 @@ uint8_t wherex(void) __naked
|
|||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
;; ESTEX CURSOR ($53): D = row, E = col. Return col in DE.
|
;; ESTEX CURSOR ($53): D = row, E = col. Return col in DE.
|
||||||
push ix
|
;; push ix
|
||||||
ld c, #0x53
|
ld c, #0x8e ; BIOS GetCursor
|
||||||
rst #0x10
|
rst #0x08
|
||||||
pop ix
|
;; ld c, #0x53
|
||||||
|
;; rst #0x10
|
||||||
|
;; pop ix
|
||||||
ld a, e
|
ld a, e
|
||||||
|
ld (_pc_place), de
|
||||||
ret
|
ret
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
@@ -472,11 +454,14 @@ uint8_t wherex(void) __naked
|
|||||||
uint8_t wherey(void) __naked
|
uint8_t wherey(void) __naked
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
push ix
|
;; push ix
|
||||||
ld c, #0x53
|
ld c, #0x8e ; BIOS GetCursor
|
||||||
rst #0x10
|
rst #0x08
|
||||||
pop ix
|
;; ld c, #0x53
|
||||||
|
;; rst #0x10
|
||||||
|
;; pop ix
|
||||||
ld a, d
|
ld a, d
|
||||||
|
ld (_pc_place), de
|
||||||
ret
|
ret
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
@@ -485,10 +470,13 @@ uint16_t wherexy(void) __naked
|
|||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
;; ESTEX CURSOR ($53): D = row, E = col. Return col in DE.
|
;; ESTEX CURSOR ($53): D = row, E = col. Return col in DE.
|
||||||
push ix
|
;; push ix
|
||||||
ld c, #0x53
|
ld c, #0x8e ; BIOS GetCursor
|
||||||
rst #0x10
|
rst #0x08
|
||||||
pop ix
|
;; ld c, #0x53
|
||||||
|
;; rst #0x10
|
||||||
|
;; pop ix
|
||||||
|
ld (_pc_place), de
|
||||||
ret
|
ret
|
||||||
__endasm;
|
__endasm;
|
||||||
}
|
}
|
||||||
@@ -577,12 +565,12 @@ uint16_t rdchar(uint8_t x, uint8_t y) __naked
|
|||||||
extern uint8_t _videomode_raw_get(void);
|
extern uint8_t _videomode_raw_get(void);
|
||||||
extern int _videomode_raw_set(uint8_t mode);
|
extern int _videomode_raw_set(uint8_t mode);
|
||||||
|
|
||||||
uint8_t get_videotextmode(void)
|
uint8_t gettextmode(void)
|
||||||
{
|
{
|
||||||
return _videomode_raw_get();
|
return _videomode_raw_get();
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_videotextmode(uint8_t mode)
|
int settextmode(uint8_t mode)
|
||||||
{
|
{
|
||||||
/* Refuse anything that isn't a known text mode — otherwise a stray
|
/* Refuse anything that isn't a known text mode — otherwise a stray
|
||||||
* GFX_MODE_* value could swap the screen out from under text I/O. */
|
* GFX_MODE_* value could swap the screen out from under text I/O. */
|
||||||
@@ -600,18 +588,17 @@ int set_videotextmode(uint8_t mode)
|
|||||||
*
|
*
|
||||||
* 0x00..0xFF — real attribute (4-bit FG | 3-bit BG | 1-bit blink)
|
* 0x00..0xFF — real attribute (4-bit FG | 3-bit BG | 1-bit blink)
|
||||||
* KEEP_EXIST_ATTR (0xFFFF) — putch/cputs fall back to fast no-attr path */
|
* KEEP_EXIST_ATTR (0xFFFF) — putch/cputs fall back to fast no-attr path */
|
||||||
int16_t g_text_attr = 0x0F;
|
|
||||||
|
|
||||||
int16_t set_text_attr(int16_t attr)
|
int16_t set_text_attr(int16_t attr)
|
||||||
{
|
{
|
||||||
int16_t prev = g_text_attr;
|
int16_t prev = g_text_attr.value;
|
||||||
g_text_attr = attr;
|
g_text_attr.value = attr;
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t get_text_attr(void)
|
int16_t get_text_attr(void)
|
||||||
{
|
{
|
||||||
return g_text_attr;
|
return g_text_attr.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Turbo-C-style palette helpers --------------------------------
|
/* ---- Turbo-C-style palette helpers --------------------------------
|
||||||
@@ -620,21 +607,21 @@ int16_t get_text_attr(void)
|
|||||||
|
|
||||||
void textcolor(uint8_t fg)
|
void textcolor(uint8_t fg)
|
||||||
{
|
{
|
||||||
/* If we were KEEP_EXIST_ATTR, switch to a real attr first. */
|
fg = (fg & 0x07);
|
||||||
uint8_t cur = ((uint16_t)g_text_attr > 0xFF) ? 0x00 : (uint8_t)g_text_attr;
|
g_text_attr.value = (g_text_attr.byte.low & 0xF0) | fg;
|
||||||
g_text_attr = (int16_t)((cur & 0xF0) | (fg & 0x0F));
|
// g_text_attr.byte.high = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void textbackground(uint8_t bg)
|
void textbackground(uint8_t bg)
|
||||||
{
|
{
|
||||||
uint8_t cur = ((uint16_t)g_text_attr > 0xFF) ? 0x00 : (uint8_t)g_text_attr;
|
bg = (bg & 0x07) << 4;
|
||||||
/* Background uses 3 bits (4..6); preserve blink (bit 7) too. */
|
g_text_attr.value = (g_text_attr.byte.low & 0x0F) | bg;
|
||||||
g_text_attr = (int16_t)((cur & 0x8F) | ((bg & 0x07) << 4));
|
// g_text_attr.byte.high = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void textattr(uint8_t attr)
|
void textattr(uint8_t attr)
|
||||||
{
|
{
|
||||||
g_text_attr = (int16_t)attr;
|
g_text_attr.value = (uint16_t)attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Solid-C compatibility ---------------------------------------- */
|
/* ---- Solid-C compatibility ---------------------------------------- */
|
||||||
|
|||||||
+14
-2
@@ -74,12 +74,24 @@ uint16_t getkey(void);
|
|||||||
#define KEY_PGUP 0x59
|
#define KEY_PGUP 0x59
|
||||||
#define KEY_INS 0x50 /* numpad 0; not verified */
|
#define KEY_INS 0x50 /* numpad 0; not verified */
|
||||||
#define KEY_DEL 0x55 /* numpad 5/.; not verified */
|
#define KEY_DEL 0x55 /* numpad 5/.; not verified */
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint16_t value;
|
||||||
|
struct {
|
||||||
|
uint8_t low;
|
||||||
|
uint8_t high;
|
||||||
|
} byte;
|
||||||
|
} two_bytes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char putch (char c);
|
char putch (char c);
|
||||||
char cputs (const char *s);
|
char cputs (const char *s);
|
||||||
int cprintf(const char *fmt, ...);
|
int cprintf(const char *fmt, ...);
|
||||||
void clrscr(void);
|
void clrscr(void);
|
||||||
void gotoxy(uint8_t x, uint8_t y);
|
void gotoxy(uint8_t x, uint8_t y);
|
||||||
|
|
||||||
|
|
||||||
/* Solid-C compatibility helpers. */
|
/* Solid-C compatibility helpers. */
|
||||||
#define home() gotoxy(0, 0)
|
#define home() gotoxy(0, 0)
|
||||||
#define inp(port) z80_inp(port)
|
#define inp(port) z80_inp(port)
|
||||||
@@ -124,8 +136,8 @@ void clrscr_attr(uint8_t attr);
|
|||||||
#define TEXT_MODE_40x32 0x02
|
#define TEXT_MODE_40x32 0x02
|
||||||
#define TEXT_MODE_80x32 0x03
|
#define TEXT_MODE_80x32 0x03
|
||||||
|
|
||||||
uint8_t get_videotextmode(void);
|
uint8_t gettextmode(void);
|
||||||
int set_videotextmode(uint8_t mode); /* 0 OK, -1 + errno on bad mode */
|
int settextmode(uint8_t mode); /* 0 OK, -1 + errno on bad mode */
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ *
|
/* ------------------------------------------------------------------ *
|
||||||
* Text-output attribute (used by the conio set: putch / cputs / cprintf).
|
* Text-output attribute (used by the conio set: putch / cputs / cprintf).
|
||||||
|
|||||||
+27
-5
@@ -1,6 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
#include <unistd.h> /* sleep */
|
#include <unistd.h> /* sleep */
|
||||||
|
#include <sprinter_exit.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exercises every conio function:
|
* Exercises every conio function:
|
||||||
@@ -16,6 +17,8 @@
|
|||||||
* (0,0), (79,0), (0,31), (79,31).
|
* (0,0), (79,0), (0,31), (79,31).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
extern two_bytes pc_place;
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
/* 1. clrscr + diagnostic probes + a centered banner.
|
/* 1. clrscr + diagnostic probes + a centered banner.
|
||||||
@@ -27,9 +30,16 @@ int main(void)
|
|||||||
*/
|
*/
|
||||||
clrscr();
|
clrscr();
|
||||||
|
|
||||||
gotoxy(0, 0); putch('0');
|
gotoxy(1, 0);
|
||||||
|
textattr(0x07);
|
||||||
|
putch('0');
|
||||||
textattr(0x70);
|
textattr(0x70);
|
||||||
gotoxy(1, 0); putch('1');
|
putch('1');
|
||||||
|
// gotoxy(10, 20);
|
||||||
|
printf("X = %u, Y = %u\n", pc_place.byte.low, pc_place.byte.high);
|
||||||
|
uint8_t x = wherex();
|
||||||
|
uint8_t y = wherey();
|
||||||
|
printf("X = %u, Y = %u\n", x, y);
|
||||||
|
|
||||||
set_putch_raw_mode(1);
|
set_putch_raw_mode(1);
|
||||||
|
|
||||||
@@ -51,11 +61,23 @@ int main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_text_attr(0x011D);
|
||||||
set_putch_raw_mode(0);
|
set_putch_raw_mode(0);
|
||||||
gotoxy(0,22);
|
gotoxy(0,22);
|
||||||
set_text_attr(0x000E);
|
cputs("Test message line 1\nTest message line2\rline3\n\r1234\t5678\b90\n\r");
|
||||||
// cputs("Test message line");
|
|
||||||
cputs("Test message line 1\nTest message line2\rline3\n\r\n\r1234\t5678\b90");
|
set_putch_raw_mode(1);
|
||||||
|
gotoxy(0,25);
|
||||||
|
cputs("Test message line 1\nTest message line2\rline3\n\r1234\t5678\b90\n\r");
|
||||||
|
|
||||||
|
set_text_attr(0x001D);
|
||||||
|
set_putch_raw_mode(0);
|
||||||
|
gotoxy(0,28);
|
||||||
|
cputs("Test message line 1\nTest message line2\rline3\n\r1234\t5678\b90\n\r");
|
||||||
|
|
||||||
|
set_putch_raw_mode(1);
|
||||||
|
gotoxy(0,31);
|
||||||
|
cputs("Test message line 1\nTest message line2\rline3\n\r1234\t5678\b90\n\r");
|
||||||
|
|
||||||
(void)getch();
|
(void)getch();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user