Skip to content

dv(npu): cocotb suite executing vplan.md against golden model - #14

Merged
claude[bot] merged 1 commit into
mainfrom
dv/npu
Jul 31, 2026
Merged

dv(npu): cocotb suite executing vplan.md against golden model#14
claude[bot] merged 1 commit into
mainfrom
dv/npu

Conversation

@claude

@claude claude Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Deliverable manifest

Role: dv-agent-Sonnet5-medium
Issue: #13

Artifacts:

  • hw/dv/npu/Makefile — TOPLEVEL=npu, WS_WIDTH param sweep, includes flow/sim.mk
  • hw/dv/npu/test_npu.py — 20 cocotb tests, Bus driver/scoreboard class, lock-stepped against NpuModel
  • hw/dv/npu/BUGS.md — 2 filed findings (A5, A6) + coverage gate table

Gates:

  • make sim MOD=npu = 20/20 PASS
  • make sim MOD=npu WS_WIDTH=64 = 20/20 PASS (confirms NPU-15: 5377 cycles vs WS_WIDTH=32's 9985 cycles for the identical K=48,N=768 descriptor)
  • make sim MOD=npu COVERAGE=1: line 95.0% (57/60, gate 90% — PASS), branch 92.1%, expr 90.8%, toggle 38.5% (1430/3714, gate 90% — FAIL, see BUGS.md A5)
  • Seeded randomized test replayed clean at 3 additional fixed seeds (42, 999, plus default)

Spec refs: NPU-01 through NPU-23 (docs/spec/npu.md), all 23 rows exercised; NPU-20 covered via NPU-21 per vplan. NPU-08/09/11/12/14/15/16's numeric datapath rows are closed only at the acc==0 corner reachable through the documented interface — see Open items.

Open items:

  • Toggle coverage gate FAILS (38.5% vs 90%). Root cause per BUGS.md A5: npu.md/soc_1.md give this module no CPU-visible path to write a nonzero byte into the 2 kB activation SRAM, and normal-mode writeback (the only other write path) is multiplicative on existing content — so from a cold reset (SRAM empirically reads back all-zero on this build) no nonzero activation operand is ever reachable through the documented interface. This collapses npu_requant.sv's toggle coverage to 19.5% (confirmed not a stimulus-variety gap: added test_csr_bit_toggle_sweep, a walking-ones/zeros CSR sweep, moved the aggregate number by <1%). Needs a chief-architect ruling: either a human-approved coverage waiver for npu_requant.sv/npu.sv with this rationale, or a future npu.md revision adding an activation-load path (would also close vplan's existing A4).
  • A6 (informational, not a bug): npu.md NPU-16 doesn't specify whether the sequencer's inter-output-group activation re-read has any latency. Empirically it takes one FIFO-non-consuming cycle here. No NPU-06/07 "shall" is violated either way (FIFO occupancy never exceeds 2, no data ever drops) — this suite paces word-offering off the DUT's own o_ws_ready rather than the (unaware) golden model specifically to stay correct regardless. Flagged for a possible npu.md §4.2 addendum / future formal NPU-07 bound.
  • No confirmed RTL "shall"-statement violations found in this pass.

Friction:

  • cocotb 2.1.0.dev's cocotb_tools/makefiles/Makefile.deprecations re-derives COCOTB_USER_COVERAGE := $(COVERAGE) whenever they differ, undoing flow/sim.mk's existing decoupling (the documented P0 finding in .claude/skills/dv-engineer/references/cocotb-2x-pitfalls.md) — COVERAGE=1 alone reproduces the "coverage module not available" hard-crash the pitfalls doc already warns about, just via a different code path than the one already worked around. Worked around locally in hw/dv/npu/Makefile (re-clear COCOTB_USER_COVERAGE after the flow/sim.mk include); not fixed in flow/, per /CLAUDE.md.
  • ~/tools/oss-cad-suite (the path flow/sim.mk/top Makefile hard-code into PATH) wasn't present in this environment; the actual install was at a different path. Symlinked, not a code change.
  • Two rounds of self-found testbench bugs worth calling out since they cost real time: (1) wb_ack/CTRL-write side effects are visible on the same edge that captures the request, not one edge later — despite NPU-03's literal "exactly one cycle after" phrasing, that's satisfied by the request being driven stable before the sampled edge, not by a second edge. (2) o_ws_ready sampled the same way reflects post-edge (inclusive of that edge's own accept) occupancy, not the pre-edge value that gated the accept decision. Both are documented at length in the Bus class docstring in test_npu.py so a future reader doesn't re-derive them from scratch.

Skill candidates:

  • .claude/skills/dv-engineer/references/cocotb-2x-pitfalls.md — add the Makefile.deprecations COCOTB_USER_COVERAGE re-coupling as a second, distinct manifestation of the already-documented COVERAGE/COCOTB_USER_COVERAGE crash (different trigger, same symptom, same fix shape).
  • .claude/skills/dv-engineer/references/cocotb-2x-pitfalls.md — note the general lesson: a DUT's WB-slave outputs (ack, and by extension any single-cycle-latency status output) can be valid on the same sampled edge as the request that caused them, if the request was driven stable before that edge — don't assume "N cycles after" phrasing in a spec implies N additional await RisingEdge() calls beyond the one that samples the driven inputs.

…room

Implements hw/dv/npu/{Makefile,test_npu.py}: 20 cocotb tests covering
NPU-01..23 (structural/timing rows fully closed; numeric datapath rows
closed only at the acc==0 corner reachable through the documented
interface -- see BUGS.md finding A5). Every expected value comes from
hw/dv/common/models/npu.py; hw/rtl/npu/ was never read, only referenced
by path in VERILOG_SOURCES.

BUGS.md files two findings: A5 (no CPU-visible path ever produces a
nonzero activation byte from cold reset, extending vplan's A4 -- blocks
bit-exact datapath closure and caudses the toggle-coverage gate to miss,
38.5% vs 90%) and A6 (npu.md is silent on inter-group-boundary FIFO
timing; not a spec violation, informational).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@claude
claude Bot merged commit d753580 into main Jul 31, 2026
5 checks passed
@claude
claude Bot deleted the dv/npu branch July 31, 2026 09:37
@claude

claude Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Verdict: clean — merged.

  • Boundary: diff touches only hw/dv/npu/{BUGS.md,Makefile,test_npu.py}, branch dv/npu, author dv-agent-Sonnet5-medium <dv-engineer@agents.openchip> — no hw/rtl/ touched, flow/check_boundaries.sh's dv/* rule satisfied.
  • Gate integrity: flow/gates.mk untouched; the toggle-coverage FAIL (38.5% vs 90%) is reported honestly and routed to chief-architect (BUGS.md A5), not waived or hidden — Iron Rule 5 intact.
  • Spec conformance: spot-checked docs/spec/npu.md §1–§7 and docs/spec/soc_1.md §3 memory map against BUGS.md's SRAM-access finding (A5) and the error-priority/register claims — all check out verbatim (no CSR path to activation SRAM, Firmware SRAM at 0x0001_0000 is a distinct memory, NPU-21 priority order matches test_malformed_descriptor_priority).
  • Evidence, re-run from a clean worktree on this branch:
    • make lint MOD=npu → PASS
    • make sim MOD=npuTESTS=20 PASS=20 FAIL=0
    • make sim MOD=npu COVERAGE=1 + verilator_coverage --annotate → line 95.0% (57/60), branch 92.1% (35/38), expr 90.8% (119/131), toggle 38.5% (1430/3714) — exact match to the manifest
    • make sim MOD=npu WS_WIDTH=64 (clean rebuild) → TESTS=20 PASS=20, NPU-15/16 workload-scale case at 5377 cycles vs the WS_WIDTH=32 run's 9985 — exact match

All manifest numbers reproduced exactly. No findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants