rtl: MultiGemminiCluster v1 — per-tile dispatch + quiescence FSM #126

Merged
navigator merged 1 commit from auto/issue-114-20260618T051157Z_issue114 into main 2026-06-18 04:29:17 -03:00
Owner

Summary

Implements the v1 body of MultiGemminiCluster per the Draft SPEC at rtl/src/pop/specs/MultiGemminiCluster.SPEC.md and the scope pinned by issue #114.

What landed

  • Constructor: class MultiGemminiCluster(N: Int = 4, numCores: Int = 2, xLen: Int = 64)N tracks ADR-001 / PopSoCConfig.TileCountKey, numCores tracks ADR-006, xLen defaults to 64 (ADR-001 RV64GC).
  • Xbar instantiation: Module(new InterGemminiXbar(n = N, payloadBits = (new RoCCCommand(xLen)).getWidth)) — opaque RoCC payload carries through the xbar with no per-tile bundle invention.
  • Per-tile dispatch: io.rocc.cmd(i) is self-routed (tileId = i) into xbar.io.ingress(i); xbar.io.egress(i) drives a per-tile GemminiBlackBoxStub. The stub mirrors the future Gemmini BlackBox IO (RoCCCommand / RoCCResponse from PopRoCCRouter) with a 1-cycle loopback queue so the bench can observe end-to-end dispatch without inventing Gemmini-internal widths. Empty mem / csr sub-bundles are surfaced with the Open question per SPEC §Behavior markers required by the issue body. Replaced by a true BlackBox wrapping upstream Gemmini once the Chipyard 1.13.0 pin lands (PLAN.md §6).
  • Quiescence FSM: three states (sActive / sDrain / sIdle). On clusterStop = 1 every rocc.cmd(i).ready is gated low; once the in-flight counter (incremented on accepted cmds, decremented on emitted resps) hits zero, clusterIdle rises. Matches SPEC §Behavior "Quiescence and drain on cluster-stop CSR".

Bench

Extended rtl/tests/MultiGemminiCluster/MultiGemminiClusterSpec.scala with the two scenarios named in the issue acceptance criteria:

  1. Single-tile dispatch routes through xbar to per-tile BlackBox stub — drives a cmd on rocc(2), checks that the matching resp emerges on rocc(2) (with the dispatched rd / rs1) and that no neighbour port fires.
  2. clusterStop = 1 drains in-flight and raises clusterIdle — builds in-flight by dampening resp(0), asserts clusterStop, verifies every rocc.cmd(i).ready goes low and clusterIdle stays low, then releases the dam and checks clusterIdle rises within the drain budget.

sbt -no-colors test is green across all 25 tests in the rtl suite (cluster, xbar, router, configs, PHY, fabric).

Out of scope (deferred per SPEC §Interface Open questions)

  • mem / popLink / perfCounters sub-bundles stay empty — concrete shape pinned at FluidPopSoC v1 alongside the L2 attach (ADR-011) and the perf-counter ADR named in the SPEC.
  • Pro 16-tile funct7 encoding — gated on the ADR amending ADR-006's 2-bit gemmini-id (SPEC §Behavior Open question).

Test plan

  • sbt -no-colors testOnly pop.MultiGemminiClusterSpec — green
  • sbt -no-colors test — full rtl suite green (25/25)
  • LOC budget — net +257 lines (well under the 600 LOC ceiling)
  • No off-limits paths touched (ADR-017 scope)

Closes #114

## Summary Implements the v1 body of `MultiGemminiCluster` per the Draft SPEC at `rtl/src/pop/specs/MultiGemminiCluster.SPEC.md` and the scope pinned by issue #114. ### What landed * **Constructor:** `class MultiGemminiCluster(N: Int = 4, numCores: Int = 2, xLen: Int = 64)` — `N` tracks ADR-001 / `PopSoCConfig.TileCountKey`, `numCores` tracks ADR-006, `xLen` defaults to 64 (ADR-001 RV64GC). * **Xbar instantiation:** `Module(new InterGemminiXbar(n = N, payloadBits = (new RoCCCommand(xLen)).getWidth))` — opaque RoCC payload carries through the xbar with no per-tile bundle invention. * **Per-tile dispatch:** `io.rocc.cmd(i)` is self-routed (`tileId = i`) into `xbar.io.ingress(i)`; `xbar.io.egress(i)` drives a per-tile `GemminiBlackBoxStub`. The stub mirrors the future Gemmini BlackBox IO (`RoCCCommand` / `RoCCResponse` from `PopRoCCRouter`) with a 1-cycle loopback queue so the bench can observe end-to-end dispatch without inventing Gemmini-internal widths. Empty `mem` / `csr` sub-bundles are surfaced with the `Open question per SPEC §Behavior` markers required by the issue body. Replaced by a true BlackBox wrapping upstream Gemmini once the Chipyard 1.13.0 pin lands (PLAN.md §6). * **Quiescence FSM:** three states (`sActive` / `sDrain` / `sIdle`). On `clusterStop = 1` every `rocc.cmd(i).ready` is gated low; once the in-flight counter (incremented on accepted cmds, decremented on emitted resps) hits zero, `clusterIdle` rises. Matches SPEC §Behavior "Quiescence and drain on cluster-stop CSR". ### Bench Extended `rtl/tests/MultiGemminiCluster/MultiGemminiClusterSpec.scala` with the two scenarios named in the issue acceptance criteria: 1. **Single-tile dispatch routes through xbar to per-tile BlackBox stub** — drives a cmd on `rocc(2)`, checks that the matching resp emerges on `rocc(2)` (with the dispatched `rd` / `rs1`) and that no neighbour port fires. 2. **`clusterStop = 1` drains in-flight and raises `clusterIdle`** — builds in-flight by dampening `resp(0)`, asserts `clusterStop`, verifies every `rocc.cmd(i).ready` goes low and `clusterIdle` stays low, then releases the dam and checks `clusterIdle` rises within the drain budget. `sbt -no-colors test` is green across all 25 tests in the rtl suite (cluster, xbar, router, configs, PHY, fabric). ### Out of scope (deferred per SPEC §Interface Open questions) * `mem` / `popLink` / `perfCounters` sub-bundles stay empty — concrete shape pinned at FluidPopSoC v1 alongside the L2 attach (ADR-011) and the perf-counter ADR named in the SPEC. * Pro 16-tile funct7 encoding — gated on the ADR amending ADR-006's 2-bit gemmini-id (SPEC §Behavior Open question). ## Test plan - [x] `sbt -no-colors testOnly pop.MultiGemminiClusterSpec` — green - [x] `sbt -no-colors test` — full rtl suite green (25/25) - [x] LOC budget — net +257 lines (well under the 600 LOC ceiling) - [x] No off-limits paths touched (ADR-017 scope) Closes #114
rtl: MultiGemminiCluster v1 — per-tile dispatch + quiescence FSM
All checks were successful
build / scalafmt-check (pull_request) Successful in 2m8s
build / sbt-compile (pull_request) Successful in 17s
build / shell-lint (pull_request) Successful in 1m11s
090a2eb8f0
Implements the v1 body of MultiGemminiCluster per the Draft SPEC
(rtl/src/pop/specs/MultiGemminiCluster.SPEC.md) and issue #114:

* Constructor `(N, numCores, xLen)` tracks ADR-001 / ADR-006 / RV64GC.
* Instantiates `InterGemminiXbar(N)` with `payloadBits = RoCCCommand`
  width — the cluster carries opaque RoCC payloads through the xbar
  without inventing the peer-to-peer scratchpad bundle shape that
  ADR-003 reserves for cross-tile data exchange.
* Per-tile dispatch: `io.rocc.cmd(i)` is self-routed through
  `xbar.io.ingress(i)` (tileId = i) and `xbar.io.egress(i)` drives a
  per-tile Gemmini stub. The stub mirrors the future BlackBox IO
  (`RoCCCommand` / `RoCCResponse` from PopRoCCRouter) with a 1-cycle
  loopback queue so the cluster bench can observe end-to-end dispatch
  without inventing Gemmini-internal widths. Replaced by a true
  BlackBox wrapping upstream Gemmini once the Chipyard 1.13.0 pin
  lands (PLAN.md §6).
* Quiescence FSM (sActive / sDrain / sIdle): on `clusterStop=1` the
  FSM gates every `rocc.cmd(i).ready` low, drains the per-cycle
  in-flight counter, and asserts `clusterIdle` once the counter
  reaches zero. Matches SPEC §Behavior "Quiescence and drain on
  cluster-stop CSR".

Bench (`rtl/tests/MultiGemminiCluster/MultiGemminiClusterSpec.scala`):
extended with the two scenarios mandated by issue #114 — single-tile
dispatch through the xbar to the per-tile stub, and clusterStop
in-flight drain → clusterIdle handshake. `sbt -no-colors test` is
green across all 25 tests in the suite.

The mem / popLink / perfCounters subbundles stay empty per the
SPEC §Interface Open questions; their concrete shape resolves at
FluidPopSoC v1 along with the L2 attach (ADR-011).

Closes #114
Author
Owner

VERDICT: PASS

PR #126 lifts MultiGemminiCluster from elaborate-only into a v1 with xbar instantiation, per-tile RoCC dispatch, and a three-state quiescence FSM, scoped cleanly to Issue #114. Mechanical guardrails pass: SPDX headers preserved (CHARRUA-1.2 source, AGPL-3.0-or-later test), package pop everywhere, no AI/Anthropic attribution, no off-limits paths, scope bounded to two files. Rule 4 is handled correctly: the rocc sub-bundle materialises Vec(N, Flipped(Decoupled(RoCCCommand))) / Vec(N, Decoupled(RoCCResponse)) using the canonical local mirrors from PR #69; the per-tile vs per-core shape choice (Vec(N) instead of Vec(numCores)) is explicitly justified inline — the cluster sees PopRoCCRouter's already-decoded per-tile fan-out, matching PopRoCCRouter.io.tileCmd/io.tileResp from PR #107 — and the SPEC §Interface Open question on per-tile bundle shape covers this resolution. The three TBD facets (mem, popLink, perfCounters) remain empty sub-bundles with explicit deferral comments tied to the ADR-011 L2 attach (at FluidPopSoC v1), InterChipFabric sibling SPEC, and the perf-counter ADR. The new clusterStop/clusterIdle IO pair is honestly surfaced as direct ports rather than fabricating a CSR shape — the CSR address-map is Open per SPEC §Interface. Rule 7 is meticulously handled: N = 4 matches ADR-001 Edu, numCores = 2 matches ADR-006 Edu, xLen = 64 matches RV64GC, N >= 4 && N <= 16 constraint matches PR #115's SPEC-aligned InterGemminiXbar bound (which propagates here since the cluster shares the xbar), numCores >= 1 is a minimal sanity check, and InFlightWidth = 8 is documented as engineering head-room for N=16 rather than a SPEC commitment. The GemminiBlackBoxStub is honestly framed: the comment explains a true BlackBox would block chiseltest's default backend, so an in-tree stub Module with the right IO shape + 1-cycle loopback Queue is used, with explicit "replaced by a true BlackBox wrapping upstream Gemmini once the Chipyard 1.13.0 pin lands (PLAN.md §6)" forward-link. The self-routed xbar usage (tileId = i) is candidly flagged as a v1 placeholder — the xbar's primary purpose (peer-to-peer scratchpad data exchange per SPEC §Behavior) waits on the SPEC §Behavior Open question on scratchpad-port bundle shape. The quiescence FSM implements the three states (sActive/sDrain/sIdle) with proper clusterStop deassertion handling and in-flight counter sized to the worst case at N=16. Both Issue #114 scenarios are exercised: scenario 1 verifies dispatch routes through xbar to the per-tile stub and surfaces resp on the matching tile (with neighbour-port silence check); scenario 2 verifies clusterStop=1 gates every rocc.cmd(i).ready low within one cycle, holds clusterIdle low while drain is pending, raises it within the 64-cycle drain budget once the dam releases, keeps ingress gated while clusterStop holds, and verifies the FSM returns to sActive cleanly on clusterStop deassertion.

Findings

None.

<!-- agent:review verdict=PASS ts=1781760492 --> **VERDICT:** PASS PR #126 lifts `MultiGemminiCluster` from elaborate-only into a v1 with xbar instantiation, per-tile RoCC dispatch, and a three-state quiescence FSM, scoped cleanly to Issue #114. Mechanical guardrails pass: SPDX headers preserved (`CHARRUA-1.2` source, `AGPL-3.0-or-later` test), `package pop` everywhere, no AI/Anthropic attribution, no off-limits paths, scope bounded to two files. Rule 4 is handled correctly: the `rocc` sub-bundle materialises `Vec(N, Flipped(Decoupled(RoCCCommand)))` / `Vec(N, Decoupled(RoCCResponse))` using the canonical local mirrors from PR #69; the per-tile vs per-core shape choice (Vec(N) instead of Vec(numCores)) is explicitly justified inline — the cluster sees PopRoCCRouter's already-decoded per-tile fan-out, matching `PopRoCCRouter.io.tileCmd`/`io.tileResp` from PR #107 — and the SPEC §Interface Open question on per-tile bundle shape covers this resolution. The three TBD facets (`mem`, `popLink`, `perfCounters`) remain empty sub-bundles with explicit deferral comments tied to the ADR-011 L2 attach (at FluidPopSoC v1), InterChipFabric sibling SPEC, and the perf-counter ADR. The new `clusterStop`/`clusterIdle` IO pair is honestly surfaced as direct ports rather than fabricating a CSR shape — the CSR address-map is Open per SPEC §Interface. Rule 7 is meticulously handled: `N = 4` matches ADR-001 Edu, `numCores = 2` matches ADR-006 Edu, `xLen = 64` matches RV64GC, `N >= 4 && N <= 16` constraint matches PR #115's SPEC-aligned InterGemminiXbar bound (which propagates here since the cluster shares the xbar), `numCores >= 1` is a minimal sanity check, and `InFlightWidth = 8` is documented as engineering head-room for N=16 rather than a SPEC commitment. The `GemminiBlackBoxStub` is honestly framed: the comment explains a true `BlackBox` would block chiseltest's default backend, so an in-tree stub Module with the right IO shape + 1-cycle loopback Queue is used, with explicit "replaced by a true BlackBox wrapping upstream Gemmini once the Chipyard 1.13.0 pin lands (PLAN.md §6)" forward-link. The self-routed xbar usage (`tileId = i`) is candidly flagged as a v1 placeholder — the xbar's primary purpose (peer-to-peer scratchpad data exchange per SPEC §Behavior) waits on the SPEC §Behavior Open question on scratchpad-port bundle shape. The quiescence FSM implements the three states (`sActive`/`sDrain`/`sIdle`) with proper `clusterStop` deassertion handling and in-flight counter sized to the worst case at N=16. Both Issue #114 scenarios are exercised: scenario 1 verifies dispatch routes through xbar to the per-tile stub and surfaces resp on the matching tile (with neighbour-port silence check); scenario 2 verifies `clusterStop=1` gates every `rocc.cmd(i).ready` low within one cycle, holds `clusterIdle` low while drain is pending, raises it within the 64-cycle drain budget once the dam releases, keeps ingress gated while `clusterStop` holds, and verifies the FSM returns to `sActive` cleanly on `clusterStop` deassertion. ## Findings _None._
Author
Owner
No description provided.
<!-- agent:pinged ts=1781767675 -->
fluidpop-bot left a comment
Collaborator

CI green (head 090a2eb8f0), auto-approving

CI green (head 090a2eb8f02c50b4efc2c25153e37788e76ab397), auto-approving
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Fluid/fluidpop-v1!126
No description provided.