Skip to content

compute_array: absorb parent BCAST_PIPE flops into cmd_unit OR delete BCAST_PIPE entirely #45

Description

@npip99

Context

tech/INVARIANTS.md R1 says: "parent design = macros + wires, no logic." compute_array.sv currently violates this with ~302 parent flops on the BCAST_PIPE forward and reverse pipes — all on parent chip clk. These were the right call during B4/B5/B6 iteration when BCAST_PIPE was a tuneable knob. With B6 (PR #40/#41) landed and stable, the routing problem that motivated BCAST_PIPE has been eliminated by the abutment chain topology.

This issue tracks TWO related cleanups. They must be sequenced — option 2 may subsume option 1.


Background: what BCAST_PIPE was for

PR #27 added BCAST_PIPE to solve the long fanout from cmd_unit to all 32 skew_lanes. Without it, push_a_bytes[256:0] had to fan out to 32 distant endpoints across ~1.5 mm of die. BCAST_PIPE=1 broke that net in half with a parent flop stage.

B6 (#40) eliminated this fanout entirely. cmd_unit now drives exactly one destination per signal — the chain head (sa_chain_w_s[0], sb_chain_w_w[0]). The chain register inside each skew_lane_a/b instance then propagates by abutment, no parent routing involved.

So BCAST_PIPE's original justification is gone. What remains is one combinational arc per signal from cmd_unit out → chain head in:

[cmd_unit internal flop] → cmd_unit M-layer output → parent route to skew_a[0] → skew_a[0] pin → [chain register]

With the current B6 layout, cmd_unit and skew_a[0] are both in the SW corner — short hop.


Two violations of R1

Forward pipe (compute_array.sv ~lines 165-230)

Registers cmd_unit's push_* outputs before feeding chain heads. With BCAST_PIPE=1:

  • push_now_piped (1 b) × 1 stage = 1 flop
  • push_slot_piped (2 b) × 1 stage = 2 flops
  • push_accum_piped (1 b) × 1 stage = 1 flop
  • push_a_bytes_piped (256 b) × 1 stage = 256 flops
  • (drain_* / scrub_en piped similarly — verify exact count when implementing)
  • Total: ~258-260 parent flops

Reverse pipe (compute_array.sv:247-299)

Registers cmd_unit's status outputs symmetrically with the forward pipe so chip-external completion events arrive in lockstep with the cells that actually finished the work.

  • mb_pipe (mma_busy, 1 b) × 1 = 1
  • md_pipe (mma_done, 1 b) × 1 = 1
  • ae_pipe (arrive_en, 1 b) × 1 = 1
  • ab_pipe (arrive_bar_id, 32 b) × 1 = 32
  • db_pipe (drain_busy, 1 b) × 1 = 1
  • dd_pipe (drain_done, 1 b) × 1 = 1
  • drv_pipe (drain_row_valid, 1 b) × 1 = 1
  • dri_pipe (drain_row_idx, 5 b) × 1 = 5
  • dl_pipe (drain_last, 1 b) × 1 = 1
  • Total: ~44 parent flops

Combined: ~302 parent flops on chip clk that should not exist at parent level.


Option 1 — Delete BCAST_PIPE entirely (recommended; try first)

The cleanest fix. B6's chain topology eliminated the routing problem BCAST_PIPE was designed to solve, so the entire mechanism is likely scaffolding we forgot to remove.

Plan

  1. Edit tech/asap7/orfs/compute_array_abut.config.mk: VERILOG_FILES/work/build/sv2v/chip_top_bcast0.v (BCAST_PIPE=0).
  2. Re-harden compute_array_abut (~40 min wall).
  3. Verify: 0 DRC, positive setup slack on the cmd_unit → chain-head paths. Current B6 close has +295 ps slack to spare, so the extra combinational arc has a lot of room — but not certain to close. If it fails by a small amount, we know empirically that BCAST_PIPE=1 IS needed and the experiment was worth running.
  4. If it closes:
    • Delete forward pipe (compute_array.sv ~165-230)
    • Delete reverse pipe (compute_array.sv:247-299)
    • Delete BCAST_PIPE parameter (compute_array.sv:13-25 comment block + parameter handling)
    • Delete chip_top_bcast{0,1,2,3}.v — replaced by single chip_top.v
    • Delete sv2v-bcast-sweep make target in tech/sky130/Makefile
    • Update pymodel to remove BCAST_PIPE cycle compensation
    • cocotb compute_array regression — must remain PASS 2/2 vs pymodel
    • One more compute_array_abut re-harden to confirm post-cleanup

Estimated savings

  • ~302 parent flops gone (off chip clk parent CTS)
  • ~4 sv2v sweep files deleted (~MB of build artifacts)
  • BCAST_PIPE parametric machinery in compute_array.sv, cmd_unit.sv, pymodel — all simpler

Risk

  • If BCAST_PIPE=0 fails to close, we waste one harden cycle (~40 min). Falls back to Option 2.

Option 2 — Absorb pipes into cmd_unit (fallback if Option 1 fails)

If the cmd_unit → chain-head combinational arc is too long to close at BCAST_PIPE=0, the pipe stage is genuinely load-bearing. In that case, move it inside cmd_unit instead of leaving it at parent.

Plan

  1. Edit cmd_unit/cmd_unit.sv: add internal register stages for all output signals (push_* forward, status reverse).
  2. Delete forward + reverse pipes from compute_array.sv.
  3. Re-harden cmd_unit (~3-5 min — tiny macro).
  4. Re-harden compute_array_abut (~40 min).
  5. Verify cocotb + 0 DRC + positive slack.

Delta to macro IO

Zero. cmd_unit's pin contract is unchanged:

  • Same 9 status output signals (45 bits total)
  • Same push_* forward outputs
  • Same widths, same pin TCL geometry
  • Just the register stage location moves from parent to cmd_unit

cmd_unit is already stateful (FSM, drain pulser, arrive handshake), already has reset, already has clk-to-output timing arcs in its .lib. Adding ~302 more flops to a macro that already has thousands is rounding error for size/power.

Architectural cost

Locks BCAST_PIPE value into hardened cmd_unit silicon. Future tuning requires re-harden. Acceptable post-B6 since:

  • B6 made BCAST_PIPE no longer the load-bearing knob it once was
  • cmd_unit re-harden is 3-5 min — not a real blocker

Sequencing & dependencies

Recommendation: Option 1 first. Cheap experiment (one harden), high upside (large cleanup). If it succeeds, Option 2 becomes unnecessary. If it fails, Option 2 is the natural fallback.

Either option must:

  • Maintain cocotb compute_array PASS 2/2 vs pymodel
  • Maintain 0 DRC on the 32×32 harden
  • Maintain positive setup + hold slack

Do not touch this before #28 (chip_top integration) — chip_top may surface other timing pressures that change the calculus. Keeping BCAST_PIPE alive as an escape hatch through chip_top closure is conservative; doing the experiment AFTER #28 lets the chip_top closure data inform whether the knob is still worth having.

Acceptance criteria

  • compute_array.sv has zero flops that aren't part of a macro instantiation (R1 invariant satisfied)
  • cocotb compute_array PASS 2/2 (no functional regression)
  • compute_array_abut 32×32: 0 DRC, 0 setup violations, 0 hold violations
  • tech/INVARIANTS.md R1 violation list updated (remove the "should be absorbed into cmd_unit per Manifest-driven build system for hardened-macro abutment designs #43-followup" line)

Related

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions