Architecture
Contain the generated code. Mediate its physical effects.
The model's program executes on our board, on the same core as the loader and the envelope monitor, in the same address space. Nothing physical separates them. What separates them is a loader, an interpreter and an envelope monitor carrying fifteen machine-checked properties between them and a capability table of three entries fixed before the program runs. Hardware protection checks and seventeen jail-break probes have held on the physical board. This page is that arrangement, subsystem by subsystem.
System definition
Endstop has two independent boundaries: one confines hostile generated code; the other mediates its physical proposals. The tables below specify each subsystem.
| Boundary | Question answered | Mechanism |
|---|---|---|
| Execution containment | What may model-authored code reach while it runs? | bounded VM, scratch-memory checks, fuel and an enumerated capability table |
| Physical mediation | Which proposed effects may reach the machine? | fixed envelope monitor, independent feedback where integrated, and the stopping path |
Consolidated implementation checklist and roadmap →
| Subsystem | Specification |
|---|---|
| Host processor | in-order RV32 soft core; no OS, no DMA, no network stack, no cache by default |
| Interpreter core | dual-budget bytecode VM with memory-region isolation1 |
| Capability table | three typed effects: read state, propose setpoint, request signature |
| Envelope monitor | multi-point limits, predicted stopping position, rate and acceleration ceilings, spectral resonance limiter, deadman |
| Feedback supervisor | captured position/rate, following error and capture-sequence freshness |
| Effect construction | trusted-side serialisation from an enumerated intent set with quantised parameters |
| Audit record | bounded capability journal sealed with Ed25519 on request |
| I/O surface | serial in; PWM or step/direction out; relay drive in series with the safety chain; SPI secure element |
| Reaction timing | machine-specific capture-to-safe-state budget |
| Board integration | bring-up, timing closure, end-to-end measurement |
We write the interpreter ourselves. The published verified VMs we evaluated proved a much larger machine than we run, arrived with a 2022 toolchain and a licence problem, and stopped at C rather than machine code. All seven properties of our own interpreter discharge, memory safety last, on 2 August 2026, to the depth a bounded model checker reaches. Physical-board loader/VM bring-up, UART diagnostics and workload-local counter timings have passed; what has been measured against the core's register-transfer description is in §2. The work in front of us is integration and measurement.
The effect path
Within the specified program interface, every admitted effect follows one path: the instruction set exposes no file, socket, allocator or unmediated output verb.
- The agent (114), running off-board on untrusted host compute (110), sends a program over a serial interface (120) that carries programs in and verdicts out.
- The program executes in the interpreter (134) under a fuel bound. It terminates by construction; there is no analysis to defeat, only a counter that reaches zero.
- It may invoke exactly three capabilities through the capability table (136): read state, propose a setpoint, request a signature. There is no file, no socket, no allocator, no fourth verb.
- Each proposed effect is checked by the envelope monitor (138) against limits validated offline, covering multi-point position, predicted stopping position, rate and acceleration ceilings, a spectral resonance limiter and a deadman.
- Effects that pass are constructed by the trusted side and emitted (144) to the target driver stage (152). A failed check requests the configured safe reaction. The product design records every verdict and periodically seals the chain; the current emulator keeps a bounded journal sealed on request.
Two boundaries carry that path, and they do different jobs. The serial interface is the first: it keeps the loader, the interpreter and the monitor out of reach of whatever is running the model, so our code is not that machine's to patch. The second is the one the safety argument rests on. Step 2 executes the submitted program on the gate's own core, in the same address space as the loader and the monitor. Nothing physical stands between them. What separates them is the interpreter's semantics (fuel, the three-entry table, memory bounds) together with the RV32 physical-memory-protection configuration that holds the monitor's state out of the program's reach.
Memory safety in the interpreter is proven. The protection configuration has held in physical denial probes on the board. In the fabric-gate prototype, output permission already sits in fabric logic the processor cannot write itself into; the next isolation milestone moves the monitor's state there and puts the actuator path behind it.
The other side is deliberately thin. The part running the model is an inference engine: tokens in, tokens out, no interpretation of what it emits and nothing wired to it. So a misaligned model, a jailbreak, a prompt injection and an attacker in full control of that accelerator all arrive here as the same object, which is a hostile program at the loader. We removed the host from this boundary, so there is no separate class of host-compromise attack to answer.
The emergency-stop chain (160) is designed to run physically around the gate and open the contactor (164) in series with the servo drive. The gate itself regenerates the drive-facing command after enforcement, so it has functional authority to produce a motion command. The independent stopping path is designed to remove drive authority without relying on the interpreter.
Two timescales, because the physics demands it
The fast control loops belong to the servo drive, and we leave them there. Current loops typically run at 8–20 kHz and velocity loops at around 5 kHz, all of it beneath us. What crosses the network is setpoints, typically at 500 Hz or as PWM.
So enforcement splits. The slow path validates the envelope offline, once, the way every certified safety configuration in industry is validated. The fast path is a constant-time comparison against that envelope on every cycle, using table lookups with no allocation and no search.
| Path | Rate | Work | Budget |
|---|---|---|---|
| Offline validation | per configuration | envelope derivation, risk assessment, signed acceptance | hours |
| Admission | per program | capability grant check; forward-only programs may be checked against a versioned tick-credit table | seconds |
| Enforcement | every cycle | multi-point limits, stop prediction, rate, resonance, deadman | fits the 500 Hz cycle in RTL simulation |
ISO 13855 converts the complete reaction time into required guard distance at the applicable approach speed. The relevant quantity is not an isolated monitor target: it is capture, phase delay, computation, output, drive response and mechanical stopping time together. Endstop has measured the monitor against the target core's RTL and in 12, 24, 48 and 96 MHz board workloads; a pilot must derive its allowable budget from the machine-specific hazard analysis and replace every remaining component with hardware measurements.
Against the NEORV32 register-transfer description, the monitor's worst tick is 13,218 cycles (528.7 µs at 25 MHz), or 26.4% of the 2 ms control cycle. With a 144-instruction interpreted program added, the per-tick workload takes 92.8% of the cycle at the pilot's 25 MHz and fits it. Place-and-route for this part closes between 90.0 and 102.5 MHz across five seeds, and at 75.4 MHz with all eight memory-protection regions enabled; at those clocks the same workload takes under a third of the cycle.
ISO 13855 prices the simulated monitor time at about 0.85 mm of separation, against a 58.9 mm servo deadband that dominates the stopping distance by roughly seventy to one, in the simulated configuration. End-to-end reaction time on a machine, from capture through drive response, is measured per machine in a pilot.
The interpreter no longer treats every instruction as the same amount of timing work. It keeps step fuel, which proves termination, separate from tick credits, which use a versioned target-specific cost table. The VM reserves an instruction's complete charge before executing it; an unaffordable capability call therefore cannot enter the callee. Forward-only programs can be rejected at load time when the fixed overhead plus every instruction charge exceeds the tick allowance.
The initial table comes from a retained no-cache NEORV32 RTL characterization. With a 25% engineering margin and rounding, charges range from 320 credits for a byte store to 480 credits for capability-call stubs, plus 416 credits of fixed invocation overhead. This is simulator characterization, not physical hardware or WCET. The capability rows are harness stubs, so operational timing admission remains disabled until deployed callees are bounded and an independent privileged deadline/watchdog prevents output commit on model error. The dated record is in the fuel-cost artifact; the full table is on the silicon page.
A second thing that was projected is now run. The design has been synthesised, placed and routed for the part the pilot targets: it takes 130 of 208 block RAMs and 6.1% of the logic; the multiplier maps onto dedicated hardware, and 25 MHz closes on every router seed we tried, the worst by 3.6×. Neither the fit nor the closure had been demonstrated by anyone before. The frequencies come from an open toolchain’s timing model, and the board has since run the soft core at up to 96 MHz; the silicon page carries every run and every part we tried.
The older figures of 216, 159 and 376 instructions per tick divided a period by a single
dispatch measurement. They are retained as historical workload arithmetic, not current
admission limits: instruction mix changes the cost, capability implementations were not
included, and the monitor shares the core. MAX_STEP_FUEL remains 1,024, but it
is only the platform-independent ceiling on dispatched instructions. A program receives
an independently configured tick-credit allowance beneath that ceiling.
The trusted side constructs the effect
The agent names an effect, and the trusted side constructs it. A gate that validates a byte string is validating a field it believes is the amount, the joint index, the destination. Encodings are adversarial: the same bytes mean different things under different parsers, and the attacker chooses the encoding.
The agent supplies an index into a pre-approved intent set and quantised parameters. The gate serialises the transaction or the setpoint itself.
Effects are named, not described
That is the design decision that came directly out of adversarial review, and it replaced an earlier design that inspected agent-supplied bytes.
Quantisation matters as much. We publish the residual: snapping parameters to a coarse grid and emitting on a fixed schedule reduces the bandwidth of any channel an agent might modulate, from arbitrary to countable.
Here is the count. The physical command is a 16-bit PWM at prescaler 8 — about 3,000 distinct steps across a servo's pulse range — emitted on a 50 Hz frame. An agent that owned every commanded position outright could modulate at most log2(3000) × 50 ≈ 580 bits per second, and less as the intent grid is made coarser than the hardware or the loop runs slower. On the bounty, getting any value out through it, at any rate, is a win.
What is trusted, and what is merely present
A trusted computing base is only meaningful if you enumerate it. Ours is 1206 measured lines, and the parts outside it are listed with equal precision.
| Component | Status | Basis |
|---|---|---|
| Interpreter core | machine-checked | ours, 667 lines; seven properties discharged with a bounded model checker1 |
| Fuel accounting | machine-checked | step fuel bounds termination; timing credits are prepaid before execution; the provisional cost table is simulator-derived |
| Memory isolation | machine-checked | every access lands in the designated region; discharged 2 August 2026 |
| Capability table | engineered | static; callee behaviour not proven |
| Envelope monitor | machine-checked | 539 lines outside the VM; eight properties discharged, one exhaustive over all 232 inputs and one over every prismatic-axis configuration |
| Audit record | part machine-checked | The emulated board collects capability events in a bounded journal and seals the current batch when the program requests a signature. The request-signature callee is written and its message-building and journal plumbing machine-checked, retained for the source-audit release; the Ed25519 leaf is audited, its field arithmetic Coq-verified. The product design — a durable control-rate hash chain with periodically signed heads and a secure monotonic counter — is not yet implemented or demonstrated on hardware. |
| PMP configuration | validated · narrow hardware mechanism | on the physical board, a user-mode sweep of every protected region boundary faulted with its documented cause, and no user-mode access reached monitor RAM, the fabric gate, UART or GPIO |
| Debug / JTAG isolation | planned | the synthesis test configuration disables JTAG tests; permanent production disablement or physical isolation is a board-integration milestone |
| Boot & signature check | planned | immutable first stage, image authentication and an anti-rollback counter, specified before any persistent configuration; the board runs volatile images only |
| Soft processor | assumed | in-order RV32, no speculation, no cache by default |
| Synthesis toolchain | assumed | open toolchain, reproducible builds intended |
| Physical access | out of scope | no tamper response in the pilot |
The pilot excludes physical attackers, power and electromagnetic side channels, and the gap between a formal hardware model and delivered silicon. Those exclusions are disqualifying for payment-HSM and cross-domain defence use, where tamper response is a baseline requirement, so we do not sell into those markets.
They are defensible for a fenced robot cell, where physical access is already controlled, and that is the market we address first.
Deliberately small, deliberately dull hardware
An in-order RISC-V soft core on an FPGA, running from on-chip memory. No operating system. No DMA engine. No network stack. No cache by default, so timing is predictable and the speculative-execution attack classes do not exist to begin with.
Everything the device can do is visible on the pin map, and that is what makes an independent audit tractable. The I/O surface is specified as the complete effect vocabulary: a serial link in, PWM or step/direction out, a relay drive that sits in series with the existing safety chain, and an SPI secure element holding keys.
Signing runs off the control path entirely. The product record is designed to append events to a hash chain at control rate and periodically sign a chain head; it does not sign every verdict, so signing speed sets how often a head is sealed, not the control rate, and the control loop never waits on it.2 The signer is written: a real Ed25519 that builds for the board in under 80 KB with no heap and uses 6.5 KB of stack, its message-building and journal plumbing machine-checked and retained for the source-audit release, its field arithmetic from a Coq-verified backend. The emulated implementation seals its bounded journal on request; continuous durable chaining under a periodic-seal policy is the next milestone.
References
- The interpreter is ours: 667 measured lines of
no_stdRust over a deliberately reduced instruction subset, verified with a bounded model checker. An earlier design inherited a published verified VM; that decision was reversed because the proof covered a much larger machine than we execute. Termination comes from a fuel cap, which holds for any program including one that loops. The harness bounds are shallow — one to three instructions, where the machine admits 256 — and deliberately so: the properties are structural. The memory-safety harness quantifies over a fully symbolic instruction, and termination is bounded by the fuel cap whatever the program does. The bounds themselves are insrc/proofs.rs, one per harness. - Measured figures for portable verified Ed25519 implementations on 32-bit RISC-V are approximately 1.2 million cycles per signature, which at the pilot's 25 MHz is about 48 ms. Implementation choice materially affects this. On the board, the signer in its default configuration, without a precomputed base-point table, measured 12,262,800 cycles per signature, about 0.49 s at 25 MHz (dated record).