Compare commits

...

3 commits

Author SHA1 Message Date
d42f010cda
WIP fixing bugs 2025-12-15 02:48:40 -08:00
84e4fde512
fix queueing errors 2025-12-15 00:47:53 -08:00
8ab63f3c6a
update fayalite 2025-12-14 21:05:59 -08:00
4 changed files with 23028 additions and 14547 deletions

8
Cargo.lock generated
View file

@ -305,7 +305,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]]
name = "fayalite"
version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#fbe4585578a043829bfb4d5af087fc7f4bf010b8"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
dependencies = [
"base64",
"bitvec",
@ -332,7 +332,7 @@ dependencies = [
[[package]]
name = "fayalite-proc-macros"
version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#fbe4585578a043829bfb4d5af087fc7f4bf010b8"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
dependencies = [
"fayalite-proc-macros-impl",
]
@ -340,7 +340,7 @@ dependencies = [
[[package]]
name = "fayalite-proc-macros-impl"
version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#fbe4585578a043829bfb4d5af087fc7f4bf010b8"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
dependencies = [
"base16ct",
"num-bigint",
@ -355,7 +355,7 @@ dependencies = [
[[package]]
name = "fayalite-visit-gen"
version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#fbe4585578a043829bfb4d5af087fc7f4bf010b8"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
dependencies = [
"indexmap",
"prettyplease",

View file

@ -24,9 +24,9 @@ use fayalite::{
prelude::*,
sim::value::SimOnlyValueTrait,
ty::StaticType,
util::ready_valid::ReadyValid,
util::{DebugAsDisplay, ready_valid::ReadyValid},
};
use std::borrow::Cow;
use std::{borrow::Cow, fmt};
pub const FETCH_BLOCK_ID_WIDTH: usize = FetchBlockIdInt::BITS as usize;
type FetchBlockIdInt = u8;
@ -246,6 +246,7 @@ pub struct RetireToNextPcInterfaceInner<C: PhantomConstGet<CpuConfig>> {
/// branch instruction is mis-speculated.
pub struct RetireToNextPcInterface<C: PhantomConstGet<CpuConfig>> {
pub inner: ReadyValid<RetireToNextPcInterfaceInner<C>>,
pub next_insn_ids: HdlOption<ArrayVec<UInt<12>, CpuConfigRobSize<C>>>,
}
#[hdl(no_static)]
@ -300,7 +301,7 @@ struct Cancel<C: PhantomConstGet<CpuConfig>> {
}
/// the output of [`Stage::run`].
/// when cancelling operations, the returned [`StageRunOutput.cancel`] should be the state after
/// when canceling operations, the returned [`StageRunOutput.cancel`] should be the state after
/// running all operations returned in [`StageRunOutput.output`].
#[hdl(no_static)]
struct StageRunOutput<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig, S: Type + Stage<C>> {
@ -311,8 +312,8 @@ struct StageRunOutput<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig, S:
trait Stages<C: PhantomConstCpuConfig>: Type {
type Outputs: Type + SimValueDefault;
type SimValueOutputQueueRefs<'a>: 'a + Copy;
type SimValueOutputQueueMuts<'a>: 'a;
type SimValueOutputQueueRefs<'a>: 'a + Copy + fmt::Debug;
type SimValueOutputQueueMuts<'a>: 'a + fmt::Debug;
fn outputs_ty(config: C) -> Self::Outputs;
fn reborrow_output_queues_as_refs<'a>(
output_queues: &'a Self::SimValueOutputQueueMuts<'_>,
@ -329,6 +330,7 @@ trait Stages<C: PhantomConstCpuConfig>: Type {
output_queues: Self::SimValueOutputQueueMuts<'_>,
) -> Option<SimValue<Self::Outputs>>;
fn visit_sim_value_ref<V: StagesVisitSimValueRef<C>>(this: &SimValue<Self>, visitor: &mut V);
fn dump_output_items(outputs: &SimValue<Self::Outputs>) -> String;
}
impl<C: PhantomConstCpuConfig> Stages<C> for () {
@ -377,14 +379,30 @@ impl<C: PhantomConstCpuConfig> Stages<C> for () {
#[hdl(sim)]
let () = this;
}
#[hdl]
fn dump_output_items(outputs: &SimValue<Self::Outputs>) -> String {
#[hdl(sim)]
let () = outputs;
String::from("()")
}
}
impl<C: PhantomConstCpuConfig, S1: Stage<C>> Stages<C> for S1 {
type Outputs = S1::Output;
type SimValueOutputQueueRefs<'a> =
&'a SimValue<Queue<StageOutput<C, S1>, StageOutputQueueSize<C, S1>>>;
type SimValueOutputQueueMuts<'a> =
&'a mut SimValue<Queue<StageOutput<C, S1>, StageOutputQueueSize<C, S1>>>;
type SimValueOutputQueueRefs<'a> = &'a SimValue<
Queue<
StageOutput<C, S1>,
StageOutputQueueSize<C, S1>,
StageWithQueuesOutputQueueName<StageName<C, S1>>,
>,
>;
type SimValueOutputQueueMuts<'a> = &'a mut SimValue<
Queue<
StageOutput<C, S1>,
StageOutputQueueSize<C, S1>,
StageWithQueuesOutputQueueName<StageName<C, S1>>,
>,
>;
fn outputs_ty(config: C) -> Self::Outputs {
S1::output_ty(config)
}
@ -402,7 +420,7 @@ impl<C: PhantomConstCpuConfig, S1: Stage<C>> Stages<C> for S1 {
output_queues: Self::SimValueOutputQueueRefs<'_>,
max_peek_len: usize,
) -> impl Iterator<Item = SimValue<Self::Outputs>> {
Queue::peek_iter(output_queues).take(max_peek_len)
Queue::peek_iter(output_queues).take(max_peek_len).cloned()
}
fn pop_output_queues(
output_queues: Self::SimValueOutputQueueMuts<'_>,
@ -412,17 +430,45 @@ impl<C: PhantomConstCpuConfig, S1: Stage<C>> Stages<C> for S1 {
fn visit_sim_value_ref<V: StagesVisitSimValueRef<C>>(this: &SimValue<Self>, visitor: &mut V) {
visitor.visit(this);
}
#[hdl]
fn dump_output_items(outputs: &SimValue<Self::Outputs>) -> String {
S1::dump_output_item(outputs)
}
}
impl<C: PhantomConstCpuConfig, S1: Stage<C>, S2: Stage<C>> Stages<C> for (S1, S2) {
type Outputs = (S1::Output, S2::Output);
type SimValueOutputQueueRefs<'a> = (
&'a SimValue<Queue<StageOutput<C, S1>, StageOutputQueueSize<C, S1>>>,
&'a SimValue<Queue<StageOutput<C, S2>, StageOutputQueueSize<C, S2>>>,
&'a SimValue<
Queue<
StageOutput<C, S1>,
StageOutputQueueSize<C, S1>,
StageWithQueuesOutputQueueName<StageName<C, S1>>,
>,
>,
&'a SimValue<
Queue<
StageOutput<C, S2>,
StageOutputQueueSize<C, S2>,
StageWithQueuesOutputQueueName<StageName<C, S2>>,
>,
>,
);
type SimValueOutputQueueMuts<'a> = (
&'a mut SimValue<Queue<StageOutput<C, S1>, StageOutputQueueSize<C, S1>>>,
&'a mut SimValue<Queue<StageOutput<C, S2>, StageOutputQueueSize<C, S2>>>,
&'a mut SimValue<
Queue<
StageOutput<C, S1>,
StageOutputQueueSize<C, S1>,
StageWithQueuesOutputQueueName<StageName<C, S1>>,
>,
>,
&'a mut SimValue<
Queue<
StageOutput<C, S2>,
StageOutputQueueSize<C, S2>,
StageWithQueuesOutputQueueName<StageName<C, S2>>,
>,
>,
);
fn outputs_ty(config: C) -> Self::Outputs {
(S1::output_ty(config), S2::output_ty(config))
@ -474,6 +520,14 @@ impl<C: PhantomConstCpuConfig, S1: Stage<C>, S2: Stage<C>> Stages<C> for (S1, S2
visitor.visit(s1);
visitor.visit(s2);
}
#[hdl]
fn dump_output_items(outputs: &SimValue<Self::Outputs>) -> String {
#[hdl(sim)]
let (s1, s2) = outputs;
let s1 = S1::dump_output_item(s1);
let s2 = S2::dump_output_item(s2);
format!("({s1}, {s2})")
}
}
trait StagesVisitSimValueRef<C: PhantomConstCpuConfig> {
@ -596,6 +650,7 @@ trait Stage<C: PhantomConstCpuConfig>: Type + SimValueDefault + ResetSteps {
type InputQueueSize: Size;
type OutputQueueSize: Size;
const HAS_EXTERNAL_PIPE: bool;
const NAME: &'static str;
fn inputs_ty(config: C) -> Self::Inputs;
fn output_ty(config: C) -> Self::Output;
@ -620,6 +675,8 @@ trait Stage<C: PhantomConstCpuConfig>: Type + SimValueDefault + ResetSteps {
from_external_pipe_output_item: &SimValue<Self::FromExternalPipeOutputItem>,
) -> SimValue<Self::Inputs>;
fn dump_output_item(item: &SimValue<Self::Output>) -> String;
/// see [`StageRunOutput`] for docs on output
fn run(
state: &mut SimValue<Self>,
@ -635,7 +692,7 @@ macro_rules! hdl_type_alias_with_generics {
#[ty = $ty:expr]
$vis:vis type $Type:ident<$C:ident: $PhantomConstCpuConfig:ident, $Arg:ident: $Trait:ident<$TraitC:ident>> = $Target:ty;
) => {
$vis type $Type<$C, $Arg> = <$Target as fayalite::phantom_const::ReturnSelfUnchanged<$C>>::Type;
$vis type $Type<$C, $Arg> = <$Target as fayalite::phantom_const::ReturnSelfUnchanged<($C, $Arg)>>::Type;
$vis struct $WithoutGenerics {}
@ -668,7 +725,7 @@ macro_rules! hdl_type_alias_with_generics {
#[size = $size:expr]
$vis:vis type $Type:ident<$C:ident: $PhantomConstCpuConfig:ident, $Arg:ident: $Trait:ident<$TraitC:ident>> = $Target:ty;
) => {
$vis type $Type<$C, $Arg> = <$Target as fayalite::phantom_const::ReturnSelfUnchanged<$C>>::Type;
$vis type $Type<$C, $Arg> = <$Target as fayalite::phantom_const::ReturnSelfUnchanged<($C, $Arg)>>::Type;
$vis struct $WithoutGenerics {}
@ -734,6 +791,12 @@ hdl_type_alias_with_generics! {
type StageFromExternalPipeOutputItem<C: PhantomConstCpuConfig, T: Stage<C>> = <T as Stage<C>>::FromExternalPipeOutputItem;
}
hdl_type_alias_with_generics! {
#[without_generics = StageNameWithoutGenerics, StageNameWithStage]
#[ty = |_config, _stage| PhantomConst::new(<T as Stage<C>>::NAME)]
type StageName<C: PhantomConstCpuConfig, T: Stage<C>> = PhantomConst<str>;
}
hdl_type_alias_with_generics! {
#[without_generics = StageMaxOutputsPerStepWithoutGenerics, StageMaxOutputsPerStepWithStage]
#[size = |config: C, _stage| T::max_outputs_per_step(config)]
@ -880,9 +943,10 @@ impl<C: PhantomConstCpuConfig> Stage<C> for NextPcStageState<C> {
type FromExternalPipeOutputItem = ();
type MaxOutputsPerStep = ConstUsize<1>;
type ExternalPipeIoWidth = ConstUsize<1>;
type InputQueueSize = ConstUsize<1>;
type OutputQueueSize = ConstUsize<1>;
type InputQueueSize = ConstUsize<2>;
type OutputQueueSize = ConstUsize<2>;
const HAS_EXTERNAL_PIPE: bool = false;
const NAME: &'static str = "next_pc";
fn inputs_ty(_config: C) -> Self::Inputs {
()
@ -945,21 +1009,46 @@ impl<C: PhantomConstCpuConfig> Stage<C> for NextPcStageState<C> {
()
}
#[hdl]
fn dump_output_item(item: &SimValue<Self::Output>) -> String {
#[hdl(sim)]
let NextPcStageOutput::<_> {
start_pc,
next_start_pc: _,
btb_entry: _,
fetch_block_id,
start_call_stack: _,
config: _,
} = item;
format!(
"fid={:#x} pc={:#x}",
fetch_block_id.as_int(),
start_pc.as_int(),
)
}
#[hdl]
fn run(
state: &mut SimValue<Self>,
_inputs: &SimValue<Self::Inputs>,
) -> SimValue<StageRunOutput<C, Self>> {
let this_ty = state.ty();
let config = state.config.ty();
let start_call_stack = state.call_stack.clone();
let fetch_block_id = state.next_fetch_block_id.as_int();
*state.next_fetch_block_id = state.next_fetch_block_id.as_int().wrapping_add(1).into();
let start_pc = state.next_pc.as_int();
#[hdl(sim)]
let Self {
call_stack,
branch_target_buffer,
next_pc,
next_fetch_block_id,
config,
} = state;
let config = config.ty();
let start_call_stack = call_stack.clone();
let fetch_block_id = next_fetch_block_id.as_int();
**next_fetch_block_id = fetch_block_id.wrapping_add(1).into();
let start_pc = next_pc.as_int();
let fetch_pc = start_pc & (!0u64 << config.get().log2_fetch_width_in_bytes);
let btb_entry_index = state
.branch_target_buffer
let btb_entry_index = branch_target_buffer
.branch_pc_to_target_map
.iter()
.position(|entry| {
@ -970,12 +1059,6 @@ impl<C: PhantomConstCpuConfig> Stage<C> for NextPcStageState<C> {
}
});
let (next_start_pc, btb_entry) = if let Some(btb_entry_index) = btb_entry_index {
#[hdl(sim)]
let Self {
call_stack,
branch_target_buffer,
..
} = state;
let entry = #[hdl(sim)]
match &branch_target_buffer.branch_pc_to_target_map[btb_entry_index] {
HdlSome(entry) => entry,
@ -1019,6 +1102,7 @@ impl<C: PhantomConstCpuConfig> Stage<C> for NextPcStageState<C> {
HdlNone(),
)
};
**next_pc = next_start_pc.into();
let output = #[hdl(sim)]
NextPcStageOutput::<_> {
start_pc,
@ -1114,6 +1198,8 @@ impl<C: PhantomConstCpuConfig> Stage<C> for NextPcStageState<C> {
#[hdl(no_static)]
struct BrPredStageOutput<C: PhantomConstGet<CpuConfig>> {
fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
start_pc: UInt<64>,
start_branch_history: UInt<6>,
branch_predictor_index: HdlOption<UIntInRange<0, { BRANCH_PREDICTOR_SIZE }>>,
config: C,
@ -1124,6 +1210,8 @@ impl<C: PhantomConstCpuConfig> SimValueDefault for BrPredStageOutput<C> {
fn sim_value_default(self) -> SimValue<Self> {
#[hdl(sim)]
Self {
fetch_block_id: self.fetch_block_id.zero(),
start_pc: 0u64,
start_branch_history: self.start_branch_history.zero(),
branch_predictor_index: #[hdl(sim)]
HdlNone(),
@ -1203,9 +1291,10 @@ impl<C: PhantomConstCpuConfig> Stage<C> for BrPredStageState<C> {
type FromExternalPipeOutputItem = ();
type MaxOutputsPerStep = ConstUsize<1>;
type ExternalPipeIoWidth = ConstUsize<1>;
type InputQueueSize = ConstUsize<1>;
type InputQueueSize = ConstUsize<2>;
type OutputQueueSize = CpuConfigMaxFetchesInFlight<C>;
const HAS_EXTERNAL_PIPE: bool = false;
const NAME: &'static str = "br_pred";
fn inputs_ty(config: C) -> Self::Inputs {
NextPcStageOutput[config]
@ -1265,6 +1354,23 @@ impl<C: PhantomConstCpuConfig> Stage<C> for BrPredStageState<C> {
input_stages_outputs.clone()
}
#[hdl]
fn dump_output_item(item: &SimValue<Self::Output>) -> String {
#[hdl(sim)]
let BrPredStageOutput::<_> {
fetch_block_id,
start_pc,
start_branch_history: _,
branch_predictor_index: _,
config: _,
} = item;
format!(
"fid={:#x} pc={:#x}",
fetch_block_id.as_int(),
start_pc.as_int(),
)
}
#[hdl]
fn run(
state: &mut SimValue<Self>,
@ -1277,7 +1383,7 @@ impl<C: PhantomConstCpuConfig> Stage<C> for BrPredStageState<C> {
start_pc,
next_start_pc: _,
btb_entry,
fetch_block_id: _,
fetch_block_id,
start_call_stack,
config: _,
} = inputs;
@ -1343,6 +1449,8 @@ impl<C: PhantomConstCpuConfig> Stage<C> for BrPredStageState<C> {
}
let output = #[hdl(sim)]
BrPredStageOutput::<_> {
fetch_block_id,
start_pc,
start_branch_history,
branch_predictor_index,
config,
@ -1450,8 +1558,9 @@ impl<C: PhantomConstCpuConfig> Stage<C> for FetchDecodeStageState<C> {
type MaxOutputsPerStep = ConstUsize<1>;
type ExternalPipeIoWidth = ConstUsize<1>;
type InputQueueSize = CpuConfigMaxFetchesInFlight<C>;
type OutputQueueSize = ConstUsize<1>;
type OutputQueueSize = ConstUsize<2>;
const HAS_EXTERNAL_PIPE: bool = true;
const NAME: &'static str = "fetch_decode";
fn inputs_ty(config: C) -> Self::Inputs {
FetchDecodeStageOutput[config]
@ -1513,6 +1622,44 @@ impl<C: PhantomConstCpuConfig> Stage<C> for FetchDecodeStageState<C> {
}
}
#[hdl]
fn dump_output_item(item: &SimValue<Self::Output>) -> String {
#[hdl(sim)]
let FetchDecodeStageOutput::<_> {
next_pc_stage_output,
decode_output,
} = item;
#[hdl(sim)]
let NextPcStageOutput::<_> {
start_pc,
next_start_pc: _,
btb_entry: _,
fetch_block_id,
start_call_stack: _,
config: _,
} = next_pc_stage_output;
#[hdl(sim)]
let DecodeToPostDecodeInterfaceInner::<_> { insns, config: _ } = decode_output;
let mut items = vec![];
for insn in ArrayVec::elements_sim_ref(insns) {
#[hdl(sim)]
let WipDecodedInsn {
fetch_block_id: _,
id,
pc,
size_in_bytes: _,
kind: _,
} = insn;
items.push(format!("id={id} pc={:#x}", pc.as_int()));
}
format!(
"fid={:#x} pc={:#x} [{}]",
fetch_block_id.as_int(),
start_pc.as_int(),
items.join(", "),
)
}
#[hdl]
fn run(
state: &mut SimValue<Self>,
@ -1522,6 +1669,36 @@ impl<C: PhantomConstCpuConfig> Stage<C> for FetchDecodeStageState<C> {
#[hdl(sim)]
let Self { config } = state;
let config = config.ty();
#[hdl(sim)]
let FetchDecodeStageOutput::<_> {
next_pc_stage_output,
decode_output,
} = inputs;
#[hdl(sim)]
let NextPcStageOutput::<_> {
start_pc,
next_start_pc: _,
btb_entry: _,
fetch_block_id,
start_call_stack: _,
config: _,
} = next_pc_stage_output;
#[hdl(sim)]
let DecodeToPostDecodeInterfaceInner::<_> { insns, config: _ } = decode_output;
for (i, insn) in ArrayVec::elements_sim_ref(insns).iter().enumerate() {
#[hdl(sim)]
let WipDecodedInsn {
fetch_block_id: insn_fetch_block_id,
id: _,
pc: insn_pc,
size_in_bytes: _,
kind: _,
} = insn;
assert_eq!(insn_fetch_block_id, fetch_block_id);
if i == 0 {
assert_eq!(insn_pc, start_pc);
}
}
let StageRunOutput { outputs, cancel } = StageRunOutput[config][this_ty];
#[hdl(sim)]
StageRunOutput::<_, _> {
@ -1618,9 +1795,10 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
type FromExternalPipeOutputItem = ();
type MaxOutputsPerStep = CpuConfigFetchWidth<C>;
type ExternalPipeIoWidth = ConstUsize<1>;
type InputQueueSize = ConstUsize<1>;
type InputQueueSize = ConstUsize<2>;
type OutputQueueSize = TwiceCpuConfigFetchWidth<C>;
const HAS_EXTERNAL_PIPE: bool = false;
const NAME: &'static str = "post_decode";
fn inputs_ty(config: C) -> Self::Inputs {
PostDecodeStageInput[config]
@ -1686,6 +1864,23 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
}
}
#[hdl]
fn dump_output_item(item: &SimValue<Self::Output>) -> String {
#[hdl(sim)]
let WipDecodedInsn {
fetch_block_id,
id,
pc,
size_in_bytes: _,
kind: _,
} = &item.insn;
format!(
"fid={:#x} id={id} pc={:#x}",
fetch_block_id.as_int(),
pc.as_int(),
)
}
#[hdl]
fn run(
state: &mut SimValue<Self>,
@ -1718,10 +1913,14 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
let DecodeToPostDecodeInterfaceInner::<_> { insns, config: _ } = decode_output;
#[hdl(sim)]
let BrPredStageOutput::<_> {
start_pc: br_pred_start_pc,
fetch_block_id: br_pred_fetch_block_id,
start_branch_history,
branch_predictor_index,
config: _,
} = br_pred_stage_output;
assert_eq!(start_pc, br_pred_start_pc);
assert_eq!(fetch_block_id, br_pred_fetch_block_id);
assert_ne!(
**ArrayVec::len_sim(&insns),
0,
@ -2039,6 +2238,9 @@ struct ExecuteRetireStageState<C: PhantomConstGet<CpuConfig> + PhantomConstCpuCo
#[hdl(no_static)]
struct ExecuteRetireStageOutput<C: PhantomConstGet<CpuConfig>> {
train_branch_predictor: HdlOption<TrainBranchPredictor>,
fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
id: UInt<12>,
pc: UInt<64>,
config: C,
}
@ -2047,12 +2249,18 @@ impl<C: PhantomConstCpuConfig> SimValueDefault for ExecuteRetireStageOutput<C> {
fn sim_value_default(self) -> SimValue<Self> {
let Self {
train_branch_predictor,
fetch_block_id,
id,
pc: _,
config,
} = self;
#[hdl(sim)]
Self {
train_branch_predictor: #[hdl(sim)]
train_branch_predictor.HdlNone(),
fetch_block_id: fetch_block_id.zero(),
id: id.zero(),
pc: 0u64,
config,
}
}
@ -2089,6 +2297,7 @@ impl<C: PhantomConstCpuConfig> Stage<C> for ExecuteRetireStageState<C> {
type InputQueueSize = CpuConfigRobSize<C>;
type OutputQueueSize = CpuConfigFetchWidth<C>;
const HAS_EXTERNAL_PIPE: bool = true;
const NAME: &'static str = "execute_retire";
fn inputs_ty(config: C) -> Self::Inputs {
ExecuteRetireStageInput[config]
@ -2150,6 +2359,23 @@ impl<C: PhantomConstCpuConfig> Stage<C> for ExecuteRetireStageState<C> {
}
}
#[hdl]
fn dump_output_item(item: &SimValue<Self::Output>) -> String {
#[hdl(sim)]
let ExecuteRetireStageOutput::<_> {
train_branch_predictor: _,
fetch_block_id,
id,
pc,
config: _,
} = item;
format!(
"fid={:#x} id={id} pc={:#x}",
fetch_block_id.as_int(),
pc.as_int(),
)
}
#[hdl]
fn run(
state: &mut SimValue<Self>,
@ -2318,6 +2544,9 @@ impl<C: PhantomConstCpuConfig> Stage<C> for ExecuteRetireStageState<C> {
#[hdl(sim)]
ExecuteRetireStageOutput::<_> {
train_branch_predictor,
fetch_block_id: &insn.fetch_block_id,
id,
pc: insn.pc,
config,
},
),
@ -2341,6 +2570,9 @@ impl<C: PhantomConstCpuConfig> Stage<C> for ExecuteRetireStageState<C> {
#[hdl(sim)]
ExecuteRetireStageOutput::<_> {
train_branch_predictor,
fetch_block_id: &insn.fetch_block_id,
id,
pc: insn.pc,
config,
},
]),
@ -2896,7 +3128,7 @@ impl ResetSteps for BranchTargetBuffer {
}
#[hdl]
struct Queue<T, Capacity: Size> {
struct Queue<T, Capacity: Size, Name: PhantomConstGet<str>> {
data: ArrayType<T, Capacity>,
/// inclusive
start: UIntInRangeType<ConstUsize<0>, Capacity>,
@ -2904,9 +3136,18 @@ struct Queue<T, Capacity: Size> {
end: UIntInRangeType<ConstUsize<0>, Capacity>,
/// used to disambiguate between a full and an empty queue
eq_start_end_means_full: Bool,
name: Name,
}
impl<T: Type, Capacity: Size> Queue<T, Capacity> {
impl<T: Type, Capacity: Size, Name: Type + PhantomConstGet<str>> Queue<T, Capacity, Name> {
fn debug_op(self, fn_name: &str, data: &SimValue<T>) {
println!("Queue::<_, _, {:?}>::{fn_name}: {data:#?}", self.name);
}
fn dump(this: &SimValue<Self>, dump_item: impl Fn(&SimValue<T>) -> String) {
let name = this.name.ty().get();
let items = Vec::from_iter(Self::peek_iter(this).map(|v| DebugAsDisplay(dump_item(&v))));
println!("Queue {name}: {items:#?}");
}
fn capacity(self) -> usize {
self.data.len()
}
@ -2951,8 +3192,11 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
let end = *this.end;
*this.end = this.ty().next_pos(end);
*this.eq_start_end_means_full = true;
let this_ty = this.ty();
let data = &mut this.data[end];
*data = dbg!(value.to_sim_value_with_type(data.ty()));
let value = value.to_sim_value_with_type(data.ty());
this_ty.debug_op("push", &value);
*data = value;
Ok(())
}
}
@ -2963,6 +3207,7 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
let end = this.ty().prev_pos(*this.end);
*this.end = end;
let data = this.data[end].clone();
this.ty().debug_op("undo_push", &data);
*this.eq_start_end_means_full = false;
Some(data)
}
@ -2976,9 +3221,8 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
}
fn peek_iter(
this: &SimValue<Self>,
) -> impl Clone + DoubleEndedIterator<Item = SimValue<T>> + ExactSizeIterator {
(0..Self::len(this))
.map(|nth| dbg!(this.data[this.ty().nth_pos_after(*this.start, nth)].clone()))
) -> impl Clone + DoubleEndedIterator<Item = &SimValue<T>> + ExactSizeIterator {
(0..Self::len(this)).map(|nth| &this.data[this.ty().nth_pos_after(*this.start, nth)])
}
fn pop(this: &mut SimValue<Self>) -> Option<SimValue<T>> {
if Self::is_empty(this) {
@ -2987,13 +3231,14 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
let start = *this.start;
*this.start = this.ty().next_pos(start);
let data = this.data[start].clone();
this.ty().debug_op("pop", &data);
*this.eq_start_end_means_full = false;
Some(data)
}
}
}
impl<T: SimValueDefault, Capacity: Size> SimValueDefault for Queue<T, Capacity> {
impl<T: SimValueDefault, Capacity: Size> SimValueDefault for Queue<T, Capacity, PhantomConst<str>> {
#[hdl]
fn sim_value_default(self) -> SimValue<Self> {
let Self {
@ -3001,9 +3246,10 @@ impl<T: SimValueDefault, Capacity: Size> SimValueDefault for Queue<T, Capacity>
start,
end,
eq_start_end_means_full: _,
name,
} = self;
#[hdl(sim)]
Queue::<T, Capacity> {
Queue::<T, Capacity, _> {
data: repeat(
data.element().sim_value_default(),
Capacity::from_usize(data.len()),
@ -3011,19 +3257,21 @@ impl<T: SimValueDefault, Capacity: Size> SimValueDefault for Queue<T, Capacity>
start: 0usize.to_sim_value_with_type(start),
end: 0usize.to_sim_value_with_type(end),
eq_start_end_means_full: false,
name,
}
}
}
impl<T: SimValueDefault, Capacity: Size> ResetSteps for Queue<T, Capacity> {
impl<T: SimValueDefault, Capacity: Size> ResetSteps for Queue<T, Capacity, PhantomConst<str>> {
#[hdl]
fn reset_step(this: &mut SimValue<Self>, step: usize) -> ResetStatus {
#[hdl(sim)]
let Queue::<T, Capacity> {
let Queue::<T, Capacity, _> {
data,
start,
end,
eq_start_end_means_full,
name: _,
} = this;
**start = 0;
**end = 0;
@ -3054,11 +3302,25 @@ impl<C: PhantomConstCpuConfig, S: Stage<C>> CancelInProgressForStageWithQueues<C
}
}
#[hdl(get(|name| PhantomConst::new_deref(format!("{name}.input_queue"))))]
type StageWithQueuesInputQueueName<Name: PhantomConstGet<str>> = PhantomConst<str>;
#[hdl(get(|name| PhantomConst::new_deref(format!("{name}.output_queue"))))]
type StageWithQueuesOutputQueueName<Name: PhantomConstGet<str>> = PhantomConst<str>;
#[hdl(no_static)]
struct StageWithQueues<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig, S: Type + Stage<C>> {
input_queue: Queue<StageInputStagesOutputs<C, S>, StageInputQueueSize<C, S>>,
input_queue: Queue<
StageInputStagesOutputs<C, S>,
StageInputQueueSize<C, S>,
StageWithQueuesInputQueueName<StageName<C, S>>,
>,
state: S,
output_queue: Queue<StageOutput<C, S>, StageOutputQueueSize<C, S>>,
output_queue: Queue<
StageOutput<C, S>,
StageOutputQueueSize<C, S>,
StageWithQueuesOutputQueueName<StageName<C, S>>,
>,
config: C,
}
@ -3169,6 +3431,18 @@ enum StageWithQueuesRunResult<C: PhantomConstCpuConfig, S: Stage<C>> {
}
impl<C: PhantomConstCpuConfig, S: Stage<C>> StageWithQueues<C, S> {
#[hdl]
fn dump_queues(this: &SimValue<Self>) {
#[hdl(sim)]
let Self {
input_queue,
state: _,
output_queue,
config: _,
} = this;
Queue::dump(input_queue, S::InputStages::dump_output_items);
Queue::dump(output_queue, S::dump_output_item);
}
fn input_queue_space_left_with_sibling(
this: &SimValue<Self>,
sibling: &<S::SiblingStage as SiblingStageOrUnit<C, S>>::SimValueStageWithQueues,
@ -3275,13 +3549,12 @@ impl<C: PhantomConstCpuConfig, S: Stage<C>> StageWithQueues<C, S> {
from_external_pipe_output_ready,
} = last_outputs;
assert_eq!(**ArrayVec::len_sim(to_external_pipe_input_input), 0);
#[hdl(sim)]
if let HdlNone = to_external_pipe_input_cancel {
unreachable!();
}
assert_eq!(**from_external_pipe_output_ready, 0);
if !**to_external_pipe_input_cancel_ready {
return CancelResult::InProgress;
#[hdl(sim)]
if let HdlSome(_) = to_external_pipe_input_cancel {
if !**to_external_pipe_input_cancel_ready {
return CancelResult::InProgress;
}
}
for _ in 0..std::mem::replace(input_queue_to_cancel, 0) {
let Some(_) = Queue::undo_push(input_queue) else {
@ -3341,7 +3614,7 @@ impl<C: PhantomConstCpuConfig, S: Stage<C>> StageWithQueues<C, S> {
state,
output_queue,
config,
} = this;
} = &mut *this;
let config = config.ty();
#[hdl(sim)]
let StageWithQueuesInputs::<_, _> {
@ -3410,12 +3683,12 @@ impl<C: PhantomConstCpuConfig, S: Stage<C>> StageWithQueues<C, S> {
unreachable!();
};
}
// handle cancelling only after handling all outputs so the outputs aren't canceled
// handle canceling only after handling all outputs so the outputs aren't canceled
#[hdl(sim)]
if let HdlSome(cancel) = cancel {
// ignore the rest of the input_queue and from_external_pipe_output_data,
// it doesn't matter that they're getting ignored since we're
// cancelling all inputs anyway.
// canceling all inputs anyway.
let cancel_count = Queue::len(input_queue);
let sibling_cancel = S::SiblingStage::make_sim_value_cancel(
S::SiblingStage::sim_value_stage_with_queues_opt(sibling).map(|sibling| {
@ -3425,7 +3698,7 @@ impl<C: PhantomConstCpuConfig, S: Stage<C>> StageWithQueues<C, S> {
// this stage's input queue and the sibling stage's input queue,
// and that outputs are removed in lock step from
// this stage's output queue and the sibling stage's output queue.
let sibling_cancel_count = if sibling_already_ran {
let mut sibling_cancel_count = if dbg!(sibling_already_ran) {
// both this stage and its sibling already pushed the same items to
// their input queues, so they are in lock-step and can use the
// same cancel count.
@ -3435,6 +3708,12 @@ impl<C: PhantomConstCpuConfig, S: Stage<C>> StageWithQueues<C, S> {
// input queue, but the sibling hasn't so subtract off those additional items
cancel_count - input_stages_outputs_popped_count
};
if **ArrayVec::len_sim(&outputs) == 0 {
// this item was removed, so we need to remove it in the sibling too
sibling_cancel_count += 1;
}
dbg!(sibling_cancel_count);
dbg!(cancel_count);
let CancelInProgressForStageWithQueues {
cancel_state: _,
input_queue_to_cancel,
@ -3625,6 +3904,7 @@ impl<C: PhantomConstCpuConfig> AllStages<C> {
execute_retire,
config: _,
} = this;
println!("Cancel: {cancel:#?}");
let next_pc =
StageWithQueues::cancel(next_pc, cancel, &inputs.next_pc, &last_outputs.next_pc);
let br_pred =
@ -3659,11 +3939,39 @@ impl<C: PhantomConstCpuConfig> AllStages<C> {
}
}
#[hdl]
fn get_execute_retire_output(
this: &SimValue<Self>,
) -> (usize, Option<SimValue<TrainBranchPredictor>>) {
let config = this.config.ty();
let mut retire_count = 0usize;
for execute_retire_output in
Queue::peek_iter(&this.execute_retire.output_queue).take(config.get().fetch_width.get())
{
retire_count += 1;
#[hdl(sim)]
let ExecuteRetireStageOutput::<_> {
train_branch_predictor,
fetch_block_id: _,
id: _,
pc: _,
config: _,
} = &execute_retire_output;
#[hdl(sim)]
if let HdlSome(train_branch_predictor) = train_branch_predictor {
// for now we only retire one conditional branch per clock cycle
// TODO: maybe improve later?
return (retire_count, Some(train_branch_predictor.clone()));
}
}
(retire_count, None)
}
#[hdl]
fn run(
this: &mut SimValue<Self>,
inputs: &SimValue<AllStagesInputs<C>>,
last_outputs: &SimValue<AllStagesOutputs<C>>,
) -> Result<(), SimValue<CancelInProgress<C>>> {
let (retire_count, _) = Self::get_execute_retire_output(this);
#[hdl(sim)]
let Self {
next_pc,
@ -3672,9 +3980,16 @@ impl<C: PhantomConstCpuConfig> AllStages<C> {
post_decode,
execute_retire,
config,
} = this;
} = &mut *this;
let config = config.ty();
let cancel_ty = CancelInProgress[config];
for _ in 0..retire_count {
// items were handled in the previous clock cycle,
// but are removed only now so you can see them for debugging
let Some(_) = Queue::pop(&mut execute_retire.output_queue) else {
unreachable!();
};
}
match StageWithQueues::run(
execute_retire,
&inputs.execute_retire,
@ -3832,28 +4147,33 @@ impl<C: PhantomConstCpuConfig> AllStages<C> {
input_stages_outputs_popped_count: _,
} => {}
}
for _ in 0..config.get().fetch_width.get() {
let Some(execute_retire_output) = Queue::pop(&mut execute_retire.output_queue) else {
break;
};
#[hdl(sim)]
let ExecuteRetireStageOutput::<_> {
train_branch_predictor,
config: _,
} = &execute_retire_output;
#[hdl(sim)]
if let HdlSome(train_branch_predictor) = train_branch_predictor {
BrPredStageState::train_branch_predictor(
&mut br_pred.state,
train_branch_predictor,
);
// for now we only retire one conditional branch per clock cycle
// TODO: maybe improve later?
break;
}
match Self::get_execute_retire_output(this) {
(_, Some(train_branch_predictor)) => BrPredStageState::train_branch_predictor(
&mut this.br_pred.state,
&train_branch_predictor,
),
(_, None) => {}
}
Ok(())
}
#[hdl]
fn dump_queues(this: &SimValue<Self>) {
#[hdl(sim)]
let Self {
next_pc,
br_pred,
fetch_decode,
post_decode,
execute_retire,
config: _,
} = this;
println!("Dump Queues:");
StageWithQueues::dump_queues(next_pc);
StageWithQueues::dump_queues(br_pred);
StageWithQueues::dump_queues(fetch_decode);
StageWithQueues::dump_queues(post_decode);
StageWithQueues::dump_queues(execute_retire);
}
}
#[hdl(no_static)]
@ -3941,6 +4261,41 @@ impl<C: PhantomConstCpuConfig> NextPcState<C> {
}
}
}
#[hdl(sim)]
if let HdlNone = cancel {
#[derive(Debug, PartialEq)]
struct FetchOp {
start_pc: SimValue<UInt<64>>,
fetch_block_id: SimValue<UInt<{ FETCH_BLOCK_ID_WIDTH }>>,
}
let br_pred_ops = Vec::from_iter(
Queue::peek_iter(&all_stages.br_pred.output_queue)
.map(|v| FetchOp {
start_pc: v.start_pc.clone(),
fetch_block_id: v.fetch_block_id.clone(),
})
.chain(
Queue::peek_iter(&all_stages.br_pred.input_queue).map(|v| FetchOp {
start_pc: v.start_pc.clone(),
fetch_block_id: v.fetch_block_id.clone(),
}),
),
);
let fetch_decode_ops = Vec::from_iter(
Queue::peek_iter(&all_stages.fetch_decode.output_queue)
.map(|v: &SimValue<FetchDecodeStageOutput<C>>| FetchOp {
start_pc: v.next_pc_stage_output.start_pc.clone(),
fetch_block_id: v.next_pc_stage_output.fetch_block_id.clone(),
})
.chain(
Queue::peek_iter(&all_stages.fetch_decode.input_queue).map(|v| FetchOp {
start_pc: v.start_pc.clone(),
fetch_block_id: v.fetch_block_id.clone(),
}),
),
);
assert_eq!(br_pred_ops, fetch_decode_ops, "queues out of sync");
}
}
}
@ -4038,6 +4393,20 @@ pub fn next_pc(config: PhantomConst<CpuConfig>) {
sim.write(state_expr, state).await;
sim.wait_for_clock_edge(cd.clk).await;
state = sim.read_past(state_expr, cd.clk).await;
AllStages::dump_queues(&state.all_stages);
let next_retire_insn_ids = sim.read_past(from_retire.next_insn_ids, cd.clk).await;
#[hdl(sim)]
if let HdlSome(next_retire_insn_ids) = &next_retire_insn_ids {
#[hdl(sim)]
if let HdlNone = &state.cancel {
let next_retire_insn_ids = ArrayVec::elements_sim_ref(&next_retire_insn_ids);
let expected_next_retire_insn_ids = Vec::from_iter(
Queue::peek_iter(&state.all_stages.execute_retire.input_queue)
.map(|v| v.insn.id.clone()),
);
assert_eq!(next_retire_insn_ids, expected_next_retire_insn_ids);
}
}
let AllStagesInputs {
next_pc,
br_pred,
@ -4058,7 +4427,16 @@ pub fn next_pc(config: PhantomConst<CpuConfig>) {
#[hdl(sim)]
if let HdlSome(data) = sim.read_past(from_retire.inner.data, cd.clk).await {
#[hdl(sim)]
let RetireToNextPcInterfaceInner::<_> { insns, config: _ } = data;
let RetireToNextPcInterfaceInner::<_> {
mut insns,
config: _,
} = data;
if !sim.read_past_bool(from_retire.inner.ready, cd.clk).await {
// since we can have `outputs.execute_retire.from_external_pipe_output_ready > 0`
// without `from_retire.inner.ready` being set, make sure we don't retire any instructions in that case
ArrayVec::truncate_sim(&mut insns, 0);
}
println!("from retire: {:#?}", ArrayVec::elements_sim_ref(&insns));
insns
} else {
execute_retire
@ -4148,7 +4526,8 @@ mod tests {
#[test]
fn test_queue() {
let mut queue: SimValue<Queue<UInt<8>, ConstUsize<8>>> = Queue::TYPE.sim_value_default();
let mut queue: SimValue<Queue<UInt<8>, ConstUsize<8>, PhantomConst<str>>> =
Queue::TYPE.sim_value_default();
let mut reference_queue = VecDeque::new();
let mut tested_full = false;
let mut tested_empty = false;

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,11 @@ use cpu::{
unit::UnitKind,
util::array_vec::ArrayVec,
};
use fayalite::{prelude::*, sim::vcd::VcdWriterDecls, util::RcWriter};
use fayalite::{
prelude::*,
sim::vcd::VcdWriterDecls,
util::{DebugAsDisplay, RcWriter},
};
use std::{
cell::Cell,
collections::{BTreeMap, BTreeSet, VecDeque},
@ -456,6 +460,7 @@ struct MockExecuteState {
queue: VecDeque<SimValue<ExecuteRetirePipeQueueEntry>>,
used_ids: BTreeSet<SimValue<UInt<12>>>,
retire_seq: RetireSeq,
canceling: bool,
config: PhantomConst<CpuConfig>,
}
@ -465,6 +470,7 @@ impl MockExecuteState {
queue: VecDeque::new(),
used_ids: BTreeSet::new(),
retire_seq: RetireSeq::new(),
canceling: false,
config,
}
}
@ -479,6 +485,7 @@ impl MockExecuteState {
fn do_retire(
&mut self,
entry: SimValue<ExecuteRetirePipeQueueEntry>,
passive: bool,
) -> Result<SimValue<RetireToNextPcInterfacePerInsn<PhantomConst<CpuConfig>>>, String> {
#[hdl(sim)]
let ExecuteRetirePipeQueueEntry {
@ -545,6 +552,18 @@ impl MockExecuteState {
"insn doesn't match expected:\ninsn: {insn:?}\nexpected insn: {expected_insn:?}"
));
}
if let Some(next_insn) = self.queue.front() {
if next_pc != next_insn.insn.pc.as_int() {
self.canceling = true;
if !passive {
println!(
"MockExecuteState: starting canceling {} instruction(s): next_pc={next_pc:#x}, mis-predicted next_pc={next_insn_pc}",
self.queue.len(),
next_insn_pc = next_insn.insn.pc
);
}
}
}
Ok(
#[hdl(sim)]
RetireToNextPcInterfacePerInsn::<_> {
@ -565,13 +584,35 @@ impl MockExecuteState {
#[hdl]
fn try_retire(
&mut self,
) -> Option<Result<SimValue<RetireToNextPcInterfacePerInsn<PhantomConst<CpuConfig>>>, String>>
{
passive: bool,
) -> Option<(
SimValue<RetireToNextPcInterfacePerInsn<PhantomConst<CpuConfig>>>,
Result<(), String>,
)> {
if self.canceling {
return None;
}
if self.queue.front()?.cycles_left.as_int() != 0 {
return None;
}
let entry = self.queue.pop_front()?;
Some(self.do_retire(entry))
let id = entry.insn.id.clone();
Some(match self.do_retire(entry, passive) {
Ok(v) => (v, Ok(())),
Err(e) => (
#[hdl(sim)]
RetireToNextPcInterfacePerInsn::<_> {
id,
next_pc: u64::from_be_bytes(*b"ErrError"),
call_stack_op: #[hdl(sim)]
CallStackOp::None(),
cond_br_taken: #[hdl(sim)]
HdlNone(),
config: self.config,
},
Err(e),
),
})
}
fn space_available(&self) -> usize {
EXECUTE_RETIRE_PIPE_QUEUE_SIZE.saturating_sub(self.queue.len())
@ -589,6 +630,16 @@ impl MockExecuteState {
},
);
}
#[hdl]
fn finish_cancel(&mut self) {
println!(
"MockExecuteState: finishing canceling {} instruction(s)",
self.queue.len(),
);
self.queue.clear();
self.used_ids.clear();
self.canceling = false;
}
}
#[hdl_module(extern)]
@ -621,6 +672,11 @@ fn mock_execute_retire_pipe(config: PhantomConst<CpuConfig>) {
retire_output.ty().inner.data.HdlNone(),
)
.await;
sim.write(
retire_output.next_insn_ids,
retire_output.next_insn_ids.ty().HdlNone(),
)
.await;
sim.write(
queue_debug,
queue_debug
@ -672,30 +728,31 @@ fn mock_execute_retire_pipe(config: PhantomConst<CpuConfig>) {
let mut sim_queue = queue_debug
.ty()
.new_sim(ExecuteRetirePipeQueueEntry.default_sim());
let mut next_insn_ids = retire_output.next_insn_ids.ty().HdlSome.new_sim(0_hdl_u12);
for entry in &state.queue {
ArrayVec::try_push_sim(&mut sim_queue, entry)
.ok()
.expect("queue is known to be small enough");
let _ = ArrayVec::try_push_sim(&mut next_insn_ids, &entry.insn.id);
}
sim.write(queue_debug, sim_queue).await;
sim.write(
retire_output.next_insn_ids,
if state.canceling {
#[hdl(sim)]
(retire_output.next_insn_ids.ty()).HdlNone()
} else {
#[hdl(sim)]
(retire_output.next_insn_ids.ty()).HdlSome(next_insn_ids)
},
)
.await;
let mut retiring = retire_vec_ty.new_sim(&empty_retire_insn);
let mut peek_state = state.clone();
while let Some(peek_retire) = peek_state.try_retire() {
if peek_retire.is_err() && **ArrayVec::len_sim(&retiring) > 0 {
while let Some((peek_retire, result)) = peek_state.try_retire(true) {
if result.is_err() && **ArrayVec::len_sim(&retiring) > 0 {
break;
}
let peek_retire = peek_retire.unwrap_or_else(|_| {
#[hdl(sim)]
RetireToNextPcInterfacePerInsn::<_> {
id: 0_hdl_u12,
next_pc: u64::from_be_bytes(*b"ErrError"),
call_stack_op: #[hdl(sim)]
CallStackOp::None(),
cond_br_taken: #[hdl(sim)]
HdlNone(),
config,
}
});
let Ok(_) = ArrayVec::try_push_sim(&mut retiring, peek_retire) else {
break;
};
@ -719,15 +776,33 @@ fn mock_execute_retire_pipe(config: PhantomConst<CpuConfig>) {
.await;
sim.write(
from_post_decode.ready,
state.space_available().min(config.get().fetch_width.get()),
if state.canceling {
0
} else {
state.space_available().min(config.get().fetch_width.get())
},
)
.await;
sim.wait_for_clock_edge(cd.clk).await;
println!(
"Dump mock execute retire pipe queue: {:#?}",
Vec::from_iter(state.queue.iter().map(|v| {
DebugAsDisplay(format!(
"fid={:#x} id={} pc={:#x}",
v.insn.fetch_block_id.as_int(),
v.insn.id,
v.insn.pc.as_int(),
))
}))
);
if state.canceling {
state.finish_cancel();
}
if sim.read_past_bool(retire_output.inner.ready, cd.clk).await {
for _ in 0..**ArrayVec::len_sim(&retiring) {
match state.try_retire() {
Some(Ok(_)) => {}
Some(Err(e)) => panic!("retire error: {e}"),
match state.try_retire(false) {
Some((_, Ok(_))) => {}
Some((_, Err(e))) => panic!("retire error: {e}"),
None => unreachable!(),
}
}
@ -737,7 +812,7 @@ fn mock_execute_retire_pipe(config: PhantomConst<CpuConfig>) {
&mut new_insns,
*sim.read_past(from_post_decode.ready, cd.clk).await,
);
for insn in ArrayVec::elements_sim_ref(&new_insns) {
for insn in dbg!(ArrayVec::elements_sim_ref(&new_insns)) {
state.start(insn, delay_sequence_index);
}
}
@ -803,7 +878,7 @@ fn test_next_pc() {
config.fetch_width = NonZeroUsize::new(2).unwrap();
let m = dut(PhantomConst::new_sized(config));
let mut sim = Simulation::new(m);
let mut writer = RcWriter::default();
let writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
struct DumpVcdOnDrop {
writer: Option<RcWriter>,
@ -821,8 +896,9 @@ fn test_next_pc() {
};
sim.write_clock(sim.io().cd.clk, false);
sim.write_reset(sim.io().cd.rst, true);
for _cycle in 0..300 {
for _cycle in 0..500 {
sim.advance_time(SimDuration::from_nanos(500));
println!("clock tick");
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_nanos(500));
sim.write_clock(sim.io().cd.clk, false);