Chiprun · the playground

Run firmware live, in a browser tab

The playground runs the engine in your browser. Not a video of a run that already happened — an actual machine you can stop, step, and step backwards through, with its registers, disassembly, waveforms and the circuit around the chip.

Live session or queued run

The playground has two tabs, and they are the same engine reached two ways. Which one you want depends on whether a person or a program is asking.

Live session

You, at a keyboard

The engine runs in a worker in your tab. Nothing is queued, nothing is uploaded, and it costs no quota. This is the only place stepping and breakpoints exist, because they need a machine that is still running.

Queued run

Your agent, or a permalink you want to share

The firmware goes to a worker, runs to a virtual-time cap, and comes back as a trace with a URL. This is what chiprun_run_firmware returns over MCP, and what the sixty runs recorded before any of this existed still open as.

What you can do to a running machine

Load a .elf or .hex — the engine sniffs the format, and an ELF also brings its symbol table — then:

  • Run free, or for a set amount of simulated time — 1 ms up to 5 s per press. The amount is relative to wherever the machine is now, so pressing it twice goes twice as far and it still means something after stepping or seeking. It is simulated time, not wall-clock: 100 ms is a different number of cycles on an 8 MHz part than on a 16 MHz one, and the button converts using the clock the fuses actually select.
  • Step one instruction, over a call, out of one, or forward to the next call.
  • Step backwards. The engine keeps snapshots and replays from the nearest one, so the machine really does go back. The scope says how far — past that horizon the state is genuinely gone, and it says that instead of pretending.
  • Break on an address by clicking it in the disassembly.
  • Seek to a moment. Put a cursor on the edge that looks wrong in the Signals panel and press Seek — the machine moves there and the register file is what it held at that instant.
  • Type at the UART while it runs. It is a real serial line, not a queue of scheduled keystrokes.
  • Edit the fuses. On these parts the low fuse is the clock, so this is not a settings panel — it decides what every other time on the screen means.

It simulates the board, not just the chip

This is the part that has no equivalent in a CPU emulator. The engine solves the circuit around the part, so the playground can answer questions a pin-level trace cannot:

  • Circuit draws the schematic — the board's own crystal, decoupling and LED, plus anything you fit.
  • Analog reports per-net voltages and per-element currents. A pin driving high into an open circuit has a level and no current, which is exactly the difference this shows.
  • Devices reports what each fitted part is doing — whether a lamp is actually lit, rather than whether its pin is high.
  • Memory reads and writes data memory, and asserts an interrupt vector the way a peripheral would. Both are direct: a write lands without the firmware running, so you can put a machine into a state it would take ten seconds of simulated time to reach on its own.
  • Fit puts an LED, resistor, buzzer or button on any pin. An LED fits as a series resistor and a lamp, which is both how you would really wire one and what makes the current readings mean anything.

What it refuses to tell you

Two panels exist to report the engine's own limits rather than paper over them, and they are worth reading before you trust a number.

Messages carries what the engine remarked on. An instruction it does not implement is reported by name, with the address to look at and how many times it happened — never executed as a no-op. A run that used one is a run whose trace is about a different program than you think.

What this run does not tell you lists what was not modelled. The Arduino Uno R3's crystal is drawn and its oscillator is not solved — the clock comes from the fuse bytes — and its on-board LED hangs off a buffer, so it draws no pin current. Both are true, neither is obvious, and a simulator that stayed quiet about them would be lying by omission.

Memory reads reach SRAM only. They do not go through the peripherals, so an address outside SRAM — which on these parts includes every I/O register — reads back as 0x00 rather than failing. Zeroes there are not evidence that a register is clear. A write outside SRAM is refused by address, and the engine names the address it would not write.

Asserting an interrupt makes a vector pending; it does not force the handler to run. With global interrupts disabled or the vector masked in its own peripheral, the machine ignores it — the firmware behaving correctly, not the injection failing.

Analog readings carry the moment they were taken, because they are recorded when a value changes rather than sampled on a clock. A reading stamped far in the past is stale, and saying so beats printing a confident number.

Boards and firmware

All 11 boards run live, and the board reference lists their clocks and fitted parts. Build for the board's exact part: avr-gcc bakes register addresses in at compile time, so an ATmega328P image on an ATmega2560 does not fail loudly — it writes to the wrong addresses and drops characters.

Nothing you load in a live session leaves your browser. That is worth knowing in both directions: it costs no quota and needs no upload, and it also means there is no permalink until you run it through the queued tab.

Interactive scenarios

A queued run can carry a scenario — stimulus on a timeline, and what to observe — which is how an agent drives a pin or types at a UART without a keyboard. The authoritative list of what a scenario may contain, and what this engine refuses, comes from chiprun_describe_board. It is generated from the same code that validates a scenario, so unlike this page it cannot drift.