HDL Generation + Hardware Safety¶
Two cooperating paths out of the Python design space and into silicon:
- Verilog / SystemVerilog emission —
VerilogGeneratorconverts a Python description of an SC network (dense SC-layer instances, neuron cores, LFSR encoders, popcount trees, event-driven AER) into a synthesisable top-level module. - SPICE emission —
SpiceGeneratorconverts a NumPy weight matrix into a memristor-crossbar SPICE netlist for analogue simulation and post-layout verification. - Formally grounded safety RTL — a hand-written
neuro_safe_monitorSystemVerilog module with six runtime invariants, each of which is the mirror of a theorem insafety_bounds.lean(see Formal Proofs). An OpenROAD ASIC-flow driver pushes the monitor (or any user SV) through Yosys synthesis + optional OpenROAD place-and-route.
from sc_neurocore.hdl_gen import VerilogGenerator, SpiceGenerator
1. Mathematical formalism¶
1.1 Q8.8 fixed-point number line¶
All monitor signals are Q8.8 (8 integer, 8 fractional), giving
$$ x_{\text{Q8.8}} = \lfloor x \cdot 2^{8} \rfloor, \qquad x \in \bigl[-128,\; 128 - 2^{-8}\bigr], \qquad \Delta = 2^{-8} \approx 0.0039. $$
The sign-extended 16-bit representation wraps at $2^{15}$; the monitor
treats probe_scc_numer as signed, everything else as unsigned. Parameter
defaults correspond to:
MAX_CURRENT = 16'h7FFF→ $+127.9961$,MAX_VOLTAGE = 16'hC000→ $-16384/256 = -64.0$ in the sign-extended reading, used as the upper bound on the saturation sign-magnitude,COHERENCE_LIMIT = 16'h0100→ $+1.0$,SC_DENOM = 16'h0100→ stream length $N = 256$,LIF_V_MAX = 16'hC000→ same upper bound on the LIF membrane.
1.2 Safety invariants (SystemVerilog ↔ Lean)¶
The monitor's six properties each latch a 1-bit violation flag when
true; any of the seven Boolean literals below asserts hardware_halt:
$$ \begin{aligned} [P1]\; & v_{\text{cv}} = (I > I_{\max}) \vee (V > V_{\max}), \ [P1]\; & v_{\text{coh}} = (\mathrm{coh} < \Theta), \ [P2]\; & v_{\text{mono}} = (\mathrm{coh}{t} < \mathrm{coh}), \ [P3]\; & v_{\text{prec}} = (k > N), \ [P4]\; & v_{\text{sc+}} = (a \oplus b > N), \ [P5]\; & v_{\text{mem}} = (V_{\text{mem}} > V_{\max}), \ [P6]\; & v_{\text{scc}} = (|\eta_{\mathrm{SCC}}| > d_{\mathrm{SCC}}). \end{aligned} $$
[P1–P2] correspond to the Lean theorems monitor_soundness and
safe_transition (pure-core Lean 4, proved). [P3–P6] correspond to
three axiomatised theorems (sc_precision_numerator_bound,
sc_add_preserves_range, scc_bounded) for which the Mathlib proof
roadmap is documented in safety_bounds.lean; [P6] is additionally
proved constructively at the hardware level by the absolute-value
computation on line 87 of the monitor.
1.3 Popcount tree latency¶
For an $N$-bit stream, the popcount tree has depth $\lceil \log_{2} N \rceil$ — with $N = 256$ that is 8 pipeline stages. At a clock period $T_{\text{clk}}$ the popcount result lags the input by
$$ t_{\text{pc}} = \lceil \log_{2} N \rceil \cdot T_{\text{clk}}. $$
This is one of the input probes to [P3], so the monitor's end-to-end
response time is bounded by $t_{\text{pc}} + t_{\text{mon}}$ where
$t_{\text{mon}} \leq 1$ clock cycle. Absolute nanosecond figures
depend on the PDK's cell delays and are emitted by OpenROAD's
report_checks; they are not claimed here without a measured run.
1.4 SPICE crossbar conductance mapping¶
SpiceGenerator.generate_crossbar(weights, …) maps weights $w_{ij} \in
[0,\,1]$ to memristor conductances
$$ G_{ij} = G_{\mathrm{off}} + w_{ij} \cdot (G_{\mathrm{on}} - G_{\mathrm{off}}), \qquad R_{ij} = 1 / G_{ij}, $$
with $G_{\mathrm{on}} = 100\,\mu\mathrm{S}$ (10 kΩ) and
$G_{\mathrm{off}} = 1\,\mu\mathrm{S}$ (1 MΩ). Each row drives an
independent voltage source (Vin_r) and each column ties to a 1 kΩ
load resistor (Rload_c), giving a column voltage
$$ V_{\text{out},c} = \sum_{r} V_{\text{in},r} \cdot \frac{R_{\text{load}}} {R_{r,c} + R_{\text{load}}}, $$
which is the analogue MAC (multiply-accumulate) that the crossbar implements physically.
2. Theory (why this particular design)¶
2.1 Separate compilers for synth vs analogue¶
The :class:VerilogGenerator is intentionally thin (~90 LOC) because
the heavy lifting lives in the 54 hand-written Verilog cores under
the repo-root hdl/ tree (e.g. sc_dense_layer_core.v,
sc_bitstream_encoder.v, sc_aer_router.v, sc_aer_priority_queue.v,
sc_lif_neuron.v,
sc_firing_rate_bank.v, plus 11 matching formal-property files under
hdl/formal/). The Python generator wires the pre-verified cores
together by name; it does not try to synthesise novel RTL on the
fly. This separation keeps the RTL part verifiable (the cores each
have their own testbench) and the Python part trivial (string
templating). Under src/sc_neurocore/hdl_gen/safety/ the repo
additionally ships two SystemVerilog files — safety_monitor.sv and
its testbench — which is what the neuro_safe_monitor described in
the rest of this page refers to.
2.2 Formal-spec ↔ RTL 1:1 correspondence¶
Every property the monitor checks has a named Lean theorem. Crucially,
the monitor's expression is the same shape as the theorem's
conclusion — e.g. v_monotone = (probe_coherence < prev_coherence)
is the negation of monotone_coherence (c1 c2 : Q8_8) : c2 ≥ c1.
This makes it straightforward to audit the RTL against the proofs by
diff, and it is a precondition for future work that would turn the
correspondence into a machine-checked bridge (SymbiYosys + SVA → Lean).
2.3 Sticky violation flags¶
violation_flags are latched with |=-style sticky behaviour; once
a property has fired, it remains set until rst_n deasserts the
register file. This mirrors the way aviation flight-control monitors
behave (Rushby 1993): a single violation must not be "washed out" by a
subsequent good cycle — the safety-case analysis depends on every
violation being observable.
The precision-overflow trap follows the same fail-observable rule for
mixed-precision datapaths. sc_precision_overflow_trap exposes both
trap_event_vector/trap_event, which mirror accepted overflow lanes in
the same cycle, and trap_vector/trap_latched, which retain every lane
until the host asserts clear_trap or reset. Clear and reset dominate
concurrent overflow pulses, so host intervention cannot accidentally
re-latch stale saturation telemetry. Optional
SC_NEUROCORE_ASSERTIONS properties bind the no-silent-overflow and
sticky-latch contracts for formal or simulation audit runs.
Live-control parameter banks are generated from MMIOUpdateSpec with
generate_live_parameter_bank(...). The emitted AXI4-Lite RTL uses
BRAM/distributed RAM style hints per bank, fixed control/status register
addresses, staged low/high write-data registers, CRC32-guarded shadow loads,
explicit apply and rollback pulses, checksum-mismatch pulses, flattened
active-only parameter_words output, and host-visible trap clear/status
signals. It also derives sticky staged-overflow, staged-underflow, and
CRC32-mismatch traps before shadow loading, and latches invalid bank/entry
selection as trap bit 0x8 plus read-only bank writes as trap bit 0x10, so
malformed MMIO payloads cannot truncate into active coefficients, bypass the
update guard, mutate calibration/read-only constants, or masquerade as a loaded
shadow update. This lets a
deployed design hot-swap weights or phase-coupling
coefficients while keeping the precision and trap contracts auditable.
The same generated core rejects partial write strobes as trap bit 0x20 and
returns a write error before any control or staged-data register is updated,
matching the default supports_partial_write=False schema contract.
Invalid active-readback bank or entry selections return a bus error and latch
the sticky invalid_selection trap, preventing host verification code from
confusing an invalid readback with a committed zero-valued coefficient.
Successful shadow loads also latch the accepted bank and entry index. Apply and
rollback use that latched identity, preventing post-load writes to bank_select
or entry_index from redirecting an in-flight coefficient update.
The local regression artefact
benchmarks/results/local_python_2026-06-04_live_control_updates.json records
the generated update-sequence timing, static RTL regeneration timing, and
overflow/underflow trap-capture simulation under recorded process affinity; it
is not a production throughput claim.
2.4 Nanosecond response budget¶
hardware_halt is a pure combinational OR of the seven violation
signals, latched on the next clock edge. The worst-case latency from
any input signal going bad to hardware_halt rising is therefore one
clock period plus the fan-in delay of the combinational OR tree.
Closed-loop f_max on a real PDK remains to be measured — the
generic-cell synth run in §7 does not produce a mapped critical
path number. Once run against SKY130 hd (or comparable) Liberty,
we expect the combinational path to stay well under the SC-tile
clock period (typically 2–4 ns at 250–500 MHz), but that is a
pending measurement, not a claim.
Either way, this is three to four orders of magnitude faster than the
~500 µs loop of the Python
:class:sc_neurocore.safety_cert.stochastic_doctor.StochasticDoctor
runtime check. The two layers are complementary: the hardware monitor
catches single-cycle excursions; the Python doctor catches slow
statistical drift.
2.5 OpenROAD vs commercial tools¶
The flow driver supports both "Yosys only" (always available) and "Yosys + OpenROAD" (optional) modes. OpenROAD is chosen over commercial PnR because (a) it is open-source and reproducible inside Docker, (b) the safety-monitor module is small enough that OpenROAD's gate counts and PPA (power-performance-area) results are directly comparable to commercial tools on this design size, and (c) the provenance chain is end-to-end inspectable — an auditor can re-run every step.
2.6 SPICE as a sanity layer, not a specification¶
The memristor-crossbar netlist is emitted from Python so that the same weight matrix used for the SC network can be pushed through analogue SPICE and the two outputs compared. It is not the system's source of truth — the Q8.8 / SC stream is — but it serves as a ground-truth cross-check on the post-layout behaviour of mixed-signal tiles.
3. Position in the pipeline¶
┌─────────────────────┐ ┌───────────────────────┐
│ Python SC network │──────▶│ VerilogGenerator │
│ (layers + cores) │ │ (string templating) │
└─────────────────────┘ └──────────┬────────────┘
│ │
│ ▼
│ top.sv + cores/*.sv
│ │
│ ▼
│ ┌──────────────────┐
│ │ neuro_safe_monitor│◀── formal.md theorems
│ └─────────┬────────┘
│ │
▼ ▼
┌─────────────────┐ ┌──────────────┐
│ SpiceGenerator │ │ run_asic_ │
│ memristor x-bar │ │ flow.sh │
└─────────────────┘ └──────┬───────┘
│ │
▼ ▼
analogue .sp netlist Yosys synth → OpenROAD PnR
- Upstream. The :class:
VerilogGeneratoris called by theOrganismEmitterinevo_substrate.mdwhenever a fit organism needs hardware deployment. - Downstream. The generated SV feeds into the ASIC flow driver; the safety monitor hooks every tile's probe bus unconditionally.
4. Features¶
- Python-driven top-level Verilog emission.
- 46 hand-written Verilog cores under
hdl/(dense SC layer, LFSR, AER router, popcount tree, bitstream encoder, LIF neuron, firing- rate bank, AXI-Lite cfg, DMA controller, …) plus 8 formal-property files underhdl/formal/, each with its own testbench. - Equation-to-Verilog compiler for arbitrary ODEs (used by the HH, Izhikevich, FitzHugh-Nagumo tiles).
- 6-property runtime safety monitor mirroring Lean 4 theorems.
- Adversarial testbench (
tb_safety_monitor.sv) that forces every property to fire. - Sticky per-property violation flags.
- Nanosecond-budget
hardware_haltoutput. - OpenROAD / Yosys ASIC-flow driver with optional Docker fallback.
- Memristor crossbar SPICE netlist emitter with configurable $G_{\mathrm{on}}$ / $G_{\mathrm{off}}$ / load resistance.
5. Usage¶
5.1 Emit a 3-layer SC network¶
from sc_neurocore.hdl_gen import VerilogGenerator
gen = VerilogGenerator(module_name="my_sc_net_top")
gen.add_layer("Dense", "l1", {"n_neurons": 32})
gen.add_layer("Dense", "l2", {"n_neurons": 32})
gen.add_layer("Dense", "l3", {"n_neurons": 10})
rtl = gen.generate()
gen.save_to_file("build/my_sc_net_top.sv")
Emits a module with clk, rst_n, input_bus[7:0], output_bus[7:0]
and three sc_dense_layer_core instances chained via 8-bit wires.
5.2 Synthesise with the safety monitor¶
cd src/sc_neurocore/hdl_gen/openroad_flow
./run_asic_flow.sh # default: safety_monitor.sv
./run_asic_flow.sh --target my_sc_net_top.sv # point at generated RTL
./run_asic_flow.sh --docker # run through the OpenROAD image
Outputs:
build/synth/— Yosys synthesis results (gate-level .v, stats).build/reports/— area, timing, cell-utilisation.
Real Yosys 0.33 run on the default monitor design (synth command,
generic cell library — no PDK mapping):
=== neuro_safe_monitor ===
Number of wires: 333
Number of wire bits: 493
Number of public wires: 14
Number of cells: 347
$_ANDNOT_ 104 $_AND_ 2 $_DFFE_PN0P_ 1
$_DFF_PN0_ 22 $_MUX_ 15 $_NAND_ 17
$_NOR_ 12 $_NOT_ 18 $_ORNOT_ 17
$_OR_ 92 $_XNOR_ 14 $_XOR_ 33
Wall: 0.25 s (Yosys 0.33 + abc)
Those are the exact numbers emitted by
yosys -p "read_verilog -sv .../safety_monitor.sv;
hierarchy -top neuro_safe_monitor;
synth; stat"
on 2026-04-20. Mapping to SKY130 hd (for tape-out area / timing)
requires dfflibmap -liberty + abc -liberty with a Liberty file
that is not bundled with Yosys Debian — install the sky130_fd_sc_hd
PDK and re-run the OpenROAD flow driver to get PPA numbers.
5.3 Emit a memristor-crossbar SPICE netlist¶
import numpy as np
from sc_neurocore.hdl_gen import SpiceGenerator
W = np.random.default_rng(7).random((16, 16))
SpiceGenerator.generate_crossbar(W, "build/xbar_16x16.sp")
Example generated block:
* Memristor Crossbar 16x16
.PARAM VDD=1.0
Vin_0 in_0 0 DC 0.0
...
R_0_0 in_0 out_0 12345.67
R_0_1 in_0 out_1 56789.01
...
Rload_0 out_0 0 1k
...
.END
6. API reference¶
6.1 VerilogGenerator¶
| Method | Purpose |
|---|---|
__init__(module_name) |
Names the top-level module. |
add_layer(layer_type, name, params) |
Appends a Dense / LFSR / AER / popcount layer spec. |
generate() -> str |
Returns the top-level Verilog source as a string. |
save_to_file(path) |
Writes generated Verilog to disk; OSError raised on failure. |
6.2 SpiceGenerator¶
| Method | Purpose |
|---|---|
generate_crossbar(weights, filename) (static) |
Emits <filename>.sp with sources, memristors, loads. |
6.3 neuro_safe_monitor (SystemVerilog)¶
| Port / parameter | Direction | Width | Purpose |
|---|---|---|---|
MAX_CURRENT |
param | 16 | Q8.8 current cap |
MAX_VOLTAGE |
param | 16 | Q8.8 voltage cap |
COHERENCE_LIMIT |
param | 16 | Q8.8 floor for [P1] |
SC_DENOM |
param | 16 | SC stream length $N$ |
LIF_V_MAX |
param | 16 | upper bound for LIF membrane |
clk, rst_n |
in | 1 | standard |
probe_current |
in | 16 | [P1] |
probe_voltage |
in | 16 | [P1] |
probe_coherence |
in | 16 | [P1/P2] |
probe_popcount_k |
in | 16 | [P3] |
probe_sc_add_result |
in | 16 | [P4] |
probe_membrane |
in | 16 | [P5] |
probe_scc_numer |
in | 16 (signed) | [P6] |
probe_scc_denom |
in | 16 | [P6] |
hardware_halt |
out | 1 | asserts on any violation (sticky) |
violation_flags[5:0] |
out | 6 | one sticky bit per property |
6.4 ASIC-flow driver (run_asic_flow.sh)¶
| Flag | Purpose |
|---|---|
--target <file.sv> |
Override the default safety_monitor.sv target. |
--docker |
Run the full Yosys + OpenROAD stack in the openroad/flow image. |
| (no flag) | Run Yosys synthesis only; skip OpenROAD if the binary is missing. |
7. Verified benchmarks¶
The HDL subsystem is not latency-critical on the Python side — the heavy lifting runs once at synthesis time. Still, we measure the three Python entry points for repeatability:
| Operation | Throughput | Latency |
|---|---|---|
VerilogGenerator.generate (3-layer top, in-memory) |
281 822 gen/s | 3.55 µs |
SpiceGenerator.generate_crossbar (16×16, disk write) |
2 551 gen/s | 392 µs |
SpiceGenerator.generate_crossbar (64×64, disk write) |
231 gen/s | 4.33 ms |
yosys synth; stat on safety_monitor.sv |
4.06 runs/s | 247 ms |
Yosys stat report (Yosys 0.33, default abc mapping to generic
cell library — no PDK):
| Metric | Value |
|---|---|
| Wires | 333 |
| Wire bits | 493 |
| Public wires | 14 |
| Cells | 347 |
DFFs ($_DFF_PN0_) |
22 |
DFF-enable ($_DFFE_PN0P_) |
1 |
Max combinational depth (reported by abc) |
not emitted without liberty |
Interpretation.
- The Python emitters are negligible on the design-time path: one
3-layer top costs 5 µs, one 64×64 memristor netlist costs 4 ms
(dominated by
open(..., "w")syscalls, not the string build). - The full
synth; statflow on the monitor completes in ~250 ms cold from shell, so the safety-monitor synth gate fits comfortably in a pre-commit hook budget. - Cell count (347) is ~2.5× the DFF count; the majority are combinational
AND-NOT / MUX / OR terms implementing the seven Boolean violation
conditions and their sticky-flag muxes. That matches the design: 6
properties × ~50 gates each, plus the six 1-bit sticky registers
and the 16-bit
prev_coherenceregister (22 DFFs total = 16 + 6). - Mapped timing (f_max, critical path ns) is not emitted without a
Liberty file — those numbers appear only after
abc -liberty <lib>. The claim that the monitor "closes timing at ≥500 MHz" is therefore deferred to the real PDK run; the current release gate only asserts the synth completes without errors.
Python timings are time.perf_counter deltas from
benchmarks/bench_hdl_gen.py; Yosys figures are the literal stat
output of Yosys 0.33 on Ubuntu 24.04.
8. Citations¶
- Rushby J. (1993). Formal methods and digital systems validation for airborne systems. NASA Contractor Report 4551. (Sticky-violation rationale.)
- Wolf C. et al. (2012–present). Yosys Open Synthesis Suite. https://yosyshq.net/yosys/
- Ajayi T. et al. (2019). OpenROAD: Toward a Self-Driving, Open-Source Digital Layout Implementation Tool Chain. GOMAC Tech.
- Strukov D.B., Snider G.S., Stewart D.R., Williams R.S. (2008). The missing memristor found. Nature 453:80–83. (Memristor model basis.)
- Nagel L.W., Pederson D.O. (1973). SPICE (Simulation Program with Integrated Circuit Emphasis). UC Berkeley ERL Memo ERL-M382.
- Chakrabarti C. et al. (2018). Designing for reliability in stochastic computing. ACM TRETS 11(3), Article 21. (Safety-monitor background.)
- Šotek M. (2026). SC-NeuroCore: formally grounded safety RTL. Internal report, ANULUM.
9. Cell-level breakdown — where the 347 gates go¶
The Yosys stat output in §7 lists 12 cell types; the physical reason
each category exists is worth documenting because it gives a direct
handle on future optimisation.
| Cell type | Count | What it implements in this design |
|---|---|---|
$_ANDNOT_ |
104 | violation terms of shape a & !b (range checks, coh < Θ, k > N, …) |
$_OR_ |
92 | inner OR trees of the seven violation expressions |
$_XOR_ |
33 | the probe_scc_numer < 0 ? ~x+1 : x two's-complement path |
$_DFF_PN0_ |
22 | 16-bit prev_coherence + 6-bit sticky violation_flags |
$_NOT_ |
18 | inverters for the !rst_n + signed-abs path |
$_ORNOT_ |
17 | a \| !b fragments of the monotone check |
$_NAND_ |
17 | synth-mapper output of mixed AND-OR patterns |
$_MUX_ |
15 | latch-vs-new selection of the 6 sticky violation bits on the DFF clock |
$_XNOR_ |
14 | equality comparators on the 16-bit probes |
$_NOR_ |
12 | synth-mapper output |
$_AND_ |
2 | residual AND gates |
$_DFFE_PN0P_ |
1 | hardware_halt edge-triggered register |
22 DFFs + 1 DFFE = 23 stateful cells. Of the 324 combinational cells,
~220 are directly attributable to the six violation expressions (≈37
gates per property after sharing); the remainder are the
two's-complement path for signed probe_scc_numer and the sticky-flag
muxes.
10. Reproducibility + determinism¶
Every number in §7 and §9 can be re-derived from the committed repo with a clean clone + two commands:
python benchmarks/bench_hdl_gen.py # Python emission + yosys synth
./src/sc_neurocore/hdl_gen/openroad_flow/run_asic_flow.sh # full flow
The benchmark script writes benchmarks/results/bench_hdl_gen.json
atomically; a CI check that diffs this JSON across runs flags any
regression in generation throughput. The Yosys cell counts are
deterministic — the same read_verilog; synth; stat sequence on Yosys
0.33 against the same safety_monitor.sv produces byte-identical
stat output across runs. If your Yosys version differs, the cell
breakdown will too; pin Yosys through the nixpkgs.yosys_0_33 or
apt install yosys=0.33* channel for bit-reproducible gate counts.
run_asic_flow.sh writes its artefacts into build/synth/ and
build/reports/, both of which are gitignored; the script writes a
build/run_metadata.json with host, Yosys version, commit SHA, and a
SHA-256 digest of the input .sv file so post-hoc audit of any
synthesised bitstream can verify the provenance chain.
11. Known limitations¶
- No equivalence check between Python-emitted SV and the pre-built
cores. The top-level module chains instances by name; if a user
mistyped
sc_dense_layer_core's port list in Python, synthesis will fail with a port-mismatch error rather than a helpful Python-side diagnostic. - ODE-to-Verilog compiler lives outside this module. The
VerilogGeneratorclass does not expose it yet — users who want the HH / Izhikevich / FHN RTL paths consume the pre-generated.svfiles under the repo-roothdl/tree directly. - SPICE emitter ignores wire parasitics. The netlist contains only ideal memristors and load resistors; BEOL stack capacitance and access-transistor resistance must be added by hand for sub-100 nm nodes.
- No power reporting. Yosys synthesis does not produce switching- activity estimates; real power figures require OpenROAD with a VCD trace or a commercial tool. The flow driver does not wire that yet.
- Monitor parameters are hard-coded in the RTL. Changing
COHERENCE_LIMITfrom 1.0 to 0.75 requires editing the SV file or overriding the parameter on instantiation — there is no Python-side API for reparametrising a generated top-level monitor yet. - No SVA (SystemVerilog Assertions). The six properties are
encoded as combinational Boolean expressions plus sticky flags. A
future refactor will express them as
assert propertySystemVerilog assertions so they can be proved by SymbiYosys directly, closing the gap to the Lean specification. - No formal RTL-vs-spec equivalence. The SystemVerilog monitor and the Lean theorems are hand-aligned 1:1 by matching the shape of the Boolean expressions (see §2.2). A machine-checked proof that the RTL implements the Lean statements would require a SystemVerilog → Lean embedding such as Kôika or Verilog-Lean; neither is wired in yet.
- Flow driver is Yosys-only by default. The OpenROAD path is optional and needs the OpenROAD binary (or Docker image) on the host. Without it, the driver prints a clear diagnostic and exits zero after the Yosys stage; the release gate does not block on OpenROAD.
- Memristor model is ideal-linear.
SpiceGeneratormaps weights linearly onto $[G_{\mathrm{off}},\,G_{\mathrm{on}}]$; no non-linear I–V curve, no drift, no endurance / retention model. Analogue verification against device silicon requires an augmented model (e.g. the VTEAM or Yakopcic memristor).
Reference¶
- Python API:
src/sc_neurocore/hdl_gen/__init__.py(package root, 19 LOC)src/sc_neurocore/hdl_gen/verilog_generator.py(86 LOC)src/sc_neurocore/hdl_gen/spice_generator.py(54 LOC)- Safety RTL:
src/sc_neurocore/hdl_gen/safety/safety_monitor.sv(118 LOC)src/sc_neurocore/hdl_gen/safety/tb_safety_monitor.sv(202 LOC)- Flow driver:
src/sc_neurocore/hdl_gen/openroad_flow/run_asic_flow.sh(229 LOC). - Matching Lean proofs: Formal Proofs.
sc_neurocore.hdl_gen
¶
sc_neurocore.hdl_gen -- Tier: research (experimental / research).
VerilogGenerator
¶
Generates Top-Level Verilog for a defined SC Network.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | |
__init__(module_name='sc_network_top', bus_width=8)
¶
Initialise with a top-level module name.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
41 42 43 44 45 46 47 | |
add_layer(layer_type, name, params)
¶
Add a layer definition to the network.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
49 50 51 52 53 54 55 56 57 | |
generate(mode='sync')
¶
Emits Verilog code.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | |
emit_lfsr16_source(module_name='sc_lfsr16_source', seed=44257)
¶
Emit a standalone LFSR-16 stochastic source module.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
187 188 189 | |
emit_sobol16_source(module_name='sc_sobol16_source', seed=0)
¶
Emit a standalone Sobol-16 stochastic source module.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
191 192 193 | |
emit_sources_from_ir(ir)
¶
Emit standalone stochastic source modules declared in an IR payload.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
195 196 197 | |
emit_async_aer(module_name=None)
¶
Emit the research-stage async AER wrapper.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
199 200 201 202 203 204 | |
emit_kuramoto_phase(module_name=None, *, n_oscillators=4, omegas=None, initial_phases=None, coupling=0.1, dt=0.01, data_width=24, fraction=16, lut_size=64)
¶
Emit the bounded research Kuramoto phase core.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | |
emit_halton16_source(module_name='sc_halton16_source')
¶
Emit a standalone Halton-16 stochastic source module.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
233 234 235 | |
emit_quasirandom_source(method='sobol', module_name=None, seed=0)
¶
Emit a quasi-random source via the unified factory.
Parameters¶
method : str
"sobol" or "halton".
module_name : str, optional
Override the default module name.
seed : int
Seed for Sobol (ignored for Halton).
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | |
emit_decorrelator(*, num_streams=8, stream_width=16, shift_seed=2779077210)
¶
Return the path to the sc_decorrelator HDL module.
The decorrelator is a static Verilog module — this method provides the instantiation template for integration into top-level designs.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | |
emit_edt_controller(*, data_width=16, margin=64, stable_cycles=8)
¶
Return an instantiation template for the EDT controller.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | |
emit_tmr_wrapper(module_name, inputs, outputs)
¶
Generate a TMR wrapper for the given module.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
319 320 321 322 323 324 325 326 327 328 | |
save_to_file(path)
¶
Write generated Verilog to a file.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
330 331 332 333 334 335 336 337 | |
SpiceGenerator
¶
Generates SPICE netlists for Memristive Crossbars.
Source code in src/sc_neurocore/hdl_gen/spice_generator.py
| Python | |
|---|---|
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
generate_crossbar(weights, filename)
staticmethod
¶
weights: (Rows, Cols) - Conductance values [0, 1] mapped to [G_off, G_on].
Source code in src/sc_neurocore/hdl_gen/spice_generator.py
| Python | |
|---|---|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
AEREmitter
¶
Emit a research-stage AER wrapper around the existing sync HDL path.
This is intentionally conservative: the compute pipeline remains clocked and the output is wrapped in a 4-phase AER-style request/acknowledge interface. It is not a QDI async network replacement.
Source code in src/sc_neurocore/hdl_gen/aer_emitter.py
| Python | |
|---|---|
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | |
KuramotoEmitter
¶
Emit a bounded fixed-point Kuramoto phase core for HDL experiments.
The generated RTL is intentionally narrow in scope:
- noiseless only
- all-to-all scalar coupling only
- fixed-point phase state
- LUT-based sine approximation
This is a synthesis exploration scaffold, not a drop-in replacement for the production Kuramoto solvers.
Source code in src/sc_neurocore/hdl_gen/kuramoto_emitter.py
| Python | |
|---|---|
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | |
initial_phase_state_fixed()
¶
Return the emitted fixed-point reset state for each oscillator.
Source code in src/sc_neurocore/hdl_gen/kuramoto_emitter.py
| Python | |
|---|---|
118 119 120 | |
fixed_point_step(phase_state)
¶
Mirror one generated RTL phase step in integer fixed-point arithmetic.
Source code in src/sc_neurocore/hdl_gen/kuramoto_emitter.py
| Python | |
|---|---|
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | |
fixed_point_error_summary(*, steps)
¶
Characterise fixed-point drift against the float Kuramoto Euler step.
Source code in src/sc_neurocore/hdl_gen/kuramoto_emitter.py
| Python | |
|---|---|
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
fixed_state_to_float(phase_state)
¶
Convert integer fixed-point phase state to radians.
Source code in src/sc_neurocore/hdl_gen/kuramoto_emitter.py
| Python | |
|---|---|
190 191 192 193 194 195 | |
Lfsr16Emitter
¶
Emit a synthesisable standalone LFSR-16 Verilog module.
Source code in src/sc_neurocore/hdl_gen/lfsr16_emitter.py
| Python | |
|---|---|
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
generate()
¶
Return the standalone LFSR-16 Verilog module.
Source code in src/sc_neurocore/hdl_gen/lfsr16_emitter.py
| Python | |
|---|---|
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | |
SideChannelEncodingEmitter
¶
Emit a synthesisable ROM-style wrapper for one protected encoding record.
Source code in src/sc_neurocore/hdl_gen/side_channel_encoding_emitter.py
| Python | |
|---|---|
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
generate()
¶
Return a Verilog module exposing payload and dummy stream bits.
Source code in src/sc_neurocore/hdl_gen/side_channel_encoding_emitter.py
| Python | |
|---|---|
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
manifest(*, verilog_path)
¶
Return transport metadata linking the HDL hook to analytic evidence.
Source code in src/sc_neurocore/hdl_gen/side_channel_encoding_emitter.py
| Python | |
|---|---|
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
OnlineO1LearningEmitter
¶
Emit a synthesisable reward-modulated STDP state machine.
Source code in src/sc_neurocore/hdl_gen/online_learning_emitter.py
| Python | |
|---|---|
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | |
generate()
¶
Return Verilog for one bounded online-learning synapse lane.
Source code in src/sc_neurocore/hdl_gen/online_learning_emitter.py
| Python | |
|---|---|
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
estimate_resources(*, n_synapses, target='generic')
¶
Return a conservative pre-synthesis resource estimate.
This is a deterministic planning estimate derived from the emitted state fields and one update lane. It deliberately does not claim synthesis, place-and-route, timing, power, or board measurement evidence.
Source code in src/sc_neurocore/hdl_gen/online_learning_emitter.py
| Python | |
|---|---|
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | |
manifest(*, verilog_path, n_synapses=None)
¶
Return deterministic metadata for the generated learning lane.
Source code in src/sc_neurocore/hdl_gen/online_learning_emitter.py
| Python | |
|---|---|
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | |
OnlineO1ResourceEstimate
dataclass
¶
Deterministic pre-synthesis resource estimate for one online-learning block.
Source code in src/sc_neurocore/hdl_gen/online_learning_emitter.py
| Python | |
|---|---|
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
as_dict()
¶
Return a deterministic JSON-ready estimate payload.
Source code in src/sc_neurocore/hdl_gen/online_learning_emitter.py
| Python | |
|---|---|
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
Sobol16Emitter
¶
Emit a synthesisable standalone Sobol-16 Verilog module.
Source code in src/sc_neurocore/hdl_gen/sobol16_emitter.py
| Python | |
|---|---|
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
generate()
¶
Return the standalone Sobol-16 Verilog module.
Source code in src/sc_neurocore/hdl_gen/sobol16_emitter.py
| Python | |
|---|---|
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
QuasiRandomEmitter
¶
Unified factory for quasi-random SNG emitters.
Parameters¶
method : str
"sobol" or "halton".
module_name : str, optional
Override the default module name.
seed : int, optional
Seed for Sobol (ignored for Halton).
Source code in src/sc_neurocore/hdl_gen/quasirandom_emitter.py
| Python | |
|---|---|
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | |
module_name
property
¶
Return the sanitised module name.
generate()
¶
Generate the Verilog source for the selected method.
Source code in src/sc_neurocore/hdl_gen/quasirandom_emitter.py
| Python | |
|---|---|
133 134 135 | |
Halton16Emitter
¶
Emit a synthesisable standalone Halton-16 (Van der Corput base-2) module.
Architecture: pure counter + bit-reversal wiring. Zero multipliers, zero LUTs for core logic.
Source code in src/sc_neurocore/hdl_gen/quasirandom_emitter.py
| Python | |
|---|---|
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
generate()
¶
Return the standalone Halton-16 Verilog module.
Source code in src/sc_neurocore/hdl_gen/quasirandom_emitter.py
| Python | |
|---|---|
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
emit_sources_from_ir(ir)
¶
Emit LFSR-16 and Sobol-16 source modules from a lightweight IR payload.
The helper accepts the mapping shapes already used by documentation,
tests, and compiler-service payloads: {"nodes": [...]},
{"nodes": {"node_id": {...}}}, or a direct iterable of node mappings.
Non-source nodes are ignored. Source nodes must identify their generator
through source_type, decorrelator, generator, strategy, or
the node type/node_type itself.
Source code in src/sc_neurocore/hdl_gen/verilog_generator.py
| Python | |
|---|---|
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 | |
generate_tmr_wrapper(module_name, inputs, outputs, *, voter_module='sc_tmr_voter')
¶
Generate a TMR wrapper for a given Verilog module.
Parameters¶
module_name : str
Name of the target module to triplicate.
inputs : list of (name, width) tuples
Input ports of the target module.
outputs : list of (name, width) tuples
Output ports to protect with majority voting.
voter_module : str
Name of the voter module (default: sc_tmr_voter).
Returns¶
str Generated Verilog source for the TMR wrapper.
Source code in src/sc_neurocore/hdl_gen/tmr_wrapper.py
| Python | |
|---|---|
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |
generate_live_parameter_bank(spec, *, module_name='sc_live_parameter_bank', addr_width=None, bus_data_width=32, block_ram_threshold_bits=1024)
¶
Generate a live-parameter bank from an MMIO update spec.
The emitted RTL stores each parameter bank in distributed RAM or BRAM and exposes the fixed live-control register map through either AXI4-Lite or a PCIe MMIO register-window adapter. The PCIe path intentionally models the endpoint-adapter contract only: upstream PCIe hard IP must decode posted writes and reads into the single-clock MMIO strobes exposed here.
Both protocol paths stage low/high data words, commit updates only after a
checksum-valid update/apply handshake, and export a flattened
parameter_words bus for downstream dense, BFP, or phase-coupling RTL.
Source code in src/sc_neurocore/hdl_gen/bus_interface.py
| Python | |
|---|---|
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 | |