Rev A rework: 10 kΩ in series with the eight data-out driver pull-ups
discrete6502 — generated from gen/board_routed_golden.kicad_pcb.
Background and measurements: “Driver contention” in project-plan.md,
sim/driver_contention.sp (the defect) and sim/revb_driver.sp
(the fix, simulated).
Why
Ratioed NMOS needs the pull-down several times stronger than its load. The transform turned the
1,018 depletion loads into 10 kΩ resistors — correct — but left the eight data-bus output
drivers with a BSS138W as the load against a BSS138W as the pull-down: a 1:1 ratio
where the die had a deliberately weak load. Measured consequences at 5 V:
262 mA and 0.90 W in the pull-up FET, against 220 mA and
~0.3 W for a SOT-323. These eight run hot enough to fail.
The “low” is not low: 1.0–1.9 V against a 1.1–1.5 V receiver
threshold, so the stage can read HIGH when it should read LOW. The CPU may write wrong data.
They are contended 47–93% of the time, because RnWstretched holds the pull-down
on through every read while the stale dor bit holds the pull-up on.
Adding 10 kΩ in series with each pull-up restores exactly the ratio the other 1,018 nodes
already have: 0.5 mA instead of 262 mA, and a low of ~3 mV. There is
no speed cost — each of these nets drives exactly one gate (27 pF), so 10 kΩ gives
a 0.6 µs rise against a 25 µs half-cycle.
The fix is simulated, not just argued
sim/revb_driver.sp measures this exact modification on a driver taken out of
gen/netlist.json rather than an invented one — dor1 → Q401 →
n798 → Q192 → db1, the worst of the eight (90% duty), carried
two stages deep to the actual data-bus output pad, so the fix is judged by what leaves the
CPU rather than by the node the resistor sits on. Before and after, same devices, same models:
At 5 V
As built
With the 10 kΩ
Contention current
262 mA
0.499 mA — 525× less
The contended “low”
1.86 V — invalid
2.9 mV — valid
db1 rise to 1.5 V
18 ns
271 ns — 90× inside a 25 µs half-cycle
db1 fall
2.8 ns
2.7 ns — unchanged
db1 high level
3.81 V
4.38 V
Peak supply current, one cycle
346 mA
0.92 mA
The output gets stronger, not weaker — which is the opposite of what a series resistor
sounds like. Probed node by node before it was believed: db1 rising couples back into the
gate that drives it through the next FET’s Cgs (21 pF) — the ordinary bootstrap this
design already relies on. As built, the pull-up’s drain is a stiff VCC, so the instant that node is
pushed above VCC the FET conducts backwards and dumps the bootstrap charge straight into the supply.
With the 10 kΩ in the way, the charge is kept. Treat it as a bonus, not as something to depend
on — it scales with the next stage’s Cgs.
The same run also settled a question about the fallback option below. At 3.3 V with
worst-case Vth (1.5 V, the datasheet maximum), the un-reworked board’s db1
stops at 1.306 V and never reaches the 1.5 V threshold of the gate it has to
drive; reworked, it reaches 1.579 V. Two source followers in series subtract
Vth twice. So running at 3.3 V is not a way to avoid the rework — the rework is what
makes 3.3 V viable.
Where — eight sites, all on the FRONT face, in one column
The eight sites on the real board, on JLCPCB’s top-side assembly view. Magenta
ring = the SOT-323 to rework; cyan ring = pad 3, the lone VCC-side pin to lift.
They sit in one column at the right-hand edge of the datapath, 11–14 mm apart — sites 7
and 8 step 3.7 mm left of the other six, which is real and not a drawing error. Positions
come from gen/board_routed_golden.kicad_pcb; the mm-to-pixel mapping was fitted on
all 36 bond pads, worst error 0.07 mm against a 0.65 mm pad pitch. Click to enlarge.
All eight are the same part (BSS138W, SOT-323) in the same orientation (0°), with identical
copper around them. Board origin is top-left; x increases right, y increases down, matching KiCad.
Signal
FET
Pad 3 (VCC) centre
Its VCC via
Node
dor0
Q3047
220.24, 189.00
220.40, 189.75
n1325
dor1
Q401
220.24, 200.20
220.40, 200.95
n798
dor2
Q684
220.24, 214.20
220.40, 214.95
n520
dor3
Q1431
220.24, 225.40
220.40, 226.15
n42
dor4
Q242
220.24, 236.60
220.40, 237.35
n1076
dor5
Q205
220.24, 247.80
220.40, 248.55
n373
dor6
Q3238
216.54, 261.80
216.70, 262.55
n7
dor7
Q3580
216.54, 275.80
216.70, 276.55
n298
Note dor6 and dor7 sit 3.70 mm to the left of the other six. Nearest neighbouring component
at every site is 1.94 mm away, so there is working room.
What the site looks like
BEFORE — as built
AFTER — pin 3 lifted, 10k bridges
One site drawn to scale from the real board geometry (95 px/mm). Pad 1 is the gate
(dor n), pad 2 the source feeding the node, pad 3 the drain that reaches
VCC through the short track and the via below it. Pad 3 sits 1.78 mm from the other two, alone on
its side of the package — which is what makes lifting it low-risk. In the AFTER panel the leg
is off its pad, so the track to the via is dead copper (dark), and the 10 kΩ stands on pad 3
with the lifted leg soldered to its top.
Why lift rather than cut. The obvious move is to cut the track between pad 3 and its
via and bridge the gap. Measured, that track is 0.75 mm centre-to-centre but only
0.25 mm of it is bare — the rest is under the pad and the via. Worse, the via is
epoxy-filled and capped with solder mask over it, so there is no exposed copper to solder to on the
far side. Lifting pin 3 avoids both problems.
The actual copper at each site
These are renders generated from gen/board_routed_golden.kicad_pcb,
not photographs — no board exists yet. Every pad, track and via below is real board geometry, drawn
at true scale, front face, 8 × 8 mm around each target. Use them to identify the right part among
its identical neighbours before you touch anything.
Gold = copper pads and vias · brighter gold = the target FET's own pads, numbered ·
yellow tracks = VCC · blue = VSS · red circle = the pull-up FET · red bar = the 0.75 mm pad-3 track
to its VCC via · green labels = neighbouring parts · scale bar = 1 mm.
dor5 / Q205 at 220.24, 247.80 — one site at ~75 px/mm. Pad 3 (right, alone) is
the one to lift; pads 1 and 2 are 1.78 mm away on the far side of the body. The red bar is the
track running down to the VCC via — note how little of it is bare between the pad and the via.
All eight sites
dor0 — Q3047 at 220.24, 189.00dor1 — Q401 at 220.24, 200.20dor2 — Q684 at 220.24, 214.20dor3 — Q1431 at 220.24, 225.40dor4 — Q242 at 220.24, 236.60dor5 — Q205 at 220.24, 247.80dor6 — Q3238 at 216.54, 261.80dor7 — Q3580 at 216.54, 275.80
Procedure, per site
Parts: eight 10 kΩ resistors. 0402 is what the board uses (LCSC C25744) but
0603 is easier to handle and there is room — nearest neighbour is 1.94 mm away.
Tools: fine-tip iron or hot air, fine tweezers, flux, magnification, a multimeter.
Locate the part. Front face, right-hand side of the die, in the column at
x ≈ 220 mm (dor6/dor7 at x ≈ 216.5 mm). Confirm against the table above before touching
anything — every neighbour is an identical SOT-323.
Measure first. Pin 3 to a VCC bond pad should read ~0 Ω. Record it; this is
your “before”.
Lift pin 3. Flux the joint. Heat pad 3 and lift the leg clear of the pad with
tweezers, bending it slightly upward. Pin 3 is the lone pin on the right-hand side, 1.78 mm
from the other two, so neither pin 1 nor pin 2 is at risk. Do not disturb the body.
Verify the break. Pin 3 lead to VCC should now read open. If it still reads
~0 Ω the leg is still touching — re-lift.
Fit the resistor. Tin pad 3. Stand the 10 kΩ on end with its lower
termination on pad 3 and solder it. Then solder the lifted leg to the resistor's upper
termination. A short piece of fine wire between leg and resistor is fine if that is easier.
Put a slip of Kapton tape between the resistor body and the lifted leg
(done on board #1, and visible as the amber patches in the photographs). The leg is
springy and sits millimetres from a component it must not touch; the tape means the only
contact between them is the joint you make deliberately, and it stops a leg that relaxes over
time from quietly shorting the resistor out. A silently undone rework is worse than an obvious
one, because the board keeps working and just runs hot again.
Verify the fix. Pin 3 lead to a VCC bond pad should now read
10 kΩ ± tolerance. Pad 3 itself to VCC should still read ~0 Ω.
Inspect. Check the resistor is not touching pin 1, pin 2, or any neighbouring
part, and that the lifted leg is not shorting to the pad it came from.
Re-measure charge retention after the rework, not before. The clock floor
(W in the tester, or the wifi panel's find the boundary) should be measured on
the board in its final electrical state. Two reasons. First, the stall test is safer after
the fix: freezing the clock is exactly the condition that parks a pull-up and a pull-down
on together, and on these eight nets the fix drops that from 262 mA to 0.5 mA. Second,
a number taken before the fix would not be the number you carry forward — eight
drivers dissipating ~0.8 W each warm the board, and leakage roughly doubles every 10 °C,
so a pre-rework floor would read pessimistically and for a reason that no longer applies. If you do
measure both, keep both: a floor that moves after the rework is telling you the eight sites were
heating their neighbours, which is worth knowing. Either way the safety rules in
pico-controller/README.md still apply — current-limited supply, 3.3 V first,
sub-millisecond stalls ramped up.
Whole-board check when all eight are done. Re-measure VCC to VSS at the bond
pads — but read it the range-aware way. There is no resistor-only path between the
rails, so the meter reads FET body diodes and legitimately shows a few hundred ohms that
changes with the range (195 Ω / 314 Ω / 3.77 kΩ on 200 Ω / 2k / 20k on board #1). A
fault is under 1 Ω, or a value that does not move between ranges. The earlier instruction here
— “should still read high” — was wrong and was falsified on hardware on
2026-08-12.
What the current will and will not do. Measured on board #1 after this
rework: 2.3 A while executing, not the few hundred mA an earlier version of this
page predicted. That is not the rework failing. These eight are only 8 of the 164
sites carrying the same ratio error, and a thermal camera later found sixteen more on the
address path running at about 80 °C —
mapped here, with the contention duty measured for each. Expect
the same operation sixteen more times before the current comes down.
The check that does confirm these eight took is thermal, not electrical, and
it is a reasonable one: under a NOP free-run these drivers measured 91.8% contended
in simulation (a single-address run — see the caveat in tools/contention_duty.py,
which makes the exact figure soft though not the direction), so
unreworked they would burn ~7 W between them and be the hottest thing on the board by far. On
board #1 they are cold in exactly that condition. If any of the eight shows up warm
under NOPs, that site did not take — and the Kapton in step 5 exists to stop precisely that.
If you would rather not rework
Run at 3.3 V. Halves the contention current (224 mA, 0.39 W) but does not fix
it: still over the package limit, and the low level is still invalid. Worse, it is now
measured to be the tighter corner — see the 1.306 V result above. 3.3 V is
not an alternative to the rework.
Do nothing and monitor. 0.8 W in a SOT-323 is roughly a 200 °C rise. Expect
the eight pull-ups to fail, and suspect data-out corruption before they do.
Rev B.DISCRETE6502_REV_B=1 python3 tools/gen_netlist.py emits
the series resistor at 142 sites — every VCC-side FET that has a pull-down to
fight — sized per net from its own gate load, because a blanket 10 kΩ on the heavy clock
nets would give a 286 µs rise and destroy the clock. Simulated too: the clock net keeps
its level to within 2 mV and rises 25× inside a half-cycle. One caveat if it is ever
fabricated — the two 100 Ω sites (cclk, cp1) dissipate
200 mW while contended in an 0402 rated 0.0625 W, so use 0805 there. That is a
respin, not a patch.