add TraceAsString around instructions and stuff to make the .vcd files much smaller and easier to read
All checks were successful
/ test (pull_request) Successful in 5m44s

This commit is contained in:
Jacob Lifshay 2026-05-13 23:34:24 -07:00
parent 8bee576a2a
commit 0d3c41fa14
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
4 changed files with 35839 additions and 1340471 deletions

View file

@ -56,7 +56,7 @@ pub struct MOpInstance<MOp> {
/// it needs to be canceled along with all other &micro;Ops that /// it needs to be canceled along with all other &micro;Ops that
/// come from the same ISA-level instruction. /// come from the same ISA-level instruction.
pub is_last_mop_in_insn: Bool, pub is_last_mop_in_insn: Bool,
pub mop: MOp, pub mop: TraceAsString<MOp>,
} }
impl<MOp: Type> SimValueDebug for MOpInstance<MOp> { impl<MOp: Type> SimValueDebug for MOpInstance<MOp> {
@ -139,14 +139,14 @@ pub struct UnitEnqueue<C: PhantomConstGet<CpuConfig>> {
pub struct UnitInputsReady<C: PhantomConstGet<CpuConfig>> { pub struct UnitInputsReady<C: PhantomConstGet<CpuConfig>> {
/// the whole `MOpInstance` is sent again so Units can just ignore all [`UnitEnqueue`] messages if desired. /// the whole `MOpInstance` is sent again so Units can just ignore all [`UnitEnqueue`] messages if desired.
pub mop: MOpInstance<RenamedMOp<C>>, pub mop: MOpInstance<RenamedMOp<C>>,
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>, pub src_values: Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>,
pub config: C, pub config: C,
} }
#[hdl(no_static)] #[hdl(no_static)]
pub struct UnitOutputReady<C: PhantomConstGet<CpuConfig>> { pub struct UnitOutputReady<C: PhantomConstGet<CpuConfig>> {
pub id: MOpId, pub id: MOpId,
pub dest_value: PRegValue, pub dest_value: TraceAsString<PRegValue>,
pub predictor_op: NextPcPredictorOp<C>, pub predictor_op: NextPcPredictorOp<C>,
} }
@ -273,13 +273,13 @@ type MOpRegCount<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(no_static)] #[hdl(no_static)]
struct RenameTableDebugState<C: PhantomConstGet<CpuConfig>> { struct RenameTableDebugState<C: PhantomConstGet<CpuConfig>> {
entries: ArrayType<RenameTableEntry<C>, MOpRegCount<C>>, entries: ArrayType<TraceAsString<RenameTableEntry<C>>, MOpRegCount<C>>,
config: C, config: C,
} }
#[derive(Debug)] #[derive(Debug)]
struct RenameTable<C: PhantomConstCpuConfig> { struct RenameTable<C: PhantomConstCpuConfig> {
entries: Box<[SimValue<RenameTableEntry<C>>; 1 << MOpRegNum::WIDTH]>, entries: Box<[SimValue<TraceAsString<RenameTableEntry<C>>>; 1 << MOpRegNum::WIDTH]>,
config: C, config: C,
} }
@ -301,7 +301,7 @@ impl<C: PhantomConstCpuConfig> Clone for RenameTable<C> {
enum RenameTableUpdate<C: PhantomConstCpuConfig> { enum RenameTableUpdate<C: PhantomConstCpuConfig> {
Write { Write {
unrenamed_reg_num: u32, unrenamed_reg_num: u32,
new: SimValue<RenameTableEntry<C>>, new: SimValue<TraceAsString<RenameTableEntry<C>>>,
}, },
UpdateForReadL2Reg { UpdateForReadL2Reg {
dest: SimValue<PRegNum<C>>, dest: SimValue<PRegNum<C>>,
@ -315,10 +315,13 @@ enum RenameTableUpdate<C: PhantomConstCpuConfig> {
impl<C: PhantomConstCpuConfig> RenameTable<C> { impl<C: PhantomConstCpuConfig> RenameTable<C> {
fn new(config: C) -> Self { fn new(config: C) -> Self {
let entries: Box<[SimValue<RenameTableEntry<C>>; 1 << MOpRegNum::WIDTH]> = let entries: Box<[SimValue<TraceAsString<RenameTableEntry<C>>>; 1 << MOpRegNum::WIDTH]> =
vec![RenameTableEntry[config].const_zero(); 1 << MOpRegNum::WIDTH] vec![
.try_into() RenameTableEntry[config].const_zero().into_trace_as_string();
.expect("size is known to match"); 1 << MOpRegNum::WIDTH
]
.try_into()
.expect("size is known to match");
Self { entries, config } Self { entries, config }
} }
#[hdl] #[hdl]
@ -350,7 +353,7 @@ impl<C: PhantomConstCpuConfig> RenameTable<C> {
(RenameTableEntry[self.config]).L1(dest); (RenameTableEntry[self.config]).L1(dest);
for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() { for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() {
#[hdl(sim)] #[hdl(sim)]
match &entry { match entry.inner() {
RenameTableEntry::<_>::L1(_) => {} RenameTableEntry::<_>::L1(_) => {}
RenameTableEntry::<_>::L2(l2) => { RenameTableEntry::<_>::L2(l2) => {
if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) { if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) {
@ -358,7 +361,7 @@ impl<C: PhantomConstCpuConfig> RenameTable<C> {
"{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \ "{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \
updating from {entry:?} to {new:?}", updating from {entry:?} to {new:?}",
); );
*entry = new.clone(); *entry = new.to_trace_as_string();
} }
} }
} }
@ -369,14 +372,14 @@ impl<C: PhantomConstCpuConfig> RenameTable<C> {
(RenameTableEntry[self.config]).L2(dest); (RenameTableEntry[self.config]).L2(dest);
for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() { for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() {
#[hdl(sim)] #[hdl(sim)]
match &entry { match entry.inner() {
RenameTableEntry::<_>::L1(l1) => { RenameTableEntry::<_>::L1(l1) => {
if l1 == src { if l1 == src {
println!( println!(
"{rename_table_name}: UpdateForWriteL2Reg: {unrenamed_reg_num:#x} \ "{rename_table_name}: UpdateForWriteL2Reg: {unrenamed_reg_num:#x} \
updating from {entry:?} to {new:?}", updating from {entry:?} to {new:?}",
); );
*entry = new.clone(); *entry = new.to_trace_as_string();
} }
} }
RenameTableEntry::<_>::L2(_) => {} RenameTableEntry::<_>::L2(_) => {}
@ -390,7 +393,7 @@ impl<C: PhantomConstCpuConfig> RenameTable<C> {
let mut seen = BTreeSet::new(); let mut seen = BTreeSet::new();
for entry in self.entries.iter() { for entry in self.entries.iter() {
#[hdl(sim)] #[hdl(sim)]
match entry { match entry.inner() {
RenameTableEntry::<_>::L1(v) => { RenameTableEntry::<_>::L1(v) => {
if UnitNum::index_sim(&v.unit_num) == Some(unit_index) { if UnitNum::index_sim(&v.unit_num) == Some(unit_index) {
seen.insert(UnitOutRegNum::value_sim(&v.unit_out_reg)); seen.insert(UnitOutRegNum::value_sim(&v.unit_out_reg));
@ -649,7 +652,7 @@ impl<C: PhantomConstCpuConfig> RobEntry<C> {
} }
} }
fn dest_reg(&self) -> Option<&SimValue<PRegNum<C>>> { fn dest_reg(&self) -> Option<&SimValue<PRegNum<C>>> {
let dest_reg = MOpTrait::dest_reg_sim_ref(&self.mop.mop); let dest_reg = MOpTrait::dest_reg_sim_ref(self.mop.mop.inner());
let unit_index = UnitNum::index_sim(&dest_reg.unit_num)?; let unit_index = UnitNum::index_sim(&dest_reg.unit_num)?;
assert_eq!(unit_index, self.unit_index); assert_eq!(unit_index, self.unit_index);
Some(dest_reg) Some(dest_reg)
@ -1035,7 +1038,7 @@ pub struct RenameExecuteRetireDebugState<C: PhantomConstGet<CpuConfig>> {
next_pc_canceling: HdlOption<NextPcCancelingDebugState>, next_pc_canceling: HdlOption<NextPcCancelingDebugState>,
unit_canceling: ArrayType<Bool, CpuConfigUnitCount<C>>, unit_canceling: ArrayType<Bool, CpuConfigUnitCount<C>>,
l1_reg_file: ArrayType< l1_reg_file: ArrayType<
ArrayType<HdlOption<PRegValue>, CpuConfig2PowOutRegNumWidth<C>>, ArrayType<HdlOption<TraceAsString<PRegValue>>, CpuConfig2PowOutRegNumWidth<C>>,
CpuConfigUnitCount<C>, CpuConfigUnitCount<C>,
>, >,
lfsr: LFSR31, lfsr: LFSR31,
@ -1050,7 +1053,7 @@ struct RenameExecuteRetireState<C: PhantomConstCpuConfig> {
rob: ReorderBuffer<C>, rob: ReorderBuffer<C>,
next_pc_canceling: Option<NextPcCancelingState>, next_pc_canceling: Option<NextPcCancelingState>,
unit_canceling: Box<[bool]>, unit_canceling: Box<[bool]>,
l1_reg_file: Box<[Box<[Option<SimValue<PRegValue>>]>]>, l1_reg_file: Box<[Box<[Option<SimValue<TraceAsString<PRegValue>>>]>]>,
lfsr: SimValue<LFSR31>, lfsr: SimValue<LFSR31>,
l2_reg_file_unit_index: usize, l2_reg_file_unit_index: usize,
config: C, config: C,
@ -1227,7 +1230,7 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
{ {
allocated_regs[unit_out_reg_index] = true; allocated_regs[unit_out_reg_index] = true;
} }
MOpTrait::for_each_src_reg_sim_ref(&renamed.mop.mop, &mut |src_reg, _index| { MOpTrait::for_each_src_reg_sim_ref(renamed.mop.mop.inner(), &mut |src_reg, _index| {
#[hdl(sim)] #[hdl(sim)]
let PRegNum::<_> { let PRegNum::<_> {
unit_num, unit_num,
@ -1245,7 +1248,7 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
.chain(self.retire_rename_table.entries.iter()) .chain(self.retire_rename_table.entries.iter())
{ {
#[hdl(sim)] #[hdl(sim)]
match entry { match entry.inner() {
RenameTableEntry::<_>::L1(entry) => { RenameTableEntry::<_>::L1(entry) => {
if Some(unit_index) == UnitNum::index_sim(&entry.unit_num) { if Some(unit_index) == UnitNum::index_sim(&entry.unit_num) {
allocated_regs[UnitOutRegNum::value_sim(&entry.unit_out_reg)] = true; allocated_regs[UnitOutRegNum::value_sim(&entry.unit_out_reg)] = true;
@ -1262,7 +1265,7 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
let mut allocated_regs = vec![false; L2RegNum.l2_reg_count()]; let mut allocated_regs = vec![false; L2RegNum.l2_reg_count()];
for renamed in self.rob.renamed() { for renamed in self.rob.renamed() {
#[hdl(sim)] #[hdl(sim)]
if let RenamedMOp::<_>::TransformedMove(l2_register_file_op) = &renamed.mop.mop { if let RenamedMOp::<_>::TransformedMove(l2_register_file_op) = renamed.mop.mop.inner() {
let l2_reg = #[hdl(sim)] let l2_reg = #[hdl(sim)]
match l2_register_file_op { match l2_register_file_op {
L2RegisterFileMOp::<_, _>::ReadL2Reg(v) => &v.common.imm, L2RegisterFileMOp::<_, _>::ReadL2Reg(v) => &v.common.imm,
@ -1278,7 +1281,7 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
.chain(self.retire_rename_table.entries.iter()) .chain(self.retire_rename_table.entries.iter())
{ {
#[hdl(sim)] #[hdl(sim)]
match entry { match entry.inner() {
RenameTableEntry::<_>::L1(_) => {} RenameTableEntry::<_>::L1(_) => {}
RenameTableEntry::<_>::L2(entry) => { RenameTableEntry::<_>::L2(entry) => {
allocated_regs[L2RegNum::value_sim(entry)] = true; allocated_regs[L2RegNum::value_sim(entry)] = true;
@ -1337,9 +1340,9 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
}, },
); );
} }
let unit_kind = UnitMOp::kind_sim(&insn.mop); let unit_kind = UnitMOp::kind_sim(insn.mop.inner());
#[hdl(sim)] #[hdl(sim)]
if let MOp::TransformedMove(move_reg_mop) = &insn.mop { if let MOp::TransformedMove(move_reg_mop) = insn.mop.inner() {
let mut src_regs = [MOpRegNum::const_zero_sim()]; let mut src_regs = [MOpRegNum::const_zero_sim()];
MOpTrait::for_each_src_reg_sim_ref(move_reg_mop, &mut |src_reg, index| { MOpTrait::for_each_src_reg_sim_ref(move_reg_mop, &mut |src_reg, index| {
src_regs[index] = src_reg.clone(); src_regs[index] = src_reg.clone();
@ -1468,14 +1471,14 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
}; };
println!("try_rename: picked {reg_to_free:?}"); println!("try_rename: picked {reg_to_free:?}");
let mut any_collisions = false; let mut any_collisions = false;
MOpTrait::for_each_src_reg_sim_ref(&insn.mop, &mut |src_reg, _| { MOpTrait::for_each_src_reg_sim_ref(insn.mop.inner(), &mut |src_reg, _| {
let renamed = let renamed =
&self.rename_table.entries[MOpRegNum::reg_num_sim(&src_reg) as usize]; &self.rename_table.entries[MOpRegNum::reg_num_sim(&src_reg) as usize];
println!( println!(
"try_rename: checking that mop src reg ({renamed:?}) doesn't conflict with picked reg" "try_rename: checking that mop src reg ({renamed:?}) doesn't conflict with picked reg"
); );
#[hdl(sim)] #[hdl(sim)]
match renamed { match renamed.inner() {
RenameTableEntry::<_>::L1(v) => { RenameTableEntry::<_>::L1(v) => {
if reg_to_free == *v { if reg_to_free == *v {
any_collisions = true; any_collisions = true;
@ -1520,7 +1523,8 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
PRegNum[self.config].const_zero(), PRegNum[self.config].const_zero(),
repeat(&reg_to_free, ConstUsize::<1>), repeat(&reg_to_free, ConstUsize::<1>),
dest, dest,
), )
.into_trace_as_string(),
}, },
self.l2_reg_file_unit_index, self.l2_reg_file_unit_index,
), ),
@ -1561,21 +1565,21 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
mop, mop,
} = &insn; } = &insn;
let mut needed_load = None; let mut needed_load = None;
let unrenamed_dest_regs = MOpDestReg::regs_sim(MOpTrait::dest_reg_sim_ref(mop)); let unrenamed_dest_regs = MOpDestReg::regs_sim(MOpTrait::dest_reg_sim_ref(mop.inner()));
let renamed_dest_reg = #[hdl(sim)] let renamed_dest_reg = #[hdl(sim)]
PRegNum::<_> { PRegNum::<_> {
unit_num: UnitNum[self.config].from_index_sim(unit_index), unit_num: UnitNum[self.config].from_index_sim(unit_index),
unit_out_reg: out_reg_num_sim, unit_out_reg: out_reg_num_sim,
}; };
let mop = MOpTrait::map_regs_sim( let mop = MOpTrait::map_regs_sim(
mop, mop.inner(),
&renamed_dest_reg, &renamed_dest_reg,
PRegNum[self.config], PRegNum[self.config],
&mut |src_reg, index| { &mut |src_reg, index| {
let renamed = &self.rename_table.entries[MOpRegNum::reg_num_sim(&src_reg) as usize]; let renamed = &self.rename_table.entries[MOpRegNum::reg_num_sim(&src_reg) as usize];
println!("renaming src[{index}] from {src_reg:?} to {renamed:?}"); println!("renaming src[{index}] from {src_reg:?} to {renamed:?}");
#[hdl(sim)] #[hdl(sim)]
match renamed { match renamed.inner() {
RenameTableEntry::<_>::L1(v) => v.clone(), RenameTableEntry::<_>::L1(v) => v.clone(),
RenameTableEntry::<_>::L2(v) => { RenameTableEntry::<_>::L2(v) => {
needed_load.get_or_insert_with(|| v.clone()); needed_load.get_or_insert_with(|| v.clone());
@ -1616,7 +1620,8 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
dest, dest,
repeat(PRegNum[self.config].const_zero_sim(), ConstUsize), repeat(PRegNum[self.config].const_zero_sim(), ConstUsize),
needed_load, needed_load,
), )
.into_trace_as_string(),
}, },
self.l2_reg_file_unit_index, self.l2_reg_file_unit_index,
), ),
@ -1644,7 +1649,8 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
mop, mop,
RenamedMOp[self.config].TransformedMove, RenamedMOp[self.config].TransformedMove,
|_move_reg| unreachable!(), |_move_reg| unreachable!(),
); )
.into_trace_as_string();
let renamed_dest_reg = #[hdl(sim)] let renamed_dest_reg = #[hdl(sim)]
(RenameTableEntry[self.config]).L1(renamed_dest_reg); (RenameTableEntry[self.config]).L1(renamed_dest_reg);
for unrenamed_reg_num in unrenamed_dest_regs { for unrenamed_reg_num in unrenamed_dest_regs {
@ -1652,7 +1658,7 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
&insn, &insn,
RenameTableUpdate::Write { RenameTableUpdate::Write {
unrenamed_reg_num, unrenamed_reg_num,
new: renamed_dest_reg.clone(), new: renamed_dest_reg.to_trace_as_string(),
}, },
); );
} }
@ -1711,14 +1717,14 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
return retval; // separate variable to work around rust-analyzer parse error return retval; // separate variable to work around rust-analyzer parse error
} }
let zero_reg = PRegNum[self.config].const_zero().into_sim_value(); let zero_reg = PRegNum[self.config].const_zero().into_sim_value();
let zero_value = zeroed(PRegValue); let zero_value = zeroed(TraceAsString[PRegValue]);
for rob in self.rob.renamed() { for rob in self.rob.renamed() {
if rob.unit_index == unit_index if rob.unit_index == unit_index
&& let Some(_) = rob.mop_in_unit_state.with_inputs_ready() && let Some(_) = rob.mop_in_unit_state.with_inputs_ready()
{ {
let mut src_values: [_; COMMON_MOP_SRC_LEN] = let mut src_values: [_; COMMON_MOP_SRC_LEN] =
std::array::from_fn(|_| Some(zero_value.clone())); std::array::from_fn(|_| Some(zero_value.clone()));
MOpTrait::for_each_src_reg_sim_ref(&rob.mop.mop, &mut |src_reg, index| { MOpTrait::for_each_src_reg_sim_ref(rob.mop.mop.inner(), &mut |src_reg, index| {
#[hdl(sim)] #[hdl(sim)]
let PRegNum::<_> { let PRegNum::<_> {
unit_num, unit_num,
@ -1730,7 +1736,6 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
.clone(); .clone();
} else { } else {
assert_eq!(*src_reg, zero_reg); assert_eq!(*src_reg, zero_reg);
src_values[index] = Some(zeroed(PRegValue));
} }
}); });
if src_values.iter().all(|v| v.is_some()) { if src_values.iter().all(|v| v.is_some()) {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -87,15 +87,15 @@ impl RandomState {
const START_PC: u64 = 0x0; // match microwatt's reset pc const START_PC: u64 = 0x0; // match microwatt's reset pc
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Insn<MOps = Vec<SimValue<self::MOp>>> { struct Insn<MOps = Vec<SimValue<TraceAsString<self::MOp>>>> {
size_in_bytes: u8, size_in_bytes: u8,
power_isa: String, power_isa: String,
mops: MOps, mops: MOps,
} }
enum LazyMOps { enum LazyMOps {
MOps(Vec<SimValue<self::MOp>>), MOps(Vec<SimValue<TraceAsString<self::MOp>>>),
Lazy(Box<dyn FnOnce(&[InsnsBuilderLabelState]) -> Vec<SimValue<self::MOp>>>), Lazy(Box<dyn FnOnce(&[InsnsBuilderLabelState]) -> Vec<SimValue<TraceAsString<self::MOp>>>>),
} }
impl Insn<LazyMOps> { impl Insn<LazyMOps> {
@ -107,7 +107,11 @@ impl Insn<LazyMOps> {
Self { Self {
size_in_bytes, size_in_bytes,
power_isa, power_isa,
mops: LazyMOps::MOps(mops.into_iter().map(|mop| mop.into_sim_value()).collect()), mops: LazyMOps::MOps(
mops.into_iter()
.map(|mop| mop.into_sim_value().into_trace_as_string())
.collect(),
),
} }
} }
fn new_lazy<I: IntoIterator<Item: ToSimValue<Type = MOp>>>( fn new_lazy<I: IntoIterator<Item: ToSimValue<Type = MOp>>>(
@ -121,7 +125,7 @@ impl Insn<LazyMOps> {
mops: LazyMOps::Lazy(Box::new(|labels| { mops: LazyMOps::Lazy(Box::new(|labels| {
lazy_mops(labels) lazy_mops(labels)
.into_iter() .into_iter()
.map(|mop| mop.into_sim_value()) .map(|mop| mop.into_sim_value().into_trace_as_string())
.collect() .collect()
})), })),
} }
@ -772,7 +776,7 @@ impl<'a, C: PhantomConstCpuConfig> MockNextPcState<'a, C> {
}; };
let mop = &insn.mops[self.next_mop_index]; let mop = &insn.mops[self.next_mop_index];
#[hdl(sim)] #[hdl(sim)]
if let MOp::AluBranch(mop) = mop { if let MOp::AluBranch(mop) = mop.inner() {
#[hdl(sim)] #[hdl(sim)]
match mop { match mop {
AluBranchMOp::<_, _>::Branch(mop) => { AluBranchMOp::<_, _>::Branch(mop) => {
@ -1043,7 +1047,8 @@ type SimOnlyMemoryChunk = SimOnly<MemoryChunk>;
struct MockMemoryDebugState<C: PhantomConstGet<()> = PhantomConst<()>> { struct MockMemoryDebugState<C: PhantomConstGet<()> = PhantomConst<()>> {
wrote_output: Bool, wrote_output: Bool,
memory: ArrayType<SimOnlyMemoryChunk, MockMemoryDebugStateMemorySize<C>>, memory: ArrayType<SimOnlyMemoryChunk, MockMemoryDebugStateMemorySize<C>>,
l1_cache: Array<HdlOption<MockCacheLineDebugState>, { MockMemory::CACHE_LINE_COUNT }>, l1_cache:
Array<TraceAsString<HdlOption<MockCacheLineDebugState>>, { MockMemory::CACHE_LINE_COUNT }>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -1291,6 +1296,7 @@ impl MockMemory {
#[hdl(sim)] #[hdl(sim)]
HdlNone() HdlNone()
} }
.into_trace_as_string()
}), }),
} }
} }
@ -1298,16 +1304,16 @@ impl MockMemory {
fn run_mop<C: PhantomConstCpuConfig>( fn run_mop<C: PhantomConstCpuConfig>(
&mut self, &mut self,
mop: &SimValue<MOpInstance<LoadStoreMOp<PRegNum<C>, PRegNum<C>>>>, mop: &SimValue<MOpInstance<LoadStoreMOp<PRegNum<C>, PRegNum<C>>>>,
src_values: &[SimValue<PRegValue>; COMMON_MOP_SRC_LEN], src_values: &[SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN],
is_speculative: bool, is_speculative: bool,
) -> Result<SimValue<PRegValue>, AddressCantBeSpeculativelyAccessed> { ) -> Result<SimValue<TraceAsString<PRegValue>>, AddressCantBeSpeculativelyAccessed> {
println!("MockMemory::run_mop: {:#x}: {:?}", mop.pc.as_int(), mop.mop); println!("MockMemory::run_mop: {:#x}: {:?}", mop.pc.as_int(), mop.mop);
println!( println!(
"<- {}{src_values:?}", "<- {}{src_values:?}",
if is_speculative { "(speculative) " } else { "" }, if is_speculative { "(speculative) " } else { "" },
); );
let retval = #[hdl(sim)] let retval = #[hdl(sim)]
match &mop.mop { match mop.mop.inner() {
LoadStoreMOp::<_, _>::Load(mop) => { LoadStoreMOp::<_, _>::Load(mop) => {
#[hdl(sim)] #[hdl(sim)]
let LoadMOp::<_, _> { load_store_common } = mop; let LoadMOp::<_, _> { load_store_common } = mop;
@ -1317,7 +1323,7 @@ impl MockMemory {
width, width,
conversion, conversion,
} = load_store_common; } = load_store_common;
let addr = src_values[0].int_fp.as_int(); let addr = src_values[0].inner().int_fp.as_int();
let loaded = #[hdl(sim)] let loaded = #[hdl(sim)]
match conversion { match conversion {
LoadStoreConversion::ZeroExt => LoadStoreConversion::ZeroExt =>
@ -1372,8 +1378,8 @@ impl MockMemory {
width, width,
conversion, conversion,
} = load_store_common; } = load_store_common;
let addr = src_values[0].int_fp.as_int(); let addr = src_values[0].inner().int_fp.as_int();
let value = src_values[1].int_fp.as_int(); let value = src_values[1].inner().int_fp.as_int();
#[hdl(sim)] #[hdl(sim)]
match conversion { match conversion {
LoadStoreConversion::ZeroExt | LoadStoreConversion::SignExt => LoadStoreConversion::ZeroExt | LoadStoreConversion::SignExt =>
@ -1399,7 +1405,7 @@ impl MockMemory {
} }
}; };
println!("-> {retval:?}"); println!("-> {retval:?}");
Ok(retval) Ok(retval.into_trace_as_string())
} }
} }
@ -1413,8 +1419,8 @@ trait MockExecutionStateTrait: Default {
&mut self, &mut self,
pc: u64, pc: u64,
mop: &SimValue<AddSubMOp<PRegNum<C>, PRegNum<C>, SrcCount>>, mop: &SimValue<AddSubMOp<PRegNum<C>, PRegNum<C>, SrcCount>>,
src_values: &[SimValue<PRegValue>; COMMON_MOP_SRC_LEN], src_values: &[SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN],
) -> SimValue<PRegValue> { ) -> SimValue<TraceAsString<PRegValue>> {
#[hdl(sim)] #[hdl(sim)]
let AddSubMOp::<_, _, _> { let AddSubMOp::<_, _, _> {
alu_common, alu_common,
@ -1447,10 +1453,11 @@ trait MockExecutionStateTrait: Default {
let pc_or_zero = if **add_pc { pc } else { 0 }; let pc_or_zero = if **add_pc { pc } else { 0 };
let [src0, src1, src2] = src_values; let [src0, src1, src2] = src_values;
let int_fp = src0 let int_fp = src0
.inner()
.int_fp .int_fp
.as_int() .as_int()
.wrapping_add(src1.int_fp.as_int()) .wrapping_add(src1.inner().int_fp.as_int())
.wrapping_add(src2.int_fp.as_int()) .wrapping_add(src2.inner().int_fp.as_int())
.wrapping_add(SimValue::value(imm).cast_to_static::<UInt<64>>().as_int()) .wrapping_add(SimValue::value(imm).cast_to_static::<UInt<64>>().as_int())
.wrapping_add(pc_or_zero); .wrapping_add(pc_or_zero);
let int_fp = #[hdl(sim)] let int_fp = #[hdl(sim)]
@ -1467,18 +1474,19 @@ trait MockExecutionStateTrait: Default {
OutputIntegerMode::ZeroExt8 => int_fp as u8 as u64, OutputIntegerMode::ZeroExt8 => int_fp as u8 as u64,
OutputIntegerMode::SignExt8 => int_fp as i8 as u64, OutputIntegerMode::SignExt8 => int_fp as i8 as u64,
}; };
#[hdl(sim)] let retval = #[hdl(sim)]
PRegValue { PRegValue {
int_fp, int_fp,
flags: PRegFlags::zeroed_sim(), // TODO: compute flags flags: PRegFlags::zeroed_sim(), // TODO: compute flags
} };
retval.into_trace_as_string()
} }
#[hdl] #[hdl]
fn run_compare<C: PhantomConstCpuConfig, SrcCount: KnownSize>( fn run_compare<C: PhantomConstCpuConfig, SrcCount: KnownSize>(
&mut self, &mut self,
mop: &SimValue<CompareMOp<PRegNum<C>, PRegNum<C>, SrcCount>>, mop: &SimValue<CompareMOp<PRegNum<C>, PRegNum<C>, SrcCount>>,
src_values: &[SimValue<PRegValue>; COMMON_MOP_SRC_LEN], src_values: &[SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN],
) -> SimValue<PRegValue> { ) -> SimValue<TraceAsString<PRegValue>> {
#[hdl(sim)] #[hdl(sim)]
let CompareMOp::<_, _, _> { let CompareMOp::<_, _, _> {
common, common,
@ -1493,13 +1501,16 @@ trait MockExecutionStateTrait: Default {
} = common; } = common;
let (lhs, rhs) = match SrcCount::VALUE { let (lhs, rhs) = match SrcCount::VALUE {
1 => ( 1 => (
src_values[0].int_fp.as_int(), src_values[0].inner().int_fp.as_int(),
SimValue::value(imm).cast_to_static::<UInt<64>>().as_int(), SimValue::value(imm).cast_to_static::<UInt<64>>().as_int(),
), ),
2 => (src_values[0].int_fp.as_int(), src_values[1].int_fp.as_int()), 2 => (
src_values[0].inner().int_fp.as_int(),
src_values[1].inner().int_fp.as_int(),
),
_ => todo!(), _ => todo!(),
}; };
let ordering_to_result = |v: Ordering| -> SimValue<PRegValue> { let ordering_to_result = |v: Ordering| -> SimValue<TraceAsString<PRegValue>> {
let mut retval = #[hdl(sim)] let mut retval = #[hdl(sim)]
PRegValue { PRegValue {
int_fp: 0u64, int_fp: 0u64,
@ -1511,7 +1522,7 @@ trait MockExecutionStateTrait: Default {
Ordering::Equal => **flags.cr_eq = true, Ordering::Equal => **flags.cr_eq = true,
Ordering::Greater => **flags.cr_gt = true, Ordering::Greater => **flags.cr_gt = true,
} }
retval retval.into_trace_as_string()
}; };
#[hdl(sim)] #[hdl(sim)]
match compare_mode { match compare_mode {
@ -1537,10 +1548,10 @@ trait MockExecutionStateTrait: Default {
fallthrough_pc: u64, fallthrough_pc: u64,
predicted_next_pc: u64, predicted_next_pc: u64,
mop: &SimValue<BranchMOp<PRegNum<C>, PRegNum<C>, SrcCount>>, mop: &SimValue<BranchMOp<PRegNum<C>, PRegNum<C>, SrcCount>>,
src_values: &[SimValue<PRegValue>; COMMON_MOP_SRC_LEN], src_values: &[SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN],
config: C, config: C,
) -> ( ) -> (
SimValue<PRegValue>, SimValue<TraceAsString<PRegValue>>,
SimValue<NextPcPredictorOp<C>>, SimValue<NextPcPredictorOp<C>>,
Option<SimValue<UnitCausedCancel<C>>>, Option<SimValue<UnitCausedCancel<C>>>,
) { ) {
@ -1577,7 +1588,7 @@ trait MockExecutionStateTrait: Default {
} else { } else {
true true
}; };
let src0_flags = PRegFlags::view_sim_ref::<PRegFlagsPowerISA>(&src0.flags); let src0_flags = PRegFlags::view_sim_ref::<PRegFlagsPowerISA>(&src0.inner().flags);
let src0_cond = #[hdl(sim)] let src0_cond = #[hdl(sim)]
match src0_cond_mode { match src0_cond_mode {
ConditionMode::Eq => **src0_flags.cr_eq, ConditionMode::Eq => **src0_flags.cr_eq,
@ -1592,6 +1603,7 @@ trait MockExecutionStateTrait: Default {
let src0_cond = src0_cond ^ **invert_src0_cond; let src0_cond = src0_cond ^ **invert_src0_cond;
let pc_or_zero = if **pc_relative { pc } else { 0 }; let pc_or_zero = if **pc_relative { pc } else { 0 };
let target_pc = src1 let target_pc = src1
.inner()
.int_fp .int_fp
.as_int() .as_int()
.wrapping_add(SimValue::value(imm).cast_to_static::<UInt<64>>().as_int()) .wrapping_add(SimValue::value(imm).cast_to_static::<UInt<64>>().as_int())
@ -1615,12 +1627,13 @@ trait MockExecutionStateTrait: Default {
} else { } else {
None None
}; };
let fallthrough_pc_value = #[hdl(sim)]
PRegValue {
int_fp: fallthrough_pc,
flags: PRegFlags::zeroed_sim(),
};
( (
#[hdl(sim)] fallthrough_pc_value.into_trace_as_string(),
PRegValue {
int_fp: fallthrough_pc,
flags: PRegFlags::zeroed_sim(),
},
#[hdl(sim)] #[hdl(sim)]
NextPcPredictorOp::<_> { NextPcPredictorOp::<_> {
call_stack_op: if **is_ret { call_stack_op: if **is_ret {
@ -1649,10 +1662,13 @@ trait MockExecutionStateTrait: Default {
fn run_mop<C: PhantomConstCpuConfig>( fn run_mop<C: PhantomConstCpuConfig>(
&mut self, &mut self,
mop: &SimValue<MOpInstance<RenamedMOp<C>>>, mop: &SimValue<MOpInstance<RenamedMOp<C>>>,
src_values: &[SimValue<PRegValue>; COMMON_MOP_SRC_LEN], src_values: &[SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN],
config: C, config: C,
) -> ( ) -> (
Option<(SimValue<PRegValue>, SimValue<NextPcPredictorOp<C>>)>, Option<(
SimValue<TraceAsString<PRegValue>>,
SimValue<NextPcPredictorOp<C>>,
)>,
Option<SimValue<UnitCausedCancel<C>>>, Option<SimValue<UnitCausedCancel<C>>>,
) { ) {
#[hdl(sim)] #[hdl(sim)]
@ -1680,7 +1696,7 @@ trait MockExecutionStateTrait: Default {
} }
}; };
#[hdl(sim)] #[hdl(sim)]
match mop { match mop.inner() {
UnitMOp::<_, _, _>::AluBranch(mop) => UnitMOp::<_, _, _>::AluBranch(mop) =>
{ {
#[hdl(sim)] #[hdl(sim)]
@ -1780,7 +1796,7 @@ impl MockExecutionStateTrait for () {
#[hdl(no_static)] #[hdl(no_static)]
struct MockUnitOpDebugState<C: PhantomConstGet<CpuConfig>> { struct MockUnitOpDebugState<C: PhantomConstGet<CpuConfig>> {
mop: MOpInstance<RenamedMOp<C>>, mop: MOpInstance<RenamedMOp<C>>,
src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>, src_values: Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>,
sent_cant_cause_cancel: Bool, sent_cant_cause_cancel: Bool,
output_ready: HdlOption<UnitOutputReady<C>>, output_ready: HdlOption<UnitOutputReady<C>>,
caused_cancel: HdlOption<UnitCausedCancel<C>>, caused_cancel: HdlOption<UnitCausedCancel<C>>,
@ -1790,7 +1806,7 @@ struct MockUnitOpDebugState<C: PhantomConstGet<CpuConfig>> {
#[derive(Debug)] #[derive(Debug)]
struct MockUnitOp<C: PhantomConstCpuConfig> { struct MockUnitOp<C: PhantomConstCpuConfig> {
mop: SimValue<MOpInstance<RenamedMOp<C>>>, mop: SimValue<MOpInstance<RenamedMOp<C>>>,
src_values: [SimValue<PRegValue>; COMMON_MOP_SRC_LEN], src_values: [SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN],
sent_cant_cause_cancel: bool, sent_cant_cause_cancel: bool,
output_ready: Option<SimValue<UnitOutputReady<C>>>, output_ready: Option<SimValue<UnitOutputReady<C>>>,
caused_cancel: Option<SimValue<UnitCausedCancel<C>>>, caused_cancel: Option<SimValue<UnitCausedCancel<C>>>,
@ -1999,7 +2015,7 @@ impl<C: PhantomConstCpuConfig, E: MockExecutionStateTrait> MockUnitState<C, E> {
config: _, config: _,
} = inputs_ready; } = inputs_ready;
assert_eq!( assert_eq!(
UnitNum::index_sim(&MOpTrait::dest_reg_sim_ref(&mop.mop).unit_num), UnitNum::index_sim(&MOpTrait::dest_reg_sim_ref(mop.mop.inner()).unit_num),
Some(self.unit_index), Some(self.unit_index),
); );
let mut op = MockUnitOp { let mut op = MockUnitOp {
@ -2225,8 +2241,8 @@ fn mock_unit<#[hdl(skip)] E: MockExecutionStateTrait>(
#[hdl(no_static)] #[hdl(no_static)]
struct MockL2RegFileOpDebugState<C: PhantomConstGet<CpuConfig>> { struct MockL2RegFileOpDebugState<C: PhantomConstGet<CpuConfig>> {
mop: MOpInstance<L2RegisterFileMOp<PRegNum<C>, PRegNum<C>>>, mop: MOpInstance<L2RegisterFileMOp<PRegNum<C>, PRegNum<C>>>,
src_values: HdlOption<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>, src_values: HdlOption<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
dest_value: HdlOption<PRegValue>, dest_value: HdlOption<TraceAsString<PRegValue>>,
sent_cant_cause_cancel: Bool, sent_cant_cause_cancel: Bool,
sent_output_ready: Bool, sent_output_ready: Bool,
config: C, config: C,
@ -2235,8 +2251,8 @@ struct MockL2RegFileOpDebugState<C: PhantomConstGet<CpuConfig>> {
#[derive(Debug)] #[derive(Debug)]
struct MockL2RegFileOp<C: PhantomConstCpuConfig> { struct MockL2RegFileOp<C: PhantomConstCpuConfig> {
mop: SimValue<MOpInstance<L2RegisterFileMOp<PRegNum<C>, PRegNum<C>>>>, mop: SimValue<MOpInstance<L2RegisterFileMOp<PRegNum<C>, PRegNum<C>>>>,
src_values: Option<[SimValue<PRegValue>; COMMON_MOP_SRC_LEN]>, src_values: Option<[SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN]>,
dest_value: Option<SimValue<PRegValue>>, dest_value: Option<SimValue<TraceAsString<PRegValue>>>,
sent_cant_cause_cancel: bool, sent_cant_cause_cancel: bool,
sent_output_ready: bool, sent_output_ready: bool,
config: C, config: C,
@ -2274,13 +2290,13 @@ type L2RegFileSize<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(no_static)] #[hdl(no_static)]
struct MockL2RegFileUnitDebugState<C: PhantomConstGet<CpuConfig>> { struct MockL2RegFileUnitDebugState<C: PhantomConstGet<CpuConfig>> {
ops: ArrayVec<MockL2RegFileOpDebugState<C>, CpuConfigMaxUnitMaxInFlight<C>>, ops: ArrayVec<MockL2RegFileOpDebugState<C>, CpuConfigMaxUnitMaxInFlight<C>>,
l2_regs: ArrayType<PRegValue, L2RegFileSize<C>>, l2_regs: ArrayType<TraceAsString<PRegValue>, L2RegFileSize<C>>,
config: C, config: C,
} }
struct MockL2RegFileUnitState<C: PhantomConstCpuConfig> { struct MockL2RegFileUnitState<C: PhantomConstCpuConfig> {
ops: VecDeque<MockL2RegFileOp<C>>, ops: VecDeque<MockL2RegFileOp<C>>,
l2_regs: Box<[SimValue<PRegValue>]>, l2_regs: Box<[SimValue<TraceAsString<PRegValue>>]>,
config: C, config: C,
} }
@ -2288,7 +2304,8 @@ impl<C: PhantomConstCpuConfig> MockL2RegFileUnitState<C> {
fn new(config: C) -> Self { fn new(config: C) -> Self {
Self { Self {
ops: VecDeque::new(), ops: VecDeque::new(),
l2_regs: vec![PRegValue::zeroed_sim(); L2RegFileSize[config]].into_boxed_slice(), l2_regs: vec![PRegValue::zeroed_sim().into_trace_as_string(); L2RegFileSize[config]]
.into_boxed_slice(),
config, config,
} }
} }
@ -2346,7 +2363,7 @@ impl<C: PhantomConstCpuConfig> MockL2RegFileUnitState<C> {
config: _, config: _,
} = op; } = op;
#[hdl(sim)] #[hdl(sim)]
match &mop.mop { match mop.mop.inner() {
L2RegisterFileMOp::<_, _>::ReadL2Reg(mop) => { L2RegisterFileMOp::<_, _>::ReadL2Reg(mop) => {
#[hdl(sim)] #[hdl(sim)]
let ReadL2RegMOp::<_, _> { common } = mop; let ReadL2RegMOp::<_, _> { common } = mop;
@ -2361,7 +2378,7 @@ impl<C: PhantomConstCpuConfig> MockL2RegFileUnitState<C> {
&& dest_value.is_none() && dest_value.is_none()
{ {
self.l2_regs[L2RegNum::value_sim(&common.imm)] = src_values[0].clone(); self.l2_regs[L2RegNum::value_sim(&common.imm)] = src_values[0].clone();
*dest_value = Some(PRegValue::zeroed_sim()); *dest_value = Some(PRegValue::zeroed_sim().into_trace_as_string());
} }
if dest_value.is_none() { if dest_value.is_none() {
// we can't run following reads yet. // we can't run following reads yet.
@ -2387,7 +2404,7 @@ impl<C: PhantomConstCpuConfig> MockL2RegFileUnitState<C> {
mop, mop,
} = mop; } = mop;
let mop = #[hdl(sim)] let mop = #[hdl(sim)]
match &mop { match mop.inner() {
RenamedMOp::<_>::TransformedMove(mop) => mop, RenamedMOp::<_>::TransformedMove(mop) => mop,
_ => { _ => {
panic!("MockL2RegFileUnitState can only handle L2RegisterFile MOps, got: {mop:#?}"); panic!("MockL2RegFileUnitState can only handle L2RegisterFile MOps, got: {mop:#?}");
@ -2402,7 +2419,7 @@ impl<C: PhantomConstCpuConfig> MockL2RegFileUnitState<C> {
size_in_bytes, size_in_bytes,
is_first_mop_in_insn, is_first_mop_in_insn,
is_last_mop_in_insn, is_last_mop_in_insn,
mop, mop: mop.into_trace_as_string(),
}; };
self.ops.push_back(MockL2RegFileOp { self.ops.push_back(MockL2RegFileOp {
mop, mop,
@ -2767,8 +2784,8 @@ fn mock_l2_reg_file_unit(config: PhantomConst<CpuConfig>, unit_index: usize) {
struct MockLoadStoreOpDebugState<C: PhantomConstGet<CpuConfig>> { struct MockLoadStoreOpDebugState<C: PhantomConstGet<CpuConfig>> {
mop: MOpInstance<LoadStoreMOp<PRegNum<C>, PRegNum<C>>>, mop: MOpInstance<LoadStoreMOp<PRegNum<C>, PRegNum<C>>>,
is_speculative: Bool, is_speculative: Bool,
src_values: HdlOption<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>, src_values: HdlOption<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
dest_value: HdlOption<PRegValue>, dest_value: HdlOption<TraceAsString<PRegValue>>,
ran_nonspeculatively: Bool, ran_nonspeculatively: Bool,
sent_cant_cause_cancel: Bool, sent_cant_cause_cancel: Bool,
sent_output_ready: Bool, sent_output_ready: Bool,
@ -2779,8 +2796,8 @@ struct MockLoadStoreOpDebugState<C: PhantomConstGet<CpuConfig>> {
struct MockLoadStoreOp<C: PhantomConstCpuConfig> { struct MockLoadStoreOp<C: PhantomConstCpuConfig> {
mop: SimValue<MOpInstance<LoadStoreMOp<PRegNum<C>, PRegNum<C>>>>, mop: SimValue<MOpInstance<LoadStoreMOp<PRegNum<C>, PRegNum<C>>>>,
is_speculative: bool, is_speculative: bool,
src_values: Option<[SimValue<PRegValue>; COMMON_MOP_SRC_LEN]>, src_values: Option<[SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN]>,
dest_value: Option<SimValue<PRegValue>>, dest_value: Option<SimValue<TraceAsString<PRegValue>>>,
ran_nonspeculatively: bool, ran_nonspeculatively: bool,
sent_cant_cause_cancel: bool, sent_cant_cause_cancel: bool,
sent_output_ready: bool, sent_output_ready: bool,
@ -2913,7 +2930,7 @@ impl<C: PhantomConstCpuConfig> MockLoadStoreUnitState<C> {
} }
} }
#[hdl(sim)] #[hdl(sim)]
match &mop.mop { match mop.mop.inner() {
LoadStoreMOp::<_, _>::Load(load_mop) => { LoadStoreMOp::<_, _>::Load(load_mop) => {
#[hdl(sim)] #[hdl(sim)]
let LoadMOp::<_, _> { load_store_common } = load_mop; let LoadMOp::<_, _> { load_store_common } = load_mop;
@ -2988,7 +3005,7 @@ impl<C: PhantomConstCpuConfig> MockLoadStoreUnitState<C> {
mop, mop,
} = mop; } = mop;
let mop = #[hdl(sim)] let mop = #[hdl(sim)]
match &mop { match mop.inner() {
RenamedMOp::<_>::LoadStore(mop) => mop, RenamedMOp::<_>::LoadStore(mop) => mop,
_ => panic!("MockLoadStoreUnitState can only handle LoadStore MOps, got: {mop:#?}"), _ => panic!("MockLoadStoreUnitState can only handle LoadStore MOps, got: {mop:#?}"),
}; };
@ -3001,7 +3018,7 @@ impl<C: PhantomConstCpuConfig> MockLoadStoreUnitState<C> {
size_in_bytes, size_in_bytes,
is_first_mop_in_insn, is_first_mop_in_insn,
is_last_mop_in_insn, is_last_mop_in_insn,
mop, mop: mop.into_trace_as_string(),
}; };
self.ops.push_back(MockLoadStoreOp { self.ops.push_back(MockLoadStoreOp {
mop, mop,