Add full compiler toolchain, libc, examples and reference docs
First substantive commit: the entire Sprinter C compiler tree on top of
the bare README+gitignore initial commit.
What's in here:
bin/sprinter-cc — driver script invoking SDCC + linker + mkexe
libc/ — Sprinter-specific libc layer over ESTEX/BIOS
(conio, gfx, io, mem, stdio + headers)
runtime/ — crt0 variants (default/small/banked/minimal)
+ heap + bank trampolines
toolchain/ — mkexe (SprintEXE packer, C + tests)
examples/ — 30 demo programs (gfx, file I/O, env, time, …)
lib/Makefile — builds the libc archive (sprinter.lib)
docs/ — converted Sprinter manuals + asm reference samples
third_party/ — solid-c reference compiler dump + sdcc setup script
release_docs/ — packaging / release notes
gitignore overhaul:
• Drop dangerous blanket patterns: *.asm (would hide docs/samples/*.asm)
and *.exe (case-insensitive match was hiding third_party/solid-c/*.EXE
on macOS APFS). Replaced with examples/*/*.{asm,exe,…} and lib/*.lib.
• Restore tracking of toolchain/mkexe/tests/{one,big}.bin — those are
INPUT fixtures, not build outputs.
• Collapse the duplicated SDCC/C/Sdcc sections into one section per
concern (build outputs / vendored / OS-junk).
• Add .sprinter-cc-*/, build/ (catches lib/build/ too), .claude/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||
EXAMPLE := gfx_mous
|
||||
include $(PROJ_ROOT)/examples/example.mk
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* gfx_mouse_test — exercises the graphics-mode mouse cursor API:
|
||||
* $09 LOAD CURSOR — install a custom cursor bitmap
|
||||
* $81 CHANGE VIDEO MODE — let the driver re-sync after switching modes
|
||||
* $0B RETURN CURSOR — read the cursor back (may be a stub in MAME)
|
||||
*
|
||||
* Flow:
|
||||
* 1. Init the mouse driver in text mode.
|
||||
* 2. Switch to 320x256x256, notify the driver.
|
||||
* 3. Build an 8x8 cursor — solid white border + transparent middle —
|
||||
* and load it. Show it. Move the mouse to verify it tracks.
|
||||
* 4. Press a key: query the driver's view of the cursor and dump the
|
||||
* result so we can compare against what we loaded.
|
||||
* 5. Hide cursor, return to text mode, print the round-trip dump.
|
||||
*
|
||||
* The driver's bitmap format is undocumented — best guess is one byte
|
||||
* per pixel (palette index, with 0 meaning transparent). We load 0xFF
|
||||
* for opaque cells and 0 for transparent so the cursor stands out
|
||||
* against any background.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
#include <mouse.h>
|
||||
#include <gfx.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define CURSOR_W 12
|
||||
#define CURSOR_H 12
|
||||
#define CURSOR_BUF_BYTES (CURSOR_W * CURSOR_H)
|
||||
|
||||
/* Cursor format (verified empirically 2026-05-31):
|
||||
* ONE BYTE per pixel — row-major, width*height bytes total.
|
||||
* 0xFF = transparent (background shows through)
|
||||
* any other byte = palette index (drawn opaque)
|
||||
*
|
||||
* Cursor bitmap lives in a dedicated video bank, not the 0x50 page used
|
||||
* by gfx_clear256 / gfx_putpixel256 — that's why 0xFF reads as transparent
|
||||
* even though in the main visible page 0xFF is a regular colour.
|
||||
*/
|
||||
|
||||
static uint8_t cursor_bitmap[CURSOR_BUF_BYTES];
|
||||
static uint8_t roundtrip_buf[CURSOR_BUF_BYTES];
|
||||
static uint8_t palette[256 * 4];
|
||||
|
||||
/* Arrow shape, 1 byte per pixel. Each cell is either:
|
||||
* _ transparent (0xFF, lets the background through)
|
||||
* O black solid pixel (0x00)
|
||||
* W white solid pixel (0xFF would mean transparent, so use 0xFF
|
||||
* palette entry by hand if you want a white pixel — for the
|
||||
* default greyscale palette in this demo, W = bright grey 0xE0)
|
||||
*
|
||||
* Feel free to edit the 12×12 grid below to draw a nicer cursor. */
|
||||
#define _ 0xFF
|
||||
#define O 0x00
|
||||
#define W 0xE0
|
||||
static const uint8_t cursor_arrow[CURSOR_BUF_BYTES] = {
|
||||
O,_,_,_,_,_,_,_,_,_,_,_,
|
||||
O,O,_,_,_,_,_,_,_,_,_,_,
|
||||
O,W,O,_,_,_,_,_,_,_,_,_,
|
||||
O,W,W,O,_,_,_,_,_,_,_,_,
|
||||
O,W,W,W,O,_,_,_,_,_,_,_,
|
||||
O,W,W,W,W,O,_,_,_,_,_,_,
|
||||
O,W,W,W,W,W,O,_,_,_,_,_,
|
||||
O,W,W,W,O,O,O,O,_,_,_,_,
|
||||
O,O,O,W,O,_,_,_,_,_,_,_,
|
||||
O,_,_,O,W,O,_,_,_,_,_,_,
|
||||
_,_,_,O,W,O,_,_,_,_,_,_,
|
||||
_,_,_,_,O,O,_,_,_,_,_,_,
|
||||
};
|
||||
#undef _
|
||||
#undef O
|
||||
#undef W
|
||||
|
||||
static void make_palette(void)
|
||||
{
|
||||
for (int i = 0; i < 256; i++) {
|
||||
palette[i*4+0] = (uint8_t)i;
|
||||
palette[i*4+1] = (uint8_t)i;
|
||||
palette[i*4+2] = (uint8_t)i;
|
||||
palette[i*4+3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the arrow pattern into our scratch (one place for the driver
|
||||
* to point IX at). */
|
||||
static void build_cursor(void)
|
||||
{
|
||||
for (int i = 0; i < CURSOR_BUF_BYTES; i++)
|
||||
cursor_bitmap[i] = cursor_arrow[i];
|
||||
}
|
||||
|
||||
static void wait_key(void)
|
||||
{
|
||||
while (!kbhit()) { /* spin */ }
|
||||
(void)getch();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
textattr(COLOR(COLOR_LIGHTGRAY, COLOR_BLACK));
|
||||
clrscr();
|
||||
cputs("gfx_mouse_test\r\n");
|
||||
|
||||
if (mouse_init() < 0) {
|
||||
cputs("mouse_init failed - no driver\r\n");
|
||||
return 1;
|
||||
}
|
||||
mouse_set_sensitivity(2, 2);
|
||||
|
||||
/* --- enter graphics, load custom cursor, then show -------------- */
|
||||
make_palette();
|
||||
build_cursor();
|
||||
|
||||
uint8_t prev = gfx_init(GFX_MODE_320x256x256, 0);
|
||||
gfx_pal_load(0, 0, 0, palette);
|
||||
gfx_clear256(0x40); /* dim grey background */
|
||||
|
||||
/* Coordinate grid every 32 px so the cursor position reads easily. */
|
||||
for (int x = 0; x < GFX_WIDTH; x += 32) gfx_vline256(x, 0, GFX_HEIGHT, 0x80);
|
||||
for (int y = 0; y < GFX_HEIGHT; y += 32) gfx_hline256(0, y, GFX_WIDTH, 0x80);
|
||||
|
||||
mouse_video_mode_changed(GFX_MODE_320x256x256);
|
||||
mouse_bounds_x(0, GFX_WIDTH - 1);
|
||||
mouse_bounds_y(0, GFX_HEIGHT - 1);
|
||||
|
||||
mouse_cursor_t custom = {
|
||||
.image = cursor_bitmap,
|
||||
.width = CURSOR_W,
|
||||
.height = CURSOR_H,
|
||||
.hot_x = 0,
|
||||
.hot_y = 0,
|
||||
};
|
||||
mouse_load_cursor(&custom);
|
||||
mouse_show();
|
||||
wait_key();
|
||||
|
||||
/* --- query driver to see what it has now ------------------------ */
|
||||
mouse_cursor_t readback = {
|
||||
.image = roundtrip_buf,
|
||||
.width = 0, .height = 0, .hot_x = 0, .hot_y = 0,
|
||||
};
|
||||
mouse_get_cursor(&readback);
|
||||
|
||||
mouse_hide();
|
||||
gfx_done(prev);
|
||||
mouse_video_mode_changed(prev); /* tell driver we're back */
|
||||
|
||||
/* --- back in text mode: report what the driver returned --------- */
|
||||
textattr(COLOR(COLOR_LIGHTGRAY, COLOR_BLACK));
|
||||
clrscr();
|
||||
cprintf("loaded : %ux%u hot (%u,%u)\r\n",
|
||||
CURSOR_W, CURSOR_H, 0, 0);
|
||||
cprintf("read back: %ux%u hot (%u,%u)\r\n",
|
||||
readback.width, readback.height, readback.hot_x, readback.hot_y);
|
||||
|
||||
uint16_t n = (uint16_t)readback.width * (uint16_t)readback.height;
|
||||
if (n > CURSOR_BUF_BYTES) n = CURSOR_BUF_BYTES;
|
||||
cprintf("bitmap (%u bytes):\r\n", n);
|
||||
for (uint16_t i = 0; i < n; i++) {
|
||||
cprintf("%02X ", roundtrip_buf[i]);
|
||||
if ((i % readback.width) == readback.width - 1) cputs("\r\n");
|
||||
}
|
||||
cputs("\r\n");
|
||||
|
||||
cputs("press any key to exit");
|
||||
wait_key();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user