mdview2: add render-cache markdown viewer (Phases 0-4)
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>
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user