Files
vt1200/harness/c-hello/hello.c
T
arti 8f831eaf33 fix(video): model the real unit's VR319 monitor
The harness forced the VR150 monitor switch, so the firmware wrote the OS
screen at 1024 px / 128-byte rows.  VT1200_VRAM_REAL then re-read that
framebuffer at the VR319 pitch, which sheared the OS and wrapped the right
quarter of every row.

Model VR319 (switch 0x60) by default -- the real unit's mode -- so the
firmware itself programs 1280x1024 with a 256-byte row pitch (CONVDP=0x14).
The renderer's pitch follows VT1200_MONITOR, and the destination span now
comes from HEBLNK..HSBLNK instead of x=0, placing the active 1280 px at
x=336 in MAME's 1696-wide raster.

Verified: clean Terminal Manager at frame 600, legible faithful diagnostics
menu and level-1 error screens, tile mode PASS with tile_check 1280/1280
tiles, tablet/mouse pixel-identical.  VT1200_MONITOR=VR150 reproduces the
old geometry; the regression baseline moves 198 -> 199 (2 PCs) and is
recorded in harness/mame/README.md.
2026-10-31 20:53:51 +02:00

105 lines
3.7 KiB
C

/*
* hello.c -- the VT1200's first C program.
*
* Writes the word HELLO straight into video RAM, no X11 involved:
*
* framebuffer bit 0x04000000, 256-byte row pitch on the real unit
* (the harness now defaults to the same VR319 layout;
* only VT1200_MONITOR=VR150 uses 128)
* pixels 1 bpp, LSB-first within each byte
* text area black 256x72 box at x=40 y=800, white 5x7 glyphs scaled 8x
*
* The program also leaves a marker word at 0x018A8000 so the host can tell the
* C runtime reached main(): 0x48454C4C == 'HELL'.
*
* K&R C only: no prototypes, no '//', no unsigned suffixes, declarations first.
* The tables are filled in code, not by static initializers, because this image
* is entered through entry.asm and does not run boot.obj's .cinit pass.
*/
#define VRAM_BASE 0x04000000 /* bit address of the framebuffer */
#ifndef ROW_BYTES
#define ROW_BYTES 256 /* real unit: 256-byte row pitch */
#endif
#define ROW_BITS (ROW_BYTES * 8)
#define BOX_X 40 /* box left edge, pixels (1 bit per pixel) */
#define BOX_Y 800 /* box top edge, pixels */
#define BOX_W 256 /* 32 bytes */
#define BOX_H 72
#define MARKER 0x018A8000 /* free RAM, outside .text and .bss */
static unsigned char font[4][7]; /* H E L O (HELLO uses L twice) */
static unsigned char order[5];
static unsigned char box[BOX_H][BOX_W / 8];
/* 5x7 glyphs, bit 4 = leftmost pixel */
static void build_font()
{
font[0][0] = 17; font[0][1] = 17; font[0][2] = 31; font[0][3] = 17;
font[0][4] = 17; font[0][5] = 17; font[0][6] = 17; /* H */
font[1][0] = 31; font[1][1] = 16; font[1][2] = 16; font[1][3] = 30;
font[1][4] = 16; font[1][5] = 16; font[1][6] = 31; /* E */
font[2][0] = 16; font[2][1] = 16; font[2][2] = 16; font[2][3] = 16;
font[2][4] = 16; font[2][5] = 16; font[2][6] = 31; /* L */
font[3][0] = 14; font[3][1] = 17; font[3][2] = 17; font[3][3] = 17;
font[3][4] = 17; font[3][5] = 17; font[3][6] = 14; /* O */
order[0] = 0; order[1] = 1; order[2] = 2; order[3] = 2; order[4] = 3;
}
int main()
{
int c, r, gx, dx, dy, px, py;
unsigned int v;
unsigned int addr;
build_font();
/* 1. prove we are here */
*(unsigned int *)MARKER = 0x48454C4C;
/* 2. clear the box (black) */
for (py = 0; py < BOX_H; py++)
for (px = 0; px < BOX_W / 8; px++)
box[py][px] = 0;
/* 3. draw HELLO, each glyph pixel as an 8x8 block */
for (c = 0; c < 5; c++) {
for (r = 0; r < 7; r++) {
v = font[order[c]][r];
for (gx = 0; gx < 5; gx++) {
if (!(v & (16 >> gx)))
continue;
for (dy = 0; dy < 8; dy++) {
for (dx = 0; dx < 8; dx++) {
px = 8 + c * 48 + gx * 8 + dx;
py = 8 + r * 8 + dy;
box[py][px >> 3] |= 1 << (px & 7);
}
}
}
}
}
/* 4. blit the box into video RAM, one byte at a time.
*
* Pointers here are BIT addresses and pointer arithmetic scales by the
* object size, so a `char *` step is 8 bits: p + n is n bytes, not n*8.
* Address the bytes as addr + px*8 bits and cast, which is unambiguous.
*/
for (py = 0; py < BOX_H; py++) {
addr = VRAM_BASE + (BOX_Y + py) * ROW_BITS + BOX_X;
for (px = 0; px < BOX_W / 8; px++) {
*(unsigned char *)(addr + px * 8) = box[py][px];
}
}
/* 5. second marker: the blit finished */
*(unsigned int *)(MARKER + 0x20) = 0x444F4E45; /* 'DONE' */
return 0;
}