Local transpose and sigma–delta weight update for on-die supervised learning.
Design files, RTL, SPICE netlists and simulation scripts for the W&E paper (Part II of this
study). The paper itself is in paper/.
All results are pre-silicon. The evidence here is Python behavioural simulation, Sky130A SPICE, and a bit-faithful RTL implementation. Nothing has been fabricated.
An analog predictive-coding substrate that trains in place under three constraints usually
treated as obstacles: no per-device calibration, no reverse analog signal path, and no global clock.
The organisation the paper calls W&E keeps the weights W and the error store E in separate
populations linked along a one-way path:
- Transpose-at-source —
Wᵀδis computed on the chip that ownsW, so no weight ever leaves the die and the router holds no weights. - The leaky jug — the error store is a leaking capacitor plus a shared threshold comparator, forming a first-order sigma–delta modulator whose cumulative quantisation error is bounded independently of the number of updates. This is what lets a per-update step of 0.019 weight LSB drive a coarse 8-bit analog cell with no per-synapse digital accumulator.
On EMNIST letters with a 48-chip topology the forwards-only rule reaches 82.50% against a full-backpropagation ceiling of 82.85% on identical topology.
.
├── paper/ The paper, its sources, and its build script
├── multi_array_level3_BIGspec/ Float rig — the learning rule (Table 1)
├── multi_array_level3_backprop/ Backprop decomposition on the small topology
├── hw_buildcheck/ Ablation ladder — how the gap was closed (Sec. 7)
├── shared/sim/ EMNIST loader and quantiser shared by the rigs
└── Sky130A_16x16_4cell_jug/ THE DESIGN — sim, RTL and SPICE for the jug chip
├── sim/ Bit-faithful model (Tables 2 and 3)
├── rtl/ Synthesisable Verilog + 17 test benches
└── circuit/ Sky130A SPICE netlists and measured output
The top-level directory names are load-bearing. The simulation scripts resolve each other by
relative path (pcn_jug.py reaches ../../multi_array_level3_BIGspec for the float reference, which
in turn reaches ../shared/sim for the data loader). Renaming or flattening these directories will
break the import chain.
| file | role |
|---|---|
main_stage2_v4.pdf |
the paper |
main_stage2_v4.tex |
LaTeX source of the PDF |
main_stage2_v4.md |
editable prose twin in markdown |
main_stage2_v3.tex |
figure/equation source; build_v4.py splices the TikZ figures and numbered equations from here so numbering stays correct |
refs.bib |
bibliography |
The learning-rule evidence, in floating point, on the BIG topology: 1152 split-sign input features → 384 → 128 → 256 across 48 chips, EMNIST letters.
| file | produces |
|---|---|
pcn_bigspec.py |
the forwards-only rule — 82.50% with all hardware constraints, 82.89% with unconstrained error broadcast |
backprop_rig_big.py |
the backpropagation ceilings — 82.85% chip-factored, 89.48% dense |
big_spec.log, big_unconstrained.log, linbase_big.log |
the recorded runs, including the 77.14% linear baseline |
pcn_bigspec.py is also imported as a module by the bit-faithful rigs, which take their topology,
weight-code constants and EMNIST features from it. It is the single definition of the network.
Quantises the weight cell, the activations, the error path and the update, and carries the jug.
| file | produces |
|---|---|
pcn_jug.py |
81.96% clean, against an 82.13% float ceiling for the same model; all of Table 2's robustness arms |
pcn_jug_skew.py |
Table 3 — forward/transpose weight skew |
jug_physical_spec.py |
translates the model's jug parameters into circuit quantities |
RESULTS.md, SKEW_RESULTS.md |
the recorded evidence, with the noise-floor caveat stated |
run_skew_focused.sh, run_skew_escalate.sh |
the skew sweeps as run |
*.log |
raw run logs |
Read RESULTS.md before quoting any number from this rig. The run-to-run noise band is ≈0.7 pp
and is not only seed variation — the float matmuls and the classifier fit are BLAS-dependent, so
the same configuration at a different thread count sums in a different order. Differences below
about 1 pp are not results.
Reproduction (defaults are the working design point: --jug_theta 8, --jug_leak 0, --agc rms):
cd Sky130A_16x16_4cell_jug/sim
python3 pcn_jug.py # clean devices -> ~81.96%
python3 pcn_jug.py --float_ref # float ceiling -> ~82.13%
python3 pcn_jug.py --jug_sign_err 0.20 # comparator wrong 20% -> ~81.62%
python3 pcn_jug.py --jug_theta_spread 2.0 # theta mismatch x2 -> ~81.20%
python3 pcn_jug.py --jug_tau 100 --jug_tau_spread 3.0 # leakage -> ~81.53%
python3 pcn_jug.py --jug_e_fwd 1.0 # counter-test: E into the MAC (degrades)
python3 pcn_jug.py --jug_multifire # counter-test: per-synapse comparator (collapses)
./run_skew_focused.sh # Table 3
# with the SPICE-measured, non-linear code->weight map instead of the linear
# assumption (Sec. 3.2) -> ~81.46%
python3 pcn_jug.py --w_map ../circuit/output/w_map.csvThe paper reports (Sec. 7) that the hardware gap was closed by elimination rather than hypothesis: every quantiser was ablated individually and each was innocent, which is what identified the update path as the one component never isolated. This directory is that record.
| file | role |
|---|---|
pcn_hw.py |
the ablation rig; --agc rms reproduces the 75.25% naive-write baseline that the jug improves on |
THE_JUG.md |
how the jug was arrived at |
HW_BUILD_CHECK.md |
the buildability audit |
RTL_RECONCILIATION.md |
model-versus-RTL reconciliation |
abl_*.log, fb_*.log, r2_*.log, hw_*.log |
the individual ablations |
Synthesisable Verilog with a full regression. All 17 test benches elaborate and pass:
cd Sky130A_16x16_4cell_jug/rtl
./run_all_tb.sh # 17 pass, 0 fail
./run_all_tb.sh tb_jug # substring filterRequires iverilog (-g2012). The directory is self-contained — the runner uses -y ., so no
external library path is needed.
New or changed for the jug design:
| module | role |
|---|---|
jug_ctrl.v |
the swept comparator, the ±1 weight-code increment, the fire one-shot |
wgt_lut.v |
the pre-distortion LUT (code → 10-bit DAC drive); loadable, so it is also the per-die calibration hook |
cap_array.v |
MAC is W only — Ce is out of the signal path; absorb subtracts θ rather than discharging |
pcn_transpose.v |
transpose-at-source; reproduces the model within ±1 LSB |
refresh_ctrl.v |
continuous refresh — the absorb→save→sync coherence cycle collapses |
RTL_STATUS.md records what changed against the earlier design and what was ported unchanged.
A note on the regression's design, since it is deliberate: a test bench counts as failed if it does not elaborate, if its output contains a failure marker, or if it never prints a pass marker. Silence is a failure. This runner was written after an earlier claim that "every block test bench passes" turned out to rest on test benches that could not fail.
The two transistor-level results the paper's central claims rest on, plus the weight-cell characterisation.
| file | claim it supports |
|---|---|
tb_jug_fire.spice, output/jug_fire.csv |
the residue subtraction removes a fixed charge Q = It independent of capacitor voltage — the design's single tight analog specification |
tb_jug_comparator.spice, jug_compare.spice, output/jug_cmp_dc.csv |
the window comparator settles within 0.75 mV, dead zone ≈0.2 µV, in 2.5 ns — the component the theory allows to be loose is in fact precise |
sweep_mn3w.spice, analyse_weight.py, output/w_transfer.csv, output/w_map.csv |
the weight cell is non-linear and non-monotonic above mid-range; sizing plus a pre-distortion table restores monotonicity |
weight_dac_10b.spice, tb_weight_dac_10b.spice, output/dac10b.csv |
the pre-distorted weight DAC |
tb_wgt_zero_jug.spice, analyse_wgt_zero.py, output/wgt_zero_jug.csv |
the zero-weight operating point (WGT_ZERO 132 → 117) |
THE_WEIGHT_IS_NOT_LINEAR.md |
the finding, and why a single-operating-point check could not see it |
SPICE_RESULTS.md, PHYSICAL_SPEC.md |
measured results and the circuit specification |
THE_WEIGHT_IS_NOT_LINEAR.md is worth reading even if you skip the rest: the effective weight peaks
near mid-range and falls above it, so the entire positive weight range was compressed and, at the
extreme, inverted. Every test bench that pinned the weight voltage to a single healthy value passed
regardless. Characterise the range, not the operating point.
output/jug_fire.csv is the largest file in the repository (≈9.7 MB); it is the raw transient trace
behind the fixed-charge claim.
DESIGN.md is the design record for the jug chip. INTERCONNECT_PROTOCOL.md and
ROUTER_PROTOCOL.md specify the inter-chip link, including packets, the state machine, dormancy,
discovery, registers, electrical and timing. As the paper's limitations state, this protocol is
specified but not yet realised across the heterogeneous process nodes the architecture
anticipates.
| paper | claim | produced by |
|---|---|---|
| Table 1 | 82.50% forwards-only, all hardware constraints | multi_array_level3_BIGspec/pcn_bigspec.py |
| Table 1 | 82.85% backprop, chip-factored / 89.48% dense | multi_array_level3_BIGspec/backprop_rig_big.py |
| Table 1 | 77.14% linear baseline on 1152 features | multi_array_level3_BIGspec/linbase_big.log |
| Table 1 | 64.09% prior fold/absorb rule | recorded in Sky130A_16x16_4cell_jug/sim/RESULTS.md |
| Sec. 6.3 | 81.96% bit-faithful, 82.13% float ceiling | Sky130A_16x16_4cell_jug/sim/pcn_jug.py |
| Sec. 6.3 | 75.25% — the same rule written naively to the 8-bit cell | hw_buildcheck/pcn_hw.py (--agc rms); see HW_BUILD_CHECK.md |
| Sec. 3.2 | 81.46% with the measured weight curve and pre-distortion | pcn_jug.py --w_map ../circuit/output/w_map.csv; see circuit/THE_WEIGHT_IS_NOT_LINEAR.md |
| Table 2 | leakage, θ mismatch, comparator sign errors | Sky130A_16x16_4cell_jug/sim/pcn_jug.py (flags above) |
| Table 3 | forward/transpose weight skew | Sky130A_16x16_4cell_jug/sim/pcn_jug_skew.py |
| Sec. 6.5 | fixed-charge pulse; comparator margin | Sky130A_16x16_4cell_jug/circuit/ |
| Sec. 6.5 | transpose within ±1 LSB, residue within 2 µV | Sky130A_16x16_4cell_jug/rtl/ |
| Sec. 7 | every quantiser innocent under ablation | hw_buildcheck/ |
The EMNIST feature caches and the trained BIG weights are not in this repository — together they are roughly 645 MB. They are regenerated, not downloaded:
multi_array_level3_BIGspec/l0_cache_emnist/— the L0 (uncentered-PCA) features, built on first run from the EMNIST letters CSV.multi_array_level3/weights_big_emnist/— the trained BIG weights; the directory is created automatically.
You will need the EMNIST letters dataset (Cohen et al., 2017) in CSV form. shared/sim/pcn_mnist.py
loads it and honours the DATASET environment variable (DATASET=emnist_letters).
Expect the first run to spend significant time building the L0 cache before training begins.
| for | needs |
|---|---|
| Python rigs | Python 3, NumPy; backprop_rig*.py additionally needs PyTorch |
| RTL regression | iverilog with -g2012 |
| SPICE | ngspice and the Sky130A PDK |
| Paper rebuild | pandoc (3.1.3 tested), a TeX distribution with IEEEtran |
Files are copied verbatim from the working tree. Some of the copied .md records therefore
contain relative cross-references written against the original layout; the directory names preserved
here resolve most of them, and the table above is authoritative for which file produces which number.
The design records in this repository are working documents, not marketing. They contain retractions,
failed predictions and superseded conclusions, kept deliberately — THE_WEIGHT_IS_NOT_LINEAR.md and
RESULTS.md in particular record results that overturned earlier claims of ours. Where a document
disagrees with the paper, the paper is the considered version and the document is the trail.
The largest known accuracy deficit is not the learning rule but the chip factoring, which costs 6.6 pp against a dense network of the same widths. That is a question of width and connectivity, and it is open.
Source-available, not open source. Full detail in NOTICE.md.
| you are | licence | what you may do |
|---|---|---|
| academic, public research, charity, government, or an individual on a noncommercial project | PolyForm Noncommercial 1.0.0 | use, modify, redistribute — for noncommercial purposes |
| a commercial company | PolyForm Free Trial 1.0.0 | evaluate only, under 32 consecutive days, no redistribution |
| a commercial company wanting more | contact the licensor | negotiated terms |
Both licence texts are unmodified canonical PolyForm texts. No downstream commercial use is possible without permission: the Noncommercial licence permits redistribution only for noncommercial purposes, so commercial rights cannot be acquired from an intermediary.
The paper itself is not under these licences. paper/main_stage2_v4.pdf and its sources are ©
Saul Dobney, all rights reserved, subject to normal academic citation and fair use. The Sky130A PDK,
EMNIST, and all third-party tooling are separately licensed by their own authors and are not
included here.
Part I of this study https://github.com/dobneyresearch/PredictiveCodingNetworks_AnalogVLSIdesign presents the analog cell and its unsupervised learning; this repository
accompanies Part II. See paper/refs.bib.
Correspondence: saul.dobney@dobney.com
Architectural direction and design decisions are the author's. The simulators, SPICE netlists and RTL were implemented with Claude Code (Opus and Fable models), whose contribution was the rate at which code and tests could be produced to explore the topology, algorithm and parameter space and to characterise the physics.