The core as a chip: z80_top, hardened on its own, as a hard macro in a ring of I/O pads,
each pin's pad on the side of the die where the Z80 has its own. The layout shows the metal stack, bottom
metal blue to top metal yellow; the clock and power picture the clock in green -- the CLK pad, every clock
wire and buffer -- over the power rings, stripes and rails (core supply red, ground blue; a split I/O
supply amber and teal) and the supply pads in their net's colour; the block map every cell by the Z80
block it was synthesized in. Where a chip has been simulated at transistor level -- its layout extracted
to transistors and wires and run in ngspice (asic/spice)
-- its pins are shown under it as a logic analyser shows them.
The timing above is OpenSTA's, from the PDKs' Liberty models. Here the chips run as
transistors, in ngspice with the PDKs' own netlists and transistor models, against the NMOS Z80
datasheet's test conditions (asic/spice).
The whole chip, GlobalFoundries GF180MCU
The chip's layout extracted with Magic to its transistors and their wiring, and run in
ngspice at each corner (tt, ss, ff): power-up, RESET, and a short program
-- a memory read, a memory write, an I/O write and read -- at 4 MHz with 15 ns edges, its outputs into
100 pF (chip.py; hours, so run now and then and committed). Its pins are
checked against the RTL at every clock edge after RESET, and the cycles measured as the Z80 manual
draws them; the figures below are each corner's: the switch over them changes the corner in place, the dimensions too.
The NMOS Z80 takes an NMI pulse of any width -- TwNMI, 80 ns at 4 MHz, is under half a
clock -- not only one a clock edge sees: a flip-flop clocked by the NMI pin itself catches it and holds it
for the core until the next rising CLK edge, which clears it
(z80_top.v). Here it is cut out of the GF180 7-track
chip, from the NMI and CLK pins to the flip-flops -- the pads, the clock tree to its leaf, the cells as Magic
extracts them from the PDK's layouts, on the routed chip's wiring -- and run at each corner with six pulses
(nmi.py).
the six cases, ttA: an 80 ns NMI pulse (TwNMI) in the low half of the clock, ttB: a 20 ns pulse, a quarter of TwNMI, ttC: NMI falling 5 ns before a rising CLK edge, ttD: NMI falling 5 ns after a rising CLK edge, ttE: two short pulses before one rising edge, ttF: a second pulse while the first is being cleared, tt
The pads
Every pad cell the chips use, from the PDK's own netlist with its transistor models, at the
corners the chips are signed off at (pads.py): the outputs into 1–250 pF, the
data bus's tri-state pads turning on and floating, the inputs on edges up to 120 ns, and the Schmitt-trigger
input CLK and RESET take. Checked in every run against the committed results; their Liberty files
replace the PDKs' own in the chips' pin-timing checks
(pin_timing.py).
outputs: edges into 1–250 pF, and their drivethe data bus: turning on, and floatinginputs: pin to core on edges up to 120 ns, and where they switchCLK and RESET: the Schmitt-trigger input
outputs: edges into 1–250 pF, and their drivethe data bus: turning on, and floatinginputs: pin to core on edges up to 120 ns, and where they switch
ASIC core layouts
The bare core (no pad ring), RTL to GDS with LibreLane. The pictures are drawn from the GDS
and the DEF: the layout shows the cell rows and the metal stack, bottom metal blue to top metal yellow; the
two cell maps show every standard cell, coloured by kind and by the Z80 block it was synthesized in.
BASIC computer: NASCOM BASIC 4.7 on the board's serial console. Tiny BASIC: the same computer
with 1K Tiny BASIC. Chip: the board as a Z80 replacement, the bus on its pins. Each board's README says how to program it.
cfast is the C model generated into a phase engine: every half clock the same pins as the model
and the RTL (make cfast_identity), at the speed an emulator needs. Here it runs against four other C Z80
emulators on the same 50 million ZEXDOC instructions, the best of 5
rounds of CPU time on GitHub's runner (AMD EPYC 9V74 80-Core Processor): the latest ci.yml run on main @ bfdb6a9,
2026-11-13 04:11 UTC. Every push runs it; how, and what the columns mean:
cfast/BENCHMARK.md.
Emulator
Sees every
ZEXDOC Minstr/s
Z80 clock
Against cfast
What it is
rz80 cfast, z80f_run
half clock
50.8
411 MHz
1.00×
the phase engine generated from the C model's timing tables, steps back to back with the bus inlined (cfast/)
rz80 cfast, z80f_tick
half clock
10.6
86 MHz
0.21×
the same steps, one half clock per call, the pins in a word
rz80 C model
half clock
4.2
34 MHz
0.08×
the reference model the RTL is checked against (cmodel/)