/* * 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 #include #include #include #include #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; }