eab5a2d6ac
New examples/mdview2 — render-cache version of mdview: each logical line is rendered into an EMM (char,attr) buffer once during file load (interleaved with index_lines()), then scrolling draws straight from the cache via ESTEX WINREST, with no re-parsing or fb() access in the steady state. Horizontal scroll still uses the old live-render path (Phase 5, not yet migrated). Format and budget were derisked empirically first (tests/winrest): confirmed ESTEX WINCOPY/WINREST buffer layout and measured EMM free space, both folded into the implementation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
152 lines
4.5 KiB
C
152 lines
4.5 KiB
C
/*
|
|
* Probe for ESTEX WINCOPY (59h) / WINREST (5Ah) — "save/restore screen
|
|
* window" calls (docs/part2/DSS 1.60 rst 10.txt:1379-1417):
|
|
*
|
|
* D=row E=col H=height L=width B=buffer page IX=buffer address
|
|
*
|
|
* Goal: reverse-engineer the on-disk cell format (char/attr order,
|
|
* per-row stride/padding) by writing four DISTINCT (char,attr) cells,
|
|
* capturing them with WINCOPY, and hex-dumping the captured page.
|
|
* A second WINREST to a different screen location confirms the
|
|
* round-trip visually.
|
|
*
|
|
* Register layout verified via `sdcc -S` for win_copy(row,col,h,w,page):
|
|
* A=row, L=col, stack [SP+2]=h [SP+3]=w [SP+4]=page (sdcccall(1)).
|
|
*
|
|
* CONFIRMED in MAME (2026-06-23): buffer format is (char,attr) pairs,
|
|
* row-major, stride = width*2 bytes, no padding. See memory note
|
|
* sprinter_winrest_format.
|
|
*
|
|
* Also reports mem_info() (total/free 16 KB EMM pages) at program
|
|
* start, to size a future mdview2 pre-render cache budget.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <conio.h>
|
|
#include <sprinter.h>
|
|
#include <sprinter_mem.h>
|
|
|
|
#define BUF_ADDR 0xC000u
|
|
|
|
static void win_copy(uint8_t row, uint8_t col, uint8_t h, uint8_t w, uint8_t page) __naked
|
|
{
|
|
(void)row; (void)col; (void)h; (void)w; (void)page;
|
|
__asm
|
|
ld iy, #2
|
|
add iy, sp
|
|
ld d, a ; D = row
|
|
ld e, l ; E = col
|
|
ld h, 0 (iy) ; H = height
|
|
ld a, 1 (iy) ; width -> L
|
|
ld l, a
|
|
ld a, 2 (iy) ; page -> B
|
|
ld b, a
|
|
push ix
|
|
ld ix, #0xC000
|
|
ld c, #0x59 ; ESTEX WINCOPY
|
|
di
|
|
rst #0x10
|
|
ei
|
|
pop ix
|
|
pop hl ; return address
|
|
inc sp
|
|
inc sp
|
|
inc sp ; discard h,w,page
|
|
jp (hl)
|
|
__endasm;
|
|
}
|
|
|
|
static void win_rest(uint8_t row, uint8_t col, uint8_t h, uint8_t w, uint8_t page) __naked
|
|
{
|
|
(void)row; (void)col; (void)h; (void)w; (void)page;
|
|
__asm
|
|
ld iy, #2
|
|
add iy, sp
|
|
ld d, a ; D = row
|
|
ld e, l ; E = col
|
|
ld h, 0 (iy) ; H = height
|
|
ld a, 1 (iy) ; width -> L
|
|
ld l, a
|
|
ld a, 2 (iy) ; page -> B
|
|
ld b, a
|
|
push ix
|
|
ld ix, #0xC000
|
|
ld c, #0x5A ; ESTEX WINREST
|
|
di
|
|
rst #0x10
|
|
ei
|
|
pop ix
|
|
pop hl
|
|
inc sp
|
|
inc sp
|
|
inc sp
|
|
jp (hl)
|
|
__endasm;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
clrscr();
|
|
|
|
/* --- mem_info() baseline, before any allocation by this program. */
|
|
uint16_t total_pages = 0, free_pages = 0;
|
|
mem_info(&total_pages, &free_pages);
|
|
|
|
textattr(0x0F);
|
|
gotoxy(0, 0);
|
|
printf("EMM pages: total=%u free=%u (each = 16 KB)\n", total_pages, free_pages);
|
|
printf(" => total %lu KB, free %lu KB\n",
|
|
(uint32_t)total_pages * 16UL, (uint32_t)free_pages * 16UL);
|
|
printf("Press a key to continue to WINCOPY/WINREST probe...\n");
|
|
(void)getchar();
|
|
|
|
/* Four distinguishable cells: char and attr both easy to recognise
|
|
* in a hex dump (A/B/C/D = 0x41..0x44, attrs 0x11/0x22/0x33/0x44). */
|
|
gotoxy(5, 10); textattr(0x11); putch('A');
|
|
gotoxy(6, 10); textattr(0x22); putch('B');
|
|
gotoxy(5, 11); textattr(0x33); putch('C');
|
|
gotoxy(6, 11); textattr(0x44); putch('D');
|
|
|
|
textattr(0x0F);
|
|
gotoxy(0, 13);
|
|
printf("Captured window drawn above (row 10-11, col 5-6).\n");
|
|
printf("Press a key to WINCOPY it...\n");
|
|
(void)getchar();
|
|
|
|
uint8_t blk = mem_alloc_pages(1);
|
|
uint8_t page = mem_get_page(blk, 0);
|
|
|
|
win_copy(10, 5, 2, 2, page);
|
|
|
|
/* Map the same physical page into our own W3 to inspect the bytes
|
|
* WINCOPY just wrote there. */
|
|
sprinter_page_w3(page);
|
|
{
|
|
volatile uint8_t *buf = (volatile uint8_t *)BUF_ADDR;
|
|
gotoxy(0, 15);
|
|
printf("Buffer dump (first 16 bytes of page %u):\n", page);
|
|
for (uint8_t i = 0; i < 16; i++) {
|
|
printf("%02X ", buf[i]);
|
|
}
|
|
printf("\n");
|
|
for (uint8_t i = 0; i < 16; i++) {
|
|
char c = (char)buf[i];
|
|
putchar((c >= 0x20 && c < 0x7F) ? c : '.');
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
printf("Press a key to WINREST it to row 20...\n");
|
|
(void)getchar();
|
|
|
|
win_rest(20, 5, 2, 2, page);
|
|
|
|
gotoxy(0, 23);
|
|
printf("Restored at row 20-21, col 5-6 -- compare colours/chars\n");
|
|
printf("with the original at row 10-11.\n");
|
|
printf("Press a key to exit...\n");
|
|
(void)getchar();
|
|
|
|
return 0;
|
|
}
|