wrote out all of next_pc and tests/next_pc

This commit is contained in:
Jacob Lifshay 2025-12-11 00:31:00 -08:00
parent cfd04469ce
commit c87a1b8e1e
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
4 changed files with 1871 additions and 703 deletions

View file

@ -163,3 +163,15 @@ pub type CpuConfigFetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.rob_size.get()))] #[hdl(get(|c| c.rob_size.get()))]
pub type CpuConfigRobSize<C: PhantomConstGet<CpuConfig>> = DynSize; pub type CpuConfigRobSize<C: PhantomConstGet<CpuConfig>> = DynSize;
pub trait PhantomConstCpuConfig:
PhantomConstGet<CpuConfig>
+ Into<PhantomConst<CpuConfig>>
+ From<PhantomConst<CpuConfig>>
+ Type
+ ToSimValue<Type = Self>
+ ToExpr<Type = Self>
{
}
impl PhantomConstCpuConfig for PhantomConst<CpuConfig> {}

File diff suppressed because it is too large Load diff

View file

@ -190,6 +190,35 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
mapped_array_vec mapped_array_vec
} }
#[hdl] #[hdl]
pub fn map_sim<U: Type>(
this: impl ToSimValue<Type = Self>,
uninit_element: impl ToSimValue<Type = U>,
mut f: impl FnMut(usize, SimValue<T>) -> SimValue<U>,
) -> SimValue<ArrayVec<U, N>> {
let this = this.into_sim_value();
let uninit_element = uninit_element.into_sim_value();
let ty = this.ty().mapped_ty(uninit_element.ty());
#[hdl(sim)]
let Self { elements, len } = this;
#[hdl(sim)]
ArrayVec::<_, _> {
elements: SimValue::from_array_elements(
ty.elements,
SimValue::into_value(elements)
.into_iter()
.enumerate()
.map(|(index, element)| {
if index < *len {
f(index, element)
} else {
uninit_element.clone()
}
}),
),
len,
}
}
#[hdl]
pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> { pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> {
let this = this.to_expr(); let this = this.to_expr();
#[hdl] #[hdl]
@ -217,3 +246,34 @@ where
<ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index) <ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index)
} }
} }
impl<T: Type> ArrayVec<T, ConstUsize<1>> {
#[hdl]
pub fn from_opt_sim(
opt: impl ToSimValue<Type = HdlOption<T>>,
uninit_element: impl ToSimValueWithType<T>,
) -> SimValue<Self> {
let opt = opt.into_sim_value();
let ty = ArrayVec[opt.ty().HdlSome][ConstUsize];
#[hdl(sim)]
match opt {
HdlSome(v) => ty.new_full_sim([v]),
HdlNone => ty.new_sim(uninit_element),
}
}
#[hdl]
pub fn into_opt_sim(this: impl ToSimValue<Type = Self>) -> SimValue<HdlOption<T>> {
let this = this.into_sim_value();
#[hdl(sim)]
let Self { elements, len } = this;
let [element] = SimValue::into_value(elements);
let ty = HdlOption[element.ty()];
if *len == 0 {
#[hdl(sim)]
ty.HdlNone()
} else {
#[hdl(sim)]
ty.HdlSome(element)
}
}
}

View file

@ -78,7 +78,7 @@ const DEMO_ILLEGAL_INSN_TRAP: u64 = 0xFF000000u64;
#[hdl] #[hdl]
struct FetchPipeQueueEntry { struct FetchPipeQueueEntry {
fetch_pc: UInt<64>, start_pc: UInt<64>,
cycles_left: UInt<8>, cycles_left: UInt<8>,
fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>, fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
} }
@ -88,7 +88,7 @@ impl FetchPipeQueueEntry {
fn default_sim(self) -> SimValue<Self> { fn default_sim(self) -> SimValue<Self> {
#[hdl(sim)] #[hdl(sim)]
FetchPipeQueueEntry { FetchPipeQueueEntry {
fetch_pc: 0u64, start_pc: 0u64,
cycles_left: 0u8, cycles_left: 0u8,
fetch_block_id: 0u8, fetch_block_id: 0u8,
} }
@ -129,7 +129,8 @@ fn mock_fetch_pipe(config: PhantomConst<CpuConfig>) {
sim.resettable( sim.resettable(
cd, cd,
async |mut sim| { async |mut sim| {
sim.write(from_fetch.inner.ready, false).await; sim.write(from_fetch.fetch.ready, false).await;
sim.write(from_fetch.cancel.ready, false).await;
sim.write( sim.write(
to_post_decode.inner.data, to_post_decode.inner.data,
to_post_decode.ty().inner.data.HdlNone(), to_post_decode.ty().inner.data.HdlNone(),
@ -179,21 +180,21 @@ fn mock_fetch_pipe(config: PhantomConst<CpuConfig>) {
if let Some(front) = queue.front().filter(|v| v.cycles_left.as_int() == 0) { if let Some(front) = queue.front().filter(|v| v.cycles_left.as_int() == 0) {
#[hdl(sim)] #[hdl(sim)]
let FetchPipeQueueEntry { let FetchPipeQueueEntry {
fetch_pc, start_pc,
cycles_left: _, cycles_left: _,
fetch_block_id, fetch_block_id,
} = front; } = front;
let fetch_pc = fetch_pc.as_int(); let start_pc = start_pc.as_int();
let fetch_end = let end_pc =
(fetch_pc + 1).next_multiple_of(config.get().fetch_width_in_bytes() as u64); (start_pc + 1).next_multiple_of(config.get().fetch_width_in_bytes() as u64);
let insns = to_post_decode.ty().inner.data.HdlSome.insns; let insns = to_post_decode.ty().inner.data.HdlSome.insns;
let zeroed_insn = UInt[insns.element().canonical().bit_width()] let zeroed_insn = UInt[insns.element().canonical().bit_width()]
.zero() .zero()
.cast_bits_to(insns.element()); .cast_bits_to(insns.element());
let mut insns = insns.new_sim(zeroed_insn); let mut insns = insns.new_sim(zeroed_insn);
let mut expected_pc = fetch_pc; let mut expected_pc = start_pc;
// TODO: handle instructions that go past the end of a fetch block // TODO: handle instructions that go past the end of a fetch block
for (pc, insn) in mock_insns.fetch_block(fetch_pc..fetch_end) { for (pc, insn) in mock_insns.fetch_block(start_pc..end_pc) {
let next_pc = pc + insn.byte_len(); let next_pc = pc + insn.byte_len();
if pc != expected_pc { if pc != expected_pc {
break; break;
@ -226,7 +227,7 @@ fn mock_fetch_pipe(config: PhantomConst<CpuConfig>) {
WipDecodedInsn { WipDecodedInsn {
fetch_block_id, fetch_block_id,
id: next_id.cast_to_static::<UInt<_>>(), id: next_id.cast_to_static::<UInt<_>>(),
pc: fetch_pc, pc: start_pc,
size_in_bytes: 0u8.cast_to_static::<UInt<_>>(), size_in_bytes: 0u8.cast_to_static::<UInt<_>>(),
kind: WipDecodedInsnKind.Interrupt(DEMO_ILLEGAL_INSN_TRAP), kind: WipDecodedInsnKind.Interrupt(DEMO_ILLEGAL_INSN_TRAP),
}, },
@ -250,8 +251,9 @@ fn mock_fetch_pipe(config: PhantomConst<CpuConfig>) {
) )
.await; .await;
} }
sim.write(from_fetch.inner.ready, queue.len() < FETCH_PIPE_QUEUE_SIZE) sim.write(from_fetch.fetch.ready, queue.len() < FETCH_PIPE_QUEUE_SIZE)
.await; .await;
sim.write(from_fetch.cancel.ready, true).await;
sim.wait_for_clock_edge(cd.clk).await; sim.wait_for_clock_edge(cd.clk).await;
if sim.read_past_bool(to_post_decode.inner.ready, cd.clk).await { if sim.read_past_bool(to_post_decode.inner.ready, cd.clk).await {
#[hdl(sim)] #[hdl(sim)]
@ -264,25 +266,31 @@ fn mock_fetch_pipe(config: PhantomConst<CpuConfig>) {
entry.cycles_left = (entry.cycles_left.as_int() - 1u8).to_sim_value(); entry.cycles_left = (entry.cycles_left.as_int() - 1u8).to_sim_value();
} }
} }
if !sim.read_past_bool(from_fetch.inner.ready, cd.clk).await { // handle cancels before pushing new fetch op
continue;
}
#[hdl(sim)] #[hdl(sim)]
if let HdlSome(inner) = sim.read_past(from_fetch.inner.data, cd.clk).await { if let HdlSome(in_progress_fetches_to_cancel) =
#[hdl(sim)] sim.read_past(from_fetch.cancel.data, cd.clk).await
let NextPcToFetchInterfaceInner { {
next_fetch_pc,
fetch_block_id,
in_progress_fetches_to_cancel,
} = &inner;
// cancel in-progress fetches from newest to oldest // cancel in-progress fetches from newest to oldest
for _ in 0..in_progress_fetches_to_cancel.as_int() { for _ in 0..*in_progress_fetches_to_cancel {
let _ = queue.pop_back(); let _ = queue.pop_back();
} }
}
if !sim.read_past_bool(from_fetch.fetch.ready, cd.clk).await {
continue;
}
// handle pushing new fetch op after handling cancels
#[hdl(sim)]
if let HdlSome(inner) = sim.read_past(from_fetch.fetch.data, cd.clk).await {
#[hdl(sim)]
let NextPcToFetchInterfaceInner {
start_pc,
fetch_block_id,
} = &inner;
queue.push_back( queue.push_back(
#[hdl(sim)] #[hdl(sim)]
FetchPipeQueueEntry { FetchPipeQueueEntry {
fetch_pc: next_fetch_pc, start_pc,
cycles_left: FetchPipeQueueEntry::get_next_delay(delay_sequence_index), cycles_left: FetchPipeQueueEntry::get_next_delay(delay_sequence_index),
fetch_block_id, fetch_block_id,
}, },