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