Search › A-Z › G › Gigatron TTL
Gigatron TTL
Gigatron TTL is a pure-JavaScript emulator by Philip Thomas of the Gigatron, a working 8-bit home computer that contains no microprocessor at all. Its processor is a state machine wired from about three dozen 74-series TTL chips. It runs the open BSD ROM in the browser, booting straight to the Snake / Racer / Mandelbrot / Loader menu, and is plugged into the emulators.org debugger so you can single-step the native TTL instruction stream, set breakpoints and watch RAM.
Runs on: Browser
Gigatron TTL Online Emulator
Play Gigatron TTL using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| Gigatron main menu (ROMv1) | Gigatron TTL | Gigatron TTL | open | Open ⛶ |
Machines emulated
Chips
Notes
Embedding
The Gigatron core (PhilThomas/gigatron, BSD) is two dependency-free ES modules: gigatron.js (the TTL state machine) and vga.js (the raster). We ignore the upstream main.js - its setInterval loop can't be paused or stepped, and it drags in jQuery / rxjs - and drive the two modules from our own boot.js instead.
Boot. Construct the machine, point the VGA at a <canvas>, fetch the ROM as 16-bit big-endian words, then run your own loop built on cpu.tick() (one TTL cycle = one native instruction) and vga.tick() (one pixel-clock):
import { Gigatron } from './gigatron.js';
import { Vga } from './vga.js';
const cpu = new Gigatron({ hz: 6250000, romAddressWidth: 16, ramAddressWidth: 15 });
const vga = new Vga(canvas, cpu, { horizontal:{ backPorch:48, visible:640 }, vertical:{ backPorch:34, visible:480 } });
const dv = new DataView(romBuffer);
for (let i = 0; i < dv.byteLength >> 1; i++) cpu.rom[i] = dv.getUint16(2*i); // big-endian
(function frame(){
for (let i = 0; i < 104167; i++) { cpu.tick(); vga.tick(); } // ~1 video frame of cycles
requestAnimationFrame(frame);
})();
The machine is plain JavaScript. Every register is a live field on the cpu object and both memories are ordinary typed arrays, nothing to reach into a wasm heap for:
| Member | Kind | What it is |
|---|---|---|
cpu.tick() | method | Execute exactly one native instruction (one TTL clock). The single-step primitive. |
cpu.pc / cpu.nextpc | field | Program counter and the pre-fetched next PC (both 16-bit ROM word addresses). |
cpu.ac .x .y .out .outx | field | Accumulator, index X, index Y, and the output / extended-output latches. |
cpu.inReg | field | The controller input latch - active-low: a pressed button clears its bit. |
cpu.rom | Uint16Array | 64K of 16-bit instruction words (the whole "program"; there is no other code store). |
cpu.ram | Uint8Array | 32K RAM: the video framebuffer, zero page, and vCPU state + bytecode. |
Input is one byte: OR a button's bit into a mask and write cpu.inReg = mask ^ 0xff. Because the CPU, ROM and RAM are all plain JavaScript, the debugger single-steps by calling cpu.tick(), reads and writes registers straight off cpu, and implements breakpoints and watchpoints as host-side checks around the loop, the vendored core is untouched.
Debugger integration
Two custom pieces plug the Gigatron into the shared debugger; the core is left pristine.
1. A native-instruction disassembler (/debugger/src/cpus/gigatron.js, registered as decoder gigatron). Each ROM word is decoded into its four fields:
const op = (w >> 13) & 7; // 0 ld 1 anda 2 ora 3 xora 4 adda 5 suba 6 st 7 branch
const mode = (w >> 10) & 7; // RAM addressing mode / write target / branch condition
const bus = (w >> 8) & 3; // 0 immediate 1 [ram] 2 ac 3 in
const d = w & 0xff; // 8-bit immediate / address / branch offset
ROM is 16-bit-word memory, but the shared disasm view hands the decoder a byte reader. So - exactly like cpus/lmc.js - the decoder pulls the full word from the live core via window.EMU_BOOT.peekRom(addr), and each word is length 1 so PC lines up with the disassembly rows.
2. A machine plug-in (gigatron-debug.js) that polls for window.EMU_BOOT (boot.js is an ES module, so it resolves after the classic framework scripts) and calls EmuKit.defineMachine with the register set (AC / X / Y / OUT / OUTX / IN / PC / nextPC, all read and write-back), the ROM (disasm) and RAM (hex + bits) chips, and an on-screen gamepad.
Breakpoints and watchpoints without touching the core. The loop in boot.js exposes both on EMU_BOOT.transport. When either set is non-empty it drops from whole-frame execution to instruction-by-instruction: it pauses after the instruction whose new cpu.pc is a breakpoint. For a write watchpoint it pre-decodes the upcoming word; if it is a store (op == 6) it recomputes the exact RAM address that store will hit from the current X/Y (mirroring the core's addr(), read-only) and pauses when that address is watched. No write hook is patched into the vendored gigatron.js.
Architecture
The Gigatron TTL (Marcel van Kervinck & Walter Belgers, 2018) is a fully functional 8-bit computer with no microprocessor at all: its "CPU" is a Harvard state machine wired from about three dozen 74-series TTL chips. A ROM steps one instruction per clock; there is no microcode and no off-the-shelf processor.
- Native instruction set - every 16-bit ROM word is one instruction: a 3-bit op, a 3-bit mode, a 2-bit bus select and an 8-bit data field. Eight operations:
ld anda ora xora adda suba stand a family of page-local branches (plusjmpthrough Y). Registers are justAC,X,Yand theOUTlatch. - vCPU - because the native machine has no call stack or 16-bit ops, the ROM hosts a tiny interpreted virtual CPU (16-bit, memory-to-memory) whose bytecode lives in RAM. Games and the menu are written in vCPU; the debugger's ROM disassembly shows the native interpreter that runs it.
- Video - there is no video chip. Software in the ROM races the beam, driving 6 colour bits + the two sync bits straight out of the
OUTport;vga.jsreconstructs the 640×480 picture from those port transitions. - Sound & input - sound is likewise generated in software on the extended-output latch; input is a single active-low byte from a SNES-style controller (D-pad + A/B/Select/Start).
- Memory - 64K×16 ROM (the program) and 32K RAM (framebuffer + zero page + vCPU state). This build runs ROMv1, the original "At the Loop" ROM, booting to the Snake / Racer / Mandelbrot / Loader menu.