This commit is contained in:
parent
59da0aec06
commit
d5a7d9dd9e
3 changed files with 293695 additions and 38183 deletions
|
|
@ -251,7 +251,8 @@ pub struct RetireToNextPcInterfaceInner<C: PhantomConstGet<CpuConfig>> {
|
||||||
/// branch instruction is mis-speculated.
|
/// branch instruction is mis-speculated.
|
||||||
pub struct RetireToNextPcInterface<C: PhantomConstGet<CpuConfig>> {
|
pub struct RetireToNextPcInterface<C: PhantomConstGet<CpuConfig>> {
|
||||||
pub inner: ReadyValid<RetireToNextPcInterfaceInner<C>>,
|
pub inner: ReadyValid<RetireToNextPcInterfaceInner<C>>,
|
||||||
pub next_insn_ids: HdlOption<ArrayVec<UInt<12>, CpuConfigRobSize<C>>>,
|
/// only for debugging
|
||||||
|
pub next_insns: HdlOption<ArrayVec<WipDecodedInsn, CpuConfigRobSize<C>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(no_static)]
|
#[hdl(no_static)]
|
||||||
|
|
@ -2036,7 +2037,9 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
|
||||||
let mut branch_offset = 0u8;
|
let mut branch_offset = 0u8;
|
||||||
let mut after_call_offset = 0u8;
|
let mut after_call_offset = 0u8;
|
||||||
let mut btb_entry_fields = None;
|
let mut btb_entry_fields = None;
|
||||||
for insn in insns {
|
let mut branch_history = start_branch_history.clone();
|
||||||
|
let mut insn_index_of_branch_history_update = 0;
|
||||||
|
for (index, insn) in insns.iter().enumerate() {
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
let WipDecodedInsn {
|
let WipDecodedInsn {
|
||||||
fetch_block_id: insn_fetch_block_id,
|
fetch_block_id: insn_fetch_block_id,
|
||||||
|
|
@ -2050,19 +2053,24 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
|
||||||
insn_fetch_block_id, fetch_block_id,
|
insn_fetch_block_id, fetch_block_id,
|
||||||
"fetch decode pipeline's output isn't in-sync with fetching_queue",
|
"fetch decode pipeline's output isn't in-sync with fetching_queue",
|
||||||
);
|
);
|
||||||
let guess_branch_addr_kind = |fallback_taken| {
|
let mut cond_branch_taken = None;
|
||||||
#[hdl(sim)]
|
let mut guess_cond_branch_addr_kind = |fallback_taken| {
|
||||||
|
let taken = #[hdl(sim)]
|
||||||
if let HdlSome(entry) = predicted_btb_entry {
|
if let HdlSome(entry) = predicted_btb_entry {
|
||||||
let addr_kind = &entry.1.addr_kind;
|
let addr_kind = &entry.1.addr_kind;
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
match addr_kind {
|
match addr_kind {
|
||||||
BTBEntryAddrKind::Unconditional | BTBEntryAddrKind::Indirect => {}
|
BTBEntryAddrKind::Unconditional | BTBEntryAddrKind::Indirect => {
|
||||||
BTBEntryAddrKind::CondTaken | BTBEntryAddrKind::CondNotTaken => {
|
fallback_taken
|
||||||
return addr_kind.clone();
|
|
||||||
}
|
}
|
||||||
|
BTBEntryAddrKind::CondTaken => true,
|
||||||
|
BTBEntryAddrKind::CondNotTaken => false,
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if fallback_taken {
|
fallback_taken
|
||||||
|
};
|
||||||
|
cond_branch_taken = Some(taken);
|
||||||
|
if taken {
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
BTBEntryAddrKind::CondTaken()
|
BTBEntryAddrKind::CondTaken()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2091,7 +2099,7 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
|
||||||
insn_kind = #[hdl(sim)]
|
insn_kind = #[hdl(sim)]
|
||||||
BTBEntryInsnKind::Branch();
|
BTBEntryInsnKind::Branch();
|
||||||
// guess backwards branches are taken and forwards branches are not
|
// guess backwards branches are taken and forwards branches are not
|
||||||
addr_kind = guess_branch_addr_kind(target_pc.as_int() <= pc.as_int());
|
addr_kind = guess_cond_branch_addr_kind(target_pc.as_int() <= pc.as_int());
|
||||||
can_train_cond_branch_predictor = true;
|
can_train_cond_branch_predictor = true;
|
||||||
Some(target_pc.as_int())
|
Some(target_pc.as_int())
|
||||||
}
|
}
|
||||||
|
|
@ -2115,7 +2123,7 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
|
||||||
insn_kind = #[hdl(sim)]
|
insn_kind = #[hdl(sim)]
|
||||||
BTBEntryInsnKind::Call();
|
BTBEntryInsnKind::Call();
|
||||||
// guess conditional calls are taken
|
// guess conditional calls are taken
|
||||||
addr_kind = guess_branch_addr_kind(true);
|
addr_kind = guess_cond_branch_addr_kind(true);
|
||||||
can_train_cond_branch_predictor = true;
|
can_train_cond_branch_predictor = true;
|
||||||
Some(target_pc.as_int())
|
Some(target_pc.as_int())
|
||||||
}
|
}
|
||||||
|
|
@ -2139,7 +2147,7 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
|
||||||
insn_kind = #[hdl(sim)]
|
insn_kind = #[hdl(sim)]
|
||||||
BTBEntryInsnKind::Ret();
|
BTBEntryInsnKind::Ret();
|
||||||
// guess conditional returns are taken
|
// guess conditional returns are taken
|
||||||
addr_kind = guess_branch_addr_kind(true);
|
addr_kind = guess_cond_branch_addr_kind(true);
|
||||||
can_train_cond_branch_predictor = true;
|
can_train_cond_branch_predictor = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -2158,6 +2166,10 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
|
||||||
// for now we just truncate the fetch block right before the second ctrl transfer insn.
|
// for now we just truncate the fetch block right before the second ctrl transfer insn.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if let Some(taken) = cond_branch_taken {
|
||||||
|
insn_index_of_branch_history_update = index;
|
||||||
|
step_branch_history(&mut branch_history, taken);
|
||||||
|
}
|
||||||
branch_offset = fallthrough_offset;
|
branch_offset = fallthrough_offset;
|
||||||
let target_pc = target_pc.unwrap_or_else(|| predicted_next_start_pc.as_int());
|
let target_pc = target_pc.unwrap_or_else(|| predicted_next_start_pc.as_int());
|
||||||
add_output_insn(
|
add_output_insn(
|
||||||
|
|
@ -2228,11 +2240,45 @@ impl<C: PhantomConstCpuConfig> Stage<C> for PostDecodeStageState<C> {
|
||||||
cancel_self: false,
|
cancel_self: false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let mut predicted_next_pc = start_pc.as_int();
|
||||||
|
for (i, output) in ArrayVec::elements_sim_ref(&outputs).iter().enumerate() {
|
||||||
|
if output.insn.pc.as_int() != predicted_next_pc {
|
||||||
|
assert!(
|
||||||
|
i > 0,
|
||||||
|
"first instruction's pc ({}) should match the fetch's start_pc {start_pc}",
|
||||||
|
output.insn.pc,
|
||||||
|
);
|
||||||
|
ArrayVec::truncate_sim(&mut outputs, i);
|
||||||
|
if i <= insn_index_of_branch_history_update {
|
||||||
|
branch_history = start_branch_history.clone();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
predicted_next_pc = output.insn.predicted_next_pc.as_int();
|
||||||
|
}
|
||||||
|
let cancel = if predicted_next_pc != predicted_next_start_pc.as_int() {
|
||||||
|
#[hdl(sim)]
|
||||||
|
cancel_ty.HdlSome(
|
||||||
|
#[hdl(sim)]
|
||||||
|
Cancel::<_> {
|
||||||
|
call_stack: start_call_stack,
|
||||||
|
start_pc: predicted_next_pc,
|
||||||
|
new_btb_entry: #[hdl(sim)]
|
||||||
|
HdlNone(),
|
||||||
|
btb_entry_index: #[hdl(sim)]
|
||||||
|
HdlNone(),
|
||||||
|
branch_history,
|
||||||
|
config,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
#[hdl(sim)]
|
||||||
|
cancel_ty.HdlNone()
|
||||||
|
};
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
StageRunOutput::<_, _> {
|
StageRunOutput::<_, _> {
|
||||||
outputs,
|
outputs,
|
||||||
cancel: #[hdl(sim)]
|
cancel,
|
||||||
cancel_ty.HdlNone(),
|
|
||||||
cancel_self: false,
|
cancel_self: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2277,6 +2323,7 @@ struct ExecuteRetireStageOutput<C: PhantomConstGet<CpuConfig>> {
|
||||||
fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
|
fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
|
||||||
id: UInt<12>,
|
id: UInt<12>,
|
||||||
pc: UInt<64>,
|
pc: UInt<64>,
|
||||||
|
next_pc: UInt<64>,
|
||||||
config: C,
|
config: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2288,6 +2335,7 @@ impl<C: PhantomConstCpuConfig> SimValueDefault for ExecuteRetireStageOutput<C> {
|
||||||
fetch_block_id,
|
fetch_block_id,
|
||||||
id,
|
id,
|
||||||
pc: _,
|
pc: _,
|
||||||
|
next_pc: _,
|
||||||
config,
|
config,
|
||||||
} = self;
|
} = self;
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
|
|
@ -2297,6 +2345,7 @@ impl<C: PhantomConstCpuConfig> SimValueDefault for ExecuteRetireStageOutput<C> {
|
||||||
fetch_block_id: fetch_block_id.zero(),
|
fetch_block_id: fetch_block_id.zero(),
|
||||||
id: id.zero(),
|
id: id.zero(),
|
||||||
pc: 0u64,
|
pc: 0u64,
|
||||||
|
next_pc: 0u64,
|
||||||
config,
|
config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2389,9 +2438,10 @@ impl<C: PhantomConstCpuConfig> Stage<C> for ExecuteRetireStageState<C> {
|
||||||
fetch_block_id,
|
fetch_block_id,
|
||||||
id,
|
id,
|
||||||
pc,
|
pc,
|
||||||
|
next_pc,
|
||||||
config: _,
|
config: _,
|
||||||
} = item;
|
} = item;
|
||||||
format!("fid={fetch_block_id} id={id} pc={pc}")
|
format!("fid={fetch_block_id} id={id} pc={pc} npc={next_pc}")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -2565,6 +2615,7 @@ impl<C: PhantomConstCpuConfig> Stage<C> for ExecuteRetireStageState<C> {
|
||||||
fetch_block_id: &insn.fetch_block_id,
|
fetch_block_id: &insn.fetch_block_id,
|
||||||
id,
|
id,
|
||||||
pc: insn.pc,
|
pc: insn.pc,
|
||||||
|
next_pc,
|
||||||
config,
|
config,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -2592,6 +2643,7 @@ impl<C: PhantomConstCpuConfig> Stage<C> for ExecuteRetireStageState<C> {
|
||||||
fetch_block_id: &insn.fetch_block_id,
|
fetch_block_id: &insn.fetch_block_id,
|
||||||
id,
|
id,
|
||||||
pc: insn.pc,
|
pc: insn.pc,
|
||||||
|
next_pc,
|
||||||
config,
|
config,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
|
@ -4120,6 +4172,7 @@ impl<C: PhantomConstCpuConfig> AllStages<C> {
|
||||||
fetch_block_id: _,
|
fetch_block_id: _,
|
||||||
id: _,
|
id: _,
|
||||||
pc: _,
|
pc: _,
|
||||||
|
next_pc: _,
|
||||||
config: _,
|
config: _,
|
||||||
} = &execute_retire_output;
|
} = &execute_retire_output;
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
|
|
@ -4312,6 +4365,47 @@ impl<C: PhantomConstCpuConfig> AllStages<C> {
|
||||||
StageWithQueues::dump_queues(post_decode);
|
StageWithQueues::dump_queues(post_decode);
|
||||||
StageWithQueues::dump_queues(execute_retire);
|
StageWithQueues::dump_queues(execute_retire);
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn assert_pcs_match_predicted_pcs(this: &SimValue<Self>) {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let Self {
|
||||||
|
next_pc,
|
||||||
|
br_pred: _,
|
||||||
|
fetch_decode,
|
||||||
|
post_decode,
|
||||||
|
execute_retire,
|
||||||
|
config: _,
|
||||||
|
} = this;
|
||||||
|
// check fetch ops:
|
||||||
|
let fetch_ops: Vec<_> = Queue::peek_iter(&post_decode.input_queue)
|
||||||
|
.map(|v| &v.0.next_pc_stage_output)
|
||||||
|
.chain(Queue::peek_iter(&fetch_decode.output_queue).map(|v| &v.next_pc_stage_output))
|
||||||
|
.chain(Queue::peek_iter(&fetch_decode.input_queue))
|
||||||
|
.chain(Queue::peek_iter(&next_pc.output_queue))
|
||||||
|
.collect();
|
||||||
|
for i in fetch_ops.windows(2) {
|
||||||
|
assert_eq!(i[0].next_start_pc, i[1].start_pc, "{i:#?}")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check insns:
|
||||||
|
// we ignore fetch_decode.output_queue and post_decode.input_queue here
|
||||||
|
// because the predicted_next_pc values aren't valid yet.
|
||||||
|
let insns: Vec<_> = Queue::peek_iter(&execute_retire.input_queue)
|
||||||
|
.map(|v| &v.insn)
|
||||||
|
.chain(Queue::peek_iter(&post_decode.output_queue).map(|v| &v.insn))
|
||||||
|
.collect();
|
||||||
|
for i in insns.windows(2) {
|
||||||
|
assert_eq!(i[0].predicted_next_pc, i[1].pc, "{i:#?}");
|
||||||
|
}
|
||||||
|
if let Some(next_input) = insns.first() {
|
||||||
|
if let Some(last_output) = Queue::peek_iter(&execute_retire.output_queue).last() {
|
||||||
|
assert_eq!(
|
||||||
|
last_output.next_pc, next_input.pc,
|
||||||
|
"last_output={last_output:#?}\nnext_input={next_input:#?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(no_static)]
|
#[hdl(no_static)]
|
||||||
|
|
@ -4435,6 +4529,13 @@ impl<C: PhantomConstCpuConfig> NextPcState<C> {
|
||||||
assert_eq!(br_pred_ops, fetch_decode_ops, "queues out of sync");
|
assert_eq!(br_pred_ops, fetch_decode_ops, "queues out of sync");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn assert_pcs_match_predicted_pcs(this: &SimValue<Self>) {
|
||||||
|
#[hdl(sim)]
|
||||||
|
if let HdlNone = &this.cancel {
|
||||||
|
AllStages::assert_pcs_match_predicted_pcs(&this.all_stages);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uint_in_range_inclusive_max<Start: Size, End: Size>(
|
fn uint_in_range_inclusive_max<Start: Size, End: Size>(
|
||||||
|
|
@ -4567,6 +4668,7 @@ pub fn next_pc(config: PhantomConst<CpuConfig>) {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
AllStages::dump_queues(&state.all_stages);
|
AllStages::dump_queues(&state.all_stages);
|
||||||
|
NextPcState::assert_pcs_match_predicted_pcs(&state);
|
||||||
let next_fetch_block_ids = sim.read_past(to_fetch.next_fetch_block_ids, cd.clk).await;
|
let next_fetch_block_ids = sim.read_past(to_fetch.next_fetch_block_ids, cd.clk).await;
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
if let HdlSome(next_fetch_block_ids) = &next_fetch_block_ids {
|
if let HdlSome(next_fetch_block_ids) = &next_fetch_block_ids {
|
||||||
|
|
@ -4579,16 +4681,16 @@ pub fn next_pc(config: PhantomConst<CpuConfig>) {
|
||||||
assert_eq!(next_fetch_block_ids, expected_next_fetch_block_ids);
|
assert_eq!(next_fetch_block_ids, expected_next_fetch_block_ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let next_retire_insn_ids = sim.read_past(from_retire.next_insn_ids, cd.clk).await;
|
let next_retire_insns = sim.read_past(from_retire.next_insns, cd.clk).await;
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
if let HdlSome(next_retire_insn_ids) = &next_retire_insn_ids {
|
if let HdlSome(next_retire_insns) = &next_retire_insns {
|
||||||
if !was_canceling && !is_canceling {
|
if !was_canceling && !is_canceling {
|
||||||
let next_retire_insn_ids = ArrayVec::elements_sim_ref(&next_retire_insn_ids);
|
let next_retire_insns = ArrayVec::elements_sim_ref(&next_retire_insns);
|
||||||
let expected_next_retire_insn_ids = Vec::from_iter(
|
let expected_next_retire_insns = Vec::from_iter(
|
||||||
Queue::peek_iter(&state.all_stages.execute_retire.input_queue)
|
Queue::peek_iter(&state.all_stages.execute_retire.input_queue)
|
||||||
.map(|v| v.insn.id.clone()),
|
.map(|v| v.insn.clone()),
|
||||||
);
|
);
|
||||||
assert_eq!(next_retire_insn_ids, expected_next_retire_insn_ids);
|
assert_eq!(next_retire_insns, expected_next_retire_insns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
was_canceling = is_canceling;
|
was_canceling = is_canceling;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -326,7 +326,9 @@ impl MockInsn {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
struct MockMachineState {
|
struct MockMachineState {
|
||||||
|
reset_at_exit: bool,
|
||||||
call_stack: Vec<u64>,
|
call_stack: Vec<u64>,
|
||||||
|
orig_input: &'static [u8],
|
||||||
input: &'static [u8],
|
input: &'static [u8],
|
||||||
output: Vec<u8>,
|
output: Vec<u8>,
|
||||||
regs: MockRegs,
|
regs: MockRegs,
|
||||||
|
|
@ -340,16 +342,36 @@ const RESET_PC: u64 = 0;
|
||||||
const EXIT_PC: u64 = u64::from_be_bytes(*b"ExitExit");
|
const EXIT_PC: u64 = u64::from_be_bytes(*b"ExitExit");
|
||||||
|
|
||||||
impl MockMachineState {
|
impl MockMachineState {
|
||||||
fn new(insns: MockInsns, input: impl AsRef<[u8]>) -> Self {
|
fn new(insns: MockInsns, input: impl AsRef<[u8]>, reset_at_exit: bool) -> Self {
|
||||||
|
let input = Interned::into_inner(input.as_ref().intern());
|
||||||
Self {
|
Self {
|
||||||
|
reset_at_exit,
|
||||||
call_stack: Vec::with_capacity(16),
|
call_stack: Vec::with_capacity(16),
|
||||||
input: Interned::into_inner(input.as_ref().intern()),
|
orig_input: input,
|
||||||
|
input,
|
||||||
output: Vec::with_capacity(16),
|
output: Vec::with_capacity(16),
|
||||||
regs: MockRegs::new(),
|
regs: MockRegs::new(),
|
||||||
pc: RESET_PC,
|
pc: RESET_PC,
|
||||||
insns,
|
insns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn reset(&mut self) {
|
||||||
|
let Self {
|
||||||
|
reset_at_exit: _,
|
||||||
|
call_stack,
|
||||||
|
orig_input,
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
regs,
|
||||||
|
pc,
|
||||||
|
insns: _,
|
||||||
|
} = self;
|
||||||
|
call_stack.clear();
|
||||||
|
*input = *orig_input;
|
||||||
|
output.clear();
|
||||||
|
*regs = MockRegs::new();
|
||||||
|
*pc = RESET_PC;
|
||||||
|
}
|
||||||
fn run_one(&mut self, trace: bool) -> RetireSeqEntry {
|
fn run_one(&mut self, trace: bool) -> RetireSeqEntry {
|
||||||
let orig_pc = self.pc;
|
let orig_pc = self.pc;
|
||||||
let insn = self
|
let insn = self
|
||||||
|
|
@ -420,7 +442,18 @@ impl MockMachineState {
|
||||||
next_pc = target;
|
next_pc = target;
|
||||||
}
|
}
|
||||||
MockInsn::Ret => next_pc = self.call_stack.pop().unwrap_or(DEMO_ILLEGAL_INSN_TRAP),
|
MockInsn::Ret => next_pc = self.call_stack.pop().unwrap_or(DEMO_ILLEGAL_INSN_TRAP),
|
||||||
MockInsn::ExitSysCall => next_pc = EXIT_PC,
|
MockInsn::ExitSysCall => {
|
||||||
|
if self.reset_at_exit {
|
||||||
|
self.reset();
|
||||||
|
return RetireSeqEntry {
|
||||||
|
pc: orig_pc,
|
||||||
|
cond_br_taken: None,
|
||||||
|
insn,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
next_pc = EXIT_PC;
|
||||||
|
}
|
||||||
|
}
|
||||||
MockInsn::Illegal => next_pc = DEMO_ILLEGAL_INSN_TRAP,
|
MockInsn::Illegal => next_pc = DEMO_ILLEGAL_INSN_TRAP,
|
||||||
}
|
}
|
||||||
self.pc = next_pc;
|
self.pc = next_pc;
|
||||||
|
|
@ -721,7 +754,7 @@ fn test_program_expr_parser() {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test(expected_output: &str, expected_exit_code: u64, input: &str) {
|
fn test(expected_output: &str, expected_exit_code: u64, input: &str) {
|
||||||
println!("starting new test case: input={input:?}\n\n");
|
println!("starting new test case: input={input:?}\n\n");
|
||||||
let mut state = MockMachineState::new(mock_program_expr_parser(), input);
|
let mut state = MockMachineState::new(mock_program_expr_parser(), input, false);
|
||||||
let exit_code = state.run_until_exit(10000, true).unwrap();
|
let exit_code = state.run_until_exit(10000, true).unwrap();
|
||||||
println!("output: {:?}", str::from_utf8(&state.output));
|
println!("output: {:?}", str::from_utf8(&state.output));
|
||||||
println!("exit code: {exit_code}");
|
println!("exit code: {exit_code}");
|
||||||
|
|
@ -1250,8 +1283,8 @@ fn mock_execute_retire_pipe(
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
sim.write(
|
sim.write(
|
||||||
retire_output.next_insn_ids,
|
retire_output.next_insns,
|
||||||
retire_output.next_insn_ids.ty().HdlNone(),
|
retire_output.next_insns.ty().HdlNone(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
sim.write(
|
sim.write(
|
||||||
|
|
@ -1294,7 +1327,7 @@ fn mock_execute_retire_pipe(
|
||||||
let config = from_post_decode.config.ty();
|
let config = from_post_decode.config.ty();
|
||||||
let mut state = MockExecuteState::new(
|
let mut state = MockExecuteState::new(
|
||||||
config,
|
config,
|
||||||
RetireSeq::new(MockMachineState::new(mock_insns, mock_input)),
|
RetireSeq::new(MockMachineState::new(mock_insns, mock_input, true)),
|
||||||
);
|
);
|
||||||
let empty_retire_insn = #[hdl(sim)]
|
let empty_retire_insn = #[hdl(sim)]
|
||||||
RetireToNextPcInterfacePerInsn::<_> {
|
RetireToNextPcInterfacePerInsn::<_> {
|
||||||
|
|
@ -1312,22 +1345,32 @@ fn mock_execute_retire_pipe(
|
||||||
let mut sim_queue = queue_debug
|
let mut sim_queue = queue_debug
|
||||||
.ty()
|
.ty()
|
||||||
.new_sim(ExecuteRetirePipeQueueEntry.default_sim());
|
.new_sim(ExecuteRetirePipeQueueEntry.default_sim());
|
||||||
let mut next_insn_ids = retire_output.next_insn_ids.ty().HdlSome.new_sim(0_hdl_u12);
|
let mut next_insns = retire_output.next_insns.ty().HdlSome.new_sim(
|
||||||
|
#[hdl(sim)]
|
||||||
|
WipDecodedInsn {
|
||||||
|
fetch_block_id: 0u8,
|
||||||
|
id: 0_hdl_u12,
|
||||||
|
pc: 0u64,
|
||||||
|
predicted_next_pc: 0u64,
|
||||||
|
size_in_bytes: 0_hdl_u4,
|
||||||
|
kind: WipDecodedInsnKind.NonBranch(),
|
||||||
|
},
|
||||||
|
);
|
||||||
for entry in &state.queue {
|
for entry in &state.queue {
|
||||||
ArrayVec::try_push_sim(&mut sim_queue, entry)
|
ArrayVec::try_push_sim(&mut sim_queue, entry)
|
||||||
.ok()
|
.ok()
|
||||||
.expect("queue is known to be small enough");
|
.expect("queue is known to be small enough");
|
||||||
let _ = ArrayVec::try_push_sim(&mut next_insn_ids, &entry.insn.id);
|
let _ = ArrayVec::try_push_sim(&mut next_insns, &entry.insn);
|
||||||
}
|
}
|
||||||
sim.write(queue_debug, sim_queue).await;
|
sim.write(queue_debug, sim_queue).await;
|
||||||
sim.write(
|
sim.write(
|
||||||
retire_output.next_insn_ids,
|
retire_output.next_insns,
|
||||||
if state.canceling {
|
if state.canceling {
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
(retire_output.next_insn_ids.ty()).HdlNone()
|
(retire_output.next_insns.ty()).HdlNone()
|
||||||
} else {
|
} else {
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
(retire_output.next_insn_ids.ty()).HdlSome(next_insn_ids)
|
(retire_output.next_insns.ty()).HdlSome(next_insns)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -1498,7 +1541,7 @@ fn test_next_pc() {
|
||||||
};
|
};
|
||||||
sim.write_clock(sim.io().cd.clk, false);
|
sim.write_clock(sim.io().cd.clk, false);
|
||||||
sim.write_reset(sim.io().cd.rst, true);
|
sim.write_reset(sim.io().cd.rst, true);
|
||||||
for cycle in 0..800 {
|
for cycle in 0..2000 {
|
||||||
sim.advance_time(SimDuration::from_nanos(500));
|
sim.advance_time(SimDuration::from_nanos(500));
|
||||||
println!("clock tick: {cycle}");
|
println!("clock tick: {cycle}");
|
||||||
sim.write_clock(sim.io().cd.clk, true);
|
sim.write_clock(sim.io().cd.clk, true);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue