Day 30: Project: the gate-level logic simulator in Python (part 1 — netlist + events)
The Stage 0 capstone project begins
Your headline Stage 0 artifact is a gate-level logic simulator in Python: it parses a netlist of gates (AND, OR, NOT, DFF), builds the connectivity, and propagates events — changes on nets — through the combinational gates until the circuit settles. Today you build the data model and the combinational evaluator; tomorrow you add clocking and waveforms.
from dataclasses import dataclass, field
@dataclass
class Gate:
op: str # "AND","OR","NOT","DFF"
inputs: list # net names
output: str # net name
class Circuit:
def __init__(self):
self.gates: list[Gate] = []
self.values: dict[str, int] = {} # net -> 0/1
self.fanout: dict[str, list[Gate]] = {}
def add(self, g: Gate):
self.gates.append(g)
for n in g.inputs:
self.fanout.setdefault(n, []).append(g)
self.values.setdefault(g.output, 0)
for n in g.inputs:
self.values.setdefault(n, 0)
def eval_comb(self, g: Gate) -> int:
a = [self.values[n] for n in g.inputs]
if g.op == "AND": return int(all(a))
if g.op == "OR": return int(any(a))
if g.op == "NOT": return int(not a[0])
return self.values[g.output] # DFF: not combinational (Day 31)
def settle(self, changed_nets):
"""Event-driven: re-evaluate only gates whose inputs changed, repeat."""
queue = list(changed_nets)
while queue:
net = queue.pop(0)
for g in self.fanout.get(net, []):
if g.op == "DFF":
continue # sequential: handled on clock edge
new = self.eval_comb(g)
if new != self.values[g.output]:
self.values[g.output] = new
queue.append(g.output) # its change may ripple onwardThis is a toy Verilator
Event-driven propagation — re-evaluate only what changed, ripple until stable — is the core algorithm of real simulators. When you meet Verilator in Stage 2 (it *compiles* your RTL for speed) you'll appreciate exactly what problem it's solving, because you built the naive version first.
Key terms
- Netlist
- A list of gates and the nets connecting them — the structural description of a circuit.
- Event-driven simulation
- Re-evaluating only the gates whose inputs changed, propagating changes until the circuit settles.
- Fan-out map
- A lookup from each net to the gates it drives, used to find what to re-evaluate on a change.
- Combinational settle
- Iterating gate evaluations until no net value changes further.
Progress for Day 30
In the event-driven simulator, why re-evaluate only the gates driven by a changed net, rather than every gate each time?