Show HN: Spin up MCU simulations like VMs

grog_61 pts0 comments

Provision Simulations as if they are VMs Book a Demo svg]:px-2.5 rounded-full md:hidden" href="https://app.simulator86.com" data-astro-cid-3ef6ksr2>Dashboard svg]:px-2.5 rounded-full hidden p-2 md:inline-flex" href="https://cal.com/simulator86/15min" data-astro-cid-3ef6ksr2>Book a Demo svg]:px-2.5 rounded-full hidden p-2 md:inline-flex" href="https://app.simulator86.com" data-astro-cid-3ef6ksr2>Dashboard

Blog<br>Jun 12, 2026<br>Provision Simulations as if they are VMs<br>We just launched our cloud to run your firmware against modern, popular MCUs — from code, not from a browser tab.<br>Tariq Rafid<br>Twitter / X

LinkedIn

We just launched our cloud to run your firmware against modern, popular MCUs — from code, not from a browser tab.

The web app is great for building and debugging interactively. But most embedded teams don’t have a simulation culture at all: testing means a board on a desk, a debugger probe, and someone manually flashing builds. That doesn’t scale past one desk, and it definitely doesn’t run in CI. Our cloud SDK is our answer — everything the simulator does, scriptable.

MCUs are code

A project, a graph, components, firmware. No GUI, no string-based wiring — you connect actual bus-level signals:

const client = createClient(env.SIM86_API_KEY)

const project = await client.createProject("smart-fan-controller")<br>const graph = project.graph

const mcu = graph.addComponent(Components.ADAFRUIT_STM32F405_EXPRESS)<br>const imu = graph.addComponent(Components.MPU6050)

mcu.setFlash("./firmware.elf") // path or Uint8Array

// connect physical bus-level signals<br>graph.connect(imu.pins.sda, mcu.pins.sda)<br>graph.connect(imu.pins.scl, mcu.pins.scl)<br>Streams and records

Everything the simulation produces is observable. Streams emit live during the run — sensor outputs, even individual CPU registers:

// live sensor output<br>imu.stream("gyro").subscribe(({ x, y }) => {<br>console.log("IMU:", { x, y })<br>})

// program counter transitions, sampled every 35ms of simulation time<br>mcu.cpu0.stream("pc", { throttle: 35 }).subscribe((pc) => {<br>console.log("PC:", pc)<br>})<br>Streams are for watching; keep them throttled. For anything high-frequency, record it instead and query it after the run:

mcu.record({<br>include: [<br>"cpu0.sp", // stack pointer register transitions<br>"usart", // tx/rx streams<br>"i2c.0x04", // I2C register at offset 0x04 from peripheral base<br>"rtt", // Segger RTT<br>],<br>})<br>Run it, poke it, query it

Runs are bounded in simulation time, and you can schedule events against the timeline — inject sensor values, press reset, see how your firmware reacts:

const run = await graph.run({<br>duration: 5000, // 5 seconds of simulation time<br>record: { include: ["cpu0.pc", "cpu0.sp", "usart"] },<br>})

// scheduled events (timing guaranteed within ±10ms)<br>await run.at(1000).do(() => {<br>imu.setYGyro(5)<br>})<br>await run.at(3000).do(() => {<br>mcu.pressReset()<br>})

const logs = await run.logs()<br>Runs are persisted, so postmortems don’t require reproducing anything:

const logs = await client<br>.getProject("my-project-id")<br>.getRuns("my-run-id")<br>.logs()<br>It pairs brilliantly with Claude Code

Coding agents are only as good as their feedback loop, and embedded development normally has the worst one imaginable: flash a board and watch it. The SDK gives an agent the loop it actually needs. Point Claude Code at a repo with the SDK installed and it can compile your firmware, run it on a simulated board, read the logs, register transitions, and bus traffic, and keep iterating until the behavior is right — unattended.

Why this matters

Most simulators are deterministic: the same binary produces the same execution, every time. That’s convenient — and it’s exactly why firmware that passes a deterministic simulator still dies on real hardware, where clocks drift and interrupts land at the worst possible moment.

Simulator86 is stochastic. Every run injects controlled timing variation, the way real silicon does. So a passing run isn’t “it worked once under lab conditions” — surviving runs here means your firmware has a genuinely working path on hardware. Put that in CI, on every commit, and you have something most embedded teams have never had: regression testing that actually predicts hardware behavior.

The SDK is available now. If you’re a business looking to build a simulation culture, talk to us.

Share this post

LinkedIn

Copy link<br>RSS

Imagination is more important than knowledge.

· A. Einstein ·

svg]:px-4" href="https://app.simulator86.com" style="display: inline-flex;"><br>Start Building

firmware graph const simulation await simulator86

Related Articles