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:
2026-06-23 22:41:32 +03:00
parent 1b39a60ff0
commit eab5a2d6ac
6 changed files with 3034 additions and 0 deletions
+151
View File
@@ -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;
}