Mainboard: routed, DRC 0, not the print candidate
The last entry ended with a decision. The breadboard is done, next is a 2-layer mainboard, power first. This one is the four days after that. There is a routed layout in KiCad with 0 DRC errors. It is not the one I am going to print, and the second half of this entry is why.
What I tried
Making the schematic one netlist. The twelve sheets had never actually been connected. Every cross-sheet label was sheet-local, so KiCad saw 122 names split per sheet, ERC reported 90 undriven inputs whose driver sat one sheet over, and a PCB ratsnest stopped at every sheet boundary. Converting them to global labels was the first job, and the proof was mechanical: the netlist after equals a name-join of the netlist before plus the fifteen CW alias pairs, pin for pin. ERC went from 477 to 2, and the real fixes underneath the label churn were small: ROM data pins typed as inputs instead of tri-state, a ‘382 ground pin typed as power out, four orphan symbols rehomed to a project library. Every symbol got a stock through-hole footprint. The draft PCB that fell out was 198 footprints dropped in sheet rows on a 374 x 524 mm outline with nothing routed.
The power sheet. I am not designing a supply. A picoPSU (24-pin ATX plug, 12 V brick behind it) gives +5 V at 6-8 A regulated to 1.5%, plus +3.3 V, +12 V, -12 V, PS_ON and PWR_OK for free. No -5 V exists on any ATX unit made since 2003, so none is drawn. The sheet is J9 (the 24-pin Mini-Fit Jr the unit snaps into), the rails to their power nets, PS_ON# to a 2-pin header. That closed the last power_pin_not_driven warning. Until this sheet the schematic had no supply on +5 V or GND at all.
The card bus. Eight 2x25 0.1-inch card-edge sockets on the core, one 50-pin table that generates the symbol (socket and edge flavours), the finger footprint and a placeholder socket footprint. Grounds bracket both buses, W0-7 on the front row, M0-15 on the back, CLK through a ‘04 buffer so no card ever sees the ‘74 output raw, and five pins named and reserved with no copper behind them: ~IRQ, ~NMI, ~DMARQ, ~DMAAK, RDY. The DIP switch, which has been “card zero” since phase E, physically left the core. Its sheet became its own project, dino_io, with an edge connector. The proof for that split is that the core and card netlists joined through the slot-0 pin numbers partition every pre-existing pin exactly as the core did before the split. ERC 0/0 on both projects.
Placement. The sheet-row draft was a bad prior. Sheets are drawn by function; nets don’t care. The first tell was PC0-15 spanning 250 mm because the two ‘245s that read the PC back onto the bus (U72, U73, phase C) sat on the MDR sheet, two rows away from the counters. So: a DIP cell grid, 14 columns at 15.24 mm and six rows sized by the tallest package in each, and simulated annealing over the cell assignment with the cost function half-perimeter wire length, CLK weighted 6x, ~CLK 4x, CLK_B 6x, the oscillator-to-divider net 6x, the reset RC node 5x. Unweighted HPWL went from 41,704 mm (sheet rows) to 32,395 mm. Every 0.1 uF sits 4 mm pad-to-pad above its chip’s VCC pin by construction. Then a hand pass: the eight OB LEDs and their 330 R resistors came off the board entirely and became a 1x8 header, J11 (“here’s an OUT, do with it what you will”), which frees the LED design and about 40 mm of board; the W park resistors moved to the top of the slot column, which is the bus terminus; reset RC and the PSU connector to the bottom right.
The slot pitch is 20.32 mm, 0.8 inch, ISA spacing, after starting at 0.7. And I had the card overhang rule wrong in the first cut of the keepout test. I forbade any part in the strip a seated card sweeps. Apple II and 5150 cards happily pass over DIPs. Only part HEIGHT matters under a card, so the test now checks that nothing taller than a DIP (the ATX connector, the electrolytic, the pushbutton, pin headers) sits in a card’s envelope. That test, test_pcb_envelope.py, is the keepout; it reads the saved board file and it is the only thing enforcing the mechanics.
Routing. Netclasses typed into KiCad’s Board Setup (Default 0.25/0.25 mm, CLK 0.3 mm on CLK/~CLK/CLK_B, PWR 1.0 mm on the four rails), typed there because KiCad owns that file and discards anything written behind its back on the next save. DSN exported with KiCad’s own pcbnew Python with the project loaded so the classes travel. Freerouting 2.4.1, headless, six runs:
run placement GND result (KiCad's count, pours on) time
1 sheet rows routed 13 open, 0 short, 10,945 tracks 58 min
2 same routed reached 1 open, SAVED 17 58 min
4 annealed stripped 0 signal open, 67 GND open, 3 short 6 min
5 run 4 seeded routed 20 GND open 15 min
6 annealed routed 0 open, 2 short, 7,708 tracks 9 min <- used
Run 6 is the board. GND pours on both layers after the SES import, 0.25 mm clearance / 0.2 mm minimum width.
What I measured
- Board: 298.85 x 222.8 mm, 2-layer, 179 footprints, about 7,400 track segments. Was 374 x 524 with 198 footprints and nothing routed.
- CLK copper after routing: CLK 338 mm across 10 loads, ~CLK 318 mm across 5, CLK_B 230 mm across 9. The envelope test guards these at +20% as a regression fence, not as physics; the per-branch stub check (~125 mm unterminated for an LS edge) needs connectivity the parser does not have yet.
- Ground on two layers: a pour alone strands 67 GND pads. Pour plus router-placed GND bridges (keep GND in the routing job) reaches every pad. B.Cu is a mesh rather than a plane, with 3,617 mm of GND as tracks. That is the 2-layer cost and it is the thing 4-layer would buy.
- kicad-cli DRC on the saved board: 0 unconnected, 0 clearance, 0 shorts. What remained was 36
starved_thermalerrors and silk warnings. - Machine draw, unchanged: 1.25-1.34 A at 5 V (bench ammeter, 09-10). Still the only power number on record.
What broke or surprised me
Freerouting saves whatever pass it was on when you stop it, and that is rarely the best one. Run 2 reached 1 unrouted at pass 28-38 and saved 17, because stopping it mid-rip-up strands whatever it had torn out. Its unrouted count is not KiCad’s either (run 1: 13 vs 2). Every short it made had the same shape: a 0.7 mm hairpin at a DIP pad exit looping through the neighbour’s exit. Fix is delete the hairpin, lay one straight segment. Five by hand.
The starved thermals were a per-layer artefact and I stepped them one at a time on purpose, as practice for the re-roll. A pad with four spokes on F.Cu and one on B.Cu still flags B.Cu. The zones had been at 0.3/0.25: the pour needed 0.85 mm of channel where the router had spaced traces for a 0.75 mm track, so it was locked out of exactly the channels it needed. Dropping to 0.25/0.2 cleared most. The rest, three moves in the order to try them: a GND jump (short track from the pad to a via on the nearest bridge on the other layer; decouplers want the short loop anyway, and a via on a through-hole board is the same plated hole as the 1,900 DIP pins); a one-layer rule area (keep-out copper fill) over a sliver the pour reaches but nothing else can, which kills the island on that layer and leaves the other layer’s spokes alone; and NOT pad connection “None”, which drops the zone on both layers and leaves a socket ground pin with no track at all unconnected. Why “Remove islands: Always” never helped: a pocket hanging off a pad’s spokes counts as connected to the pad, so the filler keeps it and DRC then reports the spokes as leading to an island, so the check is circular. 43 jump vias and one rule area later: 0 errors.
The breadboard’s power section is undocumented. When I went looking for what bulk capacitance to draw, the answer is that there are electrolytics all over the breadboards, placed sporadically and optimistically, none in the schematic. So the breadboard only shows that a power section WITH bulks works, and the schematic has none. Same rule as the 1 uF/10 uF reset capacitor in phase G: a component value is copper too.
Two additions the board has to carry that have never been built. The proposals for DMA (an 8257 on the core, fly-by, HOLD granted only at instruction boundaries, no microcode burn) and a maskable interrupt (8080-style opcode injection at the fetch, POPF/PUSHF as prerequisites, one three-ROM burn) were written against the netlist this week. Both need gates on core copper (the M driver enables, the RAM strobes, the bridge controls, the T-counter clear) that no card can reach. So Rev A either carries the hooks socketed and inert, or Rev B is a re-layout. Decision: carry them. The daughterboard option was considered and rejected for the same reason.
Re-reading that plan found a hole. “Socket empty = today’s machine” is true for the 8257 and its buffers (every output pulled to its idle level) and FALSE for the override multiplexers. An empty ‘157 socket in the ~RAM_OE_G path leaves the path open. Three in-path ‘157s and two lifted pins on U61 are where all the design risk is; the other ten packages are decoder-inert or strap-inert.
Where this lands
The rule for printing is that every unknown on the board gets a no-respin escape. A strap, a jumper, a shunt plug, a socket swap, a value change, a slower can. A respin is cheap at the fab and costs about a month.
So the DRC-0 board is a proof that the machine routes on two layers at this size. The board that prints is the re-roll of it with:
- Shunt plugs for every in-path ‘157: a 16-pin DIP header with I0-to-Y links, seated in the empty socket, so
Y = I0with zero gate delay. Three build states on one board: SHUNTED is the breadboard machine exactly; MUXED fits the HCT'157s and ’74s with the 8257 socket empty; LIVE is DMA, then INT after the burn. If the muxes eat the RAM-fetch margin at 1.024 MHz, pull the mux and seat the plug. - Jumpers on the two U61 lifts (the CET and ~MR terms), position 1 = today’s T-state clear chain character for character.
- J12, a 2x17 hook header with ground on the whole second row: CLK, ~CLK, T0, END, HALT, RESET, ~IR_LOAD out; HOLD, HLDA, AEN, INJECT, PC_UP_INH, CLKIN, RDY in; ~IRQ, IE, TC. With the ‘74 sockets empty the boundary sequencer, the only part with real design risk, gets bred on a mini-breadboard clipped to the PCB, and the same header is the logic analyzer header for the ladder.
- CLKIN header and a jumper at U20.2 with the oscillator socketed: the 500 kHz discriminator on the PCB. If 1.024 MHz misbehaves on first copper there is still a working computer to debug on. Step-clock finally has a home.
- The power section, drawn after the measurements. Inventory the breadboard’s electrolytics (board, value, rating, where on the rail, and whether it was actually seated); run the bench tasks I wrote on 09-08 and never ran (I_run, I_idle, I_halt, the rails table); buy the picoPSU and feed the BREADBOARD from it first, isasoak x3 = 0x00, so the PCB’s power section is a transcription of a working thing. Then: entry bulk plus 10 uF ceramic, one bulk per DIP row at the feed end, a fuse and a reverse Schottky, per-slot polyfuses, test points at the entry and each far corner so the rails table takes thirty seconds on the PCB too, and PWR_OK through a spare ‘14 section into the reset chain, a real power-good in place of the RC guess.
- +5 V as a grid. The current +5 V is whatever Freerouting drew, a tree. Before the re-route I lay the 1.0 mm trunks along each DIP row by hand, fed at both ends, and let the router fill signals around them. The 09-01 ground fault was 140 mV to 460 mV of offset between boards.
- Housekeeping that blocks gerbers: the slot socket is a placeholder footprint until a part is chosen; no mounting holes; a RESET-versus-CLK adjacency check on the routed board (the 09-06 wire rule); the timing sheet’s part markings, one walk of the boards.
The first milestone on Rev A is the board SHUNTED with every hook socket empty, rails at the test points under 50 mV, PROG_isa 0xB4, PROG_isasoak 0x00: the breadboard machine on a ground plane. Everything above that has a plug, a jumper or a socket as its escape, and none of it can force a respin.
Next
Putting the machine down for a bit. Pick-up point is written, the DRC-0 board and the placer scripts are committed at 29bf1ad. When it comes back up, the first thing is one walk of the boards with the bulk-cap table and the part-markings sheet in hand, then the two bench tasks, then the picoPSU. The schematic work (power section, U80-U99, the plugs and jumpers, J12, CLKIN, holes) waits on nothing but the cap values.