SearchA-ZU › Uxn

Uxn

2021 Open source · MIT Online

Uxn is a tiny 8-bit stack machine by Hundred Rabbits, paired with Varvara, the small personal computer built around it. This build runs the vanilla-JavaScript Uxn core in the browser and rasters the Varvara screen device to a canvas. It boots a public-domain demo ROM by default, and the shared emulators.org debugger single-steps the stack machine one opcode at a time with breakpoints and watchpoints.

Visit the official site ↗

Runs on: Web browser

Uxn Online Emulator

Play Uxn using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
Varvara demoUxnUxnopenOpen ⛶

Machines emulated

Chips

Notes

Embedding

uxn5 ships two cores. The default is uxn.wasm; the repository also contains a complete vanilla-JavaScript core, uxn.js, plus the Varvara device modules (screen.js, system.js, datetime.js, mouse.js). We vendor the JavaScript core so every Uxn opcode runs in plain, inspectable JavaScript with no wasm heap to reach into.

The step primitive. The core exposes uxn.step(), which executes exactly one Uxn opcode and returns the instruction byte (0 on BRK). Uxn does not free-run: the machine wakes on an event, evaluates a device vector from a start address until it hits BRK, and sleeps again. uxn5's own loop calls uxn.eval(vector) once per frame, which runs a vector to completion with no way to pause inside it. We replace that with our own loop that walks step() and checks the program counter before each opcode:

function runVector(vec){
  uxn.setpc(vec);                          // seed the PC at the vector start
  for(;;){
    var pc = uxn.getpc();               // PC of the opcode about to run
    if(breakpoints.has(pc)){ pause(); return; }
    if(uxn.step() === 0) return;      // one opcode; BRK ends the vector
  }
}

The two hooks we added. The upstream core keeps its program counter and RAM private in a closure, so we added three small, clearly-marked lines to uxn.js: getpc() / setpc(v) to read and seed the PC, and setpokehook(fn) to fire a callback on every memory write (for watchpoints). Nothing in the core calls them; they exist purely for the debugger.

MemberKindWhat it does
uxn.step()methodExecute exactly one Uxn opcode; returns the instruction byte, 0 on BRK. The single-step primitive.
uxn.getpc() / setpc(v)methodRead the live program counter, or seed it to start a vector (added for the debugger).
uxn.ramfieldThe 64 KB program memory, a plain Uint8Array.
uxn.wst / uxn.rstfieldThe working and return stacks; .ptr is the live stack pointer, .dat the 256 bytes.
uxn.devfieldThe 256-byte Varvara device page (system, console, screen, controller, mouse ports).
screen.deo(port)methodThe Varvara Screen device: pixel and sprite ports blit into the foreground / background layers, then redraw() rasters to the canvas.

Debugger integration

The machine plug-in uxn-debug.js reads window.EMU_BOOT and hands the debugger a transport, the Uxn register set and the memory chips. Because the core is plain JavaScript, every debugger feature is a host-side check around step(), with no change to the emulator's semantics.

  • Step one opcode. The Step-instruction control calls step() once. Outside a vector the loop first seeds the PC at the screen vector, so stepping always advances the visible program.
  • Breakpoints. The loop compares getpc() against a Set of addresses before each opcode and pauses on a match, keeping its place so Resume continues mid-vector.
  • Watchpoints. setpokehook flags a write to a watched address; the loop pauses as soon as the opcode that wrote it returns.
  • Registers. A Uxn machine has no A / X / Y file. The state the debugger shows is the program counter and the two stack pointers, WST and RST, all live and settable.
  • Disassembly. The uxn decoder (/debugger/src/cpus/uxn.js) splits each byte into a 5-bit base opcode and the short / return / keep mode flags, and lengthens LIT, LIT2 and the JCI / JMI / JSI immediates that carry inline bytes.

Architecture

Uxn is a tiny 8-bit stack machine, and Varvara is the small computer built around it. The whole system is a handful of plain objects:

  • uxn - the CPU: two 256-byte stacks (working and return), 64 KB of program memory, and a 256-byte device page. One opcode byte is a 5-bit operation plus three mode bits (short, return, keep), so the entire instruction set fits in 32 base opcodes.
  • screen - the Varvara Screen device. Its pixel port paints single points and fills; its sprite port blits 1-bit and 2-bit 8×8 tiles through a blending table into a foreground and a background layer, which are then composited to the canvas.
  • system - sets the four-colour palette (three 16-bit registers, one nibble per colour) and does block memory fills and copies.
  • datetime, mouse - the clock and pointer devices, read and written through the same device page.

Programs are event-driven: the reset vector runs once at boot to set the palette and install a screen vector, and from then on Varvara runs that vector once per frame. Between frames the machine is idle, which is exactly why single-stepping is framed around evaluating a vector from its start to BRK.