diff --git a/dwt/loader/evidence/real-unit-xhello/hostload_xhello_xhello.png b/dwt/loader/evidence/real-unit-xhello/hostload_xhello_xhello.png new file mode 100644 index 0000000..353984f Binary files /dev/null and b/dwt/loader/evidence/real-unit-xhello/hostload_xhello_xhello.png differ diff --git a/harness/c-hello/.gitignore b/harness/c-hello/.gitignore new file mode 100644 index 0000000..9d931c4 --- /dev/null +++ b/harness/c-hello/.gitignore @@ -0,0 +1 @@ +work/ diff --git a/harness/c-hello/README.md b/harness/c-hello/README.md new file mode 100644 index 0000000..b200ad1 --- /dev/null +++ b/harness/c-hello/README.md @@ -0,0 +1,115 @@ +# harness/c-hello — the first C program on the VT1200 + +A C hello world built with the **1987 TI TMS34010 SDK** (K&R compiler, +`GSPCC`/`GSPCG` 2.01, `GSPA`/`GSPLNK` 2.00, `RTS.LIB`) and run on **real +hardware** — not a debugger poke of assembly, and no X11: it writes the word +`HELLO` straight into video RAM. + +It is also the project's smallest end-to-end proof of the C path: + +``` +gspcpp -> gspcc -> gspcg -> gspa -> gsplnk (DOSBox, 1987 tools) + -> hello.coff (GSPLNK COFF, sections at bit addresses) + -> dwt/loader/hostload.py (rdebug -> malloc -> poke COFF -> COFF loader) + -> loader.asm (free-list check, copy .text, zero .bss, create_process) + -> _start (entry.asm) -> main -> VRAM at bit 0x04000000 +``` + +## Files + +| file | what it is | +|---|---| +| `hello.c` | the payload: 5x7 font, 8x-scaled `HELLO` in a black 256x72 box, markers at `0x018A8000` | +| `entry.asm` | the process entry: sets `STK`/`FP`, `calla _main`, `rets` (replaces `boot.obj`) | +| `build.sh` | DOSBox wrapper; `build.sh` = real unit (256-byte row pitch), `build.sh emu` = MAME (128) | +| `build/hello.coff` | linked image for the real unit, entry `_start` | +| `build/hello-emu.coff` | same source with `ROW_BYTES 128`, for MAME's canvas | +| `build/hello.map`, `hello.lst`, `entry.lst`, `hello.s` | link map and listings | +| `evidence/hello_frame.png` | real unit, **pre-fix**: the pointer-arithmetic bug, one-byte bars spread over a whole row | +| `evidence/hello_real_frame.png` | real unit, working: the current box at x=40 and, to its right, the previous run's box at x=320 (nothing erases VRAM between runs) | +| `work/` | extracted SDK + DOS scratch (git-ignored) | + +## Build + +```sh +./harness/c-hello/build.sh # real unit: .text 0x018A0000, .bss 0x01A00000 +./harness/c-hello/build.sh emu # MAME: same addresses, 128-byte row pitch +``` + +Both land inside the firmware's large free block (byte `0x0C03AA..0x400000` on a +fresh boot). The link map must show `.cinit` empty and entry `_start`: + +``` +ENTRY POINT SYMBOL: "_start" address: 018A17E0 +.text 018A0000 .cinit 018A1870 (size 0) .bss 01A00000 +``` + +## Run + +Real unit (rdebug on TCP 771; the terminal needs the OS up): + +```sh +python3 dwt/heapmap.py --host 100.103.100.103 --at 0x018A0000 # read-only preflight +python3 dwt/heapmap.py --host 100.103.100.103 --at 0x01A00000 +python3 dwt/loader/hostload.py --host 100.103.100.103 \ + --coff harness/c-hello/build/hello.coff \ + --out harness/c-hello/evidence --real --settle 3 +python3 dwt/solve.py --host 100.103.100.103 --peek 0x018A8000 --len 8 # HELL DONE +python3 dwt/screenshot.py --host 100.103.100.103 --real --out /tmp/hello.png +``` + +MAME (debugger-assisted, no network): + +```sh +VT1200_SKIP_LEVEL1=1 LOADER_AT=2500 LOADER_END=2800 LOADER_SNAP=1 \ +LOADER_COFF=$PWD/harness/c-hello/build/hello-emu.coff LOADER_OUT=/tmp/chello \ +/home/arti/code/k-space/mame0289/vt1200 vt1200 \ + -rompath harness/mame/roms -video none -sound none -nothrottle -skip_gameinfo \ + -debug -debugger none -autoboot_script dwt/loader/loader.lua -autoboot_delay 0 +``` + +Success = loader status 0, `entry=0x018A17E0`, markers `48454C4C`/`444F4E45` +(`HELL`/`DONE`), and the box on screen. On the real unit the box is at +**x=40, y=800**, 256x72 pixels. + +## Three traps this image exists to record + +1. **`boot.obj`'s `exit()` is `for(;;)` and `_c_int00` ends in `reti`.** + That is a standalone-ROM runtime, not a process. Linked with `-c`, the child + finishes `main`, spins forever (the linked `jruc self` at `0x018A1520`), and + because the VT1200 OS is cooperative it starves the whole machine; on real + hardware the terminal fell over with an illegal opcode. `-cr` is no better — + it still pulls in `boot.obj` and still defines `_c_int00`. Hence + `entry.asm`: no `boot.obj`, entry `_start`, plain `rets` back to the + `create_process` trampoline (the same return `xhello` uses). `SP` (the OS's + interrupt stack) is left alone; only `STK`/`FP` are set. +2. **Pointers are bit addresses and pointer arithmetic scales by object size.** + A `char *` step is 8 bits, so `p + px*8` advances 8 *bytes*, not one. Address + bytes as `addr + px*8` bits and cast. The pre-fix frame + (`evidence/hello_frame.png`) is that bug: 32 one-byte bars spread over a + whole row. +3. **No `.cinit`.** With `entry.asm` the runtime's autoinit pass never runs, so + the image must not need static initializers. The font and order tables are + filled in `build_font()` at runtime. + +## Geometry is not portable between the real unit and MAME + +The two framebuffers differ, and the payload carries the difference as +`ROW_BYTES`: + +| | real unit (measured) | MAME | +|---|---|---| +| base | bit `0x04000000` | bit `0x04000000` | +| row pitch | **256 bytes** (`ROW_BYTES 256`) | 128 bytes (`VMEM_PITCH_BITS`) | +| pixels per row | 1280 (160 bytes) + 96 B `0x55` mask | 1024 | +| screen | 1280x1024 | 1024x864 snapshot in MAME's 1280x901 | + +The real pitch is measured, not assumed: a payload writing at `row*2048` bits +lands on scanline `row` and a 256-pixel box at pixel 40 appears at x=40 — and +the pre-fix frame's bars, written 8 bytes apart from byte 40, run to the end of +a 1280-pixel line. Under a 128-byte pitch the same writes would wrap into the +next memory row. `dwt/screenshot.py --real` (1280 wide, stride 256, LSB-first) +also decodes live VRAM correctly, which pins the bit order. + +Do not use a MAME frame as proof of pixel placement: same code, different +framebuffer. diff --git a/harness/c-hello/build.sh b/harness/c-hello/build.sh new file mode 100755 index 0000000..ea3a678 --- /dev/null +++ b/harness/c-hello/build.sh @@ -0,0 +1,115 @@ +#!/bin/sh +# Build the C hello world with the 1987 TI TMS34010 SDK (K&R C compiler). +# +# harness/c-hello/build.sh +# +# Pipeline: gspcpp -> gspcc -> gspcg -> gspa -> gsplnk, all under DOSBox. +# entry.asm is assembled separately: it is the process entry (sets STK/FP, +# calls _main, `rets`) and replaces boot.obj, whose exit path is a `for(;;)` +# spin followed by an `reti` -- both wrong for a create_process child. +# +# .text/.data are linked at bit 0x018A0000, .bss at 0x01A00000 (both inside the +# firmware's large free block). +# +# Outputs: build/hello.coff (the linker output the COFF loader eats), +# hello.map, hello.lst, entry.lst, hello.obj +set -eu + +ROOT=$(cd "$(dirname "$0")/../.." && pwd) +DIR=$(cd "$(dirname "$0")" && pwd) +WORK="$DIR/work" +OUT="$DIR/build" +IMG="$ROOT/tools/tms34010-sdk/1987-05 TMS34010 SDK/1987-11-06 TMS34010 Simulator-C Tools-ASM Tools.img" +DOSBOX_CONF="$ROOT/harness/sdk-scratch/dosbox-bench.conf" + +TEXT=018A0000 +BSS=01A00000 +# `build.sh emu` builds a 128-byte-stride variant for MAME's 1024x1024 canvas. +MODE=${1:-real} +NAME=hello +if [ "$MODE" = "emu" ]; then NAME=hello-emu; fi + +mkdir -p "$WORK" "$OUT" + +if [ ! -x "$WORK/GSPCG.EXE" ]; then + mcopy -s -n -i "$IMG" "::/A2/*" "$WORK/" + mcopy -s -n -i "$IMG" "::/C2/*" "$WORK/" +fi + +if [ "$MODE" = "emu" ]; then + sed 's/#define ROW_BYTES 256/#define ROW_BYTES 128/' "$DIR/hello.c" > "$WORK/HELLO.C" +else + cp "$DIR/hello.c" "$WORK/HELLO.C" +fi +cp "$DIR/entry.asm" "$WORK/ENTRY.ASM" + +{ + printf '%s\n' '-a' + printf '%s\n' '-o HELLO.out' + printf '%s\n' '-m HELLO.map' + printf '%s\n' '-e _start' + printf '%s\n' 'HELLO.obj' + printf '%s\n' 'ENTRY.obj' + printf '%s\n' '-l RTS.LIB' + printf '%s\n' 'MEMORY' + printf '%s\n' '{' + printf '%s\n' " prog: origin = ${TEXT}h, length = 20000h" + printf '%s\n' " ram: origin = ${BSS}h, length = 40000h" + printf '%s\n' '}' + printf '%s\n' 'SECTIONS' + printf '%s\n' '{' + printf '%s\n' ' .text: {} > prog' + printf '%s\n' ' .data: {} > prog' + printf '%s\n' ' .cinit: {} > prog' + printf '%s\n' ' .bss: {} > ram' + printf '%s\n' '}' +} > "$WORK/HELLO.CMD" +sed -i 's/$/\r/' "$WORK/HELLO.CMD" + +rm -f "$WORK"/HELLO.OBJ "$WORK"/HELLO.OUT "$WORK"/HELLO.LST \ + "$WORK"/HELLO.MAP "$WORK"/HELLO.HI "$WORK"/HELLO.LO \ + "$WORK"/HELLO.ASM "$WORK"/HELLO.CPP "$WORK"/HELLO.IF \ + "$WORK"/ENTRY.OBJ "$WORK"/ENTRY.LST + +SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \ +timeout 240 dosbox -conf "$DOSBOX_CONF" -noprimaryconf -nolocalconf \ + -c "mount c $WORK" -c "c:" \ + -c "gspcpp HELLO" \ + -c "gspcc HELLO" \ + -c "gspcg HELLO" \ + -c "gspa HELLO HELLO.obj HELLO.lst -l" \ + -c "gspa ENTRY ENTRY.obj ENTRY.lst -l" \ + -c "gsplnk HELLO.cmd" \ + -c "exit" -exit > "$WORK/dosbox.log" 2>&1 + +if [ ! -f "$WORK/HELLO.OUT" ]; then + echo "build.sh: GSPLNK produced no HELLO.OUT" >&2 + sed 's/\r$//' "$WORK/HELLO.MAP" 2>/dev/null | tail -20 >&2 || true + exit 1 +fi +if [ ! -f "$WORK/HELLO.OBJ" ] || [ ! -f "$WORK/ENTRY.OBJ" ]; then + echo "build.sh: missing object file (compile/assemble failed)" >&2 + for f in HELLO.LST ENTRY.LST; do + sed 's/\r$//' "$WORK/$f" 2>/dev/null | grep -i 'error' | grep -vi 'no errors' >&2 || true + done + exit 1 +fi +# NB: the C code generator writes "***" banner comments into the .s file, so the +# assembly listing is full of asterisks; only real error lines are matched here. +for f in HELLO.LST ENTRY.LST; do + if sed 's/\r$//' "$WORK/$f" | grep -i 'error' | grep -qvi 'no errors'; then + echo "build.sh: $f diagnostics:" >&2 + sed 's/\r$//' "$WORK/$f" | grep -in 'error' | grep -vi 'no errors' >&2 + exit 1 + fi +done + +cp "$WORK/HELLO.OUT" "$OUT/$NAME.coff" +cp "$WORK/HELLO.OBJ" "$OUT/hello.obj" +cp "$WORK/ENTRY.OBJ" "$OUT/entry.obj" +sed 's/\r$//' "$WORK/HELLO.MAP" > "$OUT/hello.map" +sed 's/\r$//' "$WORK/HELLO.LST" > "$OUT/hello.lst" +sed 's/\r$//' "$WORK/ENTRY.LST" > "$OUT/entry.lst" +[ -f "$WORK/HELLO.ASM" ] && sed 's/\r$//' "$WORK/HELLO.ASM" > "$OUT/hello.s" +echo "build.sh: $OUT/$NAME.coff ($(wc -c < "$OUT/hello.coff") bytes)" +sed -n '1,40p' "$OUT/hello.map" diff --git a/harness/c-hello/build/entry.lst b/harness/c-hello/build/entry.lst new file mode 100644 index 0000000..83a9a31 --- /dev/null +++ b/harness/c-hello/build/entry.lst @@ -0,0 +1,35 @@ +GSP COFF Assembler, Version 2.00, 87.300 Thu Oct 29 18:24:36 2026 + (c) Copyright 1985, 1987, Texas Instruments Inc. + + PAGE 1 + + 0001 ; entry.asm -- process entry for the C hello world. + 0002 ; + 0003 ; The C runtime's boot.obj is designed for a ROM system + 0004 ; *system* stack), calls main, calls exit (which is `fo + 0005 ; `reti`. None of that fits a process made by the VT12 + 0006 ; the spin never yields, and `reti` returns from an int + 0007 ; happened (it pops a garbage PC -> illegal opcode). + 0008 ; + 0009 ; So we enter here instead: set the C program stack (ST + 0010 ; main, and `rets` back to the create_process trampolin + 0011 ; xhello payload uses. SP (the OS's interrupt stack) i + 0012 ; + 0013 ; _cstack is 4096 bytes; the compiler grows the program + 0014 + 0015 00000000 .text + 0016 .globl _start + 0017 .globl _main + 0018 00000000 _start: + 0019 00000000 0740 setf 32, 0, 1 + 0020 00000010 09EE movi _cstack, a14 + 00000020 00000000+ + 0021 00000040 4DCD move a14, a13 + 0022 00000050 0D5F calla _main + 00000060 00000000! + 0023 00000080 0960 rets + 0024 + 0025 00000000 .bss _cstack, 32768, 16 ; 32768 bits = 4096 bytes + 0026 .end + + No Errors, No Warnings diff --git a/harness/c-hello/build/entry.obj b/harness/c-hello/build/entry.obj new file mode 100644 index 0000000..2214dcd Binary files /dev/null and b/harness/c-hello/build/entry.obj differ diff --git a/harness/c-hello/build/hello-emu.coff b/harness/c-hello/build/hello-emu.coff new file mode 100644 index 0000000..13ca430 Binary files /dev/null and b/harness/c-hello/build/hello-emu.coff differ diff --git a/harness/c-hello/build/hello.coff b/harness/c-hello/build/hello.coff new file mode 100644 index 0000000..63bc09f Binary files /dev/null and b/harness/c-hello/build/hello.coff differ diff --git a/harness/c-hello/build/hello.lst b/harness/c-hello/build/hello.lst new file mode 100644 index 0000000..dc2ef32 --- /dev/null +++ b/harness/c-hello/build/hello.lst @@ -0,0 +1,415 @@ +GSP COFF Assembler, Version 2.00, 87.300 Thu Oct 29 18:24:36 2026 + (c) Copyright 1985, 1987, Texas Instruments Inc. + + PAGE 1 + + 0001 ******************************************************* + 0002 * GSP C COMPILER, Version 2.01, 87.300 * + 0003 ******************************************************* + 0004 000D FP .set A13 + 0005 000E STK .set A14 + 0006 00000000 .bss STATIC_1,224,16 + 0007 000000E0 .bss STATIC_2,40,16 + 0008 00000110 .bss STATIC_3,18432,16 + 0009 .file "HELLO.c" + 0010 ****************************************************** + 0011 * FUNCTION DEF : _build_font + 0012 ****************************************************** + 0013 00000000 _build_font: + 0014 00000000 A38F MOVE A12,-*SP,1 + 0015 00000010 1A2C MOVK 17,A12 + 0016 00000020 05EC MOVB A12,@STATIC_1 + 00000030 00000000+ + 0017 00000050 05EC MOVB A12,@STATIC_1+8 + 00000060 00000008+ + 0018 00000080 11CC ADDK 14,A12 + 0019 00000090 05EC MOVB A12,@STATIC_1+16 + 000000A0 00000010+ + 0020 000000C0 15CC SUBK 14,A12 + 0021 000000D0 05EC MOVB A12,@STATIC_1+24 + 000000E0 00000018+ + 0022 00000100 05EC MOVB A12,@STATIC_1+32 + 00000110 00000020+ + 0023 00000130 05EC MOVB A12,@STATIC_1+40 + 00000140 00000028+ + 0024 00000160 05EC MOVB A12,@STATIC_1+48 + 00000170 00000030+ + 0025 00000190 11CC ADDK 14,A12 + 0026 000001A0 05EC MOVB A12,@STATIC_1+56 + 000001B0 00000038+ + 0027 000001D0 15EC SUBK 15,A12 + 0028 000001E0 05EC MOVB A12,@STATIC_1+64 + 000001F0 00000040+ + 0029 00000210 05EC MOVB A12,@STATIC_1+72 + 00000220 00000048+ + 0030 00000240 11CC ADDK 14,A12 + 0031 00000250 05EC MOVB A12,@STATIC_1+80 + 00000260 00000050+ + 0032 00000280 15CC SUBK 14,A12 + 0033 00000290 05EC MOVB A12,@STATIC_1+88 + 000002A0 00000058+ + 0034 000002C0 05EC MOVB A12,@STATIC_1+96 + 000002D0 00000060+ + 0035 000002F0 11EC ADDK 15,A12 + 0036 00000300 05EC MOVB A12,@STATIC_1+104 + 00000310 00000068+ + 0037 00000330 15EC SUBK 15,A12 + 0038 00000340 05EC MOVB A12,@STATIC_1+112 + 00000350 00000070+ + 0039 00000370 05EC MOVB A12,@STATIC_1+120 + 00000380 00000078+ + 0040 000003A0 05EC MOVB A12,@STATIC_1+128 + GSP COFF Assembler, Version 2.00, 87.300 Thu Oct 29 18:24:36 2026 + (c) Copyright 1985, 1987, Texas Instruments Inc. + + PAGE 2 + + 000003B0 00000080+ + 0041 000003D0 05EC MOVB A12,@STATIC_1+136 + 000003E0 00000088+ + 0042 00000400 05EC MOVB A12,@STATIC_1+144 + 00000410 00000090+ + 0043 00000430 05EC MOVB A12,@STATIC_1+152 + 00000440 00000098+ + 0044 00000460 11EC ADDK 15,A12 + 0045 00000470 05EC MOVB A12,@STATIC_1+160 + 00000480 000000A0+ + 0046 000004A0 162C SUBK 17,A12 + 0047 000004B0 05EC MOVB A12,@STATIC_1+168 + 000004C0 000000A8+ + 0048 000004E0 106C ADDK 3,A12 + 0049 000004F0 05EC MOVB A12,@STATIC_1+176 + 00000500 000000B0+ + 0050 00000520 05EC MOVB A12,@STATIC_1+184 + 00000530 000000B8+ + 0051 00000550 05EC MOVB A12,@STATIC_1+192 + 00000560 000000C0+ + 0052 00000580 05EC MOVB A12,@STATIC_1+200 + 00000590 000000C8+ + 0053 000005B0 05EC MOVB A12,@STATIC_1+208 + 000005C0 000000D0+ + 0054 000005E0 146C SUBK 3,A12 + 0055 000005F0 05EC MOVB A12,@STATIC_1+216 + 00000600 000000D8+ + 0056 00000620 458C SUB A12,A12 + 0057 00000630 05EC MOVB A12,@STATIC_2 + 00000640 000000E0+ + 0058 00000660 102C ADDK 1,A12 + 0059 00000670 05EC MOVB A12,@STATIC_2+8 + 00000680 000000E8+ + 0060 000006A0 418C ADD A12,A12 + 0061 000006B0 05EC MOVB A12,@STATIC_2+16 + 000006C0 000000F0+ + 0062 000006E0 05EC MOVB A12,@STATIC_2+24 + 000006F0 000000F8+ + 0063 00000710 102C ADDK 1,A12 + 0064 00000720 05EC MOVB A12,@STATIC_2+32 + 00000730 00000100+ + 0065 00000750 EPI0_1: + 0066 00000750 97EC MOVE *SP+,A12,1 + 0067 00000760 0960 RETS 0 + 0068 .globl _main + 0069 ****************************************************** + 0070 * FUNCTION DEF : _main + 0071 ****************************************************** + 0072 00000770 _main: + 0073 00000770 098F MMTM SP,A3,A5,A7,A12,FP + 00000780 150C + 0074 00000790 4DCD MOVE STK,FP + 0075 000007A0 0B0E ADDI 288,STK + 000007B0 0120 + 0076 000007C0 0D5F CALLA _build_font + 000007D0 00000000' + GSP COFF Assembler, Version 2.00, 87.300 Thu Oct 29 18:24:36 2026 + (c) Copyright 1985, 1987, Texas Instruments Inc. + + PAGE 3 + + 0077 000007F0 09EC MOVI 1212501068,A12 + 00000800 48454C4C + 0078 00000820 078C MOVE A12,@0018A8000h,1 + 00000830 018A8000 + 0079 00000850 578C CLR A12 + 0080 00000860 B38D MOVE A12,*FP(192),1 + 00000870 00C0 + 0081 00000880 C01F JRUC L1 + 0082 00000890 L4: + 0083 00000890 578C CLR A12 + 0084 000008A0 B38D MOVE A12,*FP(160),1 + 000008B0 00A0 + 0085 000008C0 C011 JRUC L5 + 0086 000008D0 L8: + 0087 000008D0 B7A7 MOVE *FP(192),A7,1 + 000008E0 00C0 + 0088 000008F0 2507 SLL 8,A7 + 0089 00000900 0B27 ADDI STATIC_3,A7 + 00000910 00000110+ + 0090 00000930 B7A5 MOVE *FP(160),A5,1 + 00000940 00A0 + 0091 00000950 2465 SLL 3,A5 + 0092 00000960 40A7 ADD A5,A7 + 0093 00000970 56A5 CLR A5 + 0094 00000980 8CA7 MOVB A5,*A7 + 0095 00000990 B7A7 MOVE *FP(160),A7,1 + 000009A0 00A0 + 0096 000009B0 1027 ADDK 1,A7 + 0097 000009C0 B2ED MOVE A7,*FP(160),1 + 000009D0 00A0 + 0098 000009E0 L5: + 0099 000009E0 B7A7 MOVE *FP(160),A7,1 + 000009F0 00A0 + 0100 00000A00 0B47 CMPI 32,A7 + 00000A10 FFDF + 0101 00000A20 C4EA JRLT L8 + 0102 00000A30 B7A5 MOVE *FP(192),A5,1 + 00000A40 00C0 + 0103 00000A50 1025 ADDK 1,A5 + 0104 00000A60 B2AD MOVE A5,*FP(192),1 + 00000A70 00C0 + 0105 00000A80 L1: + 0106 00000A80 B7A7 MOVE *FP(192),A7,1 + 00000A90 00C0 + 0107 00000AA0 0B47 CMPI 72,A7 + 00000AB0 FFB7 + 0108 00000AC0 C4DC JRLT L4 + 0109 00000AD0 578C CLR A12 + 0110 00000AE0 838D MOVE A12,*FP,1 + 0111 00000AF0 C000 JRUC L9 + 00000B00 0085 + 0112 00000B10 L12: + 0113 00000B10 578C CLR A12 + 0114 00000B20 B38D MOVE A12,*FP(32),1 + 00000B30 0020 + 0115 00000B40 C079 JRUC L13 + GSP COFF Assembler, Version 2.00, 87.300 Thu Oct 29 18:24:36 2026 + (c) Copyright 1985, 1987, Texas Instruments Inc. + + PAGE 4 + + 0116 00000B50 L16: + 0117 00000B50 87A7 MOVE *FP,A7,1 + 0118 00000B60 2467 SLL 3,A7 + 0119 00000B70 0B27 ADDI STATIC_2,A7 + 00000B80 000000E0+ + 0120 00000BA0 0548 SETF 8,0,0 + 0121 00000BB0 84E7 MOVE *A7,A7 + 0122 00000BC0 09CC MOVI 56,A12 + 00000BD0 0038 + 0123 00000BE0 5D87 MPYS A12,A7 + 0124 00000BF0 0B27 ADDI STATIC_1,A7 + 00000C00 00000000+ + 0125 00000C20 B7A5 MOVE *FP(32),A5,1 + 00000C30 0020 + 0126 00000C40 2465 SLL 3,A5 + 0127 00000C50 40A7 ADD A5,A7 + 0128 00000C60 84E7 MOVE *A7,A7 + 0129 00000C70 B2ED MOVE A7,*FP(224),1 + 00000C80 00E0 + 0130 00000C90 578C CLR A12 + 0131 00000CA0 B38D MOVE A12,*FP(64),1 + 00000CB0 0040 + 0132 00000CC0 C057 JRUC L17 + 0133 00000CD0 L20: + 0134 00000CD0 1A07 MOVK 16,A7 + 0135 00000CE0 B7A5 MOVE *FP(64),A5,1 + 00000CF0 0040 + 0136 00000D00 03A5 NEG A5 + 0137 00000D10 64A7 SRA A5,A7 + 0138 00000D20 B7A5 MOVE *FP(224),A5,1 + 00000D30 00E0 + 0139 00000D40 50A7 AND A5,A7 + 0140 00000D50 CA49 JRZ L18 + 0141 00000D60 56E7 CLR A7 + 0142 00000D70 B2ED MOVE A7,*FP(128),1 + 00000D80 0080 + 0143 00000D90 C040 JRUC L22 + 0144 00000DA0 L25: + 0145 00000DA0 578C CLR A12 + 0146 00000DB0 B38D MOVE A12,*FP(96),1 + 00000DC0 0060 + 0147 00000DD0 C032 JRUC L26 + 0148 00000DE0 L29: + 0149 00000DE0 87A7 MOVE *FP,A7,1 + 0150 00000DF0 4CE5 MOVE A7,A5 + 0151 00000E00 24A7 SLL 5,A7 + 0152 00000E10 2485 SLL 4,A5 + 0153 00000E20 40E5 ADD A7,A5 + 0154 00000E30 1105 ADDK 8,A5 + 0155 00000E40 B7A7 MOVE *FP(64),A7,1 + 00000E50 0040 + 0156 00000E60 2467 SLL 3,A7 + 0157 00000E70 40E5 ADD A7,A5 + 0158 00000E80 B7A7 MOVE *FP(96),A7,1 + 00000E90 0060 + 0159 00000EA0 40E5 ADD A7,A5 + GSP COFF Assembler, Version 2.00, 87.300 Thu Oct 29 18:24:36 2026 + (c) Copyright 1985, 1987, Texas Instruments Inc. + + PAGE 5 + + 0160 00000EB0 B2AD MOVE A5,*FP(160),1 + 00000EC0 00A0 + 0161 00000ED0 B7A7 MOVE *FP(32),A7,1 + 00000EE0 0020 + 0162 00000EF0 2467 SLL 3,A7 + 0163 00000F00 1107 ADDK 8,A7 + 0164 00000F10 B7A5 MOVE *FP(128),A5,1 + 00000F20 0080 + 0165 00000F30 40A7 ADD A5,A7 + 0166 00000F40 B2ED MOVE A7,*FP(192),1 + 00000F50 00C0 + 0167 00000F60 2507 SLL 8,A7 + 0168 00000F70 0B27 ADDI STATIC_3,A7 + 00000F80 00000110+ + 0169 00000FA0 B7A5 MOVE *FP(160),A5,1 + 00000FB0 00A0 + 0170 00000FC0 2BA5 SRA 3,A5 + 0171 00000FD0 2465 SLL 3,A5 + 0172 00000FE0 40A7 ADD A5,A7 + 0173 00000FF0 B7A5 MOVE *FP(160),A5,1 + 00001000 00A0 + 0174 00001010 18EC MOVK 7,A12 + 0175 00001020 5185 AND A12,A5 + 0176 00001030 1823 MOVK 1,A3 + 0177 00001040 62A3 SLL A5,A3 + 0178 00001050 2703 SLL 24,A3 + 0179 00001060 2D03 SRL 24,A3 + 0180 00001070 0548 SETF 8,0,0 + 0181 00001080 84E5 MOVE *A7,A5 + 0182 00001090 5465 OR A3,A5 + 0183 000010A0 8CA7 MOVB A5,*A7 + 0184 000010B0 B7A7 MOVE *FP(96),A7,1 + 000010C0 0060 + 0185 000010D0 1027 ADDK 1,A7 + 0186 000010E0 B2ED MOVE A7,*FP(96),1 + 000010F0 0060 + 0187 00001100 L26: + 0188 00001100 B7A7 MOVE *FP(96),A7,1 + 00001110 0060 + 0189 00001120 0B47 CMPI 8,A7 + 00001130 FFF7 + 0190 00001140 C4C9 JRLT L29 + 0191 00001150 B7A5 MOVE *FP(128),A5,1 + 00001160 0080 + 0192 00001170 1025 ADDK 1,A5 + 0193 00001180 B2AD MOVE A5,*FP(128),1 + 00001190 0080 + 0194 000011A0 L22: + 0195 000011A0 B7A7 MOVE *FP(128),A7,1 + 000011B0 0080 + 0196 000011C0 0B47 CMPI 8,A7 + 000011D0 FFF7 + 0197 000011E0 C4BB JRLT L25 + 0198 000011F0 L18: + 0199 000011F0 B7A7 MOVE *FP(64),A7,1 + 00001200 0040 + GSP COFF Assembler, Version 2.00, 87.300 Thu Oct 29 18:24:36 2026 + (c) Copyright 1985, 1987, Texas Instruments Inc. + + PAGE 6 + + 0200 00001210 1027 ADDK 1,A7 + 0201 00001220 B2ED MOVE A7,*FP(64),1 + 00001230 0040 + 0202 00001240 L17: + 0203 00001240 B7A7 MOVE *FP(64),A7,1 + 00001250 0040 + 0204 00001260 0B47 CMPI 5,A7 + 00001270 FFFA + 0205 00001280 C4A4 JRLT L20 + 0206 00001290 B7A5 MOVE *FP(32),A5,1 + 000012A0 0020 + 0207 000012B0 1025 ADDK 1,A5 + 0208 000012C0 B2AD MOVE A5,*FP(32),1 + 000012D0 0020 + 0209 000012E0 L13: + 0210 000012E0 B7A7 MOVE *FP(32),A7,1 + 000012F0 0020 + 0211 00001300 0B47 CMPI 7,A7 + 00001310 FFF8 + 0212 00001320 C482 JRLT L16 + 0213 00001330 87A5 MOVE *FP,A5,1 + 0214 00001340 1025 ADDK 1,A5 + 0215 00001350 82AD MOVE A5,*FP,1 + 0216 00001360 L9: + 0217 00001360 87A7 MOVE *FP,A7,1 + 0218 00001370 0B47 CMPI 5,A7 + 00001380 FFFA + 0219 00001390 C400 JRLT L12 + 000013A0 FF76 + 0220 000013B0 578C CLR A12 + 0221 000013C0 B38D MOVE A12,*FP(192),1 + 000013D0 00C0 + 0222 000013E0 C02E JRUC L30 + 0223 000013F0 L33: + 0224 000013F0 B7A7 MOVE *FP(192),A7,1 + 00001400 00C0 + 0225 00001410 0B07 ADDI 800,A7 + 00001420 0320 + 0226 00001430 2547 SLL 10,A7 + 0227 00001440 0B27 ADDI 67108904,A7 + 00001450 04000028 + 0228 00001470 B2ED MOVE A7,*FP(256),1 + 00001480 0100 + 0229 00001490 578C CLR A12 + 0230 000014A0 B38D MOVE A12,*FP(160),1 + 000014B0 00A0 + 0231 000014C0 C016 JRUC L34 + 0232 000014D0 L37: + 0233 000014D0 B7A7 MOVE *FP(256),A7,1 + 000014E0 0100 + 0234 000014F0 B7A5 MOVE *FP(160),A5,1 + 00001500 00A0 + 0235 00001510 2465 SLL 3,A5 + 0236 00001520 40E5 ADD A7,A5 + 0237 00001530 B7A7 MOVE *FP(192),A7,1 + 00001540 00C0 + GSP COFF Assembler, Version 2.00, 87.300 Thu Oct 29 18:24:36 2026 + (c) Copyright 1985, 1987, Texas Instruments Inc. + + PAGE 7 + + 0238 00001550 2507 SLL 8,A7 + 0239 00001560 0B27 ADDI STATIC_3,A7 + 00001570 00000110+ + 0240 00001590 B7A3 MOVE *FP(160),A3,1 + 000015A0 00A0 + 0241 000015B0 2463 SLL 3,A3 + 0242 000015C0 4067 ADD A3,A7 + 0243 000015D0 9CE5 MOVB *A7,*A5 + 0244 000015E0 B7A7 MOVE *FP(160),A7,1 + 000015F0 00A0 + 0245 00001600 1027 ADDK 1,A7 + 0246 00001610 B2ED MOVE A7,*FP(160),1 + 00001620 00A0 + 0247 00001630 L34: + 0248 00001630 B7A7 MOVE *FP(160),A7,1 + 00001640 00A0 + 0249 00001650 0B47 CMPI 32,A7 + 00001660 FFDF + 0250 00001670 C4E5 JRLT L37 + 0251 00001680 B7A5 MOVE *FP(192),A5,1 + 00001690 00C0 + 0252 000016A0 1025 ADDK 1,A5 + 0253 000016B0 B2AD MOVE A5,*FP(192),1 + 000016C0 00C0 + 0254 000016D0 L30: + 0255 000016D0 B7A7 MOVE *FP(192),A7,1 + 000016E0 00C0 + 0256 000016F0 0B47 CMPI 72,A7 + 00001700 FFB7 + 0257 00001710 C4CD JRLT L33 + 0258 00001720 09EC MOVI 1146048069,A12 + 00001730 444F4E45 + 0259 00001750 078C MOVE A12,@0018A8020h,1 + 00001760 018A8020 + 0260 00001780 5708 CLR A8 + 0261 00001790 EPI0_2: + 0262 00001790 0B0E ADDI -288,STK + 000017A0 FEE0 + 0263 000017B0 09AF MMFM SP,A3,A5,A7,A12,FP + 000017C0 30A8 + 0264 000017D0 0960 RETS 0 + 0265 .end + + No Errors, No Warnings diff --git a/harness/c-hello/build/hello.map b/harness/c-hello/build/hello.map new file mode 100644 index 0000000..ebbdb6c --- /dev/null +++ b/harness/c-hello/build/hello.map @@ -0,0 +1,49 @@ +***************************************************** +GSP COFF Linker, Version 2.00, 87.300 +***************************************************** +Thu Oct 29 18:24:36 2026 + +OUTPUT FILE NAME: +ENTRY POINT SYMBOL: "_start" address: 018A17E0 + + +MEMORY CONFIGURATION + + name origin length attributes + -------- -------- --------- ---------- + prog 018A0000 000020000 RWIX + ram 01A00000 000040000 RWIX + + +SECTION ALLOCATION MAP + + output attributes/ +section page origin length input sections +-------- ---- ---------- ---------- ---------------- +.text 0 018A0000 00001870 + 018A0000 000017E0 HELLO.obj (.text) + 018A17E0 00000090 ENTRY.obj (.text) + +.data 0 018A1870 00000000 + +.cinit 0 018A1870 00000000 UNINITIALIZED + +.bss 0 01A00000 0000C910 UNINITIALIZED + 01A00000 00004910 HELLO.obj (.bss) + 01A04910 00008000 ENTRY.obj (.bss) + + +GLOBAL SYMBOLS + +address name address name +-------- ---- -------- ---- +01A00000 .bss 018A0000 .text +018A1870 .data 018A0770 _main +018A0000 .text 018A17E0 _start +018A0770 _main 018A1870 edata +018A17E0 _start 018A1870 .data +018A1870 edata 018A1870 etext +01A0C910 end 01A00000 .bss +018A1870 etext 01A0C910 end + +[8 symbols] diff --git a/harness/c-hello/build/hello.obj b/harness/c-hello/build/hello.obj new file mode 100644 index 0000000..5e2a957 Binary files /dev/null and b/harness/c-hello/build/hello.obj differ diff --git a/harness/c-hello/build/hello.s b/harness/c-hello/build/hello.s new file mode 100644 index 0000000..d297605 --- /dev/null +++ b/harness/c-hello/build/hello.s @@ -0,0 +1,265 @@ +******************************************************* +* GSP C COMPILER, Version 2.01, 87.300 * +******************************************************* +FP .set A13 +STK .set A14 + .bss STATIC_1,224,16 + .bss STATIC_2,40,16 + .bss STATIC_3,18432,16 + .file "HELLO.c" +****************************************************** +* FUNCTION DEF : _build_font +****************************************************** +_build_font: + MOVE A12,-*SP,1 + MOVK 17,A12 + MOVB A12,@STATIC_1 + MOVB A12,@STATIC_1+8 + ADDK 14,A12 + MOVB A12,@STATIC_1+16 + SUBK 14,A12 + MOVB A12,@STATIC_1+24 + MOVB A12,@STATIC_1+32 + MOVB A12,@STATIC_1+40 + MOVB A12,@STATIC_1+48 + ADDK 14,A12 + MOVB A12,@STATIC_1+56 + SUBK 15,A12 + MOVB A12,@STATIC_1+64 + MOVB A12,@STATIC_1+72 + ADDK 14,A12 + MOVB A12,@STATIC_1+80 + SUBK 14,A12 + MOVB A12,@STATIC_1+88 + MOVB A12,@STATIC_1+96 + ADDK 15,A12 + MOVB A12,@STATIC_1+104 + SUBK 15,A12 + MOVB A12,@STATIC_1+112 + MOVB A12,@STATIC_1+120 + MOVB A12,@STATIC_1+128 + MOVB A12,@STATIC_1+136 + MOVB A12,@STATIC_1+144 + MOVB A12,@STATIC_1+152 + ADDK 15,A12 + MOVB A12,@STATIC_1+160 + SUBK 17,A12 + MOVB A12,@STATIC_1+168 + ADDK 3,A12 + MOVB A12,@STATIC_1+176 + MOVB A12,@STATIC_1+184 + MOVB A12,@STATIC_1+192 + MOVB A12,@STATIC_1+200 + MOVB A12,@STATIC_1+208 + SUBK 3,A12 + MOVB A12,@STATIC_1+216 + SUB A12,A12 + MOVB A12,@STATIC_2 + ADDK 1,A12 + MOVB A12,@STATIC_2+8 + ADD A12,A12 + MOVB A12,@STATIC_2+16 + MOVB A12,@STATIC_2+24 + ADDK 1,A12 + MOVB A12,@STATIC_2+32 +EPI0_1: + MOVE *SP+,A12,1 + RETS 0 + .globl _main +****************************************************** +* FUNCTION DEF : _main +****************************************************** +_main: + MMTM SP,A3,A5,A7,A12,FP + MOVE STK,FP + ADDI 288,STK + CALLA _build_font + MOVI 1212501068,A12 + MOVE A12,@0018A8000h,1 + CLR A12 + MOVE A12,*FP(192),1 + JRUC L1 +L4: + CLR A12 + MOVE A12,*FP(160),1 + JRUC L5 +L8: + MOVE *FP(192),A7,1 + SLL 8,A7 + ADDI STATIC_3,A7 + MOVE *FP(160),A5,1 + SLL 3,A5 + ADD A5,A7 + CLR A5 + MOVB A5,*A7 + MOVE *FP(160),A7,1 + ADDK 1,A7 + MOVE A7,*FP(160),1 +L5: + MOVE *FP(160),A7,1 + CMPI 32,A7 + JRLT L8 + MOVE *FP(192),A5,1 + ADDK 1,A5 + MOVE A5,*FP(192),1 +L1: + MOVE *FP(192),A7,1 + CMPI 72,A7 + JRLT L4 + CLR A12 + MOVE A12,*FP,1 + JRUC L9 +L12: + CLR A12 + MOVE A12,*FP(32),1 + JRUC L13 +L16: + MOVE *FP,A7,1 + SLL 3,A7 + ADDI STATIC_2,A7 + SETF 8,0,0 + MOVE *A7,A7 + MOVI 56,A12 + MPYS A12,A7 + ADDI STATIC_1,A7 + MOVE *FP(32),A5,1 + SLL 3,A5 + ADD A5,A7 + MOVE *A7,A7 + MOVE A7,*FP(224),1 + CLR A12 + MOVE A12,*FP(64),1 + JRUC L17 +L20: + MOVK 16,A7 + MOVE *FP(64),A5,1 + NEG A5 + SRA A5,A7 + MOVE *FP(224),A5,1 + AND A5,A7 + JRZ L18 + CLR A7 + MOVE A7,*FP(128),1 + JRUC L22 +L25: + CLR A12 + MOVE A12,*FP(96),1 + JRUC L26 +L29: + MOVE *FP,A7,1 + MOVE A7,A5 + SLL 5,A7 + SLL 4,A5 + ADD A7,A5 + ADDK 8,A5 + MOVE *FP(64),A7,1 + SLL 3,A7 + ADD A7,A5 + MOVE *FP(96),A7,1 + ADD A7,A5 + MOVE A5,*FP(160),1 + MOVE *FP(32),A7,1 + SLL 3,A7 + ADDK 8,A7 + MOVE *FP(128),A5,1 + ADD A5,A7 + MOVE A7,*FP(192),1 + SLL 8,A7 + ADDI STATIC_3,A7 + MOVE *FP(160),A5,1 + SRA 3,A5 + SLL 3,A5 + ADD A5,A7 + MOVE *FP(160),A5,1 + MOVK 7,A12 + AND A12,A5 + MOVK 1,A3 + SLL A5,A3 + SLL 24,A3 + SRL 24,A3 + SETF 8,0,0 + MOVE *A7,A5 + OR A3,A5 + MOVB A5,*A7 + MOVE *FP(96),A7,1 + ADDK 1,A7 + MOVE A7,*FP(96),1 +L26: + MOVE *FP(96),A7,1 + CMPI 8,A7 + JRLT L29 + MOVE *FP(128),A5,1 + ADDK 1,A5 + MOVE A5,*FP(128),1 +L22: + MOVE *FP(128),A7,1 + CMPI 8,A7 + JRLT L25 +L18: + MOVE *FP(64),A7,1 + ADDK 1,A7 + MOVE A7,*FP(64),1 +L17: + MOVE *FP(64),A7,1 + CMPI 5,A7 + JRLT L20 + MOVE *FP(32),A5,1 + ADDK 1,A5 + MOVE A5,*FP(32),1 +L13: + MOVE *FP(32),A7,1 + CMPI 7,A7 + JRLT L16 + MOVE *FP,A5,1 + ADDK 1,A5 + MOVE A5,*FP,1 +L9: + MOVE *FP,A7,1 + CMPI 5,A7 + JRLT L12 + CLR A12 + MOVE A12,*FP(192),1 + JRUC L30 +L33: + MOVE *FP(192),A7,1 + ADDI 800,A7 + SLL 10,A7 + ADDI 67108904,A7 + MOVE A7,*FP(256),1 + CLR A12 + MOVE A12,*FP(160),1 + JRUC L34 +L37: + MOVE *FP(256),A7,1 + MOVE *FP(160),A5,1 + SLL 3,A5 + ADD A7,A5 + MOVE *FP(192),A7,1 + SLL 8,A7 + ADDI STATIC_3,A7 + MOVE *FP(160),A3,1 + SLL 3,A3 + ADD A3,A7 + MOVB *A7,*A5 + MOVE *FP(160),A7,1 + ADDK 1,A7 + MOVE A7,*FP(160),1 +L34: + MOVE *FP(160),A7,1 + CMPI 32,A7 + JRLT L37 + MOVE *FP(192),A5,1 + ADDK 1,A5 + MOVE A5,*FP(192),1 +L30: + MOVE *FP(192),A7,1 + CMPI 72,A7 + JRLT L33 + MOVI 1146048069,A12 + MOVE A12,@0018A8020h,1 + CLR A8 +EPI0_2: + ADDI -288,STK + MMFM SP,A3,A5,A7,A12,FP + RETS 0 + .end diff --git a/harness/c-hello/entry.asm b/harness/c-hello/entry.asm new file mode 100644 index 0000000..cb9d733 --- /dev/null +++ b/harness/c-hello/entry.asm @@ -0,0 +1,26 @@ +; entry.asm -- process entry for the C hello world. +; +; The C runtime's boot.obj is designed for a ROM system: _c_int00 sets SP (the +; *system* stack), calls main, calls exit (which is `for(;;)`) and ends in +; `reti`. None of that fits a process made by the VT1200's create_process: +; the spin never yields, and `reti` returns from an interrupt that never +; happened (it pops a garbage PC -> illegal opcode). +; +; So we enter here instead: set the C program stack (STK = A14, FP = A13), call +; main, and `rets` back to the create_process trampoline -- the same return the +; xhello payload uses. SP (the OS's interrupt stack) is left alone. +; +; _cstack is 4096 bytes; the compiler grows the program stack upward from STK. + + .text + .globl _start + .globl _main +_start: + setf 32, 0, 1 + movi _cstack, a14 + move a14, a13 + calla _main + rets + + .bss _cstack, 32768, 16 ; 32768 bits = 4096 bytes + .end diff --git a/harness/c-hello/evidence/hello_frame.png b/harness/c-hello/evidence/hello_frame.png new file mode 100644 index 0000000..a178497 Binary files /dev/null and b/harness/c-hello/evidence/hello_frame.png differ diff --git a/harness/c-hello/evidence/hello_real_frame.png b/harness/c-hello/evidence/hello_real_frame.png new file mode 100644 index 0000000..ab0de27 Binary files /dev/null and b/harness/c-hello/evidence/hello_real_frame.png differ diff --git a/harness/c-hello/hello.c b/harness/c-hello/hello.c new file mode 100644 index 0000000..e8aef05 --- /dev/null +++ b/harness/c-hello/hello.c @@ -0,0 +1,103 @@ +/* + * 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 emulator uses 128; this image is linked for the real one) + * 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; +}