Skip to content

software/emulator — the YACC1 emulator (reference model)

main.c (2026-06-03, single file, ~1300 lines): 8-bit ACC/TMP, 16-bit R0–R7, 64K, 16 ports, console on port 2 / UART on P0=$40,P1, refuses writes above $DFFF, -m/-f options. Uses ../opcodes.h. Build: make (plain Makefile, 2026-09-20); make run loads firmware/rom/shipped/rom, i.e. what the machine runs, via -f (Intel hex; the assembler's .img files are the same format). -m, also the default with no arguments, loads firmware/basic/basic.img + firmware/monitor/monitor.img found relative to the executable, so it also works from a Finder double-click or any working directory (2026-09-20, see tools/patched_files.txt). -f FILE is relative to the current directory as before. -S (2026-09-25) is the program watch: every JSRUR to $5000 is Y1/OS starting a program, and at the next one and at exit a line on stderr gives its instructions (program N: 930775 instructions, stack $CFFF down to $CFE5, 26 bytes), with its deepest stack point when it runs on its own stack (y1cc --stack: a MVIW R1 into $5000-$CFFF); tests/native/run.py counts every compile, assembly and run with it and checks each compiler pass's stack against its data. -P FILE (2026-09-25) is the PC histogram: every instruction is counted at its address, and at every program start (as -S sees it) and at exit the counts so far go to FILE as a block program N (0: the monitor and the boot) of AAAA count lines, then start again; tests/native/profile.py names the addresses from the programs' and the OS's assembly (instructions per function of every compiler pass, the assembler and the OS). The UART (2026-09-26): INP P1 while P0 selects the I/O card's 16550 (UARTCS $40 | register << 3) reads it as software/ucemu models it: RBR = the next console byte (waits for it), LSR = $60 (transmitter empty) | data ready, where data ready is a NON-blocking poll of stdin (after 20,000 empty polls in a row, with no input or output meanwhile, each poll waits up to 1 ms, so a program idling on the line does not spin the host), IIR = $01, the rest 0; OUTA P1 while P0 = $40 prints (as OUTI P1 always did). Port 2 and the UART share one input stream: a byte the data-ready poll took is the next one INP P2 returns. On this path, unlike port 2, q is an ordinary byte (port 2 still turns it into 0, the old quit key); CR becomes LF on both, as on ucemu. Until then the ROM's console was port 2 only here (BRDEV never branches), with no way to test for a waiting byte, so a program could not time out; /BIN/KERMIT polls the UART directly (os/kermit_io.asm, tests/kermit). -x (2026-09-22) is the scripted mode the compiler tests use: no load/dump chatter, no raw tty mode, stdout flushed, and HALT exits with HALT at aaaa after N instructions, R3=xxxx on stderr (emulator -x -f prog.img < input). Same day: BRVR and JSRUR now do what the microcode does (indirect jump through the word at Rn, and PC ← Rn), so the monitor's G AAAA (BRVR R7) and T menu (JSRUR R7) work on the emulator; G AAAA jumps THROUGH the word at AAAA, which a program must therefore start with (the C compiler emits that vector). Load firmware/rom/shipped/rom (BASIC at $E000, monitor at $F000) to run what the machine runs.