Microarchitecture

The explorer replays a cycle-accurate model of this document’s pipeline contracts (stage widths, registered queues, IQ reclaim, completion register, L1D hit latency) on CoreMark instruction bytes. It is not NPC/Verilator and branches do not redirect.

Raptor is an out-of-order, super-scalar RISC-V processor core with register renaming, a reorder buffer (ROB), per-class issue queues (a parameterized multi-port ALQ plus BRQ / MDQ / FPQ / IOQ), scalar F/D plus Zfhmin floating-point execution, and virtual memory support.

Pipeline

rapt_core composes rapt_frontend, rapt_backend, the instruction/data caches, and the memory interconnect. The frontend owns prediction, fetch, FQU and decode. The backend owns rename/checkpoints, ROB, dispatch, physical registers, issue/execute, completion validation, LSU/SQ, CSR and retirement. Decoded uops, memory requests/responses, recovery and control broadcasts cross these boundaries; the grouping itself introduces no pipeline register. FPGA fixed-vector adapters and checkpoint build/link commands are described in the OOC flow.

The ordered front/back-end stream has independent DecodeWidth, RenameWidth, DispatchWidth, and CommitWidth. Queue entries are instructions, not fixed pairs. Execution-port and completion-port counts are independent of those widths. Local design notes: docs.agent/architecture/superscalar-widths.md (agent working documents are not part of the published manual).

L1I/BPU -> IFU response register -> IFU held suffix -> FQU -> IDU input register + decode
        -> RNQ -> rename -> renamed output queue -> UOQ (PRF pre-read)
        -> ROB allocation -> K-entry candidate scan -> W-entry DPU compact
        -> winner payload read -> issue queues -> FUs -> ownership/arbitration
        -> completion register
        -> ROB ready-prefix retirement -> RAT / PRF / CSR / CMU

The queues and registered payload boundaries are explicit. This diagram is not an exact-cycle latency model; no IPC, mispredict-penalty or Fmax improvement is claimed from the width refactor alone.

The default fetch response boundary (RAPT_FETCH_RESPONSE_STAGE=1) adds one frontend register stage to the previous organization. Backend timing decoupling uses registered IQ vacancy (RAPT_IQ_RECLAIM_ON_ISSUE=0); it does not add a fixed-latency execution stage. Variable-latency queues and functional units still prevent a universal instruction latency from being inferred from a stage count.

Store & Load Ordering

IOQ short-range alias checks use a symmetric overlap matrix. Each word address is split into a two-bit offset and an upper chunk; a range of up to four words can cross at most one chunk boundary. The upper successor is shared across comparisons. Translated accesses compare page offsets, preserving wraparound aliases even when adjacent virtual pages map to noncontiguous physical pages.

Branch Misprediction Recovery

Recovery now has two explicit phases. When a non-faulting misprediction completion is accepted, ROU registers the oldest outstanding owner and publishes one rapt_recovery_if redirect transaction containing ROB slot, allocation generation, target and rename-checkpoint identity. A subsequently completed older misprediction replaces the transaction and produces a new one-cycle redirect. IFU immediately starts a target data-SRAM read-ahead; IFU/FQU/IDU and RNU remain fenced and empty while pending is asserted. A later head retirement still performs the architecturally precise whole-pipe flush: cmu_bcast.flush_pipe reasserts the target, PRF transient state is invalidated, and committed state remains the final recovery authority.

Simulation-only ROB lifecycle events measure completion-to-retirement latency separately from the existing flush-to-frontend-delivery interval. The host observer distinguishes retired mispredicts from younger canceled ones, tracks overlap and ROB-head domains, and checks identity/residence-time conservation. These probes are absent under SYNTHESIS; timestamps and histograms live in C++, not hardware. Local results and the remaining selective-recovery requirements are recorded in docs.agent/evaluation/recovery-latency-evaluation.md.

A completed, non-faulting misprediction creates that registered oldest transaction through rapt_recovery_pending. Arbitration uses ROB-ring age from the current head and a balanced completion-port reduction tree. From the following cycle, RAPT_RECOVERY_DISPATCH_FENCE=1 stops new UOQ-to-ROB allocations while older ROB work continues to issue and retire. Each renamed control-flow uop also owns a parameterized rename checkpoint: post-branch MAP, free bitmap and a live-ancestor mask. Correct resolution releases it; a misprediction restores the selected snapshot, invalidates its descendant checkpoints, flushes RNQ/rename output state and fences further rename until the existing precise retirement flush. Free-set recovery unions the snapshot with registers released by older commits after the snapshot. Correctly resolved checkpoint releases use the separate multiport checkpoint_release_if; they are not overloaded onto the single recovery transaction. The completion-time redirect currently overlaps only target-side read-ahead with retirement wait: it does not admit correct-path decode/rename, restore predictor/RAS checkpoint state, or selectively squash ROB/IQ/IOQ/SQ entries. Completion producers carry a ROB allocation generation and pass through one ownership firewall before any ROB/PRF/IQ/FPR/LSU side effect. This blocks stale generations under the current full-flush lifecycle, but finite generation is not a cancellation/reuse protocol for future selective recovery. Local proof, cost and remaining lease requirements are recorded in docs.agent/evaluation/completion-identity-evaluation.md; recovery-fence work reduction is in docs.agent/evaluation/recovery-request-evaluation.md, and the unified transaction/read-ahead results are in docs.agent/evaluation/recovery-transaction-evaluation.md.

Module Details

Frontend

IFU (rapt_ifu.sv)

Walks complete 16/32-bit instructions in the existing L1I lookahead window, up to DecodeWidth. Each instruction carries its own PC, predicted next PC and fault metadata. The first control-flow, serializing or faulting instruction ends a fetched prefix. A held suffix survives partial downstream acceptance; system/atomic/trap instructions block further fetch until recovery. RAPT_FETCH_LOOKAHEAD controls cache/predictor lookahead capability separately from ordered stage widths. The fixed cache byte window may supply fewer than DecodeWidth instructions.

The response register captures the request PC, raw instruction window, lookahead validity, fault metadata and primary prediction together. Prefix assembly, decompression and auxiliary branch prediction use this registered response. The request address advances using the primary prediction or a provisional packet boundary derived from raw instruction lengths and control opcodes; lookahead permission and auxiliary prediction do not feed this calculation. A different resolved packet boundary cancels the younger request and corrects its PC before another response can be captured. Backpressure holds the response; normal streaming can consume one response and capture the next on the same edge. Redirect and recovery clear both the response and held suffix. A pending response also prevents the instruction IO guard from treating the pipeline as empty, including when successive dynamic requests have the same PC.

Read-ahead: ordinary SRAM reads follow the registered request PC. A completion-time recovery redirect clears both IFU buffers and supplies a side-effect-free target data-SRAM hint, but recovery.pending prevents returned data and prediction history from being accepted until precise cleanup. This hides some synchronous SRAM latency without creating a cache request or modifying cache state.

FQU (rapt_fqu.sv)

Registered instruction-stream queue between IFU and IDU, implemented with rapt_stream_queue. It has no empty-queue fall-through. Partial dequeue and same-cycle enqueue/reclaim are supported, and decode groups may cross original fetch boundaries. Flush, system resume, accepted IDU resteer, and a pending recovery transaction cancel resident instructions and same-cycle acceptance.

BPU (rapt_bpu.sv)

Component Implementation Key details
DIRP Default TAGE; alternatives: gshare, bimodal/PHT, static Selected by RAPT_BPU_DIRP_* macros
PHT (rapt_bpu_pht.sv) 2-bit saturating, PHT_SIZE entries (256) Used by bimodal/PHT mode and as local predictor base
BTB (rapt_bpu_btb.sv) 2-way SA, BTB_SIZE entries (128), 7-bit tag (* keep_hierarchy *), sync read, XOR-hash, LRU
History (rapt_predict_history.sv) 64-bit GHR plus 8-bit PHR at fetch, decode and commit boundaries Accepted conditional events; post-decode/post-commit repair
RAS (rapt_ras.sv) RSB_SIZE entries per image (4) Independent committed/speculative data, bounded count, decode-order actions

BTB entry types: COND, DIRE, INDR, RETU. Direction predictor state is trained from committed branch outcomes; BTB updates occur on flushes (including JALR). Predictor structures are invalidated or repaired on fence_time / flush paths as appropriate.

Return prediction has an explicit stage boundary: IFU uses its request-aligned BTB target; IDU uses the pre-action RAS top to repair accepted returns, including BTB misses. Both speculative push and pop occur only on accepted decode control instructions (at most one per group), never on prediction queries. Full flush restores the post-commit RAS data, pointer and count; an IDU-only resteer retains the accepted action. Local rationale, overflow-policy and verification notes are kept in docs.agent/evaluation/ras-recovery-evaluation.md.

Direction history uses one acceptance protocol for primary and auxiliary conditionals, including BTB misses. Prediction queries, stalls, non-control BTB aliases and faulting instructions do not advance it. IDU resteer restores the post-decode watermark; full flush restores the post-commit watermark, appending an outcome only when a conditional actually commits. The next-PC predictor query sees this post-event history on the same edge. fence_time clears all three watermarks. The predicted direction bit travels with the instruction; next-PC equality alone is insufficient when a taken target is fall-through. Local proof, cost and regression notes are in docs.agent/evaluation/prediction-history-evaluation.md.

L1I (rapt_l1i.sv)

N-way set-associative I-cache (L1I_N_WAYS, default 4). 2^L1I_LEN sets (64), 2^L1I_LINE_LEN words/line (16 RV32 words = 64 B). Default capacity is 16 KiB. 7-state FSM (IDLE, PTWAIT, TRAP, RD_A, RD_0, RD_1, FINA).

Storage Implementation
Data Banked rapt_sram_1rw per way per word (single-port, sync read)
Tags Banked rapt_sram_1rw per way per word (combinational compare from SRAM output)
Valid Register arrays per way (l1i_valid[way][set]) for fast fence.i bulk invalidation

3-tier pre-read uses the IFU’s exact next-PC hint: current bank reads the hinted word, next bank reads +2, and remaining banks read +4. This provides inst_n1 and inst_n2 for the parameterized instruction-prefix walker while hiding hit-path target/stride transitions. Cache lines retain per-word valid bits; on the default non-SDRAM AR path, RAPT_L1I_REFILL_WORDS=8 refills one 32 B sector per miss through an 8-entry AR FIFO. The value is capped by the configured line length and may be overridden for experiments; SDRAM burst targets retain their dedicated two-beat burst refill path. Way replacement reuses a matching partial line, then chooses an invalid candidate, then a per-set tree-PLRU victim for more than two ways (two-way configurations retain their toggle). ITLB + IPTW support Sv32/Sv39 translation.

Cache-response ownership is separate from request acceptance. Recovery and invalidation detach refill ownership while already accepted reads drain; their late data or errors must not affect a replacement fetch at the same PC. Error responses are consumed without installing a valid cache word. An error in a lookahead word does not fault an unrelated current instruction; a later demand must request that absent word again.

For a 32-bit instruction starting at a halfword boundary, the second-word error may arrive before the first halfword’s synchronous SRAM read reveals instruction length. second_error_pending retains that error with its virtual fetch PC. Only first-halfword readiness is needed to classify it: a compressed instruction discards the unrelated error, while a spanning instruction reports the second halfword’s address. Recovery, invalidation, PC changes and consumption end this ownership; the state is functional and remains present in synthesis.

IDU (rapt_idu.sv)

A compacting input register feeds DecodeWidth instances of rapt_decode_slot. The decoder is pure combinational per-slot logic; acceptance, prefix termination, call pushes and early resteers belong to the surrounding stage. Direct JAL, stale conditional targets and non-control prediction aliases are corrected only when that instruction is accepted. Unaccepted suffixes remain registered.

Backend

RNU (rapt_rnu.sv)

RNQ accepts DecodeWidth instructions and supplies RenameWidth candidates. Cycle-start MAP reads plus older-slot tag bypass implement arbitrary intra-group RAW and WAW dependencies. A shared bounded-count rank tree selects free physical identities; only accepted GPR writers consume ranks. This avoids cascading a full updated MAP and a physical-register priority encoder through every slot. A registered output queue decouples renamed instructions from UOQ acceptance.

rapt_rename_admit separates resource qualification from tag assignment. Each slot independently counts preceding destination/checkpoint demands, checks the corresponding ranked resource availability, then accepts only an ordered prefix whose older slots are valid and qualified. An earlier rejection blocks later slots without feeding an accepted-rank increment back into their qualification. Accepted-rank bookkeeping remains in tag/payload construction, including the existing invalid-slot values; admission adds no sequential stage. Allocation still cannot consume same-cycle retirement releases.

RNU owns speculative MAP, committed RAT and a free bitmap. RAT update gives the youngest committed writer priority. Flush reconstructs MAP and the free set from the post-commit RAT, reclaiming speculative identities even before ROB allocation. rapt_rename_checkpoint independently owns branch-checkpoint allocation, ancestry, release and restore state. Checkpoint exhaustion stalls the ordered rename prefix. Clearing a correctly resolved ID from every live ancestry mask makes numeric-ID reuse safe; it avoids confusing an old checkpoint incarnation with a later branch. The single oldest restore arrives through rapt_recovery_if; independent correct-resolution releases arrive through multiport checkpoint_release_if. Checkpoint ID travels alongside each renamed uop through UOQ into ROB. Current PMU probes report occupancy, capacity stalls and the conservative recovery-fence interval. The old standalone map/freelist modules are retained only for historical harnesses.

PRF (rapt_prf.sv)

PHY_SIZE physical entries, two read ports per RenameWidth position, and a typed completion array. UOQ captures ready operands and continues snooping completion while resident. Commit deallocates stale mappings and settles current mappings; a younger WAW deallocation overrides settlement of an older version. Flush invalidates transient speculative results. Debug architectural reads select the requested RAT entry before reading one PRF value; the DM/core link carries an address and one XLEN-wide combinational response, with no extra command cycle. The complete committed/speculative register views remain available for RVFI and simulation rather than requiring 32 physical debug read values at the DM boundary.

FPR (rapt_fpr.sv)

Separate 32 x 64-bit architectural floating-point register bank. The fixed 64-bit width supports RV32 and RV64, with single-precision values NaN-boxed in the same storage used by double precision. FP arithmetic writes through the FEU path and FP loads write through the LSU path, with local bypassing for recent writes. The bank no longer has a combinational IOQ write-through path into FPU completion generation; accepted writes cross its registered storage boundary. FP dependency tags include the ROB allocation generation; this bank is not a second renamed physical register file.

ROU (rapt_rou.sv)

Dispatch queue + reorder buffer + commit logic.

DPU (rapt_dpu.sv)

Stateless, capacity-aware compactor driven by uop.schedule.domain, not execution opcode classes. For K age-ordered candidate tokens it computes the number of older valid candidates in the same domain, compares that rank with the domain’s ordered capacity prefix, and uses the shared rank selector to choose the oldest W admissible tokens. It then produces fixed-W per-domain grant masks; endpoint adapters translate those grants to IQ free indices or IOQ tail ranks. Full operand-bearing payloads do not cross the K-wide DPU boundary and are assembled by ROU only for selected tokens. Domain classification belongs to decode/composition. This is bounded dispatch bypass, not an arbitrary full-ROB scheduler.

IEU (ieu/rapt_ieu.sv)

FEU (feu/rapt_feu.sv)

Owns the four-entry in-order FPQ and scalar F/D arithmetic plus Zfhmin half-precision conversion, FMA, divide/square-root, conversions, comparison/classification, sign injection and move operations under feu/fpu/. It reads/writes the architectural FPR bank and produces the FPU candidate for the configured shared completion endpoint. rapt_cdb_arb.sv arbitrates that endpoint: an FPU completion wins over the configured integer system pipe, and the losing issue source is backpressured. No dispatch or issue position owns this endpoint. FP loads/stores remain in LSU.

The scalar FEU permits one long operation in flight. rapt_fpu_mul_fma uses that contract to share one significand multiplier per precision between FMUL and FMA, retaining their four- and six-stage pipelines respectively. FMUL consumes the product in stage 2 and FMA in stage 1; normalization, rounding and flags remain in their original pipelines. The standalone rapt_fpu_mul and rapt_fpu_fma wrappers retain private multipliers and their existing APIs, including for vector users. This sharing is a resource binding for the current serial scalar endpoint, not a multi-request arbiter: increasing FP concurrency requires revisiting product ownership, ready and completion routing explicitly.

For a single in-order IQ port, payload selection pre-reads the oldest surviving resident independently of operand readiness and port enable. The issue selector still controls valid and state updates; this adds no pipeline stage. While waiting, the output may carry that head’s identity rather than slot zero’s, so consumers must qualify effects with valid. Reset and full flush suppress valid immediately but do not steer the unqualified payload; queue state is still cleared on the clock edge. This separates reset/flush and late load confirmation from FP opcode/FPR-address selection. Unordered and multiport queues retain grant-based payload selection. Directed checks cover both valid transfers and waiting-head identity, including reset pulses and flush; each timing change requires its own mapped comparison.

CMU (rapt_cmu.sv)

Broadcast unit. Outputs: rpc, cpc, branch resolution, flush_pipe, fence_i, fence_time, time_trap. It selects the actual control-flow slot from the parameterized retirement prefix (currently at most one control instruction), and exposes every retirement slot to simulation/RVFI. Retirement packets carry explicit original compressed length and trap status: expanded instruction bits cannot recover length. Shared RISC-V RAS hint classification drives call (push) and ret (pop), both true for a coroutine switch and both suppressed for faulting instructions. Rename recovery consumes typed per-slot PRF identities.

CSR (rapt_csr.sv)

64-slot CSR storage array (42 csr_t enum members in the default configuration: 41 named CSRs plus the MNONE__ sentinel), M/S-mode. Trap entry/exit (ecall/ebreak/mret/sret), privilege transitions (M/S/U), delegation (medeleg/mideleg), MSTATUS<->SSTATUS mirroring, mcycle/time counters. Broadcasts: priv, satp, MMU enables, tvec, and pmpcfg/pmpaddr shadow arrays for PMP.

PMP (rapt_pmp.sv)

8 usable PMP entries (RAPT_PMP_NUM=8) across all presets and both XLENs, with 16 architectural CSR slots (RAPT_PMP_CSR_NUM=16). Slots 8–15 are read-only zero: their address/configuration writes are ignored and never update the 8-entry permission replicas. RV32 uses pmpcfg0/1 for the usable entries; RV64 uses pmpcfg0, while odd configuration CSRs remain illegal. The remaining legal configuration banks read zero. This retains the architectural CSR numbering while eliminating the upper entries’ storage and comparators. Verification declarations distinguish NUM_PMP_ENTRIES=16 from NUM_USABLE_PMP_ENTRIES=8.

Combinational match logic supports TOR / NA4 / NAPOT modes, with locked (L bit) entries enforced even in M-mode. The CSR file owns the architectural PMP registers and sends updates through pmp_update_if to local rapt_pmp_state copies. Checks cover instruction fetch, load/store accesses and implicit PTW PTE reads. Empty PMP tables allow M-mode accesses and deny S/U-mode accesses. Entry 7 remains writable unless it locks itself; the read-only-zero entry 8 cannot lock entry 7 as a TOR predecessor.

Eight entries reduce the available firmware/domain isolation regions; software requiring more must be reconfigured. Existing 16-entry FPGA/boot/profile results do not validate this revision. Area/timing improvement and OpenSBI/Linux/network operation require fresh synthesis and board validation. Directed checks: make -C verify verilator-csr-pmp-warl-rv32 verilator-csr-pmp-warl-rv64 verilator-csr-pmp-lock-rv32 verilator-csr-pmp-lock-rv64 verilator-pmp-permissions-rv32 verilator-pmp-permissions-rv64.

RVA22S64 compatibility: the ratified RVA22S64 v1.0 requirements specify the supervisor execution environment and Ss1p12, but do not mandate 16 usable PMP regions. The RISC-V architectural parameter model distinguishes implemented CSR slots from usable entries and permits read-only-zero entries. Therefore, retaining 16 CSR slots with 8 usable entries does not itself invalidate the default/RV64 RVA22S64 support statement. This is a compatibility assessment of the capacity change, not renewed whole-profile certification or a guarantee for firmware requiring more regions. Preserve M-only CSR access, illegal RV64 odd configuration CSRs, upper-slot read-zero/write-ignore behavior, lower-entry priority, full-access coverage, locks and PTW checks; make -C verify pmp-capacity-check covers the directed capacity contracts, not all profile obligations.

rapt_pmp_permissions shares range matching and first-entry selection across read/write permission results for the same address and byte footprint. L1D uses three parallel address checks (load, store/CMO, PTW); CMO read and store write permission checks share the store footprint. Partial matches, locked entries, effective privilege and complete-byte coverage retain the same fault semantics. rapt_pmp remains the single-request compatibility interface.

Memory Subsystem

LSU (lsu/rapt_lsu.sv)

Backend optimization handoff

The EXU split is intentionally structural. The following optimization items remain separate microarchitecture projects, now rooted at their owning module:

L1D (rapt_l1d.sv)

4-way set-associative. 2^L1D_LEN sets (64), 2^L1D_LINE_LEN words/line (16 RV32 words or 8 RV64 words = 64 B). Default capacity is 16 KiB. 6-state FSM (IDLE, PTWAIT, TRAP, LD_CHECK, LD_A, LD_D).

Storage Implementation
Data Banked rapt_sram_1rw wide subarrays (single-port, sync read, write bypass)
Tag/Valid Per-line tags and per-word valid register arrays for simultaneous ld/st checks + set invalidation

Each default L1 has 64 sets × 64 B × 4 ways = 16 KiB, with tree-PLRU replacement. The 4 KiB per-way span keeps every index bit within the page offset for both Sv32 and Sv39.

RAPT_L1D_MSHRS=2 enables two ordinary RAM miss owners in the default preset; 0 selects the blocking path, and the miss table supports 1–4 entries. Each entry holds one physical line, per-word data/error state and its outstanding bus owner. Same-line requests share a refill. A miss returns rmiss rather than a completion; IOQ excludes that instruction until a refill/capacity wake, then replays it through translation, permission checks and cache lookup. Wake does not write registers. The initial replay waits for RLAST; critical-word-first wakeup is not implemented. Completed lines are protected from replacement until a replay consumes them. Replay installs only the demanded word into L1D; remaining words stay in the small refill buffer until replacement or invalidation. There is no background whole-line installation or BOOM-style per-MSHR replay queue in this version.

AXI IDs 8–11 belong to MSHRs; legacy data/PTW remain on IDs 2/4. Flush kills unissued misses immediately and drains issued owners through RLAST without publishing their data. Stores wait for pending refills and invalidate buffered lines before writing. MMIO, atomics, split loads and the full-width FP load path keep the blocking protocol. Existing PBMT/IOQ ordering restrictions remain. External slave and optional L2 serialization can limit memory-level parallelism even when both MSHRs are occupied.

Cacheable main-memory misses issue one aligned full-line INCR read. The demanded word returns as its beat arrives; the accepted transaction retains ownership through RLAST, including after flush or an error. Good beats populate per-word valid state. A demand error faults after the burst drains; errors on other beats leave those words invalid. Refill is restricted to one translated page, a supported RAM range and a uniform PMP region. PMP boundaries, PBMT NC/IO and narrow ROM/SRAM/device paths retain word accesses; no-allocation metadata also prevents optional L2 from widening these requests or PTW reads. Ordinary stores wait while the full-line refill drains.

Write-through policy. Partial stores (SB/SH): read-modify-write (RMW) 2-cycle merge in IDLE. Speculative SRAM read: VIPT-safe virtual index in IDLE. Separate DTLB + DSTLB instances; shared DPTW for both. Reservation register for LR/SC. Cacheability via addr_cacheable().

Zicbom cbo.inval, cbo.clean, and cbo.flush are serializing operations. Their effective address is translated and checked as a CMO access before retirement: load or store permission is sufficient, the PTE A bit is required, the D bit is not, and failures use store/AMO page- or access-fault causes. M/S/U execution is gated by the corresponding menvcfg/senvcfg CBIE and CBCFE controls. After the unified SQ drains, INVAL/FLUSH invalidate every way of the VA-selected L1D set (default: one 64-byte line per way). The commit broadcast carries only VA [11:6], reusing the accepted IOQ completion address stored in the ROB. No maintenance tag comparator is needed. Smaller-line presets clear every set covered by the aligned 64-byte CBO block; custom geometries extending beyond the page offset clear all possible physical index colors. CLEAN only drains the write-through SQ. CBO does not flush instruction/data TLBs or the I-cache. Faulting and stale-generation completions cannot initiate set maintenance. Optional L2 receives the same VA block broadcast, queues all matching physical set colors, and holds new requests until accepted reads/writes and pending installs drain and the selected sets are invalidated. This prevents an older refill from restoring a line after maintenance.

Zicboz cbo.zero uses the same checked effective-address path with ordinary store permissions, including PTE A and D checks and CBZE gating. At commit, the SQ retains one aligned block descriptor through the final memory B response. The AXI adapter emits one AW, eight 64-bit W beats in RV64 (sixteen 32-bit beats in RV32), and one B, zeroing exactly the naturally aligned 64-byte block. L1D invalidates the touched block on completion, including error completion. Optional L2 streams the burst, invalidates touched sets, and holds reads until the real downstream B. The RV32 RNP bridge splits the burst into its existing word transactions while retaining the core-side owner and final B. This also implements Zic64b on physical configurations whose cache lines are only 16 bytes. Zicbop prefetch encodings are accepted as non-faulting HINTs.

TLB (rapt_tlb.sv)

Reusable fully-associative Sv32/Sv39 TLB. ENTRIES is configured independently for instruction and data translation (RAPT_ITLB_ENTRIES / RAPT_DTLB_ENTRIES; both 16 in the default configuration). Lookup is combinational and honors global PTEs. Fill first refreshes an existing translation, then consumes an invalid entry, and finally uses round-robin replacement. L1D instantiates separate load/store lookup replicas (u_dtlb and u_dstlb) but cross-fills both from every completed DPTW, avoiding a second walk when a page changes access direction. Bulk flush clears all entries.

PTW (rapt_ptw.sv)

Reusable page-table walker. RV32 uses a Sv32 two-level FSM (IDLE->LVL1_REQ/LVL1_WAIT->LVL0_REQ/LVL0_WAIT); RV64 uses a Sv39 three-level FSM (IDLE->LVL2_REQ/LVL2_WAIT->LVL1_REQ/LVL1_WAIT->LVL0_REQ/LVL0_WAIT). Leaf detection follows PTE.R||PTE.X. Svade is implemented: A=0, or D=0 for a store, produces a page fault and the walker never modifies a PTE. Instantiated as: u_iptw (L1I), u_dptw (L1D).

BUS (rapt_bus.sv)

rapt_bus.sv arbitrates core memory traffic onto mem_link_if. Reads use request IDs (L1I, L1D, TLBI, TLBD): L1I has a configurable refill-request FIFO, L1D has a held request slot, and L1D has issue priority. Responses are demultiplexed by ID. rapt_axi_master.sv converts that internal link to AXI4, supports up to eight outstanding reads with per-ID ownership tracking, and handles AW and W handshakes independently for one outstanding write. The bus is SoC-memory-map agnostic; the cluster-level rapt_router.sv decodes CLINT/PLIC MMIO and forwards all other transactions off chip.

L2 (rapt_l2.sv)

Optional unified AXI4 cache between the core bus/router path and off-chip memory. When RAPT_L2_EN is undefined, the module collapses to a transparent passthrough; the default configuration currently leaves it disabled. When enabled, the configured implementation is a 16 KiB direct-mapped cache (2^RAPT_L2_LEN sets, 64 B lines) with multi-way support reserved.

CLINT (rapt_clint.sv)

Cluster-level 64-bit mtime counter with mtimecmp and msip. mtime is paced by RAPT_MTIME_DIV, and the timer interrupt is level-triggered when mtime >= mtimecmp. CLINT MMIO is decoded by rapt_router.sv beside the PLIC.

The CLINT write interface carries byte strobes. The router shifts data and strobes together into the addressed register half; mtimecmp preserves bytes whose strobes are clear, and msip changes only when byte zero is enabled. Both XLEN configurations expose the +4 high-half addresses of mtime and mtimecmp; RV64 also supports full-width access at their base addresses. mtime accepts byte-enabled writes; a nonempty write wins a coincident timer tick while the divider phase continues. The shared counter also supplies CSR time/timeh and Sstc comparisons. These register semantics do not establish supported transfer widths for other MMIO devices.

The platform also supports naturally aligned byte/halfword accesses within these CLINT registers. The router normalizes AXI lanes to the transfer’s first byte; the endpoint then selects the addressed byte within the register. Reads share one register-selection and byte-alignment path. Writes reposition the normalized data and strobes within the register, preserving all unselected bytes. MSIP’s upper bytes remain read-only zero. Byte/halfword support is a platform choice; RV64 aligned 64-bit mtime/mtimecmp accesses still use one atomic register transaction. RV32 FLD/FSD may decompose into two word transactions and do not provide an atomic 64-bit timer snapshot.

NPC architectural snapshots save CLINT mtime as the authoritative time state. Legacy csr_time/csr_timeh metadata is exported from that counter and ignored on load, including when older snapshots contain different values. CLINT time advances during the restore trampoline and is not rewound at the first resumed commit. This is architectural resume with elapsed restore time, not cycle-exact replay of the timer divider phase.

PLIC (rapt_plic.sv)

Cluster-level Platform-Level Interrupt Controller. Default NDEV=31 sources and NCTX=2 contexts (ctx0 M-mode hart 0, ctx1 S-mode hart 0). Implements priority, pending, enable, threshold, and claim/complete registers in the standard 0x0c00_0000 16 MB window. The legacy single-bit io_interrupt input is merged into PLIC source 1, and the core consumes meip/seip from the PLIC context outputs.

Threshold controls interrupt notification; polling a claim register still selects the highest-priority enabled pending source, with priority zero excluded. Completion checks the full 32-bit command and the receiving context’s enable mask, so an out-of-range ID cannot alias a valid source. An enabled context may complete a source claimed by another context. These rules follow the PLIC 1.0 claim and completion specification.

For word-aligned PLIC register transactions, the router shifts byte strobes with write data into the endpoint. Unselected enable bytes are preserved; priority, threshold and completion require the low byte, and zero strobes cause no write side effect. The core’s supported-access PMA permits naturally aligned 32-bit ordinary loads/stores in this PLIC window. Other ordinary access widths raise load/store access faults before device data reads or SQ allocation. This is the platform’s width policy; the PLIC specification defines atomic 32-bit register accesses without mandating this particular fault policy for every other width.

Split loads carry their original architectural width separately from each physical fragment’s permission footprint. L1D captures both with the request; IOQ checks stores using the architectural width before SQ allocation. Consequently RV32 FLD/FSD cannot turn an unsupported eight-byte device access into two permitted word accesses. The policy applies after translation as well as in Bare mode, independently of PBMT. Other devices’ supported widths require separate region contracts. The existing software pending-set extension remains a platform-specific behavior and is not evidence of full PLIC 1.0 conformance.

NPC differential interrupt synchronization observes the driving PLIC seip_q bit for hart 0. It does not use an optimized-away core input shadow or replace the hardware level with the combined software/hardware mip.SEIP value.

Interfaces

Inter-module (rapt_if.svh, rapt_*_if.svh)

Interface Direction Description
ifu_bpu_if IFU<->BPU PC for prediction; NPC + taken back
ifu_l1i_if IFU<->L1I PC fetch request; inst_n0 + inst_n1 + trap response
ifu_idu_if IFU<->FQU / FQU<->IDU fetch slot[] with per-instruction metadata; valid/ready[]
idu_rnu_if IDU->RNU slot[DecodeWidth] with uop, operands and arch IDs
rnu_rou_if RNU->ROU slot[RenameWidth] with uop, physical mappings and control-flow checkpoint identity
rapt_recovery_if ROU->IFU/FQU/IDU/RNU One oldest-mispredict transaction: pending, one-shot redirect, owner/generation, target and checkpoint
checkpoint_release_if ROU->RNU Completion-width correct-control releases; independent of recovery ownership
{domain,token} candidate[K] ROU->DPU Age-ordered lightweight steering candidates; identity does not depend on endpoint ready
token winner[W] DPU->ROU Oldest capacity-admissible candidate identities
SlotT dispatch[W] ROU->EUs Winner uop/operands/ROB tag; full payload remains DispatchWidth-wide
rou_lsu_if ROU->LSU Store commit (addr/data/alu)
rou_csr_if ROU->CSR CSR write + trap/system on commit
rou_cmu_if ROU->CMU slot[CommitWidth] events plus scalar recovery effects
dpu_iq_if DPU<->IEU/FEU Queue allocation and free-slot backpressure
dpu_ioq_if DPU<->LSU IOQ capacity and accepted global slot mask
CompletionT completion[] EUs->ROU/PRF/LSU/IQs Guarded effects/results with ROB slot + allocation generation identity
rob_completion_owner_if ROU->core guards Read-only live/executing/generation/destination ownership directory
load_fast_if LSU->IEU/FEU Guarded early-load identity, rebusy, and full-identity confirmation data
IssueT issue[] IQ->pipe Whole-uop issue packets; per-port availability/capability
exu_prf_if ROU->PRF Operand pre-read (2 per rename position)
fpr_if FEU/LSU<->FPR FP register reads and arithmetic/load writeback
lsu_pipe_if LSU internal IOQ/AGU to SQ load request and response
exu_csr_if IEU->CSR CSR read port
lsu_l1d_mmu_if LSU->L1D Store MMU + SC reservation check
cmu_bcast_if CMU->all Retire broadcast (flush, fence, branch, call/ret)
csr_bcast_if CSR->all Priv, SATP, MMU enable, tvec
lsu_l1d_if LSU->L1D Load/store data path
l1i_bus_if L1I->BUS I-cache miss read
l1d_bus_if L1D->BUS D-cache miss read + write-through

Legacy RNU harness interfaces

rapt_rnu_internal_if.svh and the old standalone MAP/freelist modules are not instantiated by the core. Their historical formal harness does not prove the current integrated allocator; see the new rename recovery test. The superscalar-structure-check target excludes these legacy harnesses and the LSU’s intentionally physical hit-under-miss channels, while rejecting fixed A/B lane APIs anywhere in the active ordered frontend/backend pipeline.

Configuration (rapt_config.svh)

Parameter Default Description
RAPT_XLEN 32 Register width (64 with RAPT_RV64)
RAPT_M_FAST 1 Single-cycle mul/div (sim mode)
RAPT_L1I_LINE_LEN 4 L1I line: 2⁴ = 16 words (64 B in RV32)
RAPT_L1I_LEN 6 L1I sets: 2⁶ = 64
RAPT_L1I_N_WAYS 4 L1I ways (4-way SA)
RAPT_L1I_REFILL_WORDS 8 Words per L1I sector refill (capped at line size)
RAPT_PHT_SIZE 256 PHT entries
RAPT_BTB_SIZE 128 BTB entries (64 sets × 2 ways)
RAPT_BTB_WAYS 2 BTB associativity (single LRU bit per set requires exactly 2)
RAPT_RSB_SIZE 4 Return stack entries
RAPT_BPU_DIRP_TAGE defined Default direction predictor
RAPT_RIQ_SIZE 8 Rename queue (RNQ) entries
RAPT_IIQ_SIZE 8 Dispatch queue (UOQ) entries
RAPT_ROB_SIZE 32 Reorder buffer entries
RAPT_ROB_GENERATION_BITS 4 Per-slot allocation generation width; not a standalone cancellation protocol
RAPT_BRANCH_CHECKPOINTS 16 Independent control-flow rename snapshots; exhaustion backpressures rename
RAPT_RS_SIZE 8 ALU issue queue (ALQ) entries, shared by ALU-CSR/ALU
RAPT_IOQ_SIZE 8 In-order memory queue entries
BRQ_SIZE (param) 4 Branch issue queue entries
MDQ_SIZE (param) 4 MUL/DIV issue queue entries
RAPT_SQ_SIZE 16 Unified store queue entries
RAPT_L1D_LINE_LEN 4 / 3 RV32: 16 words/line; RV64: 8 words/line
RAPT_L1D_LEN 6 L1D sets: 2⁶ = 64
RAPT_L1D_N_WAYS 4 L1D ways (4-way SA)
RAPT_CACHE_SRAMLEN 128 Cache data-SRAM subarray width in bits
RAPT_ITLB_ENTRIES 16 Fully-associative ITLB entries
RAPT_DTLB_ENTRIES 16 Entries in each L1D DTLB lookup replica
RAPT_L2_EN undefined Optional L2 defaults to passthrough
RAPT_L2_LEN 8 L2 sets: 2⁸ = 256 when enabled
RAPT_L2_N_WAYS 1 L2 ways when enabled
RAPT_COMMIT_WIDTH 2 Maximum ready-prefix retirement width
RAPT_DECODE_WIDTH 2 Decode / frontend slot width
RAPT_RENAME_WIDTH 2 Rename / PRF pre-read width (ifndef fallback: DecodeWidth)
RAPT_DISPATCH_WIDTH 2 ROB / execution-queue allocation width (ifndef fallback: RenameWidth)
RAPT_INTEGER_ISSUE_PORTS 2 Number of physical integer issue/FU ports
RAPT_INTEGER_SYSTEM_PORT 0 Integer-port index owning CSR/system capability and the FP-shared completion endpoint
RAPT_PHY_SIZE 64 Physical registers, including architectural mappings
RAPT_PMP_NUM 8 Usable PMP comparators (all presets, both XLENs)
RAPT_PMP_CSR_NUM 16 Architectural PMP CSR slots; indices 8–15 are read-only zero
RAPT_STEER_SCAN_ENTRIES 4 ROB dispatch age-window K (DispatchWidth ≤ K ≤ ROB_SIZE)
RAPT_CACHE_LINE_BYTES 64 Software-visible CMO / cache line size

Key Types (rapt_pkg.sv)

Type Description
uop_t Micro-op: typed schedule (domain + issue-port mask) and execute payload (int/branch/memory/fp/sys), rd/imm, pc/pnpc, inst, trap/cause/tval
prd_t Physical register descriptor: op1/op2 + pr1/pr2/prd/prs
rob_state_t ROB state: ROB_DP (allocated, pending dispatch), ROB_EX (executing), ROB_WB (written-back), ROB_CM (committed / empty)
rob_entry_t Retirement state: phys regs, arch rd, state/generation, branch result + next PC, store flag, CSR/FP-flag snapshot, trap/tval/cause, difftest skip (store payload lives in the unified SQ)
addr_cacheable() Returns true for cacheable regions (SRAM, mrom, flash, PMEM, sdram)
addr_mapped() Returns true for any mapped memory or MMIO region
addr_mmio() Returns true for MMIO regions that difftest should skip
raptor docs shell parsed from Makefile + HDL · not a simulator