Hack
An authored, in-browser Hack computer - the 16-bit teaching machine from "The Elements of Computing Systems" (nand2tetris). It has two 16-bit registers (A and D) plus M = RAM[A], an instruction ROM, and a 16-bit data RAM whose 16384..24575 window is the 512x256 monochrome SCREEN and whose 24576 word (KBD) is the keyboard. It boots running an animated screen-fill program and plugs into the shared debugger, so you can single-step one instruction, set breakpoints on a ROM address, watch a RAM address, and type on the keyboard.
Runs on: Web browser
Hack Online Emulator
Play Hack using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| Animated screen fill | Hack | open | Open ⛶ |
Notes
Embedding
The Hack computer here is authored from scratch in one small file, hack.js. It is a plain global - Hack.create(canvas) returns a machine object whose whole state is ordinary JavaScript, so the debugger reaches straight into it with no wasm heap or hidden loop.
Boot. Assemble a program with the bundled tiny assembler and load it into the ROM, then run your own loop built on hack.step() (execute exactly one instruction):
var hack = Hack.create(canvas);
hack.load(Hack.assemble('@SCREEN\nD=A\n...')); // dest=comp;jump source -> ROM
(function loop(){
hack.step(); // one instruction
hack.render();
requestAnimationFrame(loop);
})();
The machine is plain fields. Everything the debugger needs is live on the object:
| Member | Kind | What it does |
|---|---|---|
hack.step() | method | Fetch, decode and execute one instruction. The single-step primitive. |
hack.A · hack.D · hack.pc | fields | The two 16-bit registers and the 15-bit program counter, read and written live. |
hack.rom · hack.ram | fields | The instruction ROM and the 16-bit data RAM (the 16384..24575 window is the screen; 24576 is KBD). |
hack.peek(a) · hack.poke(a,v) | methods | Side-effect-free read / write of a RAM word, used by the debugger's memory views. |
hack.kbSet(code) | method | Write a Hack key code into RAM[24576] (the keyboard register). |
Hack.assemble(src) | static | Assemble @value and dest=comp;jump source into a ROM image. |
Because the registers, ROM and RAM are ordinary JavaScript, breakpoints are a host-side Set of PC values checked before each step(), and watchpoints are checked inside poke - no changes to the core.
Debugger integration
The boot shim publishes window.EMU_BOOT with a full transport: pause / resume / isPaused, stepInsn(n) (one instruction), step(n) (a burst), reset, plus breakpoints (a Set of ROM addresses the loop checks before each step) and watchpoints (a Set of RAM addresses, checked inside poke). A CPU decoder - /debugger/src/cpus/hack.js - turns each ROM word back into @value or dest=comp;jump. It reads the true 16-bit word off EMU_BOOT.hack.rom, because the shared views hand decoders a byte-masked reader that would truncate a word.
Architecture
The Hack computer is the target machine of "The Elements of Computing Systems" (nand2tetris), small enough to build from NAND gates, complete enough to run real programs:
- Registers A and D - two 16-bit registers. M is the pseudo-register RAM[A]: the memory word the A register currently points at.
- Instruction ROM - 16-bit instructions, one per word, addressed by the 15-bit program counter PC.
- Data RAM - 16-bit words. RAM[16384..24575] is the 512x256 monochrome SCREEN (each word is 16 horizontal pixels); RAM[24576] is the keyboard (KBD).
There are two instruction kinds:
| Pattern | Kind | Effect |
|---|---|---|
0vvvvvvvvvvvvvvv | A-instruction | A ← v (a 15-bit constant) |
111a cccccc ddd jjj | C-instruction | ALU computes comp from D and (A or M); dest latches it into A/D/M; jump compares it to 0 and may set PC ← A. |
The shared debugger's hack decoder turns each ROM word back into @value or dest=comp;jump, so you can watch the fetch-decode-execute cycle one instruction at a time.