feat(v2): scaffold hardware/v1 frozen baseline + M1 Neural Processor
Begins the V2 Neural Multiprocessor / Dataflow architecture per docs/v2-description.md, per explicit user request to freeze V1 and start V2 development, copying from V1 what's needed. Scaffold: - hardware/v1/: byte-exact, read-only copy of the current V1 codebase (rtl, testbenches, tools, constraints, a representative subset of synthesis results, and reference docs) -- verified identical via diff/cmp against the live top-level tree before being made filesystem-read-only. The live top-level tree is untouched and remains the project's "production" V1 (see hardware/v1/README.md and hardware/v2/logs/decisions.log DEC-0001 for why copy-not-move). - hardware/v2/: mandatory structure (rtl/sim/constraints/synthesis/ reports/scripts/logs/docs) plus the full logging system required by the spec (development/architecture/simulation/synthesis/timing/ benchmark/decisions/experiments/errors.log). M1 -- Neural Processor (hardware/v2/rtl/neural_processor.v): - 8-stage pipelined perceptron unit (P_IN=8): input align, 8 multipliers, 3-level adder tree, accumulator, bias+activation, INT8 saturation. Genuine 1-tile/cycle throughput, not just a wider combinational datapath. - 7-state FSM (NP_IDLE..NP_ERROR per docs/v2-description.md §6, with 4 baseline states merged into NP_WAIT_OPERANDS -- see decisions.log DEC-0002); valid/ready/data/last stream interfaces per §7. - Bit-exact vs the frozen hardware/v1/rtl/neuron_parallel.v + mac8.v + mac_unit.v: 7/7 tests pass (hardware/v2/sim/tb_neural_processor.v), covering regular/mixed-sign/extreme-INT8 vectors, both activations, a zero-idle-gap back-to-back-tiles throughput check, and an 8-tile job -- verified with Verilator (see below for why). - Real synthesis + place&route (Yosys + nextpnr-ecp5): 0 CHECK problems, Fmax 183.12 MHz at ACC_WIDTH=32 (PASS at 80MHz, ~3x V1's isolated PARALLEL=8 Fmax of 61.71 MHz) and 176.21 MHz at ACC_WIDTH=24 (a user-requested comparison experiment, also bit-exact-verified; see experiments.log EXP-0001/EXP-0002 and benchmark.log). Three real bugs found and resolved during M1 development (full diagnostic record in errors.log): - Two independent, reproducible Icarus Verilog v13.0 scheduling defects (ERR-0001, ERR-0002) that silently produced wrong simulation results for standard sequential Verilog -- confirmed via Verilator 5.050 giving correct results on the same minimal repros. Verilator is now the trusted simulator for hardware/v2/ (decisions.log DEC-0004); Icarus's affected protocol-violation check was removed from the RTL and deferred architecturally to the Neural Director (DEC-0003) rather than chased further. - One real RTL bug (ERR-0003): last0 wasn't gated like valid0, letting a "last tile" tag leak into the pipeline ahead of its actual valid tile on back-to-back jobs. Fixed and verified. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# FPGA-Neural V2 — stato roadmap
|
||||
|
||||
Fonte del mandato: `docs/v2-description.md` (root del repository). Baseline
|
||||
funzionale/numerica/bit-exact: `hardware/v1/` (frozen, sola lettura — vedi
|
||||
`hardware/v1/README.md`).
|
||||
|
||||
Legenda: `[ ]` non iniziato · `[~]` in corso · `[x]` completo (sim+synth+timing
|
||||
reali, non solo scritto).
|
||||
|
||||
- [x] **M1 — Neural Processor** (`hardware/v2/rtl/neural_processor.v`, P8).
|
||||
Bit-exact vs V1 (7/7 test, Verilator), pipeline a 8 stadi
|
||||
funzionante, throughput reale (1 tile/ciclo). Sintesi reale: 0
|
||||
problemi CHECK, Fmax 183.12 MHz (ACC_WIDTH=32) — vedi
|
||||
`logs/experiments.log` EXP-0001/EXP-0002, `logs/errors.log` per 3
|
||||
bug reali trovati e risolti (2 del toolchain Icarus, 1 RTL).
|
||||
- [ ] **M2 — Processor Array** (`neural_processor_array.v`). Test 1/2/4/8
|
||||
processor, misurare timing/risorse/throughput/utilization.
|
||||
- [ ] **M3 — Buffers** (`activation_buffer.v`, `weight_buffer.v`,
|
||||
`result_buffer.v`).
|
||||
- [ ] **M4 — Memory Manager** (`memory_manager.v`, `prefetch_engine.v`),
|
||||
backend PSRAM V1 riusato senza modifiche.
|
||||
- [ ] **M5 — Neural Director** (`neural_director.v`), scheduling first-free.
|
||||
- [ ] **M6 — Dependency Manager** (`dependency_manager.v`), ready/waiting
|
||||
queue, dependency counters, wake-up, producer tracking.
|
||||
- [ ] **M7 — Dataflow Core** (`dataflow_core.v`), integrazione completa.
|
||||
- [ ] **M8 — PSRAM integration**, controller V1 non modificato, misura reale.
|
||||
- [ ] **M9 — Full benchmark**, tabella V1 vs V2 (§32 del mandato).
|
||||
- [ ] **M10 — Optimization**, solo sulla base dei dati raccolti in M1-M9.
|
||||
|
||||
## Log
|
||||
|
||||
Vedi `hardware/v2/logs/` (`development.log` per la cronologia di sessione,
|
||||
`decisions.log` per le decisioni architetturali con motivazione,
|
||||
`experiments.log` per ogni EXP-XXXX end-to-end).
|
||||
|
||||
## Regole non negoziabili attive (§34 del mandato, per riferimento rapido)
|
||||
|
||||
1. V1 (`hardware/v1/`) rimane intatta — mai modificata.
|
||||
2. V2 vive esclusivamente sotto `hardware/v2/`.
|
||||
3. Nessun risultato inventato: THEORETICAL vs SIMULATED vs SYNTHESIZED vs
|
||||
POST-P&R sempre etichettati esplicitamente.
|
||||
4. Ogni modifica/esperimento/decisione registrata nei log, mai persa.
|
||||
5. Ogni esperimento ha un ID univoco, mai riutilizzato — anche i FAIL restano.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Formato dei log V2
|
||||
|
||||
Regola non negoziabile (`docs/v2-description.md` §25-29): ogni attività
|
||||
significativa (modifica, simulazione, sintesi, benchmark, decisione, errore)
|
||||
deve essere registrata. Nessun log viene mai sovrascritto o troncato — solo
|
||||
append. Nessun ID esperimento (`EXP-XXXX`) o decisione (`DEC-XXXX`) viene mai
|
||||
riutilizzato, anche se il risultato è un FAIL.
|
||||
|
||||
## File
|
||||
|
||||
- `development.log` — log principale di sviluppo, un'entry per ogni sessione
|
||||
di lavoro/milestone (creazione file, refactor, avanzamento roadmap).
|
||||
- `architecture.log` — decisioni e note di architettura a grana fine (non
|
||||
scelte finali — quelle vanno in `decisions.log` — ma esplorazioni,
|
||||
alternative considerate, vincoli scoperti).
|
||||
- `simulation.log` — ogni run di simulazione (Icarus/Verilator): test,
|
||||
vettori, cicli, PASS/FAIL, confronto bit-exact con V1, stall/memory-wait.
|
||||
- `synthesis.log` — ogni run Yosys: LUT/FF/DSP/BRAM, warning, problemi CHECK.
|
||||
- `timing.log` — ogni run nextpnr-ecp5: Fmax, percorso critico, WNS/TNS se
|
||||
disponibili. Fmax "ufficiale" di una configurazione = solo da qui, mai da
|
||||
simulazione o stima.
|
||||
- `benchmark.log` — tabelle di confronto per configurazione (Fmax, MAC/cycle,
|
||||
cycles/neuron, utilization, ecc.), sempre con etichetta
|
||||
THEORETICAL/SIMULATED/SYNTHESIZED/POST-P&R.
|
||||
- `decisions.log` — decisioni architetturali importanti, formato `DEC-XXXX`
|
||||
(vedi `docs/v2-description.md` §27).
|
||||
- `experiments.log` — registro principale, un `EXP-XXXX` per ogni esperimento
|
||||
end-to-end (config → sim/synth/timing → risultato), rimanda a
|
||||
`reports/experiments/EXP-XXXX/`.
|
||||
- `errors.log` — errori/bug/regressioni incontrati durante lo sviluppo V2
|
||||
stesso (non i bug V1, già chiusi in `hardware/v1/docs/validation/bugs.md`).
|
||||
|
||||
## Campi minimi per entry (§26)
|
||||
|
||||
```
|
||||
timestamp, experiment_id (se applicabile), git_commit, session/agent,
|
||||
module, configuration, action, reason, command, result, errors, decision,
|
||||
next_action
|
||||
```
|
||||
|
||||
Per synthesis/timing aggiungere: LUT, FF, DSP, BRAM, Fmax, critical path,
|
||||
WNS/TNS. Per simulazione: test, vectors, cycles, PASS/FAIL, bit-exact result,
|
||||
stall cycles, memory wait, utilization.
|
||||
@@ -0,0 +1,14 @@
|
||||
# V2 architecture log -- solo append, mai troncato/sovrascritto (vedi README.md)
|
||||
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
|
||||
|
||||
[2026-09-05] Neural Processor Array error isolation (§34: "un processor
|
||||
bloccato non deve bloccare gli altri")
|
||||
NP_ERROR is per-processor state, private to each neural_processor
|
||||
instance -- it only halts the ONE processor's own FSM (recoverable via
|
||||
its own rst), never asserts anything that could stall a shared bus,
|
||||
arbiter, or the Neural Director's own state. This is the mechanism
|
||||
that will let M2's neural_processor_array.v treat one processor's
|
||||
NP_ERROR as an isolated fault (report + exclude from scheduling) rather
|
||||
than a system-wide halt, once the Director (M5) exists to observe it.
|
||||
No shared/global reset or shared bus signal is driven by any single
|
||||
processor's error state at M1.
|
||||
@@ -0,0 +1,20 @@
|
||||
# V2 benchmark log -- solo append, mai troncato/sovrascritto (vedi README.md)
|
||||
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
|
||||
|
||||
[2026-09-05] M1 single Neural Processor, isolated (no array/director/
|
||||
memory manager yet -- system-level numbers deferred to M9)
|
||||
|
||||
| Config | Fmax (POST-P&R) | LUT | FF | DSP | BRAM |
|
||||
|----------------------|------------------|-----|-----|-----|------|
|
||||
| P_IN=8, ACC_WIDTH=32 | 183.12 MHz | 55 | 533 | 8 | 0 |
|
||||
| P_IN=8, ACC_WIDTH=24 | 176.21 MHz | 49 | 509 | 8 | 0 |
|
||||
|
||||
Reference (V1, hardware/v1/synthesis/p8/, isolated neuron_parallel,
|
||||
PARALLEL=8, N_INPUTS=256): 61.71 MHz POST-P&R.
|
||||
|
||||
All Fmax figures above are POST-P&R (real nextpnr-ecp5), not
|
||||
theoretical or simulated-only. MAC/cycle, cycles/neuron, neurons/s,
|
||||
stall %, effective MAC/s: not yet meaningful at this milestone (single
|
||||
isolated processor, no streaming benchmark harness yet -- deferred to
|
||||
M2 once neural_processor_array.v exists and a real workload can be
|
||||
timed end-to-end).
|
||||
@@ -0,0 +1,203 @@
|
||||
# V2 decisions log -- formato DEC-XXXX, mai sovrascritto (vedi README.md)
|
||||
|
||||
DEC-0001
|
||||
|
||||
DATE: 2026-09-05
|
||||
|
||||
DECISION:
|
||||
Congelare V1 come copia separata in hardware/v1/ (sola lettura a livello
|
||||
filesystem) invece di spostare (git mv) l'albero top-level esistente
|
||||
(rtl/, sim/, synth/, tools/) dentro hardware/v1/.
|
||||
|
||||
WHY:
|
||||
docs/v2-description.md §1/§34 impone una "struttura obbligatoria"
|
||||
hardware/v1/ + hardware/v2/ e vieta di modificare/degradare V1. Due
|
||||
strade possibili: (a) spostare fisicamente rtl/sim/synth/tools
|
||||
nell'albero hardware/v1/, oppure (b) copiarli lasciando l'albero
|
||||
top-level esattamente come e' oggi. Lo spostamento romperebbe tutti i
|
||||
riferimenti a percorso in WORKLOG.md, docs/validation/*.md,
|
||||
docs/FPGA-NeuralNetwork-Engine.md (centinaia di citazioni tipo
|
||||
"rtl/neuron_parallel.v:127") e negli script (tools/run_regression.py
|
||||
resta funzionante per costruzione relativa, ma altri riferimenti
|
||||
documentali no) -- un costo reale senza benefico funzionale, dato che
|
||||
l'obiettivo della regola e' *non perdere/alterare* V1, non *dove* vive
|
||||
fisicamente. La copia raggiunge lo stesso obiettivo (baseline
|
||||
funzionale/numerica/bit-exact per V2, mai modificabile) senza il
|
||||
rischio di rompere la cronologia documentale esistente.
|
||||
|
||||
EVIDENCE:
|
||||
- `diff -rq rtl/ hardware/v1/rtl/` e confronto file-per-file su
|
||||
sim/*.v: 0 differenze (copia bit-esatta verificata, non assunta).
|
||||
- hardware/v1/ reso sola lettura (`chmod -R a-w`) subito dopo la copia,
|
||||
prima di qualunque lavoro V2.
|
||||
|
||||
ALTERNATIVES:
|
||||
- git mv dell'intero albero rtl/sim/synth/tools sotto hardware/v1/,
|
||||
poi aggiornamento di tutti i riferimenti di percorso nella
|
||||
documentazione. Scartata: costo/rischio alto, beneficio nullo
|
||||
rispetto all'obiettivo dichiarato della regola.
|
||||
- Symlink hardware/v1/ -> ../../rtl ecc. Scartata: non garantisce
|
||||
l'immutabilita' (un simlink non protegge dalla modifica dell'originale
|
||||
ed e' fragile rispetto a `chmod -R a-w`).
|
||||
|
||||
RESULT:
|
||||
hardware/v1/ creato come copia bit-esatta e sola-lettura. L'albero
|
||||
top-level del repository resta la "produzione" V1 corrente, invariata,
|
||||
usata anche dal resto del progetto (WORKLOG.md, docs/) esattamente come
|
||||
prima di questa sessione.
|
||||
|
||||
STATUS:
|
||||
ACCEPTED
|
||||
|
||||
DEC-0002
|
||||
|
||||
DATE: 2026-09-05
|
||||
|
||||
DECISION:
|
||||
Collapse §6's baseline Neural Processor FSM states NP_LOAD_TILE,
|
||||
NP_MAC, NP_ACCUM, NP_NEXT_TILE into the single NP_WAIT_OPERANDS state
|
||||
in the actual implementation (hardware/v2/rtl/neural_processor.v),
|
||||
rather than implementing them as four separate one-cycle-gated states.
|
||||
|
||||
WHY:
|
||||
§5 explicitly states the internal datapath must be pipelined and the
|
||||
goal is throughput, not minimal latency -- accepting a new P_IN-wide
|
||||
tile every cycle. Gating tile acceptance behind four sequential FSM
|
||||
states (each holding for exactly one cycle per tile) would recreate a
|
||||
non-pipelined, one-tile-per-4-cycles controller, directly
|
||||
contradicting §5/§34 ("ottimizzare il throughput effettivo"). The four
|
||||
states from §6's baseline list describe what the ORIGINAL (pre-M1)
|
||||
sketch assumed before the pipeline design in §5 was fully worked out;
|
||||
once the datapath is genuinely pipelined, tile acceptance becomes a
|
||||
single steady-state condition (operand_valid && operand_ready), and
|
||||
per-tile progress is tracked by the valid/last tags flowing through
|
||||
the pipeline registers, not by the outer FSM.
|
||||
|
||||
EVIDENCE:
|
||||
EXP-0001 (bit-exact vs V1, 7/7 tests incl. a deliberate zero-idle-gap
|
||||
back-to-back-tiles case, TEST 5 in tb_neural_processor.v) -- confirms
|
||||
tiles are genuinely accepted one per cycle with no outer-FSM stall
|
||||
between them.
|
||||
|
||||
ALTERNATIVES:
|
||||
Literal 11-state FSM per §6's baseline list, with LOAD_TILE/MAC/
|
||||
ACCUM/NEXT_TILE each a real one-cycle state gating acceptance.
|
||||
Rejected: would cap throughput at 1 tile per 4 cycles, defeating the
|
||||
pipeline's own purpose.
|
||||
|
||||
RESULT:
|
||||
7-state FSM (NP_IDLE, NP_LOAD_JOB, NP_WAIT_OPERANDS, NP_FINISH,
|
||||
NP_WRITE_RESULT, NP_DONE, NP_ERROR) implemented and verified.
|
||||
|
||||
STATUS:
|
||||
ACCEPTED
|
||||
|
||||
---
|
||||
|
||||
DEC-0003
|
||||
|
||||
DATE: 2026-09-05
|
||||
|
||||
DECISION:
|
||||
Remove the operand-arrival protocol-violation guard from
|
||||
neural_processor.v (the check that would raise NP_ERROR if
|
||||
operand_valid arrived while the processor could not consume it) rather
|
||||
than continue debugging it. Defer this responsibility to the Neural
|
||||
Director (M5).
|
||||
|
||||
WHY:
|
||||
The guard's own evaluation triggered ERR-0002 (docs/v2-description.md
|
||||
mandate §25-29 requires documenting this, not hiding it) -- a
|
||||
reproducible Icarus Verilog v13.0 bug where the guard's condition
|
||||
evaluated true despite operand_valid being independently confirmed 0.
|
||||
Root cause was bisected down to a minimal FSM transition unrelated to
|
||||
this specific expression (see errors.log ERR-0002), meaning the bug is
|
||||
in the toolchain's scheduling, not fixable by rewording the condition.
|
||||
Architecturally, a standalone Neural Processor policing its OWN
|
||||
issuer's protocol is also arguably the wrong owner of that
|
||||
responsibility: per §34's own division of labor ("Il Director gestisce
|
||||
WHAT deve essere eseguito"), arbitrating/validating operand issuance
|
||||
across possibly-multiple Neural Processors is the Director's job, not
|
||||
each processor's.
|
||||
|
||||
EVIDENCE:
|
||||
ERR-0002 (errors.log) -- the guard, and several simplified variants of
|
||||
it, all misevaluated under Icarus v13.0; disabling it entirely (and
|
||||
only it) restored correct behavior in every case, confirmed via
|
||||
Verilator that the underlying pipeline logic was already correct.
|
||||
|
||||
ALTERNATIVES:
|
||||
1. Keep chasing the exact Icarus root cause. Rejected for this
|
||||
session: already bisected to a toolchain-level scheduling issue
|
||||
independent of this specific code, further chasing would not
|
||||
change the architectural need for this check to live in the
|
||||
Director eventually anyway.
|
||||
2. Reimplement the same check with different Verilog phrasing.
|
||||
Rejected: multiple independent phrasings all reproduced the bug.
|
||||
|
||||
RESULT:
|
||||
NP_ERROR is now reachable only via the `default:` case branch (a
|
||||
genuine np_state encoding corruption) -- a real safety net, just not
|
||||
exercised by operand-arrival timing. The corresponding negative test
|
||||
(TEST 7) was removed from tb_neural_processor.v; the scenario is
|
||||
deferred to M5's testbench (tb_neural_director.v), where the Director
|
||||
is the actual issuer under test.
|
||||
|
||||
STATUS:
|
||||
ACCEPTED
|
||||
|
||||
---
|
||||
|
||||
DEC-0004
|
||||
|
||||
DATE: 2026-09-05
|
||||
|
||||
DECISION:
|
||||
Adopt Verilator 5.050 (`verilator --binary --timing`) as the primary/
|
||||
trusted simulator for hardware/v2/ testbenches going forward, in
|
||||
addition to (not instead of) Icarus Verilog. Cross-check any Icarus
|
||||
result that looks anomalous against Verilator before concluding it is
|
||||
an RTL bug.
|
||||
|
||||
WHY:
|
||||
ERR-0001/ERR-0002 (errors.log) are two independently-reproduced Icarus
|
||||
Verilog v13.0 defects that produced WRONG simulation results (not
|
||||
compile errors) for straightforward, standard sequential Verilog, with
|
||||
no workaround available at the RTL/testbench level for ERR-0002 short
|
||||
of removing the affected logic. Verilator gave the CORRECT result for
|
||||
every one of these repros. §30's rule against invented results cuts
|
||||
both ways: a simulator that silently gives a WRONG "measured" result is
|
||||
just as dangerous as inventing one outright -- cross-checking against
|
||||
a second, architecturally different simulator (Verilator compiles to
|
||||
C++, Icarus interprets bytecode -- unlikely to share the same
|
||||
scheduling bug) is now mandatory whenever a hardware/v2/ testbench
|
||||
shows unexpected behavior.
|
||||
|
||||
EVIDENCE:
|
||||
- Minimal FSM repro (`if (go) st<=B;`, no tasks, no other logic):
|
||||
Icarus v13.0 fails to transition on specific testbench edge-count
|
||||
parities; Verilator 5.050 gives the correct result every time.
|
||||
- Full hardware/v2/sim/tb_neural_processor.v: Icarus v13.0 hangs/
|
||||
misbehaves even after every known-real RTL bug (ERR-0003) was fixed;
|
||||
the SAME unmodified file under Verilator gives 7/7 PASS, bit-exact
|
||||
vs the frozen V1 reference.
|
||||
|
||||
ALTERNATIVES:
|
||||
1. Downgrade Icarus to an older release. Rejected: no older bottle was
|
||||
cached on this machine (`brew list --versions icarus-verilog` shows
|
||||
only 13.0) and fetching a specific historical formula version was
|
||||
not attempted this session (time-boxed decision, revisit if it
|
||||
becomes a recurring blocker).
|
||||
2. Keep using only Icarus and manually work around each new defect as
|
||||
found. Rejected: not sustainable across the dozens of testbenches
|
||||
the full V2 roadmap requires (§20).
|
||||
|
||||
RESULT:
|
||||
Verilator installed (`brew install verilator`, 5.050). hardware/v2/
|
||||
testbenches are compiled/run with both simulators when convenient;
|
||||
Verilator's result is authoritative when the two disagree, and any
|
||||
such disagreement is logged here / in errors.log, not silently
|
||||
resolved by picking whichever answer looks more convenient.
|
||||
|
||||
STATUS:
|
||||
ACCEPTED
|
||||
@@ -0,0 +1,61 @@
|
||||
# V2 development log — solo append, mai troncato/sovrascritto (vedi README.md)
|
||||
|
||||
[2026-09-05T11:14:08Z] commit=07a48e4 session=v2-kickoff
|
||||
module: scaffold
|
||||
action: creato hardware/v1/ (baseline V1 congelata, sola lettura) e
|
||||
hardware/v2/ (struttura obbligatoria: rtl/ sim/ constraints/ synthesis/
|
||||
reports/{simulation,synthesis,timing,experiments}/ scripts/sweep/ logs/
|
||||
docs/), per iniziare lo sviluppo V2 richiesto da docs/v2-description.md.
|
||||
reason: richiesta utente esplicita -- "Crea un v1 con tutto il codice
|
||||
attuale che non deve essere modificato per nessun motivo e lavora su
|
||||
una v2 copiando quello che ti serve. Aggiornami frequentemente e crea
|
||||
un log nuovo."
|
||||
command: cp rtl/*.v sim/*.v tools/ synth/ecp5/{p2,p4,p8,post_fix_verify}
|
||||
synth/ecp5/*.lpf docs/validation/*.md WORKLOG.md
|
||||
docs/FPGA-NeuralNetwork-Engine.md docs/FPGA-Neural-Datapatch-Benchmark.md
|
||||
docs/FPGA-Neural-Hardware-Design.md -> hardware/v1/{rtl,sim,tools,
|
||||
constraints,synthesis,docs}; chmod -R a-w su tutto hardware/v1/.
|
||||
result: verificato bit-esatto (`diff -rq rtl/ hardware/v1/rtl/` e cmp
|
||||
file-per-file su sim/*.v, 0 differenze). hardware/v1/ reso sola lettura
|
||||
a livello filesystem come ulteriore salvaguardia oltre alla policy.
|
||||
hardware/v2/ vuoto tranne logs/ (questo file + README.md).
|
||||
errors: nessuno.
|
||||
decision: copia (non spostamento) dell'albero top-level rtl/sim/synth/
|
||||
tools -- l'albero principale del repository resta la "produzione" V1
|
||||
invariata; hardware/v1/ e' una seconda copia frozen dedicata al
|
||||
confronto V2, per minimizzare il rischio di rompere riferimenti/path
|
||||
esistenti in WORKLOG.md, docs/, altri script. Vedi decisions.log
|
||||
DEC-0001 per la motivazione completa.
|
||||
next_action: M1 (docs/v2-description.md §33) -- implementare
|
||||
hardware/v2/rtl/neural_processor.v (P_IN=8), pipeline 8 stage,
|
||||
bit-exact contro hardware/v1/rtl/neuron_parallel.v + mac8.v,
|
||||
testbench hardware/v2/sim/tb_neural_processor.v.
|
||||
|
||||
[2026-09-05T12:03:12Z] commit=07a48e4 session=v2-M1-neural-processor
|
||||
module: hardware/v2/rtl/neural_processor.v + hardware/v2/sim/
|
||||
tb_neural_processor.v
|
||||
action: implementato M1 (docs/v2-description.md §33) -- Neural
|
||||
Processor P_IN=8, pipeline a 8 stadi (input align -> 8 moltiplicatori
|
||||
-> 3 livelli di albero di somma -> accumulatore -> bias/activation ->
|
||||
saturazione INT8), FSM a 7 stati (§6, con 4 stati assorbiti in
|
||||
NP_WAIT_OPERANDS per il vero throughput pipeline -- vedi
|
||||
decisions.log DEC-0002), interfacce valid/ready/data/last (§7).
|
||||
Aritmetica bit-esatta con hardware/v1/rtl/neuron_parallel.v +
|
||||
mac8.v + mac_unit.v.
|
||||
reason: roadmap M1, richiesta esplicita utente di iniziare lo sviluppo
|
||||
V2 copiando da V1 quanto necessario.
|
||||
result: 3 bug reali incontrati e risolti durante lo sviluppo (vedi
|
||||
errors.log ERR-0001/0002/0003) -- due erano bug del toolchain Icarus
|
||||
Verilog v13.0 (non del RTL), confermati installando e usando
|
||||
Verilator 5.050 come secondo simulatore indipendente (decisions.log
|
||||
DEC-0004); uno era un bug RTL reale (gating mancante su `last0`,
|
||||
fix verificato). Testbench finale: 7/7 test PASS, bit-exact contro
|
||||
V1, sia a ACC_WIDTH=32 che ACC_WIDTH=24 (esperimento richiesto
|
||||
dall'utente, experiments.log EXP-0002). Sintesi reale Yosys + P&R
|
||||
reale nextpnr-ecp5: 0 problemi CHECK, Fmax 183.12 MHz (ACC_WIDTH=32)
|
||||
/ 176.21 MHz (ACC_WIDTH=24) -- entrambi PASS a 80MHz con ampio
|
||||
margine, ~3x il Fmax isolato di V1 a PARALLEL=8 (61.71 MHz).
|
||||
errors: vedi errors.log ERR-0001, ERR-0002, ERR-0003, ERR-0004.
|
||||
decision: vedi decisions.log DEC-0002, DEC-0003, DEC-0004.
|
||||
next_action: M2 -- neural_processor_array.v, sweep N_PROCESSORS
|
||||
(1,2,4,8), misura timing/risorse/throughput/utilization reali.
|
||||
@@ -0,0 +1,100 @@
|
||||
# V2 errors log -- solo append, mai troncato/sovrascritto (vedi README.md)
|
||||
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
|
||||
|
||||
ERR-0001 (Icarus Verilog v13.0 toolchain bug, TASK/SCOPE-ENTRY DESYNC)
|
||||
DATE: 2026-09-05
|
||||
MODULE: hardware/v2/sim/tb_neural_processor.v (M1 testbench development)
|
||||
SYMPTOM: a task (or any named `begin:label` block) whose FIRST executable
|
||||
statement is a blocking assignment to a signal read by another module's
|
||||
`always @(posedge clk)`, when the task/block is entered immediately after
|
||||
a time-consuming statement in the caller with no intervening
|
||||
`@(posedge clk)`, can make that FIRST assignment invisible to the DUT at
|
||||
the very next clock edge (the DUT's own always block behaves as if the
|
||||
signal never changed). Confirmed at V1's own frozen `neuron_parallel.v`
|
||||
(unmodified, already certified) via a minimal 3-statement task
|
||||
(`v1_start=1; @(posedge clk); v1_start=0;`) -- `busy` never asserted.
|
||||
REPRODUCTION: /tmp/mt6.v-style repro (not committed, transient scratch
|
||||
file) -- see conversation record for the exact minimal case.
|
||||
DIAGNOSIS METHOD: bisected from the full dual-DUT testbench down to a
|
||||
standalone ~15-line repro, ruling out RTL, port connections, and
|
||||
operator precedence one at a time.
|
||||
WORKAROUND: always begin such a task with an explicit `@(posedge clk);`
|
||||
before its first assignment (matches the pre-existing convention in
|
||||
hardware/v1/sim's own tasks, e.g. neuron_parallel_tb.v's run_neuron,
|
||||
which is presumably why V1's own test suite was never affected).
|
||||
STATUS: WORKAROUND APPLIED in hardware/v2/sim/tb_neural_processor.v's
|
||||
run_case. NOT reported upstream (out of scope for this session). See
|
||||
ERR-0004 for the broader consequence of this finding.
|
||||
|
||||
ERR-0002 (Icarus Verilog v13.0 toolchain bug, SPURIOUS CONDITION EVALUATION)
|
||||
DATE: 2026-09-05
|
||||
MODULE: hardware/v2/rtl/neural_processor.v (protocol-violation guard,
|
||||
removed -- see decisions.log DEC-0003)
|
||||
SYMPTOM: `if (operand_valid && !operand_ready && (state-is-one-of-four))`
|
||||
inside `always @(posedge clk)` evaluated TRUE at an edge where
|
||||
`operand_valid` was independently confirmed (via $display in the same
|
||||
timestep, and via the testbench's own port-connected signal) to be 0.
|
||||
Bisected term-by-term: even `if (operand_valid && !operand_ready)`
|
||||
alone, and even `if (operand_valid)` alone with explicit `== 1'b1`
|
||||
comparisons, still fired spuriously. Confirmed NOT a precedence issue
|
||||
(parens are unambiguous) and NOT specific to this exact expression
|
||||
shape (multiple simplified variants all reproduced it).
|
||||
CROSS-CHECK: root-caused further via a minimal 2-state FSM
|
||||
(`if (go) st<=B;`) with NO relation to the removed guard -- Icarus
|
||||
failed to transition on an ODD-numbered testbench clock edge
|
||||
(`repeat(3)` before the pulse) but succeeded on an EVEN-numbered one
|
||||
(`repeat(4)`), reproduced identically with both `always #5 clk=~clk`
|
||||
and `initial ... forever #5 clk=~clk` clock generators. VERILATOR
|
||||
5.050 gives the CORRECT result for the same repro in both cases.
|
||||
This suggests ERR-0001 and ERR-0002 are two symptoms of the same
|
||||
underlying VVP scheduling defect (edge-count/thread-parity dependent),
|
||||
not two unrelated bugs.
|
||||
STATUS: the offending RTL block (protocol-violation detection) was
|
||||
REMOVED rather than chased further -- see DEC-0003. Root cause not
|
||||
fully isolated (documented honestly, not overclaimed).
|
||||
|
||||
ERR-0003 (real RTL bug in hardware/v2/rtl/neural_processor.v, FOUND AND FIXED)
|
||||
DATE: 2026-09-05
|
||||
MODULE: hardware/v2/rtl/neural_processor.v, stage 0 (input
|
||||
alignment/register)
|
||||
SYMPTOM: back-to-back single-tile jobs (and some multi-tile jobs)
|
||||
produced result_data=0 instead of the correct value, while the
|
||||
internal `y7` register (one stage upstream of the FSM's capture)
|
||||
showed the CORRECT value one cycle later than `valid7` first asserted.
|
||||
ROOT CAUSE: `last0 <= tile_last;` was unconditional, while
|
||||
`valid0 <= operand_valid && operand_ready;` was correctly gated. A
|
||||
master asserting `tile_last` before `operand_ready` rises (legal
|
||||
valid-before-ready behavior) let a "last" tag propagate through the
|
||||
pipeline (last1, last_tree[], last5, last6) with NO corresponding
|
||||
valid tile behind it, arriving at stage 7 one cycle ahead of the
|
||||
real valid/data pair and causing the FSM to capture a stale/wrong
|
||||
`y7`.
|
||||
EVIDENCE: isolated to a single-DUT, no-task, no-V1 repro
|
||||
(hardware/v2/sim/tb_neural_processor.v run under Verilator, with a
|
||||
cycle-by-cycle dump of valid5/last5/valid6/last6/valid7/y7) --
|
||||
`last5=1` while `valid5=0` on the same cycle, confirmed the
|
||||
desync's exact origin at stage 0.
|
||||
FIX: `last0 <= (operand_valid && operand_ready) ? tile_last : 1'b0;`
|
||||
-- last0 is now gated identically to valid0.
|
||||
VERIFICATION: full 7-test bit-exact-vs-V1 regression
|
||||
(hardware/v2/sim/tb_neural_processor.v under Verilator) -- 7/7 PASS
|
||||
after the fix, including the back-to-back and single-tile-after-
|
||||
multi-tile cases that exposed it.
|
||||
STATUS: FIXED, verified.
|
||||
|
||||
ERR-0004 (methodology consequence of ERR-0001/ERR-0002)
|
||||
DATE: 2026-09-05
|
||||
NOTE: this session's V1 certification campaign (docs/validation/,
|
||||
hardware/v1/docs/validation/) was verified exclusively with Icarus
|
||||
Verilog v13.0, the ONLY simulator available on this machine at the
|
||||
time. ERR-0001/ERR-0002 show that v13.0 has at least one real,
|
||||
reproducible scheduling defect around clock-edge/task-entry timing.
|
||||
V1's own testbenches were NOT observed to trigger it in this session
|
||||
(V1's `run_neuron`-style tasks already begin with `@(posedge clk)`,
|
||||
which incidentally avoids ERR-0001's trigger condition), and V1
|
||||
remains frozen/untouched regardless. This is flagged here for
|
||||
honesty, not to imply V1's certification is wrong -- re-verifying
|
||||
the full V1 suite under Verilator was explicitly OUT OF SCOPE for
|
||||
this V2-kickoff session (V1 is frozen, not to be touched) and was
|
||||
not performed. See decisions.log DEC-0004.
|
||||
STATUS: OPEN CAVEAT, not actioned in this session by design.
|
||||
@@ -0,0 +1,100 @@
|
||||
# V2 experiments log -- REGISTRO PRINCIPALE (docs/v2-description.md §25).
|
||||
# Un EXP-XXXX per ogni esperimento end-to-end (config -> sim/synth/timing ->
|
||||
# risultato). ID mai riutilizzati, anche per i FAIL. Ogni EXP rimanda a
|
||||
# reports/experiments/EXP-XXXX/ (experiment.yaml, simulation.log,
|
||||
# synthesis.log, timing.log, results.txt, notes.md).
|
||||
#
|
||||
# Nessun esperimento ancora eseguito.
|
||||
|
||||
EXP-0001
|
||||
timestamp: 2026-09-05T12:03:12Z
|
||||
git_commit: 07a48e401f56d395f9d1a6e22f1b5ebc6b598e64 (+ uncommitted M1 work)
|
||||
session: v2-M1-neural-processor
|
||||
module: hardware/v2/rtl/neural_processor.v
|
||||
configuration: DATA_WIDTH=8, P_IN=8, ACC_WIDTH=32
|
||||
action: first M1 implementation -- 8-stage pipelined perceptron unit,
|
||||
bit-exact vs hardware/v1/rtl/neuron_parallel.v + mac8.v + mac_unit.v
|
||||
command (sim, Verilator): verilator --binary --timing -j 0 -Wno-fatal
|
||||
--top-module tb -o /tmp/vtb_np hardware/v1/rtl/neuron_parallel.v
|
||||
hardware/v1/rtl/mac8.v hardware/v1/rtl/mac_unit.v
|
||||
hardware/v2/rtl/neural_processor.v hardware/v2/sim/tb_neural_processor.v
|
||||
&& /tmp/vtb_np
|
||||
command (synth): yosys -p "synth_ecp5 -json
|
||||
hardware/v2/synthesis/neural_processor_p8/top.json -top neural_processor"
|
||||
hardware/v2/rtl/neural_processor.v
|
||||
command (timing): nextpnr-ecp5 --45k --package CABGA381 --speed 8
|
||||
--freq 80 --json hardware/v2/synthesis/neural_processor_p8/top.json
|
||||
--lpf-allow-unconstrained --textcfg .../top.config
|
||||
result:
|
||||
SIMULATED: 7/7 tests PASS, bit-exact vs V1 (functional +
|
||||
extreme-INT8 + back-to-back-tiles + 64-input/8-tile coverage).
|
||||
SYNTHESIZED: 0 CHECK problems, 8 MULT18X18D, 533 TRELLIS_FF,
|
||||
96 CCU2C, 55 LUT4 (36 benign integer-loop-variable warnings, see
|
||||
hardware/v2/logs/synthesis.log).
|
||||
POST-P&R: Fmax = 183.12 MHz, PASS at 80MHz target (real
|
||||
nextpnr-ecp5 measurement, hardware/v2/synthesis/neural_processor_p8/
|
||||
nextpnr.log). Compare V1 isolated PARALLEL=8: 61.71 MHz
|
||||
(hardware/v1/synthesis/p8/) -- ~3x higher Fmax for the pipelined
|
||||
single-processor datapath alone (not yet a system-level
|
||||
comparison -- no Memory Manager/Director/multi-processor overhead
|
||||
included at this milestone).
|
||||
errors: ERR-0001, ERR-0002, ERR-0003 (see errors.log) encountered and
|
||||
resolved/worked around during development.
|
||||
decision: see decisions.log DEC-0002, DEC-0003, DEC-0004.
|
||||
next_action: EXP-0002 (ACC_WIDTH=24 comparison), then M2 (Processor
|
||||
Array, N_PROCESSORS sweep).
|
||||
|
||||
EXP-0002
|
||||
timestamp: 2026-09-05T12:03:12Z
|
||||
git_commit: 07a48e401f56d395f9d1a6e22f1b5ebc6b598e64 (+ uncommitted M1 work)
|
||||
session: v2-M1-neural-processor
|
||||
module: hardware/v2/rtl/neural_processor.v
|
||||
configuration: DATA_WIDTH=8, P_IN=8, ACC_WIDTH=24 (vs EXP-0001's
|
||||
ACC_WIDTH=32 baseline) -- requested explicitly by the user as a test
|
||||
variant ("come test nel perceptrone crea una versione con
|
||||
accumulatori a 24 bit anziche' a 32 bit").
|
||||
reason: ACC_WIDTH is already fully parametric throughout
|
||||
neural_processor.v (no code duplication needed); 24 bits is a real,
|
||||
non-degenerate choice -- worst-case realistic accumulation (e.g. 256
|
||||
INT8 inputs all at +-127/+-128) needs at most 23 signed bits
|
||||
(256 * 128 = 32768, |value| <= 2^22 for the largest single-tile-
|
||||
chain sums this project's configs reach), so 24 bits carries a
|
||||
legitimate 1-bit margin, not an arbitrary/unsafe truncation.
|
||||
command (sim, Verilator): same as EXP-0001 with a copy of
|
||||
tb_neural_processor.v with ACC_WIDTH localparam changed to 24 (V1's
|
||||
own neuron_parallel instantiated at ACC_WIDTH=24 too, for a true
|
||||
bit-exact comparison at the SAME width -- V1's ACC_WIDTH is also a
|
||||
module parameter, no V1 modification needed).
|
||||
command (synth): yosys -p "read_verilog
|
||||
hardware/v2/rtl/neural_processor.v; chparam -set ACC_WIDTH 24
|
||||
neural_processor; synth_ecp5 -json
|
||||
hardware/v2/synthesis/neural_processor_p8_acc24/top.json -top
|
||||
neural_processor"
|
||||
command (timing): nextpnr-ecp5, same flags as EXP-0001, json from
|
||||
the ACC_WIDTH=24 build.
|
||||
result:
|
||||
SIMULATED: 7/7 tests PASS, bit-exact vs V1 at ACC_WIDTH=24 (no
|
||||
overflow in any test vector, as expected from the margin analysis
|
||||
above).
|
||||
SYNTHESIZED: 0 CHECK problems, 8 MULT18X18D (unchanged, multiplier
|
||||
width is DATA_WIDTH-driven not ACC_WIDTH-driven), 509 TRELLIS_FF
|
||||
(was 533 at ACC_WIDTH=32, -24 FF as expected for 8 fewer
|
||||
accumulator bits carried through ~3 pipeline-stage copies),
|
||||
88 CCU2C (was 96), 49 LUT4 (was 55).
|
||||
POST-P&R: Fmax = 176.21 MHz (was 183.12 MHz at ACC_WIDTH=32) --
|
||||
REAL measurement, both from nextpnr-ecp5. The 24-bit build is
|
||||
~4% SLOWER despite fewer resources -- almost certainly placement
|
||||
noise (consistent with this project's established finding,
|
||||
hardware/v1/docs/WORKLOG.md "Timing closure", that seed-to-seed
|
||||
placement variance on this device dominates small logic-width
|
||||
differences), NOT attributed to a real architectural effect
|
||||
without a seed sweep to confirm. Reported as-measured, not
|
||||
overinterpreted -- see hardware/v2/logs/benchmark.log.
|
||||
errors: none.
|
||||
decision: ACC_WIDTH=32 remains the M1 default (matches V1 exactly for
|
||||
ongoing bit-exact comparisons); ACC_WIDTH=24 confirmed as a viable,
|
||||
correctly-functioning, slightly-smaller alternative, not adopted as
|
||||
default without a proper seed sweep (out of scope for this single
|
||||
comparison run).
|
||||
next_action: revisit ACC_WIDTH choice during M10 (Optimization) with a
|
||||
real seed sweep, not before.
|
||||
@@ -0,0 +1,17 @@
|
||||
# V2 simulation log -- solo append, mai troncato/sovrascritto (vedi README.md)
|
||||
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
|
||||
|
||||
[2026-09-05] EXP-0001/EXP-0002 -- hardware/v2/sim/tb_neural_processor.v
|
||||
test: 7 cases (16/32/8/8/8/8/64-input jobs; ACT_NONE + ACT_RELU;
|
||||
extreme INT8 saturation; back-to-back zero-idle-gap tiles)
|
||||
vectors: regular positive, mixed-sign cancellation, extreme INT8
|
||||
(-128,-127,-1,0,1,126,127,127 in one 8-lane tile), back-to-back
|
||||
jobs, 8-tile (64-input) job
|
||||
simulator: Verilator 5.050 (--binary --timing) -- see decisions.log
|
||||
DEC-0004 for why Icarus v13.0 is not trusted for this testbench
|
||||
cycles: not separately profiled at this milestone (throughput/stall
|
||||
cycle counting deferred to M9 per §22)
|
||||
PASS/FAIL: 7/7 PASS (ACC_WIDTH=32); 7/7 PASS (ACC_WIDTH=24, EXP-0002)
|
||||
bit-exact result: V1.y === V2.result_data for every case, both widths
|
||||
stall cycles / memory wait / utilization: N/A (no Memory Manager yet,
|
||||
M1 operands fed directly by testbench per the roadmap)
|
||||
@@ -0,0 +1,16 @@
|
||||
# V2 synthesis log -- solo append, mai troncato/sovrascritto (vedi README.md)
|
||||
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
|
||||
|
||||
[2026-09-05] EXP-0001 -- neural_processor (P_IN=8, ACC_WIDTH=32)
|
||||
LUT: 55 FF: 533 DSP(MULT18X18D): 8 BRAM: 0 CCU2C: 96
|
||||
CHECK: 0 problems. 36 warnings, all "multiple conflicting drivers for
|
||||
neural_processor.\gi" -- benign Yosys quirk for an `integer` used as
|
||||
a synthesizable for-loop index in stage 0's unrolled always block,
|
||||
not a real multi-driver conflict (cross-verified functionally
|
||||
correct on 2 independent simulators). Log: hardware/v2/synthesis/
|
||||
neural_processor_p8/yosys.log
|
||||
|
||||
[2026-09-05] EXP-0002 -- neural_processor (P_IN=8, ACC_WIDTH=24)
|
||||
LUT: 49 FF: 509 DSP(MULT18X18D): 8 BRAM: 0 CCU2C: 88
|
||||
CHECK: 0 problems, same 36 benign warnings as EXP-0001.
|
||||
Log: hardware/v2/synthesis/neural_processor_p8_acc24/yosys.log
|
||||
@@ -0,0 +1,22 @@
|
||||
# V2 timing log -- solo append, mai troncato/sovrascritto (vedi README.md)
|
||||
# Nessuna entry ancora -- popolato incrementalmente man mano che avanza lo sviluppo V2.
|
||||
|
||||
[2026-09-05] EXP-0001 -- neural_processor (P_IN=8, ACC_WIDTH=32)
|
||||
nextpnr-ecp5 --45k --package CABGA381 --speed 8 --freq 80
|
||||
--lpf-allow-unconstrained
|
||||
Fmax: 183.12 MHz -- PASS at 80 MHz (real place&route measurement)
|
||||
Critical path: job_ready -> TRELLIS_IO output pad (i.e. the design's
|
||||
own logic is NOT the bottleneck at this Fmax -- an unconstrained
|
||||
output pin dominates; a real system-level Fmax will differ once
|
||||
this signal is consumed on-chip instead of driven to a pad in
|
||||
isolation). Log: hardware/v2/synthesis/neural_processor_p8/nextpnr.log
|
||||
WNS/TNS: not reported by this nextpnr version in this invocation.
|
||||
|
||||
[2026-09-05] EXP-0002 -- neural_processor (P_IN=8, ACC_WIDTH=24)
|
||||
Same command as above, ACC_WIDTH=24 build.
|
||||
Fmax: 176.21 MHz -- PASS at 80 MHz (real place&route measurement)
|
||||
Delta vs ACC_WIDTH=32: -6.91 MHz (-3.8%) despite FEWER resources --
|
||||
attributed to placement noise, not a real architectural effect
|
||||
(no seed sweep run to confirm either way -- see experiments.log
|
||||
EXP-0002 and benchmark.log). Log: hardware/v2/synthesis/
|
||||
neural_processor_p8_acc24/nextpnr.log
|
||||
@@ -0,0 +1,382 @@
|
||||
// ============================================================
|
||||
// FPGA-Neural V2 -- Neural Processor (M1, docs/v2-description.md §5/§6/§7)
|
||||
//
|
||||
// Autonomous, pipelined perceptron unit. Processes ONE neuron (job) at a
|
||||
// time, but the internal MAC datapath is a genuine 8-stage pipeline
|
||||
// (P_IN=8 baseline): a new tile of P_IN inputs/weights can be accepted
|
||||
// every cycle while the previous tiles are still draining through the
|
||||
// adder tree/accumulator/activation stages -- throughput-oriented per
|
||||
// §5 ("l'obiettivo principale e' il throughput, non la minima latenza").
|
||||
//
|
||||
// Arithmetic is bit-exact with hardware/v1/rtl/neuron_parallel.v +
|
||||
// mac8.v + mac_unit.v (same MAC order, same sign-extended INT32-style
|
||||
// accumulation, same bias/activation/saturation logic) -- verified in
|
||||
// sim/tb_neural_processor.v against the frozen V1 reference. See
|
||||
// hardware/v2/logs/decisions.log DEC-0002 for why the outer FSM merges
|
||||
// the LOAD_TILE/MAC/ACCUM/NEXT_TILE states from §6's baseline list into
|
||||
// a single pipelined NP_WAIT_OPERANDS state.
|
||||
//
|
||||
// Stage pipeline (P_IN=8, TREE_LEVELS=log2(P_IN)=3):
|
||||
// Stage 0 input alignment/register
|
||||
// Stage 1 P_IN multipliers (INT8 x INT8)
|
||||
// Stage 2..(1+TREE_LEVELS) balanced adder tree, one level per stage
|
||||
// Stage (2+TREE_LEVELS) accumulator (running sum across tiles)
|
||||
// Stage (3+TREE_LEVELS) bias add + activation
|
||||
// Stage (4+TREE_LEVELS) INT8 saturation / output register
|
||||
// For P_IN=8 this is stages 0..7 (8 stages total), matching §5 exactly.
|
||||
// ============================================================
|
||||
|
||||
module neural_processor #(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter P_IN = 8,
|
||||
parameter ACC_WIDTH = 32
|
||||
)(
|
||||
input clk,
|
||||
input rst,
|
||||
|
||||
// ---- job descriptor (NP_LOAD_JOB) ----
|
||||
// Address fields (input/weight/bias base addresses) from §6's
|
||||
// baseline job descriptor are intentionally NOT part of this
|
||||
// interface yet -- M1 has no Memory Manager (§v2-description.md
|
||||
// roadmap M4), operands are streamed directly by the testbench.
|
||||
// They will be added when the Memory Manager (M4) is integrated.
|
||||
input job_valid,
|
||||
output job_ready,
|
||||
input [15:0] job_node_id,
|
||||
input signed [DATA_WIDTH-1:0] job_bias,
|
||||
input [1:0] job_activation,
|
||||
|
||||
// ---- operand stream (valid/ready/data/last, §7) ----
|
||||
input operand_valid,
|
||||
output operand_ready,
|
||||
input signed [DATA_WIDTH*P_IN-1:0] input_data,
|
||||
input signed [DATA_WIDTH*P_IN-1:0] weight_data,
|
||||
input tile_last,
|
||||
|
||||
// ---- result stream (valid/ready/data, §7) ----
|
||||
output reg result_valid,
|
||||
input result_ready,
|
||||
output reg signed [DATA_WIDTH-1:0] result_data,
|
||||
output reg [15:0] result_node_id,
|
||||
|
||||
// observability (testbench/debug, not part of the handshake contract)
|
||||
output reg [3:0] np_state,
|
||||
output reg np_error
|
||||
);
|
||||
|
||||
// ============================================================
|
||||
// ACTIVATION ENCODING -- identical to hardware/v1/rtl/neuron_parallel.v
|
||||
// ============================================================
|
||||
localparam ACT_NONE = 2'd0;
|
||||
localparam ACT_RELU = 2'd1;
|
||||
|
||||
// ============================================================
|
||||
// OUTER FSM STATE ENCODING (§6 baseline, see DEC-0002 for the
|
||||
// 4-state merge)
|
||||
// ============================================================
|
||||
localparam NP_IDLE = 4'd0;
|
||||
localparam NP_LOAD_JOB = 4'd1;
|
||||
localparam NP_WAIT_OPERANDS = 4'd2; // absorbs LOAD_TILE/MAC/ACCUM/NEXT_TILE
|
||||
localparam NP_FINISH = 4'd3; // draining pipeline after tile_last
|
||||
localparam NP_WRITE_RESULT = 4'd4;
|
||||
localparam NP_DONE = 4'd5;
|
||||
localparam NP_ERROR = 4'd6;
|
||||
|
||||
localparam TREE_LEVELS = $clog2(P_IN);
|
||||
localparam PROD_WIDTH = 2 * DATA_WIDTH;
|
||||
|
||||
// ---- job context (latched at NP_LOAD_JOB, held for the whole job) ----
|
||||
reg signed [DATA_WIDTH-1:0] bias_reg;
|
||||
reg [1:0] activation_reg;
|
||||
reg [15:0] node_id_reg;
|
||||
|
||||
assign operand_ready = (np_state == NP_WAIT_OPERANDS);
|
||||
|
||||
// ============================================================
|
||||
// STAGE 0 -- input alignment/register
|
||||
// ============================================================
|
||||
reg valid0, last0;
|
||||
reg signed [DATA_WIDTH-1:0] x0 [0:P_IN-1];
|
||||
reg signed [DATA_WIDTH-1:0] w0 [0:P_IN-1];
|
||||
|
||||
integer gi;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
valid0 <= 1'b0;
|
||||
last0 <= 1'b0;
|
||||
end else begin
|
||||
valid0 <= operand_valid && operand_ready;
|
||||
// last0 must be gated exactly like valid0 -- otherwise a
|
||||
// tile_last asserted by the master before operand_ready
|
||||
// rises (ordinary valid-before-ready behavior, see
|
||||
// operand_ready's own comment above) leaks a "last" tag
|
||||
// into the pipeline with no corresponding valid tile,
|
||||
// racing ahead of the real one and corrupting the
|
||||
// valid5/last5-derived capture at stage 6/7 (see
|
||||
// hardware/v2/logs/errors.log ERR-0003).
|
||||
last0 <= (operand_valid && operand_ready) ? tile_last : 1'b0;
|
||||
if (operand_valid && operand_ready) begin
|
||||
for (gi = 0; gi < P_IN; gi = gi + 1) begin
|
||||
x0[gi] <= input_data[gi*DATA_WIDTH +: DATA_WIDTH];
|
||||
w0[gi] <= weight_data[gi*DATA_WIDTH +: DATA_WIDTH];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ============================================================
|
||||
// STAGE 1 -- P_IN multipliers, sign-extended to ACC_WIDTH
|
||||
// (same per-lane product as hardware/v1/rtl/mac_unit.v)
|
||||
// ============================================================
|
||||
reg valid1, last1;
|
||||
reg signed [ACC_WIDTH-1:0] prod1 [0:P_IN-1];
|
||||
|
||||
wire signed [PROD_WIDTH-1:0] product_comb [0:P_IN-1];
|
||||
genvar gm;
|
||||
generate
|
||||
for (gm = 0; gm < P_IN; gm = gm + 1) begin : GEN_MUL
|
||||
assign product_comb[gm] = x0[gm] * w0[gm];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
valid1 <= 1'b0;
|
||||
last1 <= 1'b0;
|
||||
end else begin
|
||||
valid1 <= valid0;
|
||||
last1 <= last0;
|
||||
for (gi = 0; gi < P_IN; gi = gi + 1) begin
|
||||
prod1[gi] <= {{(ACC_WIDTH-PROD_WIDTH){product_comb[gi][PROD_WIDTH-1]}}, product_comb[gi]};
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ============================================================
|
||||
// STAGES 2..(1+TREE_LEVELS) -- balanced adder tree, one level/stage
|
||||
// (same tree order as hardware/v1/rtl/mac8.v)
|
||||
// ============================================================
|
||||
// Level 0 (combinational view of the registered products) is kept
|
||||
// as plain wires, never written by an always block -- only levels
|
||||
// 1..TREE_LEVELS are real registers, each with exactly one driver
|
||||
// (its own GEN_TREE_NODE always block), avoiding any reg array
|
||||
// with mixed combinational/sequential drivers across generate
|
||||
// blocks.
|
||||
wire signed [ACC_WIDTH-1:0] level0 [0:P_IN-1];
|
||||
genvar gz;
|
||||
generate
|
||||
for (gz = 0; gz < P_IN; gz = gz + 1) begin : GEN_TREE_L0
|
||||
assign level0[gz] = prod1[gz];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
reg [TREE_LEVELS-1:0] valid_tree;
|
||||
reg [TREE_LEVELS-1:0] last_tree;
|
||||
reg signed [ACC_WIDTH-1:0] tree [1:TREE_LEVELS][0:P_IN-1];
|
||||
|
||||
genvar gl, gn;
|
||||
generate
|
||||
for (gl = 0; gl < TREE_LEVELS; gl = gl + 1) begin : GEN_TREE_LEVEL
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
valid_tree[gl] <= 1'b0;
|
||||
last_tree[gl] <= 1'b0;
|
||||
end else begin
|
||||
valid_tree[gl] <= (gl == 0) ? valid1 : valid_tree[gl-1];
|
||||
last_tree[gl] <= (gl == 0) ? last1 : last_tree[gl-1];
|
||||
end
|
||||
end
|
||||
for (gn = 0; gn < (P_IN >> (gl+1)); gn = gn + 1) begin : GEN_TREE_NODE
|
||||
if (gl == 0) begin : GEN_FROM_LEVEL0
|
||||
always @(posedge clk) begin
|
||||
tree[1][gn] <= level0[2*gn] + level0[2*gn+1];
|
||||
end
|
||||
end else begin : GEN_FROM_TREE
|
||||
always @(posedge clk) begin
|
||||
tree[gl+1][gn] <= tree[gl][2*gn] + tree[gl][2*gn+1];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
wire valid_tree_out = (TREE_LEVELS == 0) ? valid1 : valid_tree[TREE_LEVELS-1];
|
||||
wire last_tree_out = (TREE_LEVELS == 0) ? last1 : last_tree[TREE_LEVELS-1];
|
||||
wire signed [ACC_WIDTH-1:0] tile_sum = (TREE_LEVELS == 0) ? prod1[0] : tree[TREE_LEVELS][0];
|
||||
|
||||
// ============================================================
|
||||
// STAGE (2+TREE_LEVELS) -- accumulator (running sum across tiles
|
||||
// of the SAME job; cleared at NP_LOAD_JOB)
|
||||
// ============================================================
|
||||
reg signed [ACC_WIDTH-1:0] acc_reg;
|
||||
reg valid5, last5;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
acc_reg <= {ACC_WIDTH{1'b0}};
|
||||
valid5 <= 1'b0;
|
||||
last5 <= 1'b0;
|
||||
end else begin
|
||||
valid5 <= valid_tree_out;
|
||||
last5 <= last_tree_out;
|
||||
if (np_state == NP_LOAD_JOB) begin
|
||||
acc_reg <= {ACC_WIDTH{1'b0}};
|
||||
end else if (valid_tree_out) begin
|
||||
acc_reg <= acc_reg + tile_sum;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ============================================================
|
||||
// STAGE (3+TREE_LEVELS) -- bias add + activation
|
||||
// (same encoding/logic as hardware/v1/rtl/neuron_parallel.v)
|
||||
// ============================================================
|
||||
wire signed [ACC_WIDTH-1:0] bias_ext =
|
||||
{{(ACC_WIDTH-DATA_WIDTH){bias_reg[DATA_WIDTH-1]}}, bias_reg};
|
||||
|
||||
// acc_reg already reflects THIS cycle's update (non-blocking), so
|
||||
// when last5 is set the just-updated acc_reg (available next
|
||||
// cycle) is the complete sum -- final_acc is therefore computed
|
||||
// one cycle after last5/valid5 using the settled acc_reg value.
|
||||
reg valid6, last6;
|
||||
reg signed [ACC_WIDTH-1:0] final_acc_reg;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
valid6 <= 1'b0;
|
||||
last6 <= 1'b0;
|
||||
end else begin
|
||||
valid6 <= valid5;
|
||||
last6 <= last5;
|
||||
final_acc_reg <= acc_reg + bias_ext;
|
||||
end
|
||||
end
|
||||
|
||||
wire final_acc_sign = final_acc_reg[ACC_WIDTH-1];
|
||||
wire final_acc_upper_all0 = ~(|final_acc_reg[ACC_WIDTH-1:DATA_WIDTH-1]);
|
||||
wire final_acc_upper_all1 = &final_acc_reg[ACC_WIDTH-1:DATA_WIDTH-1];
|
||||
wire final_acc_in_range = final_acc_upper_all0 | final_acc_upper_all1;
|
||||
wire final_acc_le_zero = final_acc_sign | ~(|final_acc_reg);
|
||||
|
||||
wire signed [DATA_WIDTH-1:0] y_none =
|
||||
final_acc_in_range ? final_acc_reg[DATA_WIDTH-1:0]
|
||||
: (final_acc_sign ? {1'b1, {(DATA_WIDTH-1){1'b0}}}
|
||||
: {1'b0, {(DATA_WIDTH-1){1'b1}}});
|
||||
|
||||
wire signed [DATA_WIDTH-1:0] y_relu =
|
||||
final_acc_le_zero ? {DATA_WIDTH{1'b0}}
|
||||
: (final_acc_upper_all0 ? final_acc_reg[DATA_WIDTH-1:0]
|
||||
: {1'b0, {(DATA_WIDTH-1){1'b1}}});
|
||||
|
||||
// ============================================================
|
||||
// STAGE (4+TREE_LEVELS) -- output register / saturation result
|
||||
// ============================================================
|
||||
reg valid7;
|
||||
reg signed [DATA_WIDTH-1:0] y7;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
valid7 <= 1'b0;
|
||||
end else begin
|
||||
valid7 <= last6;
|
||||
case (activation_reg)
|
||||
ACT_NONE: y7 <= y_none;
|
||||
default: y7 <= y_relu;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// A new job must not be accepted (and acc_reg must not be cleared)
|
||||
// while any tile from a PREVIOUS job is still draining through the
|
||||
// datapath -- otherwise a back-to-back job launched immediately
|
||||
// after NP_DONE could have its own first tile(s) race a stale
|
||||
// in-flight tile still working through stages 0..7, or have
|
||||
// NP_LOAD_JOB clear acc_reg while it still holds a not-yet-read
|
||||
// partial sum. job_ready is gated on this so NP_IDLE simply holds
|
||||
// one extra cycle when needed -- transparent to the job handshake,
|
||||
// no protocol change.
|
||||
wire pipeline_busy = valid0 || valid1 || (|valid_tree) || valid5 || valid6 || valid7;
|
||||
assign job_ready = (np_state == NP_IDLE) && !pipeline_busy;
|
||||
|
||||
// ============================================================
|
||||
// OUTER FSM (§6) -- job/result handshake around the pipeline above
|
||||
// ============================================================
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
np_state <= NP_IDLE;
|
||||
np_error <= 1'b0;
|
||||
result_valid <= 1'b0;
|
||||
result_data <= {DATA_WIDTH{1'b0}};
|
||||
result_node_id <= 16'h0;
|
||||
bias_reg <= {DATA_WIDTH{1'b0}};
|
||||
activation_reg <= ACT_RELU;
|
||||
node_id_reg <= 16'h0;
|
||||
end else begin
|
||||
case (np_state)
|
||||
|
||||
NP_IDLE: begin
|
||||
if (job_valid && job_ready) begin
|
||||
bias_reg <= job_bias;
|
||||
activation_reg <= job_activation;
|
||||
node_id_reg <= job_node_id;
|
||||
np_state <= NP_LOAD_JOB;
|
||||
end
|
||||
end
|
||||
|
||||
NP_LOAD_JOB: begin
|
||||
np_state <= NP_WAIT_OPERANDS;
|
||||
end
|
||||
|
||||
NP_WAIT_OPERANDS: begin
|
||||
if (operand_valid && operand_ready && tile_last) begin
|
||||
np_state <= NP_FINISH;
|
||||
end
|
||||
end
|
||||
|
||||
NP_FINISH: begin
|
||||
// Draining: wait for the tagged-last tile's result
|
||||
// to reach the output stage (valid7).
|
||||
if (valid7) begin
|
||||
result_valid <= 1'b1;
|
||||
result_data <= y7;
|
||||
result_node_id <= node_id_reg;
|
||||
np_state <= NP_WRITE_RESULT;
|
||||
end
|
||||
end
|
||||
|
||||
NP_WRITE_RESULT: begin
|
||||
if (result_valid && result_ready) begin
|
||||
result_valid <= 1'b0;
|
||||
np_state <= NP_DONE;
|
||||
end
|
||||
end
|
||||
|
||||
NP_DONE: begin
|
||||
np_state <= NP_IDLE;
|
||||
end
|
||||
|
||||
NP_ERROR: begin
|
||||
// Recoverable only via rst -- documented in
|
||||
// hardware/v2/logs/architecture.log: an error must
|
||||
// not block the rest of the Neural Processor
|
||||
// Array (§34), only this one processor.
|
||||
end
|
||||
|
||||
// Reachable only if np_state ever holds a value outside
|
||||
// 0..6 (a genuine encoding corruption -- not exercised
|
||||
// in normal operation). Upstream protocol misuse
|
||||
// (an operand arriving when this processor cannot
|
||||
// consume it) is NOT policed here -- see
|
||||
// hardware/v2/logs/decisions.log DEC-0003: that
|
||||
// responsibility belongs to the Neural Director (M5),
|
||||
// which is the actual issuer of operand traffic and
|
||||
// the only component that can otherwise arbitrate
|
||||
// among multiple Neural Processors.
|
||||
default: np_state <= NP_ERROR;
|
||||
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,320 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
// ============================================================
|
||||
// M1 testbench (docs/v2-description.md §20/§21): hardware/v2/rtl/
|
||||
// neural_processor.v vs the frozen V1 golden reference
|
||||
// (hardware/v1/rtl/neuron_parallel.v + mac8.v + mac_unit.v),
|
||||
// instantiated side by side and driven with IDENTICAL operands, then
|
||||
// compared bit-exact.
|
||||
//
|
||||
// V1's neuron_parallel presents its whole N_INPUTS-wide input/weight
|
||||
// bus at once (single `start` pulse); V2's neural_processor streams
|
||||
// P_IN-wide tiles with a valid/ready/last handshake. This testbench
|
||||
// bridges the two: it holds the full N_INPUTS-wide vector locally and
|
||||
// feeds it to V1 in one shot while streaming it to V2 tile-by-tile,
|
||||
// then asserts V1.y === V2.result_data for every case.
|
||||
//
|
||||
// Coverage (§20):
|
||||
// - functional: regular positive/negative/mixed vectors, several
|
||||
// N_INPUTS/tile counts;
|
||||
// - extreme INT8 (§20 list): -128, -127, -1, 0, 1, 126, 127, and an
|
||||
// all-poison saturating case;
|
||||
// - both activations (ACT_NONE, ACT_RELU);
|
||||
// - back-to-back jobs with NO idle gap (throughput check: a new
|
||||
// job's first tile is presented the very cycle after the previous
|
||||
// job's NP_DONE), proving tiles can stream without the outer FSM
|
||||
// stalling between jobs.
|
||||
//
|
||||
// NOT covered here: operand-arrival protocol misuse (an operand sent
|
||||
// while this processor cannot consume it). See
|
||||
// hardware/v2/logs/decisions.log DEC-0003 -- that check was removed
|
||||
// from neural_processor.v after triggering a reproducible Icarus
|
||||
// Verilog v13.0 evaluation bug (hardware/v2/logs/errors.log ERR-0002)
|
||||
// and is deferred to the Neural Director (M5), the actual owner of
|
||||
// operand-issue arbitration.
|
||||
//
|
||||
// Icarus Verilog v13.0 toolchain note (hardware/v2/logs/errors.log
|
||||
// ERR-0001): a task (or any named `begin:label` block) whose FIRST
|
||||
// executable statement is a blocking assignment, called immediately
|
||||
// after a time-consuming statement in the caller with no intervening
|
||||
// `@(posedge clk)`, can silently fail to make that assignment visible
|
||||
// to other modules at the next clock edge (reproduced in isolation
|
||||
// down to a 3-line task; fixed by always beginning such a task with an
|
||||
// explicit `@(posedge clk);` before its first assignment). run_case
|
||||
// below follows this rule -- the same defensive convention already
|
||||
// used throughout hardware/v1/sim's own tasks (e.g.
|
||||
// neuron_parallel_tb.v's run_neuron), which is why V1's own tests were
|
||||
// never affected.
|
||||
// ============================================================
|
||||
|
||||
module tb;
|
||||
|
||||
localparam DATA_WIDTH = 8;
|
||||
localparam P_IN = 8;
|
||||
localparam ACC_WIDTH = 32;
|
||||
localparam MAX_N = 64; // largest N_INPUTS exercised in this tb
|
||||
|
||||
reg clk, rst;
|
||||
initial begin clk = 0; forever #5 clk = ~clk; end
|
||||
|
||||
integer errors;
|
||||
integer tests;
|
||||
|
||||
// ---------------- V1 golden reference ----------------
|
||||
reg v1_start;
|
||||
reg signed [DATA_WIDTH*MAX_N-1:0] v1_x_bus, v1_w_bus;
|
||||
reg signed [DATA_WIDTH-1:0] v1_bias;
|
||||
reg [1:0] v1_activation;
|
||||
reg [15:0] v1_n_inputs_real;
|
||||
wire v1_busy, v1_done;
|
||||
wire signed [DATA_WIDTH-1:0] v1_y;
|
||||
|
||||
neuron_parallel #(
|
||||
.DATA_WIDTH(DATA_WIDTH), .N_INPUTS(MAX_N), .PARALLEL(P_IN), .ACC_WIDTH(ACC_WIDTH)
|
||||
) v1_dut (
|
||||
.clk(clk), .rst(rst), .start(v1_start),
|
||||
.x_bus(v1_x_bus), .w_bus(v1_w_bus), .bias(v1_bias),
|
||||
.activation(v1_activation), .n_inputs_real(v1_n_inputs_real),
|
||||
.y(v1_y), .busy(v1_busy), .done(v1_done)
|
||||
);
|
||||
|
||||
// ---------------- V2 neural_processor under test ----------------
|
||||
reg job_valid;
|
||||
wire job_ready;
|
||||
reg [15:0] job_node_id;
|
||||
reg signed [DATA_WIDTH-1:0] job_bias;
|
||||
reg [1:0] job_activation;
|
||||
|
||||
reg operand_valid;
|
||||
wire operand_ready;
|
||||
reg signed [DATA_WIDTH*P_IN-1:0] input_data, weight_data;
|
||||
reg tile_last;
|
||||
|
||||
wire result_valid;
|
||||
reg result_ready;
|
||||
wire signed [DATA_WIDTH-1:0] result_data;
|
||||
wire [15:0] result_node_id;
|
||||
wire [3:0] np_state;
|
||||
wire np_error;
|
||||
|
||||
neural_processor #(
|
||||
.DATA_WIDTH(DATA_WIDTH), .P_IN(P_IN), .ACC_WIDTH(ACC_WIDTH)
|
||||
) v2_dut (
|
||||
.clk(clk), .rst(rst),
|
||||
.job_valid(job_valid), .job_ready(job_ready),
|
||||
.job_node_id(job_node_id), .job_bias(job_bias), .job_activation(job_activation),
|
||||
.operand_valid(operand_valid), .operand_ready(operand_ready),
|
||||
.input_data(input_data), .weight_data(weight_data), .tile_last(tile_last),
|
||||
.result_valid(result_valid), .result_ready(result_ready),
|
||||
.result_data(result_data), .result_node_id(result_node_id),
|
||||
.np_state(np_state), .np_error(np_error)
|
||||
);
|
||||
|
||||
// local operand storage for one case (up to MAX_N elements)
|
||||
reg signed [DATA_WIDTH-1:0] xmem [0:MAX_N-1];
|
||||
reg signed [DATA_WIDTH-1:0] wmem [0:MAX_N-1];
|
||||
integer i;
|
||||
integer watchdog;
|
||||
integer n_inputs;
|
||||
integer n_tiles;
|
||||
integer t, k;
|
||||
reg signed [DATA_WIDTH-1:0] v2_result_captured;
|
||||
reg v1_done_captured, v2_valid_captured;
|
||||
integer v2_cycles;
|
||||
|
||||
task automatic run_case(
|
||||
input integer n, // real number of inputs (multiple of P_IN)
|
||||
input signed [DATA_WIDTH-1:0] bias,
|
||||
input [1:0] activation,
|
||||
input signed [DATA_WIDTH-1:0] expect_y,
|
||||
input [15:0] node_id
|
||||
);
|
||||
begin
|
||||
@(posedge clk); // see toolchain note in the file header -- always sync first
|
||||
tests = tests + 1;
|
||||
n_inputs = n;
|
||||
n_tiles = n / P_IN;
|
||||
|
||||
// ---- drive V1 ----
|
||||
v1_x_bus = {DATA_WIDTH*MAX_N{1'b0}};
|
||||
v1_w_bus = {DATA_WIDTH*MAX_N{1'b0}};
|
||||
for (i = 0; i < n_inputs; i = i + 1) begin
|
||||
v1_x_bus[i*DATA_WIDTH +: DATA_WIDTH] = xmem[i];
|
||||
v1_w_bus[i*DATA_WIDTH +: DATA_WIDTH] = wmem[i];
|
||||
end
|
||||
v1_bias = bias;
|
||||
v1_activation = activation;
|
||||
v1_n_inputs_real = n_inputs[15:0];
|
||||
v1_start = 1;
|
||||
@(posedge clk);
|
||||
v1_start = 0;
|
||||
|
||||
watchdog = 0;
|
||||
while (!v1_done && watchdog < 200) begin
|
||||
@(posedge clk);
|
||||
watchdog = watchdog + 1;
|
||||
end
|
||||
v1_done_captured = v1_done;
|
||||
if (!v1_done) begin
|
||||
$display("FAIL n=%0d: V1 reference did not complete (watchdog)", n_inputs);
|
||||
errors = errors + 1;
|
||||
end
|
||||
|
||||
// ---- drive V2 (streamed, P_IN-wide tiles) in parallel
|
||||
// with issuing the job descriptor ----
|
||||
job_node_id = node_id;
|
||||
job_bias = bias;
|
||||
job_activation = activation;
|
||||
job_valid = 1;
|
||||
while (!job_ready) @(posedge clk); // wait for NP_IDLE before the handshake edge
|
||||
@(posedge clk); // handshake: job_valid & job_ready both true on this edge
|
||||
job_valid = 0;
|
||||
|
||||
for (t = 0; t < n_tiles; t = t + 1) begin
|
||||
input_data = {DATA_WIDTH*P_IN{1'b0}};
|
||||
weight_data = {DATA_WIDTH*P_IN{1'b0}};
|
||||
for (k = 0; k < P_IN; k = k + 1) begin
|
||||
input_data[k*DATA_WIDTH +: DATA_WIDTH] = xmem[t*P_IN + k];
|
||||
weight_data[k*DATA_WIDTH +: DATA_WIDTH] = wmem[t*P_IN + k];
|
||||
end
|
||||
tile_last = (t == n_tiles - 1);
|
||||
operand_valid = 1;
|
||||
while (!operand_ready) @(posedge clk); // wait for NP_WAIT_OPERANDS
|
||||
@(posedge clk); // handshake edge
|
||||
end
|
||||
operand_valid = 0;
|
||||
tile_last = 0;
|
||||
|
||||
result_ready = 1;
|
||||
v2_cycles = 0;
|
||||
while (!result_valid && v2_cycles < 200) begin
|
||||
@(posedge clk);
|
||||
v2_cycles = v2_cycles + 1;
|
||||
end
|
||||
v2_valid_captured = result_valid;
|
||||
if (!result_valid) begin
|
||||
$display("FAIL n=%0d: V2 neural_processor did not produce result_valid (watchdog)", n_inputs);
|
||||
errors = errors + 1;
|
||||
end else begin
|
||||
v2_result_captured = result_data;
|
||||
@(posedge clk); // let result_valid clear (NP_WRITE_RESULT -> NP_DONE)
|
||||
end
|
||||
|
||||
if (v1_done_captured && v2_valid_captured) begin
|
||||
if (v1_y !== v2_result_captured) begin
|
||||
$display("FAIL n=%0d bias=%0d act=%0d: V1.y=%0d V2.result=%0d MISMATCH (expected both == %0d)",
|
||||
n_inputs, bias, activation, v1_y, v2_result_captured, expect_y);
|
||||
errors = errors + 1;
|
||||
end else if (v1_y !== expect_y) begin
|
||||
$display("FAIL n=%0d: V1/V2 agree (%0d) but disagree with hand-computed expectation %0d",
|
||||
n_inputs, v1_y, expect_y);
|
||||
errors = errors + 1;
|
||||
end else begin
|
||||
$display("PASS n=%0d bias=%0d act=%0d: V1.y=V2.result=%0d (bit-exact, matches hand-computed expectation)",
|
||||
n_inputs, bias, activation, v1_y);
|
||||
end
|
||||
end
|
||||
|
||||
// let both DUTs return fully idle before the next case
|
||||
while (!job_ready || np_state !== 4'd0) @(posedge clk);
|
||||
end
|
||||
endtask
|
||||
|
||||
// Compute the exact expected saturated/activated result in Verilog
|
||||
// integer math (independent "third oracle", not derived from
|
||||
// either DUT), used for a handful of hand-picked cases below.
|
||||
function automatic signed [DATA_WIDTH-1:0] expect_relu(input integer acc, input integer bias);
|
||||
integer s;
|
||||
begin
|
||||
s = acc + bias;
|
||||
if (s <= 0) expect_relu = 0;
|
||||
else if (s > 127) expect_relu = 127;
|
||||
else expect_relu = s[DATA_WIDTH-1:0];
|
||||
end
|
||||
endfunction
|
||||
|
||||
function automatic signed [DATA_WIDTH-1:0] expect_none(input integer acc, input integer bias);
|
||||
integer s;
|
||||
begin
|
||||
s = acc + bias;
|
||||
if (s > 127) expect_none = 127;
|
||||
else if (s < -128) expect_none = -128;
|
||||
else expect_none = s[DATA_WIDTH-1:0];
|
||||
end
|
||||
endfunction
|
||||
|
||||
integer acc_calc;
|
||||
|
||||
initial begin
|
||||
errors = 0;
|
||||
tests = 0;
|
||||
rst = 1;
|
||||
v1_start = 0; v1_x_bus = 0; v1_w_bus = 0; v1_bias = 0; v1_activation = 1; v1_n_inputs_real = 0;
|
||||
job_valid = 0; job_node_id = 0; job_bias = 0; job_activation = 1;
|
||||
operand_valid = 0; input_data = 0; weight_data = 0; tile_last = 0;
|
||||
result_ready = 0;
|
||||
repeat(4) @(posedge clk);
|
||||
rst = 0;
|
||||
@(posedge clk);
|
||||
|
||||
// ---- TEST 1: regular positive vector, 16 inputs, ACT_RELU ----
|
||||
for (i = 0; i < 16; i = i + 1) begin xmem[i] = 3; wmem[i] = 2; end
|
||||
acc_calc = 16 * 3 * 2; // 96
|
||||
run_case(16, 8'sd0, 2'd1, expect_relu(acc_calc, 0), 16'd1);
|
||||
|
||||
// ---- TEST 2: mixed sign, 32 inputs, ACT_NONE, negative bias ----
|
||||
for (i = 0; i < 32; i = i + 1) begin
|
||||
xmem[i] = (i % 2 == 0) ? 8'sd5 : -8'sd5;
|
||||
wmem[i] = 8'sd4;
|
||||
end
|
||||
acc_calc = 0; // alternating +20/-20 cancels exactly over 32 terms
|
||||
run_case(32, -8'sd10, 2'd0, expect_none(acc_calc, -10), 16'd2);
|
||||
|
||||
// ---- TEST 3: extreme INT8 values (docs/v2-description.md §20) ----
|
||||
// -128 * 127 summed across all 8 lanes of a single tile, ACT_NONE
|
||||
// (deliberately saturating, both directions exercised via bias).
|
||||
xmem[0]=-8'sd128; wmem[0]=8'sd127;
|
||||
xmem[1]=-8'sd127; wmem[1]=8'sd1;
|
||||
xmem[2]=-8'sd1; wmem[2]=8'sd1;
|
||||
xmem[3]=8'sd0; wmem[3]=8'sd127;
|
||||
xmem[4]=8'sd1; wmem[4]=8'sd1;
|
||||
xmem[5]=8'sd126; wmem[5]=8'sd1;
|
||||
xmem[6]=8'sd127; wmem[6]=8'sd1;
|
||||
xmem[7]=8'sd127; wmem[7]=8'sd127;
|
||||
acc_calc = (-128*127) + (-127*1) + (-1*1) + (0*127) + (1*1) + (126*1) + (127*1) + (127*127);
|
||||
run_case(8, 8'sd0, 2'd0, expect_none(acc_calc, 0), 16'd3);
|
||||
run_case(8, 8'sd0, 2'd1, expect_relu(acc_calc, 0), 16'd4);
|
||||
|
||||
// ---- TEST 4: n_inputs=0 is NOT exercised here (P_IN>0 always
|
||||
// required in V2 -- a job with zero tiles is a protocol
|
||||
// question for the Neural Director, not this unit; V1's
|
||||
// BUG-003/004 zero-input edge cases are V1-specific fixes,
|
||||
// out of scope for M1's bit-exact comparison). ----
|
||||
|
||||
// ---- TEST 5: back-to-back jobs, no idle gap between them
|
||||
// (throughput check) ----
|
||||
for (i = 0; i < 8; i = i + 1) begin xmem[i] = 1; wmem[i] = 1; end
|
||||
acc_calc = 8;
|
||||
run_case(8, 8'sd0, 2'd1, expect_relu(acc_calc, 0), 16'd5);
|
||||
for (i = 0; i < 8; i = i + 1) begin xmem[i] = 2; wmem[i] = 2; end
|
||||
acc_calc = 8*4;
|
||||
run_case(8, 8'sd0, 2'd1, expect_relu(acc_calc, 0), 16'd6);
|
||||
|
||||
// ---- TEST 6: 64-input job (8 tiles), ACT_RELU ----
|
||||
for (i = 0; i < 64; i = i + 1) begin xmem[i] = 1; wmem[i] = 1; end
|
||||
acc_calc = 64;
|
||||
run_case(64, 8'sd5, 2'd1, expect_relu(acc_calc, 5), 16'd7);
|
||||
|
||||
// TEST 7 (protocol-violation negative test) removed -- see
|
||||
// decisions.log DEC-0003 and the file header note above.
|
||||
|
||||
$display("========================================");
|
||||
if (errors == 0)
|
||||
$display("ALL %0d TESTS PASSED (bit-exact vs hardware/v1 golden reference)", tests);
|
||||
else
|
||||
$display("FAILED: %0d/%0d test(s) had errors -- see messages above", errors, tests);
|
||||
$display("========================================");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,211 @@
|
||||
|
||||
|
||||
Info: Logic utilisation before packing:
|
||||
Info: Total LUT4s: 247/43848 0%
|
||||
Info: logic LUTs: 55/43848 0%
|
||||
Info: carry LUTs: 192/43848 0%
|
||||
Info: RAM LUTs: 0/ 5481 0%
|
||||
Info: RAMW LUTs: 0/10962 0%
|
||||
|
||||
Info: Total DFFs: 533/43848 1%
|
||||
|
||||
Info: Packing IOs..
|
||||
Info: Packing constants..
|
||||
Info: Packing carries...
|
||||
Info: Packing LUTs...
|
||||
Info: Packing LUT5-7s...
|
||||
Info: Packing FFs...
|
||||
Info: 200 FFs paired with LUTs.
|
||||
Info: Generating derived timing constraints...
|
||||
Info: Promoting globals...
|
||||
Info: promoting clock net clk$TRELLIS_IO_IN to global network
|
||||
Info: Checksum: 0x25ed72db
|
||||
|
||||
Info: Device utilisation:
|
||||
Info: TRELLIS_IO: 192/ 245 78%
|
||||
Info: DCCA: 1/ 56 1%
|
||||
Info: DP16KD: 0/ 108 0%
|
||||
Info: MULT18X18D: 8/ 72 11%
|
||||
Info: ALU54B: 0/ 36 0%
|
||||
Info: EHXPLLL: 0/ 4 0%
|
||||
Info: EXTREFB: 0/ 2 0%
|
||||
Info: DCUA: 0/ 2 0%
|
||||
Info: PCSCLKDIV: 0/ 2 0%
|
||||
Info: IOLOGIC: 0/ 160 0%
|
||||
Info: SIOLOGIC: 0/ 85 0%
|
||||
Info: GSR: 0/ 1 0%
|
||||
Info: JTAGG: 0/ 1 0%
|
||||
Info: OSCG: 0/ 1 0%
|
||||
Info: SEDGA: 0/ 1 0%
|
||||
Info: DTR: 0/ 1 0%
|
||||
Info: USRMCLK: 0/ 1 0%
|
||||
Info: CLKDIVF: 0/ 4 0%
|
||||
Info: ECLKSYNCB: 0/ 10 0%
|
||||
Info: DLLDELD: 0/ 8 0%
|
||||
Info: DDRDLL: 0/ 4 0%
|
||||
Info: DQSBUFM: 0/ 10 0%
|
||||
Info: TRELLIS_ECLKBUF: 0/ 8 0%
|
||||
Info: ECLKBRIDGECS: 0/ 2 0%
|
||||
Info: DCSC: 0/ 2 0%
|
||||
Info: TRELLIS_FF: 533/ 43848 1%
|
||||
Info: TRELLIS_COMB: 285/ 43848 0%
|
||||
Info: TRELLIS_RAMW: 0/ 5481 0%
|
||||
|
||||
Info: Placed 0 cells based on constraints.
|
||||
Info: Creating initial analytic placement for 398 cells, random placement wirelen = 48233.
|
||||
Info: at initial placer iter 0, wirelen = 12124
|
||||
Info: at initial placer iter 1, wirelen = 11322
|
||||
Info: at initial placer iter 2, wirelen = 11157
|
||||
Info: at initial placer iter 3, wirelen = 11173
|
||||
Info: Running main analytical placer, max placement attempts per cell = 129795.
|
||||
Info: at iteration #1, type ALL: wirelen solved = 11120, spread = 14753, legal = 16255; time = 0.01s
|
||||
Info: at iteration #2, type ALL: wirelen solved = 11258, spread = 13822, legal = 15182; time = 0.00s
|
||||
Info: at iteration #3, type ALL: wirelen solved = 11337, spread = 14156, legal = 15283; time = 0.00s
|
||||
Info: at iteration #4, type ALL: wirelen solved = 11332, spread = 13597, legal = 13906; time = 0.00s
|
||||
Info: HeAP Placer Time: 0.05s
|
||||
Info: of which solving equations: 0.02s
|
||||
Info: of which spreading cells: 0.00s
|
||||
Info: of which strict legalisation: 0.00s
|
||||
|
||||
Info: Running simulated annealing placer for refinement.
|
||||
Info: at iteration #1: temp = 0.000000, timing cost = 41, wirelen = 13906
|
||||
Info: at iteration #5: temp = 0.000000, timing cost = 113, wirelen = 11955
|
||||
Info: at iteration #8: temp = 0.000000, timing cost = 111, wirelen = 11890
|
||||
Info: SA placement time 0.07s
|
||||
|
||||
Info: Max frequency for clock '$glbnet$clk$TRELLIS_IO_IN': 168.69 MHz (PASS at 80.00 MHz)
|
||||
|
||||
Info: Max delay <async> -> posedge $glbnet$clk$TRELLIS_IO_IN: 8.82 ns
|
||||
Info: Max delay posedge $glbnet$clk$TRELLIS_IO_IN -> <async> : 5.91 ns
|
||||
|
||||
Info: Slack histogram:
|
||||
Info: legend: * represents 2 endpoint(s)
|
||||
Info: + represents [1,2) endpoint(s)
|
||||
Info: [ 6572, 6831) |+
|
||||
Info: [ 6831, 7090) |+
|
||||
Info: [ 7090, 7349) |*****+
|
||||
Info: [ 7349, 7608) |*****************+
|
||||
Info: [ 7608, 7867) |************************************************************
|
||||
Info: [ 7867, 8126) |*******************+
|
||||
Info: [ 8126, 8385) |********+
|
||||
Info: [ 8385, 8644) |*****+
|
||||
Info: [ 8644, 8903) |**+
|
||||
Info: [ 8903, 9162) |**+
|
||||
Info: [ 9162, 9421) |*******+
|
||||
Info: [ 9421, 9680) |*******+
|
||||
Info: [ 9680, 9939) |*************************+
|
||||
Info: [ 9939, 10198) |************************************+
|
||||
Info: [ 10198, 10457) |************+
|
||||
Info: [ 10457, 10716) |*********+
|
||||
Info: [ 10716, 10975) |************+
|
||||
Info: [ 10975, 11234) |******+
|
||||
Info: [ 11234, 11493) |******+
|
||||
Info: [ 11493, 11752) |*******+
|
||||
Info: Checksum: 0x90337da1
|
||||
Info: Routing globals...
|
||||
Info: routing clock net $glbnet$clk$TRELLIS_IO_IN using global 0
|
||||
|
||||
Info: Routing..
|
||||
Info: Setting up routing queue.
|
||||
Info: Routing 2003 arcs.
|
||||
Info: | (re-)routed arcs | delta | remaining| time spent |
|
||||
Info: IterCnt | w/ripup wo/ripup | w/r wo/r | arcs| batch(sec) total(sec)|
|
||||
Info: 1000 | 120 879 | 120 879 | 1169| 0.22 0.22|
|
||||
Info: 2000 | 172 1715 | 52 836 | 224| 0.12 0.35|
|
||||
Info: 2225 | 174 1929 | 2 214 | 0| 0.08 0.43|
|
||||
Info: Routing complete.
|
||||
Info: Router1 time 0.43s
|
||||
Info: Checksum: 0x87c32d65
|
||||
|
||||
Info: Critical path report for clock '$glbnet$clk$TRELLIS_IO_IN' (posedge -> posedge):
|
||||
Info: type curr total name
|
||||
Info: clk-to-q 0.40 0.40 Source x0[1]_TRELLIS_FF_Q_7.Q
|
||||
Info: routing 1.05 1.44 Net x0[1][7] (43,23) -> (43,22)
|
||||
Info: Sink product_comb[1]_MULT18X18D_P9.A15
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:99.44-99.46
|
||||
Info: logic 3.07 4.51 Source product_comb[1]_MULT18X18D_P9.P1
|
||||
Info: routing 0.95 5.46 Net product_comb[1][1] (43,22) -> (43,23)
|
||||
Info: Sink prod1[1]_TRELLIS_FF_Q_1.M
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:135.34-135.46
|
||||
Info: setup 0.00 5.46 Source prod1[1]_TRELLIS_FF_Q_1.M
|
||||
Info: 3.46 ns logic, 2.00 ns routing
|
||||
|
||||
Info: Critical path report for cross-domain path '<async>' -> 'posedge $glbnet$clk$TRELLIS_IO_IN':
|
||||
Info: type curr total name
|
||||
Info: source 0.00 0.00 Source operand_valid$tr_io.O
|
||||
Info: routing 3.08 3.08 Net operand_valid$TRELLIS_IO_IN (90,29) -> (38,23)
|
||||
Info: Sink operand_valid_LUT4_C.C
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:50.43-50.56
|
||||
Info: logic 0.18 3.26 Source operand_valid_LUT4_C.F
|
||||
Info: routing 0.82 4.08 Net operand_valid_LUT4_C_Z[1] (38,23) -> (30,21)
|
||||
Info: Sink operand_valid_LUT4_C_Z_LUT4_D.D
|
||||
Info: Defined in:
|
||||
Info: /opt/homebrew/bin/../share/yosys/lattice/cells_map_trellis.v:108.23-108.24
|
||||
Info: logic 0.18 4.26 Source operand_valid_LUT4_C_Z_LUT4_D.F
|
||||
Info: routing 0.85 5.12 Net operand_valid_LUT4_C_Z_LUT4_D_Z (30,21) -> (37,24)
|
||||
Info: Sink last0_TRELLIS_FF_Q_LSR_LUT4_Z.D
|
||||
Info: Defined in:
|
||||
Info: /opt/homebrew/bin/../share/yosys/lattice/cells_map_trellis.v:108.23-108.24
|
||||
Info: logic 0.18 5.30 Source last0_TRELLIS_FF_Q_LSR_LUT4_Z.F
|
||||
Info: routing 0.43 5.72 Net last0_TRELLIS_FF_Q_LSR (37,24) -> (38,24)
|
||||
Info: Sink last0_TRELLIS_FF_Q.LSR
|
||||
Info: setup 0.29 6.01 Source last0_TRELLIS_FF_Q.LSR
|
||||
Info: 0.83 ns logic, 5.18 ns routing
|
||||
|
||||
Info: Critical path report for cross-domain path 'posedge $glbnet$clk$TRELLIS_IO_IN' -> '<async>':
|
||||
Info: type curr total name
|
||||
Info: clk-to-q 0.40 0.40 Source np_state_TRELLIS_FF_Q_1.Q
|
||||
Info: routing 0.68 1.07 Net np_state[1]$TRELLIS_IO_OUT (39,23) -> (38,23)
|
||||
Info: Sink operand_ready_LUT4_D_C_LUT4_Z.C
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:63.43-63.51
|
||||
Info: logic 0.18 1.25 Source operand_ready_LUT4_D_C_LUT4_Z.F
|
||||
Info: routing 0.03 1.29 Net operand_ready_LUT4_D_C[1] (38,23) -> (38,23)
|
||||
Info: Sink valid6_LUT4_C_Z_LUT4_Z.D
|
||||
Info: Defined in:
|
||||
Info: /opt/homebrew/bin/../share/yosys/lattice/cells_map_trellis.v:108.23-108.24
|
||||
Info: logic 0.18 1.47 Source valid6_LUT4_C_Z_LUT4_Z.F
|
||||
Info: routing 0.49 1.95 Net job_valid_LUT4_C_Z[1] (38,23) -> (38,23)
|
||||
Info: Sink job_ready_LUT4_Z.D
|
||||
Info: Defined in:
|
||||
Info: /opt/homebrew/bin/../share/yosys/lattice/cells_map_trellis.v:108.23-108.24
|
||||
Info: logic 0.18 2.13 Source job_ready_LUT4_Z.F
|
||||
Info: routing 2.34 4.47 Net job_ready$TRELLIS_IO_OUT (38,23) -> (0,29)
|
||||
Info: Sink job_ready$tr_io.I
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:44.42-44.51
|
||||
Info: 0.94 ns logic, 3.53 ns routing
|
||||
|
||||
Info: Max frequency for clock '$glbnet$clk$TRELLIS_IO_IN': 183.12 MHz (PASS at 80.00 MHz)
|
||||
|
||||
Info: Max delay <async> -> posedge $glbnet$clk$TRELLIS_IO_IN: 6.01 ns
|
||||
Info: Max delay posedge $glbnet$clk$TRELLIS_IO_IN -> <async> : 4.47 ns
|
||||
|
||||
Info: Slack histogram:
|
||||
Info: legend: * represents 1 endpoint(s)
|
||||
Info: + represents [1,1) endpoint(s)
|
||||
Info: [ 7039, 7277) |*****************************+
|
||||
Info: [ 7277, 7515) |*********************************************+
|
||||
Info: [ 7515, 7753) |****+
|
||||
Info: [ 7753, 7991) |***+
|
||||
Info: [ 7991, 8229) |******+
|
||||
Info: [ 8229, 8467) |****+
|
||||
Info: [ 8467, 8705) |*****************+
|
||||
Info: [ 8705, 8943) |*************************************+
|
||||
Info: [ 8943, 9181) |**************************+
|
||||
Info: [ 9181, 9419) |************+
|
||||
Info: [ 9419, 9657) |***********+
|
||||
Info: [ 9657, 9895) |***************************************+
|
||||
Info: [ 9895, 10133) |************************************************************
|
||||
Info: [ 10133, 10371) |*************************+
|
||||
Info: [ 10371, 10609) |*********+
|
||||
Info: [ 10609, 10847) |****+
|
||||
Info: [ 10847, 11085) |*********+
|
||||
Info: [ 11085, 11323) |***************+
|
||||
Info: [ 11323, 11561) |*********+
|
||||
Info: [ 11561, 11799) |*********+
|
||||
|
||||
Info: Program finished normally.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
||||
|
||||
|
||||
Info: Logic utilisation before packing:
|
||||
Info: Total LUT4s: 225/43848 0%
|
||||
Info: logic LUTs: 49/43848 0%
|
||||
Info: carry LUTs: 176/43848 0%
|
||||
Info: RAM LUTs: 0/ 5481 0%
|
||||
Info: RAMW LUTs: 0/10962 0%
|
||||
|
||||
Info: Total DFFs: 509/43848 1%
|
||||
|
||||
Info: Packing IOs..
|
||||
Info: Packing constants..
|
||||
Info: Packing carries...
|
||||
Info: Packing LUTs...
|
||||
Info: Packing LUT5-7s...
|
||||
Info: Packing FFs...
|
||||
Info: 184 FFs paired with LUTs.
|
||||
Info: Generating derived timing constraints...
|
||||
Info: Promoting globals...
|
||||
Info: promoting clock net clk$TRELLIS_IO_IN to global network
|
||||
Info: Checksum: 0x016d332d
|
||||
|
||||
Info: Device utilisation:
|
||||
Info: TRELLIS_IO: 192/ 245 78%
|
||||
Info: DCCA: 1/ 56 1%
|
||||
Info: DP16KD: 0/ 108 0%
|
||||
Info: MULT18X18D: 8/ 72 11%
|
||||
Info: ALU54B: 0/ 36 0%
|
||||
Info: EHXPLLL: 0/ 4 0%
|
||||
Info: EXTREFB: 0/ 2 0%
|
||||
Info: DCUA: 0/ 2 0%
|
||||
Info: PCSCLKDIV: 0/ 2 0%
|
||||
Info: IOLOGIC: 0/ 160 0%
|
||||
Info: SIOLOGIC: 0/ 85 0%
|
||||
Info: GSR: 0/ 1 0%
|
||||
Info: JTAGG: 0/ 1 0%
|
||||
Info: OSCG: 0/ 1 0%
|
||||
Info: SEDGA: 0/ 1 0%
|
||||
Info: DTR: 0/ 1 0%
|
||||
Info: USRMCLK: 0/ 1 0%
|
||||
Info: CLKDIVF: 0/ 4 0%
|
||||
Info: ECLKSYNCB: 0/ 10 0%
|
||||
Info: DLLDELD: 0/ 8 0%
|
||||
Info: DDRDLL: 0/ 4 0%
|
||||
Info: DQSBUFM: 0/ 10 0%
|
||||
Info: TRELLIS_ECLKBUF: 0/ 8 0%
|
||||
Info: ECLKBRIDGECS: 0/ 2 0%
|
||||
Info: DCSC: 0/ 2 0%
|
||||
Info: TRELLIS_FF: 509/ 43848 1%
|
||||
Info: TRELLIS_COMB: 263/ 43848 0%
|
||||
Info: TRELLIS_RAMW: 0/ 5481 0%
|
||||
|
||||
Info: Placed 0 cells based on constraints.
|
||||
Info: Creating initial analytic placement for 383 cells, random placement wirelen = 46481.
|
||||
Info: at initial placer iter 0, wirelen = 11770
|
||||
Info: at initial placer iter 1, wirelen = 10956
|
||||
Info: at initial placer iter 2, wirelen = 10842
|
||||
Info: at initial placer iter 3, wirelen = 10779
|
||||
Info: Running main analytical placer, max placement attempts per cell = 118341.
|
||||
Info: at iteration #1, type ALL: wirelen solved = 10799, spread = 13649, legal = 15271; time = 0.01s
|
||||
Info: at iteration #2, type ALL: wirelen solved = 10896, spread = 13311, legal = 14579; time = 0.00s
|
||||
Info: at iteration #3, type ALL: wirelen solved = 10992, spread = 13115, legal = 14832; time = 0.00s
|
||||
Info: at iteration #4, type ALL: wirelen solved = 11026, spread = 13134, legal = 14328; time = 0.00s
|
||||
Info: at iteration #5, type ALL: wirelen solved = 11094, spread = 13023, legal = 14166; time = 0.00s
|
||||
Info: at iteration #6, type ALL: wirelen solved = 11079, spread = 12892, legal = 14099; time = 0.00s
|
||||
Info: at iteration #7, type ALL: wirelen solved = 11085, spread = 12769, legal = 13752; time = 0.00s
|
||||
Info: HeAP Placer Time: 0.06s
|
||||
Info: of which solving equations: 0.03s
|
||||
Info: of which spreading cells: 0.00s
|
||||
Info: of which strict legalisation: 0.00s
|
||||
|
||||
Info: Running simulated annealing placer for refinement.
|
||||
Info: at iteration #1: temp = 0.000000, timing cost = 58, wirelen = 13752
|
||||
Info: at iteration #5: temp = 0.000000, timing cost = 31, wirelen = 11848
|
||||
Info: at iteration #8: temp = 0.000000, timing cost = 32, wirelen = 11772
|
||||
Info: SA placement time 0.07s
|
||||
|
||||
Info: Max frequency for clock '$glbnet$clk$TRELLIS_IO_IN': 140.15 MHz (PASS at 80.00 MHz)
|
||||
|
||||
Info: Max delay <async> -> posedge $glbnet$clk$TRELLIS_IO_IN: 10.14 ns
|
||||
Info: Max delay posedge $glbnet$clk$TRELLIS_IO_IN -> <async> : 7.14 ns
|
||||
|
||||
Info: Slack histogram:
|
||||
Info: legend: * represents 1 endpoint(s)
|
||||
Info: + represents [1,1) endpoint(s)
|
||||
Info: [ 5365, 5684) |*+
|
||||
Info: [ 5684, 6003) |*+
|
||||
Info: [ 6003, 6322) |*****+
|
||||
Info: [ 6322, 6641) |*+
|
||||
Info: [ 6641, 6960) |****+
|
||||
Info: [ 6960, 7279) |*************+
|
||||
Info: [ 7279, 7598) |******************************+
|
||||
Info: [ 7598, 7917) |************************************************************
|
||||
Info: [ 7917, 8236) |******************************+
|
||||
Info: [ 8236, 8555) |************************+
|
||||
Info: [ 8555, 8874) |************************+
|
||||
Info: [ 8874, 9193) |***+
|
||||
Info: [ 9193, 9512) |*******+
|
||||
Info: [ 9512, 9831) |*************+
|
||||
Info: [ 9831, 10150) |******************************+
|
||||
Info: [ 10150, 10469) |***********************************************+
|
||||
Info: [ 10469, 10788) |*******************+
|
||||
Info: [ 10788, 11107) |******+
|
||||
Info: [ 11107, 11426) |*********+
|
||||
Info: [ 11426, 11745) |***********+
|
||||
Info: Checksum: 0x1b8c90ca
|
||||
Info: Routing globals...
|
||||
Info: routing clock net $glbnet$clk$TRELLIS_IO_IN using global 0
|
||||
|
||||
Info: Routing..
|
||||
Info: Setting up routing queue.
|
||||
Info: Routing 1906 arcs.
|
||||
Info: | (re-)routed arcs | delta | remaining| time spent |
|
||||
Info: IterCnt | w/ripup wo/ripup | w/r wo/r | arcs| batch(sec) total(sec)|
|
||||
Info: 1000 | 99 900 | 99 900 | 1080| 0.21 0.21|
|
||||
Info: 2000 | 117 1773 | 18 873 | 99| 0.10 0.31|
|
||||
Info: 2100 | 119 1867 | 2 94 | 0| 0.02 0.32|
|
||||
Info: Routing complete.
|
||||
Info: Router1 time 0.32s
|
||||
Info: Checksum: 0x5be6926a
|
||||
|
||||
Info: Critical path report for clock '$glbnet$clk$TRELLIS_IO_IN' (posedge -> posedge):
|
||||
Info: type curr total name
|
||||
Info: clk-to-q 0.40 0.40 Source x0[5]_TRELLIS_FF_Q_5.Q
|
||||
Info: routing 1.20 1.60 Net x0[5][5] (22,23) -> (31,22)
|
||||
Info: Sink product_comb[5]_MULT18X18D_P9.A5
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:99.44-99.46
|
||||
Info: logic 3.07 4.66 Source product_comb[5]_MULT18X18D_P9.P11
|
||||
Info: routing 1.01 5.68 Net product_comb[5][11] (31,22) -> (31,29)
|
||||
Info: Sink prod1[5]_TRELLIS_FF_Q_11.M
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:135.34-135.46
|
||||
Info: setup 0.00 5.68 Source prod1[5]_TRELLIS_FF_Q_11.M
|
||||
Info: 3.46 ns logic, 2.21 ns routing
|
||||
|
||||
Info: Critical path report for cross-domain path '<async>' -> 'posedge $glbnet$clk$TRELLIS_IO_IN':
|
||||
Info: type curr total name
|
||||
Info: source 0.00 0.00 Source rst$tr_io.O
|
||||
Info: routing 4.48 4.48 Net rst$TRELLIS_IO_IN (90,47) -> (21,21)
|
||||
Info: Sink result_ready_LUT4_A_Z_LUT4_D.C
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:35.11-35.14
|
||||
Info: logic 0.18 4.66 Source result_ready_LUT4_A_Z_LUT4_D.F
|
||||
Info: routing 1.37 6.03 Net result_ready_LUT4_A_Z_LUT4_D_Z (21,21) -> (5,25)
|
||||
Info: Sink last0_TRELLIS_FF_Q_LSR_LUT4_Z.D
|
||||
Info: Defined in:
|
||||
Info: /opt/homebrew/bin/../share/yosys/lattice/cells_map_trellis.v:108.23-108.24
|
||||
Info: logic 0.18 6.21 Source last0_TRELLIS_FF_Q_LSR_LUT4_Z.F
|
||||
Info: routing 0.23 6.44 Net last0_TRELLIS_FF_Q_LSR (5,25) -> (5,25)
|
||||
Info: Sink last0_TRELLIS_FF_Q.LSR
|
||||
Info: setup 0.29 6.73 Source last0_TRELLIS_FF_Q.LSR
|
||||
Info: 0.65 ns logic, 6.08 ns routing
|
||||
|
||||
Info: Critical path report for cross-domain path 'posedge $glbnet$clk$TRELLIS_IO_IN' -> '<async>':
|
||||
Info: type curr total name
|
||||
Info: clk-to-q 0.40 0.40 Source valid_tree_TRELLIS_FF_Q_1.Q
|
||||
Info: routing 0.61 1.01 Net valid_tree[0] (3,21) -> (3,21)
|
||||
Info: Sink valid6_LUT4_C_Z_LUT4_Z_1.C
|
||||
Info: Defined in:
|
||||
Info: hardware/v2/rtl/neural_processor.v:174.49-174.59
|
||||
Info: logic 0.18 1.19 Source valid6_LUT4_C_Z_LUT4_Z_1.F
|
||||
Info: routing 0.56 1.75 Net valid6_LUT4_C_Z[0] (3,21) -> (5,23)
|
||||
Info: Sink job_ready_LUT4_Z.B
|
||||
Info: Defined in:
|
||||
Info: /opt/homebrew/bin/../share/yosys/lattice/cells_map_trellis.v:108.23-108.24
|
||||
Info: logic 0.18 1.93 Source job_ready_LUT4_Z.F
|
||||
Info: routing 3.34 5.27 Net job_ready$TRELLIS_IO_OUT (5,23) -> (47,0)
|
||||
Info: Sink job_ready$tr_io.I
|
||||
Info: Defined in:
|
||||
Info: /opt/homebrew/bin/../share/yosys/lattice/cells_map_trellis.v:108.23-108.24
|
||||
Info: 0.75 ns logic, 4.52 ns routing
|
||||
|
||||
Info: Max frequency for clock '$glbnet$clk$TRELLIS_IO_IN': 176.21 MHz (PASS at 80.00 MHz)
|
||||
|
||||
Info: Max delay <async> -> posedge $glbnet$clk$TRELLIS_IO_IN: 6.73 ns
|
||||
Info: Max delay posedge $glbnet$clk$TRELLIS_IO_IN -> <async> : 5.27 ns
|
||||
|
||||
Info: Slack histogram:
|
||||
Info: legend: * represents 1 endpoint(s)
|
||||
Info: + represents [1,1) endpoint(s)
|
||||
Info: [ 6825, 7074) |********************+
|
||||
Info: [ 7074, 7323) |************************************************************
|
||||
Info: [ 7323, 7572) |********+
|
||||
Info: [ 7572, 7821) |*****+
|
||||
Info: [ 7821, 8070) |*****+
|
||||
Info: [ 8070, 8319) |******+
|
||||
Info: [ 8319, 8568) |*****+
|
||||
Info: [ 8568, 8817) |******************************************+
|
||||
Info: [ 8817, 9066) |***************************************+
|
||||
Info: [ 9066, 9315) |**************+
|
||||
Info: [ 9315, 9564) |*************************+
|
||||
Info: [ 9564, 9813) |***************+
|
||||
Info: [ 9813, 10062) |****************************************+
|
||||
Info: [ 10062, 10311) |************************************************+
|
||||
Info: [ 10311, 10560) |*********+
|
||||
Info: [ 10560, 10809) |********************+
|
||||
Info: [ 10809, 11058) |********+
|
||||
Info: [ 11058, 11307) |****+
|
||||
Info: [ 11307, 11556) |********+
|
||||
Info: [ 11556, 11805) |********+
|
||||
|
||||
Info: Program finished normally.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user