/*
 * sprinter.h — low-level Sprinter platform definitions for C programs.
 *
 * Numbers and behaviour cross-checked against docs/converted/ (IvanMak.txt,
 * DiskSyscalls.txt, BIOS_v3.txt, ProgrammerManual.txt).
 */

#ifndef SPRINTER_H
#define SPRINTER_H

#include <stdint.h>

/* ---- I/O ports ----------------------------------------------------- */

/* Memory window page-select ports (write 8-bit physical page number). */
#define PORT_PAGE_W0   0x82   /* window 0: 0x0000-0x3FFF (ESTEX system) */
#define PORT_PAGE_W1   0xA2   /* window 1: 0x4000-0x7FFF (HOME)        */
#define PORT_PAGE_W2   0xC2   /* window 2: 0x8000-0xBFFF (stack+heap)  */
#define PORT_PAGE_W3   0xE2   /* window 3: 0xC000-0xFFFF (paged)       */

/* Graphics ports (used in stage 3+). */
#define PORT_RGADR     0x89   /* graphic Y / Spectrum-page selector    */
#define PORT_RGMOD     0xC9   /* bit 0 = active screen page 0/1        */

/* ---- ESTEX RST 10h function numbers -------------------------------- */
/* Full list in docs/converted/DiskSyscalls.txt (DSS v1.6).             */

#define ESTEX_VERSION   0x00
#define ESTEX_CHDISK    0x01
#define ESTEX_CURDISK   0x02
#define ESTEX_DSKINFO   0x03

#define ESTEX_CREATE    0x0A
#define ESTEX_CREATE_NEW 0x0B
#define ESTEX_DELETE    0x0E
#define ESTEX_RENAME    0x10
#define ESTEX_OPEN      0x11
#define ESTEX_CLOSE     0x12
#define ESTEX_READ      0x13
#define ESTEX_WRITE     0x14
#define ESTEX_MOVE_FP   0x15
#define ESTEX_ATTRIB    0x16
#define ESTEX_F_FIRST   0x19
#define ESTEX_F_NEXT    0x1A
#define ESTEX_MKDIR     0x1B
#define ESTEX_RMDIR     0x1C
#define ESTEX_CHDIR     0x1D
#define ESTEX_CURDIR    0x1E

#define ESTEX_SYSTIME   0x21

#define ESTEX_WAITKEY   0x30
#define ESTEX_SCANKEY   0x31
#define ESTEX_ECHOKEY   0x32
#define ESTEX_CTRLKEY   0x33

#define ESTEX_SETWIN    0x38
#define ESTEX_SETWIN1   0x39
#define ESTEX_SETWIN2   0x3A
#define ESTEX_SETWIN3   0x3B
#define ESTEX_INFOMEM   0x3C
#define ESTEX_GETMEM    0x3D
#define ESTEX_FREEMEM   0x3E
#define ESTEX_SETMEM    0x3F

#define ESTEX_EXEC      0x40
#define ESTEX_EXIT      0x41
#define ESTEX_WAIT      0x42

#define ESTEX_ENV       0x46   /* env API: B=0 sysenv, B=1 getenv, B=2 putenv */

#define ESTEX_SETVMOD   0x50
#define ESTEX_GETVMOD   0x51
#define ESTEX_LOCATE    0x52
#define ESTEX_CURSOR    0x53
#define ESTEX_SELPAGE   0x54
#define ESTEX_SCROLL    0x55
#define ESTEX_CLEAR     0x56
#define ESTEX_RDCHAR    0x57
#define ESTEX_WRCHAR    0x58
#define ESTEX_WINCOPY   0x59
#define ESTEX_WINREST   0x5A
#define ESTEX_PUTCHAR   0x5B
#define ESTEX_PCHARS    0x5C
#define ESTEX_PRINT     0x5F

/* ---- BIOS RST 8 function numbers ----------------------------------- */
/* Full list in docs/converted/BIOS_v3.txt (BIOS v3.00).               */

#define BIOS_EMM_INFO      0xC0   /* HL=total pages, BC=free pages       */
#define BIOS_EMM_INIT      0xC1
#define BIOS_EMM_ALLOC     0xC2   /* B=npages -> A=blk_id                */
#define BIOS_EMM_FREE      0xC3   /* A=blk_id                            */
#define BIOS_EMM_GETPAGE   0xC4   /* A=blk_id, B=log -> A=physical       */
#define BIOS_EMM_LIST      0xC5
#define BIOS_EMM_PORT_FOR  0xC6   /* A=window -> C=port, B=current page  */
#define BIOS_EMM_NEXTPAGE  0xC7

/* ---- Inline paging intrinsics -------------------------------------- */
/*
 * Each generates a single "OUT (port), A" + the load of the literal.
 * Wrap in DI/EI yourself for graphics-grade timing; for one-shot setup
 * the inline form is fine.
 */
__sfr __at PORT_PAGE_W0 _io_page_w0;
__sfr __at PORT_PAGE_W1 _io_page_w1;
__sfr __at PORT_PAGE_W2 _io_page_w2;
__sfr __at PORT_PAGE_W3 _io_page_w3;

static inline void sprinter_page_w0(uint8_t page) { _io_page_w0 = page; }
static inline void sprinter_page_w1(uint8_t page) { _io_page_w1 = page; }
static inline void sprinter_page_w2(uint8_t page) { _io_page_w2 = page; }
static inline void sprinter_page_w3(uint8_t page) { _io_page_w3 = page; }

/* ---- Sprinter-specific debug helpers ------------------------------ */
/* Use hex8() / hex16() / hex32() from <stdio.h> for hex debug output. */

#ifdef DEBUG_RT
/*
 * Runtime diagnostics — exposed only when the program is built with
 * `sprinter-cc --debug`.  The flag below is set by crt0 before main().
 *
 *   0 — crt0 did NOT self-allocate a W2 page (tiny mode never needs to,
 *       and in small mode DSS itself maps W2 when the image > 16 KB).
 *   1 — crt0 had to allocate and map a W2 page via ESTEX $3D + $3A
 *       (small mode with image ≤ 16 KB).
 */
extern uint8_t w2_self_allocated;
#endif

/* ---- Environment (ESTEX $46) -------------------------------------- */
/*
 *   getenv(name)         — return pointer to value, or NULL if not set.
 *                          Returned buffer is ESTEX-owned (shared static);
 *                          copy if needed before the next getenv() call.
 *   putenv("name=value") — add/replace.  Pass "name" with no '=' to remove.
 *   sysenv(buf)          — copy the WHOLE environment into caller's buf,
 *                          as a series of NUL-terminated "NAME=value"
 *                          strings followed by an extra NUL marking end:
 *                            "PATH=...\0SOLID=H\0\0"
 *                          Caller is responsible for sizing buf large
 *                          enough for the entire environment.
 *
 * Return values:
 *   getenv:  pointer to value (NUL-terminated) on success,
 *            NULL when the variable is not present (errno unchanged),
 *            NULL with errno set on real error.
 *   putenv:  0 on success, -1 on error (errno set).
 *   sysenv:  buf on success, (char*)-1 on error (errno set).
 */
char *getenv(const char *name);
int   putenv(const char *namevalue);
char *sysenv(char *buf);

#endif /* SPRINTER_H */
