pub mod decode;
pub mod fetch1;
pub mod fetch2;
pub mod rename;
use crate::common::PhysAddr;
use crate::uarch::ctx::StageCtx;
use crate::uarch::pipeline::engine::ExecutionEngine;
use crate::uarch::pipeline::frontend::fetch1::FetchBuffer;
use crate::uarch::pipeline::latches::{
Fetch1Fetch2Entry, IdExEntry, IfIdEntry, Latch, RenameIssueEntry,
};
use std::marker::PhantomData;
pub const STAGE_DELAY: u64 = 1;
const FETCH_LANDING_DELAY: u64 = 0;
#[derive(Debug)]
pub struct Frontend<E: ExecutionEngine> {
pub fetch_pc: u64,
pub fetch1_fetch2: Latch<Fetch1Fetch2Entry>,
pub fetch_buffer: FetchBuffer,
pub fetch2_decode: Latch<IfIdEntry>,
pub decode_rename: Latch<IdExEntry>,
_marker: PhantomData<E>,
}
impl<E: ExecutionEngine> Frontend<E> {
pub fn new(pc: u64) -> Self {
Self {
fetch_pc: pc,
fetch1_fetch2: Latch::new(FETCH_LANDING_DELAY),
fetch_buffer: FetchBuffer::default(),
fetch2_decode: Latch::new(STAGE_DELAY),
decode_rename: Latch::new(STAGE_DELAY),
_marker: PhantomData,
}
}
pub fn tick(
&mut self,
state: &mut StageCtx<'_>,
engine: &mut E,
rename_output: &mut Latch<RenameIssueEntry>,
) {
let now = state.cycle;
if let Some(decoded) = self.decode_rename.ready(now) {
let mut renamed = Vec::new();
rename::rename_stage(state, decoded, engine, &mut renamed);
rename_output.push(now, renamed);
}
if self.decode_rename.is_empty()
&& !engine.common().vector_config_unresolved
&& let Some(fetched) = self.fetch2_decode.ready(now)
{
let vector = engine.vector_config(&state.hart().csrs);
let mut decoded = Vec::new();
let outcome = decode::decode_stage(
state,
fetched,
&mut decoded,
engine.has_register_renaming(),
vector,
);
engine.common_mut().vector_config_unresolved = outcome.ended_at_vsetvl;
self.decode_rename.push(now, decoded);
if let Some(pc) = outcome.redirect {
self.fetch2_decode.clear();
self.fetch1_fetch2.clear();
engine.common_mut().drop_fetches();
self.fetch_pc = pc;
return;
}
}
if self.fetch2_decode.is_empty()
&& let Some(mut landed) = self.fetch1_fetch2.ready(now).map(std::mem::take)
{
let mut decoded = Vec::new();
fetch2::fetch2_stage(state, &mut landed, &mut decoded);
self.fetch2_decode.push(now, decoded);
}
if engine.common().trap.stops_fetch() {
return;
}
if engine.common().fetch_in_flight() || engine.common().fetch_held(state.cycle) {
state.counter(state.core().stat_paths.pipeline.stalls_fetch_wait).inc();
return;
}
if self.fetch1_fetch2.is_empty() {
fetch1::fetch1_stage(
state,
engine,
&mut self.fetch_buffer,
&mut self.fetch1_fetch2,
&mut self.fetch_pc,
);
}
}
pub const fn is_empty(&self) -> bool {
self.fetch1_fetch2.is_empty()
&& self.fetch2_decode.is_empty()
&& self.decode_rename.is_empty()
}
pub fn flush(&mut self) {
self.fetch1_fetch2.clear();
self.fetch2_decode.clear();
self.decode_rename.clear();
}
}
pub(super) fn read_inst_half(state: &StageCtx<'_>, paddr: u64) -> u16 {
state.memory.read(PhysAddr::new(paddr), 2).unwrap_or(0) as u16
}