GSys LibreCore — a source-available RISC-V core and agentic build platform, derived from OpenHW CVA6. Explore the layered architecture.

Simultaneous Multithreading (SMT)

GSys LibreCore supports two hardware threads (NrHarts=2) sharing pipeline resources with per-hart architectural state. Default packages keep NrHarts=1 for identity netlists.

Scaffold + bring-up: architecture/multi-threading/ (README.md, smt2-bringup.md, dts-linux-smt.md, smt-linux-rootfs.md).

Software view

ItemBehavior
mhartid for thread hhart_id_base + h
ISA stringSame on both threads
SBI / OpenSBITwo harts in the domain
LinuxTwo cpu@ nodes; enable after OpenSBI knows both

What the RTL guarantees

  1. Per-hart arch state — RF banks, CSR banks, PC bank, RAS banks, GHR banks
  2. Fine-grain, drain-friendly switch — IF flush + drop unissued; EX/scoreboard drain; BP tables preserved where not banked
  3. Commit isolation — CSR writes keyed by instruction hart_id
  4. Fetch view — privilege / MMU CSR mux by active fetch hart

On OoO profiles (OoOEn && NrHarts=2), residency switches by drained handoff: the thread selector changes only when the scoreboard and store queues are empty, so the hart-blind OoO backend never interleaves two harts’ work. Mixed residency (SmtDrainedHandoff=0) is promoted to production on the single-core g6lc64_smt2_ooo_int package (T9d/M2, evidence re-baselined on the eWT tree); on multi-core packages it stays qualification-gated behind G6LC_OOO_SMT_MIXED_QUALIFY. FP on the OoO path is legal single-hart and under the drained handoff (M4 — g6lc64_ooo_int2_l3 is RV64GC+B); FP under mixed residency stays refused pending the hart-tagged lazy-FS audit.

Window geometry. Both OoO SMT2 packages run a 16-entry scoreboard ring (NrScoreboardEntries=16, adopted T10d: the int2_l3 four-hart boot 18,297,381 cycles vs 18,419,779 at ring 8, the mixed smt2_ooo_int boot 10,459,588 vs 10,556,456, branch-bound IPC unchanged, mixed-commit FO4 31.0). The full T9f/M3 uplift bundle (ring 32, TAGE_LITE, BPCkptDepth 32, DeepSpec+MemDepPred, FTQ 8 / FDIP / loop buffer) was measured and not adopted: every knob regressed the strict boot on its own (TAGE_LITE at 3×64 entries multiplies boot mispredicts ~4.75×, DeepSpec/memdep replays dominate, FTQ/FDIP taxes every control transfer), and mispredict recovery is mark-and-drain through the commit head, so a deeper window pays more per mispredict — the M3b fast-squash candidate is sketched in plan T9f. Ring 32 additionally exposed a drained-handoff hole: a drain can pend for millions of cycles while the resident hart holds scoreboard entries. The bounded-drain machinery (SmtDrainForceCycles, N1c: no-commit counter, WFI-immediate force, hart-scoped flush + PC rewind, PMU events, leaf and bounded proof) is landed and inert on every qualified package (force count 0, anchors byte-identical), but on the ring-32 boot the force never armed: the stalled head was uncommittable, so the head-class/killable gates masked it. The bound is therefore conditional, not construction-grade; the head-level root cause is the open item (plan T10f) and ring 32 stays off. Landed from the M3 work is the switch-safety fix: smt_restore_i reseeds the FTQ and steps the cursor (arch_step=FtqEn) and clears the loop buffer on every switch (formal g6lc_fetch_restore + the tb_g6lc_fetch_restore leaf; the NOFLUSH mutant is detected).

Qualification anchors (strict OpenSBI, single-threaded Verilator, byte-exact per-hart traces): g6lc64_smt2 12,406,273 cycles, g6lc64_smt2_ooo_int (mixed, ring 16) 10,459,588, g6lc64_smt2_l3 13,691,686. A run killed by the wall clock now reports TERMINATED (exit 124) instead of a truncated SUCCESS.

Modules under core/smt/ include thread select, hart state, banked RF, PC bank, and CSR bank helpers.

Switch policies

PolicyIntent
Round-robin quantumBound IF unfairness (SmtFetchQuantum)
Switch-on-missPeer switch on D$/I$ miss when peer ready
Hybrid (typical SMT2 package)Miss switch + anti-starvation (SmtStarveLimit)

Enable

core/include/g6lc64_smt2_config_pkg.sv         # NrHarts=2, SMT_HYBRID, in-order (anchor)
core/include/g6lc64_smt2_l3_config_pkg.sv      # + non-inclusive L3
core/include/g6lc64_smt2_ooo_int_config_pkg.sv # NrHarts=2 over OoO, mixed residency, ring 16 (production)
core/include/g6lc64_ooo_int2_config_pkg.sv     # two-core WT + L2 COH_OOO (integer anchor, drained)
core/include/g6lc64_ooo_int2_l3_config_pkg.sv  # + L3, RV64GC+B, ring 16 (drained)
g6lc-build verify --target g6lc64_smt2
g6lc-build verify --target g6lc64_smt2_ooo_int
g6lc-build test --suite smt-linux-boot-path   # if catalogued

Bring-up sequence (product)

  1. Keep NrHarts=1 green on default packages.
  2. Select SMT2 package; bare-metal boot hart 0 only.
  3. Park hart 1 in WFI; exercise switch-on-miss.
  4. Dual-thread litmus / rdcycle before Linux.
  5. OpenSBI expected_harts / domain for two harts.
  6. Linux maxcpus=2 smoke with validated DTS.

DTS of record: corev_apu/bootrom/ariane-smt2.dts Validate: build-platform/scripts/validate-cva6-dts.* (after fetch-linux-dts).

Software track: software/smt2-linux/.

Known limits

  • Shared BHT/BTB (RAS/GHR banked) → mild cross-hart pollution
  • Dual-commit of two different harts in one cycle is not a specialized product path (single CSR port discipline)
  • Full KVM-on-SMT is out of scope for SMT bring-up — use H/server packages separately after bare-metal SMT is green

Verification suites (optional / residual)

Suite id (typical)Focus
smt-linux-boot-pathDTS + IRQ path / boot path
smt-linux-rootfsRootfs preflight + dual-park; full image via CVA6_LINUX_PAYLOAD

Diagnostics compartment smt2 exists under g6lc-build diag for focused Verilator surfaces.