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

Open
opened 2026-05-26 18:12:06 -03:00 by navigator · 6 comments
Owner

Goal

Implement v1 behaviour of MultiGemminiCluster per Draft SPEC at rtl/src/pop/specs/MultiGemminiCluster.SPEC.md (#93). Skeleton (#81) lands the empty IO bundle; this issue lands the per-tile dispatch + drain logic.

Scope — strictly what the Draft SPEC pins

  • Constructor: class MultiGemminiCluster(N: Int = 4, numCores: Int = 2)N tracks ADR-001 / PopSoCConfig.TileCountKey; numCores tracks ADR-006.
  • Instantiate xbar = Module(new InterGemminiXbar(N)) (the dependency that lands in rtl: InterGemminiXbar v1 should be merged first — issue body should mention this dep).
  • Per-tile dispatch: rocc ingress from PopRoCCRouter already decoded per tile; cluster forwards each per-tile stream to xbar.io.ingress(tileId), egress feeds the per-Gemmini RoCC attach (stub — actual Gemmini instantiation is out of scope until upstream pin lands; use a BlackBox placeholder for each Gemmini with the RoCCCommand/RoCCResponse mirror types from PopRoCCRouter).
  • Quiescence on clusterStop = Input(Bool()): de-assert all rocc(i).ready, wait until in-flight count is 0, then assert clusterIdle = Output(Bool()). Per SPEC §Behavior "Quiescence and drain on cluster-stop CSR".

Open Questions — do NOT invent

  • Gemmini BlackBox port shape beyond rocc — Open. Add minimal mem / csr ports as empty BlackBox bundles with // Open question per SPEC §Behavior comments.
  • L2 coherence wiring — Open. Mention in comment that ADR-011 fixes intra-chip coherence; L2 attach happens at FluidPopSoC v1, not here.

Acceptance criteria

  • rtl/src/pop/MultiGemminiCluster.scala body materialises xbar instantiation + per-tile dispatch + quiescence FSM
  • rtl/tests/MultiGemminiCluster/MultiGemminiClusterSpec.scala extended with two scenarios:
    • Single-tile dispatch routes through xbar to per-tile BlackBox
    • clusterStop=1 drains in-flight requests and raises clusterIdle after queue empties
  • sbt -no-colors test green
  • No Gemmini-internal width invention; BlackBox ports stay opaque

Plan refs

PLAN.md §8.2, §12.3; ADR-001, ADR-003, ADR-006, ADR-011.

Notes

Depends on rtl: InterGemminiXbar v1 (which is a separate queued issue) — open question whether resolver should wait or skip. If the xbar v1 PR has not merged yet, resolver should stub the xbar wiring with BlackBox and fail with a <!-- agent:fail reason=blocker:xbar-v1-pending --> comment.

## Goal Implement v1 behaviour of `MultiGemminiCluster` per Draft SPEC at `rtl/src/pop/specs/MultiGemminiCluster.SPEC.md` (#93). Skeleton (#81) lands the empty IO bundle; this issue lands the per-tile dispatch + drain logic. ## Scope — strictly what the Draft SPEC pins - Constructor: `class MultiGemminiCluster(N: Int = 4, numCores: Int = 2)` — `N` tracks ADR-001 / `PopSoCConfig.TileCountKey`; `numCores` tracks ADR-006. - Instantiate `xbar = Module(new InterGemminiXbar(N))` (the dependency that lands in `rtl: InterGemminiXbar v1` should be merged first — issue body should mention this dep). - Per-tile dispatch: `rocc` ingress from `PopRoCCRouter` already decoded per tile; cluster forwards each per-tile stream to `xbar.io.ingress(tileId)`, egress feeds the per-Gemmini RoCC attach (stub — actual Gemmini instantiation is out of scope until upstream pin lands; use a `BlackBox` placeholder for each Gemmini with the `RoCCCommand`/`RoCCResponse` mirror types from PopRoCCRouter). - Quiescence on `clusterStop = Input(Bool())`: de-assert all `rocc(i).ready`, wait until in-flight count is 0, then assert `clusterIdle = Output(Bool())`. Per SPEC §Behavior "Quiescence and drain on cluster-stop CSR". ## Open Questions — do NOT invent - Gemmini BlackBox port shape beyond `rocc` — Open. Add minimal `mem` / `csr` ports as empty BlackBox bundles with `// Open question per SPEC §Behavior` comments. - L2 coherence wiring — Open. Mention in comment that ADR-011 fixes intra-chip coherence; L2 attach happens at FluidPopSoC v1, not here. ## Acceptance criteria - [ ] `rtl/src/pop/MultiGemminiCluster.scala` body materialises xbar instantiation + per-tile dispatch + quiescence FSM - [ ] `rtl/tests/MultiGemminiCluster/MultiGemminiClusterSpec.scala` extended with two scenarios: - Single-tile dispatch routes through xbar to per-tile BlackBox - `clusterStop=1` drains in-flight requests and raises `clusterIdle` after queue empties - [ ] `sbt -no-colors test` green - [ ] No Gemmini-internal width invention; BlackBox ports stay opaque ## Plan refs PLAN.md §8.2, §12.3; ADR-001, ADR-003, ADR-006, ADR-011. ## Notes Depends on `rtl: InterGemminiXbar v1` (which is a separate queued issue) — open question whether resolver should wait or skip. If the xbar v1 PR has not merged yet, resolver should stub the xbar wiring with `BlackBox` and fail with a `<!-- agent:fail reason=blocker:xbar-v1-pending -->` comment.
Author
Owner
No description provided.
<!-- agent:claim by=dispatcher run=20260526T211323Z_issue114 ts=1779830003 -->
Author
Owner

Explanation:

Issue #114 says:

If the xbar v1 PR has not merged yet, resolver should stub the xbar wiring with BlackBox and fail with a <!-- agent:fail reason=blocker:xbar-v1-pending --> comment.

State on origin/main at run start (commit 0023338):

  • rtl/src/pop/InterGemminiXbar.scala is still the empty-IO skeleton from #49 / #64class InterGemminiXbar extends Module with val io = IO(new Bundle { }). No ingress/egress port count, no payload width, no per-port back-pressure shape is pinned.
  • Issue #112 (InterGemminiXbar v1 — N×N decoupled crossbar with round-robin arbitration) is open and currently agent:in-progress on a sibling resolver run. No PR for it is open against main yet (only #107, #108 from the same cohort have landed).

Wiring MultiGemminiCluster v1 against the empty-IO skeleton would force the cluster to invent the xbar.io.ingress(tileId) / xbar.io.egress(...) Decoupled bundle shape (and the per-tile scratchpad port shape behind it) ahead of InterGemminiXbar.SPEC lifting those Open questions in #112. That violates the "No Gemmini-internal width invention" acceptance criterion and the "No widths, no port counts" rule of the existing skeleton header, and would lock the xbar v1 resolver into the shape this resolver happened to guess.

Follow-up: re-queue #114 once #112 lands on main.

<!-- agent:fail reason=blocker:xbar-v1-pending --> Explanation: Issue #114 says: > If the xbar v1 PR has not merged yet, resolver should stub the xbar wiring with `BlackBox` and fail with a `<!-- agent:fail reason=blocker:xbar-v1-pending -->` comment. State on `origin/main` at run start (commit `0023338`): - `rtl/src/pop/InterGemminiXbar.scala` is still the empty-IO skeleton from #49 / #64 — `class InterGemminiXbar extends Module` with `val io = IO(new Bundle { })`. No ingress/egress port count, no payload width, no per-port back-pressure shape is pinned. - Issue #112 (InterGemminiXbar v1 — N×N decoupled crossbar with round-robin arbitration) is `open` and currently `agent:in-progress` on a sibling resolver run. No PR for it is open against `main` yet (only #107, #108 from the same cohort have landed). Wiring `MultiGemminiCluster` v1 against the empty-IO skeleton would force the cluster to invent the `xbar.io.ingress(tileId)` / `xbar.io.egress(...)` Decoupled bundle shape (and the per-tile scratchpad port shape behind it) ahead of `InterGemminiXbar.SPEC` lifting those Open questions in #112. That violates the "No Gemmini-internal width invention" acceptance criterion and the "No widths, no port counts" rule of the existing skeleton header, and would lock the xbar v1 resolver into the shape this resolver happened to guess. Follow-up: re-queue #114 once #112 lands on `main`.
Author
Owner
No description provided.
<!-- agent:fail reason=no-pr-marker run=20260526T211323Z_issue114 -->
Author
Owner
No description provided.
<!-- agent:claim by=dispatcher run=20260526T233902Z_issue114 ts=1779838742 -->
Author
Owner

Explanation:

Issue #114 says:

If the xbar v1 PR has not merged yet, resolver should stub the xbar wiring with BlackBox and fail with a <!-- agent:fail reason=blocker:xbar-v1-pending --> comment.

State on origin/main at run start (commit 153e6e1):

  • rtl/src/pop/InterGemminiXbar.scala is still the empty-IO skeleton from #49 / #64class InterGemminiXbar extends Module with val io = IO(new Bundle { }). No ingress/egress port count, no payload bundle shape, and no per-port back-pressure discipline are committed in-tree.
  • Issue #112 (InterGemminiXbar v1 — N×N decoupled crossbar with round-robin arbitration) is labelled agent:pr-open with PR #115 against main. PR #115 is open, mergeable=true, but not merged. It is the PR that would pin class InterGemminiXbar(n, payloadBits, fifoDepth) plus the ingress(i) / egress(i) Decoupled bundles on the cluster side.

Wiring MultiGemminiCluster v1 against the empty-IO skeleton would force this cluster to invent the xbar.io.ingress(tileId) / xbar.io.egress(...) Decoupled bundle shape (and the per-tile scratchpad port shape behind it) ahead of InterGemminiXbar.SPEC lifting those Open questions in #112 / #115. That violates the "No Gemmini-internal width invention" acceptance criterion of this issue and the "No widths, no port counts" rule of the existing skeleton header, and would lock the xbar v1 resolver into the shape this resolver happened to guess.

Follow-up: re-queue #114 once #115 lands on main.

<!-- agent:fail reason=blocker:xbar-v1-pending --> Explanation: Issue #114 says: > If the xbar v1 PR has not merged yet, resolver should stub the xbar wiring with `BlackBox` and fail with a `<!-- agent:fail reason=blocker:xbar-v1-pending -->` comment. State on `origin/main` at run start (commit `153e6e1`): - `rtl/src/pop/InterGemminiXbar.scala` is still the empty-IO skeleton from #49 / #64 — `class InterGemminiXbar extends Module` with `val io = IO(new Bundle { })`. No ingress/egress port count, no payload bundle shape, and no per-port back-pressure discipline are committed in-tree. - Issue #112 (InterGemminiXbar v1 — N×N decoupled crossbar with round-robin arbitration) is labelled `agent:pr-open` with PR #115 against `main`. PR #115 is `open`, `mergeable=true`, but **not merged**. It is the PR that would pin `class InterGemminiXbar(n, payloadBits, fifoDepth)` plus the `ingress(i)` / `egress(i)` Decoupled bundles on the cluster side. Wiring `MultiGemminiCluster` v1 against the empty-IO skeleton would force this cluster to invent the `xbar.io.ingress(tileId)` / `xbar.io.egress(...)` Decoupled bundle shape (and the per-tile scratchpad port shape behind it) ahead of `InterGemminiXbar.SPEC` lifting those Open questions in #112 / #115. That violates the "No Gemmini-internal width invention" acceptance criterion of this issue and the "No widths, no port counts" rule of the existing skeleton header, and would lock the xbar v1 resolver into the shape this resolver happened to guess. Follow-up: re-queue #114 once #115 lands on `main`.
Author
Owner
No description provided.
<!-- agent:fail reason=no-pr-marker run=20260526T233902Z_issue114 -->
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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#114
No description provided.