pub struct Pipeline {
pub cop2_latch: u64,
pub ic_rf: Latch,
pub rf_ex: Latch,
pub ex_dc: Latch,
pub dc_wb: Latch,
pub retired: u64,
pub cop1: Cop1Control,
pub fpr: Fpr,
pub tlb: Tlb,
pub icache: Icache,
pub dcache: Dcache,
pub cop0: Cop0,
/* private fields */
}Expand description
The four inter-stage latches plus the pipeline control state.
Fields§
§cop2_latch: u64The whole of COP2: one 64-bit latch.
COP2 is not populated on the VR4300, and what remains is a single
value that every MTC2/DMTC2 writes and every MFC2/DMFC2 reads,
with the register index ignored. See the EX stage and ledger C-20.
ic_rf: LatchIC → RF.
rf_ex: LatchRF → EX.
ex_dc: LatchEX → DC.
dc_wb: LatchDC → WB.
retired: u64Instructions retired at WB — a work tally, not a time position.
cop1: Cop1ControlCOP1 control registers (T-12-006).
fpr: FprThe floating-point register file (T-13-001).
tlb: TlbThe joint TLB and its instruction micro-TLB (T-12-004).
icache: IcacheThe 16 KiB primary instruction cache (T-11-003).
dcache: DcacheThe 8 KiB primary write-back data cache (T-11-003).
cop0: Cop0The COP0 register file (T-12-001).
Public because exception dispatch, the TLB and the interrupt path all read it, and they land in separate tickets.
Implementations§
Source§impl Pipeline
impl Pipeline
Sourcepub const fn stalled_by(&self) -> Option<Interlock>
pub const fn stalled_by(&self) -> Option<Interlock>
The interlock currently stalling the pipeline, if any.
Sourcepub const fn prev_cycle_was_run(&self) -> bool
pub const fn prev_cycle_was_run(&self) -> bool
Was the previous PCycle a run cycle? Gates interrupt acceptance.
Sourcepub const fn ll_bit(&self) -> bool
pub const fn ll_bit(&self) -> bool
The link bit, as SC would test it.
Exposed for the COP0 / ERET work in Sprint 2, which must clear it.
Sourcepub const fn ll_addr(&self) -> u64
pub const fn ll_addr(&self) -> u64
LLAddr (COP0 register 17): PA(31:4) of the most recent LL.
Reads straight out of the COP0 file. LL writes it there and nowhere
else — there is deliberately no second copy, because two stores of one
architectural value drift, and MFC0 $rt, $17 would then disagree with
the CPU’s own idea of the link address.
Sourcepub const fn stall_for(&mut self, cycles: u32, cause: Interlock)
pub const fn stall_for(&mut self, cycles: u32, cause: Interlock)
Request a stall of cycles PCycles.
A zero-cycle request is not a stall and is ignored. Recording it would
still consume a cycle in Pipeline::advance and mark it as not-a-run
cycle, which silently inserts a bubble and suppresses interrupt
acceptance on the following cycle (UM §4.7.1) — a one-cycle timing error
with no visible cause.
Sourcepub const fn signal_nmi(&mut self)
pub const fn signal_nmi(&mut self)
Assert the NMI line.
Latched, then taken at the next instruction boundary. Nothing in the core calls this yet: on hardware the source is the console’s reset button, which reaches the CPU as PRENMI followed by NMI, and the frontend owns that button (Phase 6). It exists now because the exception itself is Phase 1 work and belongs with the rest of the exception model — the wire from the button is a separate, later concern.
Sourcepub const fn abort_from(&mut self, at: Stage, exc: Exception)
pub const fn abort_from(&mut self, at: Stage, exc: Exception)
Stamp an abort into at and every latch upstream of it — the
kill-younger-instructions step. Instructions older than at have already
passed and are unaffected.
§Ordering contract
A stage must call this BEFORE it moves its latch. The instruction
executing in stage S this cycle sits in S’s input latch until the move,
so stamping first is what makes the abort travel with the instruction that
caused it. Calling it after the move stamps the abort onto the younger
instruction instead, and the causing one escapes — a misalignment that no
single-cycle assertion catches. an_abort_survives_the_cascade advances
the pipeline to verify it, rather than checking latch state in place.
The abort also raises an internal pending-flush flag, so the instruction fetched later in the same cycle is a bubble rather than a live wrong-path fetch.
Sourcepub const fn abort_with(&mut self, at: Stage, exc: Exception, bad_vaddr: u64)
pub const fn abort_with(&mut self, at: Stage, exc: Exception, bad_vaddr: u64)
Pipeline::abort_from, additionally recording the offending address
for the exceptions that write BadVAddr.
Sourcepub fn advance<B: Bus>(
&mut self,
bus: &mut B,
regs: &mut Regs,
next_pc: &mut u64,
)
pub fn advance<B: Bus>( &mut self, bus: &mut B, regs: &mut Regs, next_pc: &mut u64, )
Advance the pipeline by exactly one PCycle.
Stages run WB → DC → EX → RF → IC. Because each stage reads its input latch before any upstream stage writes it, no value moves two stages in one cycle and no double buffering is required. Do not reorder this.
Hot path: allocation-free.
Sourcepub fn advance_at<B: Bus>(
&mut self,
bus: &mut B,
regs: &mut Regs,
next_pc: &mut u64,
count_now: u64,
)
pub fn advance_at<B: Bus>( &mut self, bus: &mut B, regs: &mut Regs, next_pc: &mut u64, count_now: u64, )
Pipeline::advance, with the scheduler’s Count timeline supplied.
Count is derived from the master clock (ADR 0006), so the position
is passed in rather than incremented here. This is the path the scheduler
uses (crate::Cpu::tick_at); Pipeline::advance is a convenience
for callers with no scheduler, and holds the timeline rather than
guessing at it.