DEV Community

Tacettin Sancak
Tacettin Sancak

Posted on • Originally published at digiwleea.wleeaf.dev

An AI tutor that is not allowed to lie about circuits

My circuit simulator has an AI tutor. You can ask it to build you a full adder,
and a few seconds later a working full adder appears on your canvas, wired,
laid out, and correct. Every time. Not because the language model is reliable,
but because the system around it refuses to let an unreliable answer through.

That's the interesting part. Anyone can pipe an LLM's output onto a canvas. The
problem is that a tutor that draws a wrong circuit is worse than no tutor at
all: a beginner cannot tell the difference, and the whole point of a simulator
is that the thing on screen is true. So the rule I built the integration around
is simple: the model proposes, the engine disposes. Nothing the model says
reaches the canvas until the real simulator has proven it.

The model never places anything

The first design decision: the model is not allowed to talk about geometry at
all. Its build tool takes a logical netlist, a list of nodes ("an AND gate
here, an input called A there") and connections between named pins. No
coordinates, no wire paths, no layout hints.

This isn't just about saving tokens. Early experiments made it obvious that
LLMs are confidently terrible at 2D placement: parts overlap, wires cross
bodies, pins end up on the wrong side. Worse, coordinate output looks
plausible, so failures are silent. A logical netlist, by contrast, is the
model's native register: it is a statement about meaning ("the adder's carry
feeds the OR gate"), and meaning is exactly what a language model is good at
and exactly what I can verify.

So the contract is: the model describes what the circuit is, and my layout
engine decides where everything goes.

Layout is a claim, and claims get checked

Here is the guarantee the layout engine makes: a candidate layout is emitted
only if, after actually placing the parts and routing the wires, the resulting
electrical connectivity is exactly the netlist the model asked for. Not
approximately. Exactly.

Verification is not a heuristic. The candidate is run through the same pipeline
a hand-built circuit uses: parts are placed on the grid, wires are routed
around obstacles, the circuit is flattened, and a union-find pass groups every
wire endpoint and pin into electrical nets. That gives a partition of all pins
into nets. The intended netlist gives another partition. If the two partitions
are not identical, the candidate is thrown away. A wire that brushes a
neighboring pin, a route that shorted two nets, a pin left floating: all of
these change the partition, so all of them are caught by construction rather
than by a list of special cases I hoped was complete.

The check runs on the real simulator's data structures, not a parallel
implementation. That matters. A separate "validator" would drift from the
engine over time and start approving circuits the engine disagrees with. Using
the engine itself means the verification is definitionally in sync with what
the user will experience.

A cascade of layout strategies

One layout algorithm cannot handle everything, so the engine tries a sequence
of them, and the verify gate is what makes the cascade safe: the first
candidate that proves itself wins, and a strategy that fails costs nothing
but time.

Transistor-level circuits go to a CMOS schematic generator that knows what
pull-up and pull-down networks are supposed to look like. Gate-level circuits
get a classic schematic layout. Circuits built from larger blocks go through a
proper graph-layout pass (ELK), with each part's ports pinned at their true pin
offsets so the router's plan survives contact with the actual component
shapes. After that come progressively more conservative fallbacks, ending in a
channel router that is provably collision-free: ugly, but never wrong.

The ordering encodes taste: try the layout a human engineer would draw first,
fall back toward guaranteed-correct-but-plain. Because every candidate passes
the same partition check, adding a new strategy is risk-free. The worst a bad
strategy can do is waste its slice of the wall-clock budget.

The loop: do, check, continue

Correct layout only guarantees the circuit matches what the model asked for.
It does not guarantee the model asked for the right thing. An LLM will
cheerfully produce a "full adder" whose sum output is just A XOR B.

So after every build, the system sweeps the circuit through the simulator and
hands the model back the actual truth table of the thing it just built. Not
"looks good!", the real input-to-output mapping, measured. For clocked
circuits it runs the simulation forward over clock cycles and reports behavior
over time, because a single-instant reading of a flip-flop tells you nothing.

This turns the tutor into an agent with a lab bench. It builds, reads the
measurement, notices the sum column is wrong, rebuilds with the missing XOR,
and checks again. The model's judgment is still fallible, but it is now
fallible in front of an instrument, and the instrument does not flatter it.
Most wrong first attempts fix themselves within an iteration or two, without
the user ever seeing the broken version.

Failing is a feature

The last piece is what happens when nothing verifies: the tutor simply does
not build. It says so, and the canvas stays untouched.

That felt unsatisfying to ship. Every instinct says "degrade gracefully, show
something". But showing something is precisely the failure mode this whole
design exists to prevent. A tutor that occasionally draws a subtly shorted
circuit teaches a beginner that circuits are mysterious and untrustworthy. A
tutor that occasionally says "I couldn't build that correctly, let me try a
different structure" teaches them that correctness is checkable. In an
educational tool, the second lesson is half the curriculum.

The same gate protects the library: when the tutor authors a reusable
component, it builds the part off-canvas, verifies it against the simulator,
and only then saves. Nothing unverified is ever persisted anywhere.

What generalizes

None of this is specific to circuits. The pattern is:

  1. Constrain the model's output to the semantic layer it is actually good at, and keep it away from layers where its errors are silent.
  2. Verify with the production engine, not a lookalike validator, and verify the whole property (partition equality), not a checklist of known failure modes.
  3. Feed measured reality back into the loop, so the model iterates against an instrument instead of its own confidence.
  4. Prefer honest refusal over plausible wrongness.

LLMs are proposal generators with excellent taste and no integrity. The
engineering is in building the judge.


This is from building digiwleea, a free browser lab where you build a CPU starting from single transistors. Originally published on the digiwleea engineering blog.

Top comments (0)