diff --git a/Cargo.lock b/Cargo.lock index ade3f36..78eca32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,7 +388,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fayalite" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#226631594458f4137739baf98d2a9cd2c257242e" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#8e4eeef72340f1205ed5d2277dab112cdf352b35" dependencies = [ "base64", "bitvec", @@ -417,7 +417,7 @@ dependencies = [ [[package]] name = "fayalite-proc-macros" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#226631594458f4137739baf98d2a9cd2c257242e" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#8e4eeef72340f1205ed5d2277dab112cdf352b35" dependencies = [ "fayalite-proc-macros-impl", ] @@ -425,7 +425,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#226631594458f4137739baf98d2a9cd2c257242e" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#8e4eeef72340f1205ed5d2277dab112cdf352b35" dependencies = [ "base16ct 0.2.0", "num-bigint", @@ -440,7 +440,7 @@ dependencies = [ [[package]] name = "fayalite-visit-gen" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#226631594458f4137739baf98d2a9cd2c257242e" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#8e4eeef72340f1205ed5d2277dab112cdf352b35" dependencies = [ "indexmap", "prettyplease", diff --git a/crates/cpu/src/fetch.rs b/crates/cpu/src/fetch.rs index a87018d..52e3585 100644 --- a/crates/cpu/src/fetch.rs +++ b/crates/cpu/src/fetch.rs @@ -523,7 +523,7 @@ impl L1ICacheStateSim { kind, read_data, config: _, - } = memory_operation_finish.into_sim_value(); + } = memory_operation_finish; #[hdl(sim)] match kind { MemoryOperationFinishKind::Success(success) => @@ -746,7 +746,7 @@ impl L1ICacheStateSim { let NextPcToFetchInterfaceInner { start_pc, fetch_block_id, - } = fetch.into_sim_value(); + } = fetch; let entry_ty = FetchQueueEntry[config]; self.queue.push_back( #[hdl(sim)] @@ -895,7 +895,7 @@ impl L1ICacheStateSim { let CacheReadData::<_> { cache_line_index: read_cache_line_index, cache_line, - } = cache_read_data.into_sim_value(); + } = cache_read_data; let config = self.config(); for entry in &mut self.queue { #[hdl(sim)] @@ -1151,6 +1151,8 @@ fn l1_i_cache_impl(config: PhantomConst) { sim.wait_for_clock_edge(cd.clk).await; } sim.write(from_next_pc.cancel.ready, true).await; + let memory_interface_start_data_ty = memory_interface.start.data.ty(); + let to_decode_fetched_data_ty = to_decode_fetched.data.ty(); let cache_read_data_ty = CacheReadData[config]; let mut state = L1ICacheStateSim::new(state_expr); loop { @@ -1166,11 +1168,26 @@ fn l1_i_cache_impl(config: PhantomConst) { .await; sim.write( memory_interface.start.data, - state.clone().try_start_memory_operation(), + if let Some(v) = state.clone().try_start_memory_operation() { + #[hdl(sim)] + memory_interface_start_data_ty.HdlSome(v) + } else { + #[hdl(sim)] + memory_interface_start_data_ty.HdlNone() + }, + ) + .await; + sim.write( + to_decode_fetched.data, + if let Some(v) = state.clone().to_decode_fetched() { + #[hdl(sim)] + to_decode_fetched_data_ty.HdlSome(v) + } else { + #[hdl(sim)] + to_decode_fetched_data_ty.HdlNone() + }, ) .await; - sim.write(to_decode_fetched.data, state.clone().to_decode_fetched()) - .await; state.write_debug_state(&mut sim).await; sim.write(max_cancel_in_fetch, state.queue.len()).await; state diff --git a/crates/cpu/src/instruction.rs b/crates/cpu/src/instruction.rs index 969b1ee..e8f2af1 100644 --- a/crates/cpu/src/instruction.rs +++ b/crates/cpu/src/instruction.rs @@ -12,7 +12,7 @@ use fayalite::{ intern::Interned, module::wire_with_loc, prelude::*, - ty::{SimValueDebug, StaticType, TypeProperties}, + ty::{StaticType, TypeProperties}, util::ConstBool, }; use std::{ @@ -86,6 +86,14 @@ pub trait MOpVisitVariants: MOpTrait { VisitOps::Target: MOpTrait; } +pub trait MOpDebug: MOpTrait { + fn mop_debug(this: &SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result; +} + +pub trait MOpImmDebug: Type { + fn mop_imm_debug(this: &SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result; +} + pub trait MOpTrait: Type { type Mapped: MOpTrait; type DestReg: Type; @@ -373,7 +381,7 @@ impl MOpVisitVariants for T { } } -#[hdl(cmp_eq)] +#[hdl] pub enum OutputIntegerMode { Full64, DupLow32, @@ -402,6 +410,40 @@ impl OutputIntegerMode { } } +impl HdlPartialEqImpl for OutputIntegerMode { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned())) + == SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned())) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + pub const MOP_IMM_WIDTH: usize = 34; pub const MOP_MIN_REG_WIDTH: usize = 8; pub const COMMON_MOP_SRC_LEN: usize = 3; @@ -452,12 +494,9 @@ impl fmt::Debug for CommonMOpDefaultImm { } } -impl SimValueDebug for CommonMOpDefaultImm { - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - ::fmt(value, f) +impl MOpImmDebug for CommonMOpDefaultImm { + fn mop_imm_debug(this: &SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(this, f) } } @@ -586,7 +625,7 @@ impl HdlPartialEqImpl for CommonMOpDefaultImm - SimValueDebug for CommonMOp -{ - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - fmt::Display::fmt(&Self::mop_debug(value, true), f) - } -} - impl CommonMOp { @@ -624,11 +652,32 @@ impl= MOP_MIN_REG_WIDTH, "{self:#?}"); } - fn debug_sources( - this: &::SimValue, - is_first: bool, - is_last: bool, - ) -> impl fmt::Display { + fn debug_dest(this: &SimValue) -> impl fmt::Debug { + use std::any::Any; + fmt::from_fn(move |f| { + if let Some(dest) = ::downcast_ref::>(&this.dest) { + f.debug_set() + .entries( + MOpDestReg::regs_sim(dest) + .into_iter() + .filter(|&v| v != MOpRegNum::CONST_ZERO_REG_NUM), + ) + .finish() + } else if let Some(dest) = + ::downcast_ref::>>>(&this.dest) + { + fmt::Debug::fmt(&PRegNum::debug_sim(dest), f) + } else if let Some(dest) = ::downcast_ref::< + SimValue>>, + >(&this.dest) + { + fmt::Debug::fmt(&UnitOutRegNum::debug_sim(dest), f) + } else { + fmt::Debug::fmt(&this.dest, f) + } + }) + } + fn debug_sources(this: &SimValue, is_first: bool, is_last: bool) -> impl fmt::Display { fmt::from_fn(move |f| { let mut need_comma = !is_first; for src in &this.src { @@ -645,12 +694,15 @@ impl::SimValue, debug_imm: bool) -> impl fmt::Display { + fn mop_debug(this: &SimValue, debug_imm: bool) -> impl fmt::Display + where + Imm: MOpImmDebug, + { fmt::from_fn(move |f| { - write!(f, "{:?}", this.dest)?; + fmt::Debug::fmt(&Self::debug_dest(this), f)?; fmt::Display::fmt(&Self::debug_sources(this, false, !debug_imm), f)?; if debug_imm { - fmt::Debug::fmt(&this.imm, f)?; + MOpImmDebug::mop_imm_debug(&this.imm, f)?; } Ok(()) }) @@ -762,7 +814,7 @@ pub const COMMON_MOP_3_IMM_WIDTH: usize = common_mop_max_imm_size(3); macro_rules! common_mop_struct { ( - #[debug($(#[$debug_hdl:ident])? |$debug_value:ident, $debug_f:ident| $debug_block:block $(where $($debug_where:tt)*)?)] + #[debug($(#[$hdl:ident])? |$debug_this:ident, $debug_f:ident| $debug_block:block $(where $($debug_where:tt)*)?)] #[mapped(<$NewDestReg:ident, $SrcRegWidth:ident> $mapped_ty:ty)] $(#[$struct_meta:meta])* $vis:vis struct $MOp:ident<$($Generic:ident: $GenericBound:ident),* $(,)?> { @@ -789,11 +841,11 @@ macro_rules! common_mop_struct { } } - impl<$($Generic: $GenericBound),*> SimValueDebug for $MOp<$($Generic),*> + impl<$($Generic: $GenericBound),*> MOpDebug for $MOp<$($Generic),*> $(where $($debug_where)*)? { - $(#[$debug_hdl])? - fn sim_value_debug($debug_value: &::SimValue, $debug_f: &mut fmt::Formatter<'_>) -> fmt::Result $debug_block + $(#[$hdl])? + fn mop_debug($debug_this: &SimValue, $debug_f: &mut fmt::Formatter<'_>) -> fmt::Result $debug_block } }; ( @@ -907,6 +959,7 @@ macro_rules! common_mop_struct { macro_rules! mop_enum { ( + $(#[debug(where $($debug_where:tt)*)])? #[impl_mop_into = $impl_mop_into:tt] $(#[$enum_meta:meta])* $vis:vis enum $MOp:ident< @@ -975,21 +1028,23 @@ macro_rules! mop_enum { impl< $DestReg: Type, $SrcRegWidth: Size, - $($MOpTypes: Type,)* + $($MOpTypes: Type + MOpTrait,)* $($Sizes: Size,)* - > fayalite::ty::SimValueDebug for $MOp< + > crate::instruction::MOpDebug for $MOp< $DestReg, $SrcRegWidth, $($MOpTypes,)* $($Sizes,)* - > { + > + $(where $($debug_where)*)? + { #[hdl] - fn sim_value_debug(this: &::SimValue, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn mop_debug(this: &SimValue, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { #![allow(unreachable_patterns)] #[hdl(sim)] match this { - Self::$FirstVariant(v) => std::fmt::Debug::fmt(v, f), - $(Self::$Variant(v) => std::fmt::Debug::fmt(v, f),)* + Self::$FirstVariant(v) => <$first_ty as crate::instruction::MOpDebug>::mop_debug(v, f), + $(Self::$Variant(v) => <$ty as crate::instruction::MOpDebug>::mop_debug(v, f),)* _ => std::fmt::Debug::fmt(this, f), } } @@ -1328,7 +1383,7 @@ common_mop_struct! { } } -impl +impl AluCommonMOp { #[hdl] @@ -1386,7 +1441,7 @@ common_mop_struct! { maybe_write_comma_flag!(f, add_pc, **add_pc) })] #[mapped( AddSubMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct AddSubMOp { #[common] pub alu_common: AluCommonMOp>, @@ -1547,7 +1602,7 @@ impl Lut4 { } /// immediate values for [`LogicalFlagsMOp`]. See [`LogicalFlagsMOp`] for a description of the operation. -#[hdl(cmp_eq, custom_debug(sim))] +#[hdl(cmp_eq)] pub struct LogicalFlagsMOpImm { pub src0_start: UIntInRange<0, { PRegFlags::FLAG_COUNT }>, pub src1_start: UIntInRange<0, { PRegFlags::FLAG_COUNT }>, @@ -1556,20 +1611,17 @@ pub struct LogicalFlagsMOpImm { pub dest_count: UIntInRangeInclusive<0, { PRegFlags::FLAG_COUNT }>, } -impl SimValueDebug for LogicalFlagsMOpImm { +impl MOpImmDebug for LogicalFlagsMOpImm { #[hdl] - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - type SimValueT = ::SimValue; - let SimValueT:: { + fn mop_imm_debug(this: &SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result { + #[hdl(sim)] + let Self { src0_start, src1_start, src2_start, dest_start, dest_count, - } = value; + } = this; write!( f, "{{[{dest_start}..][..{dest_count}] <= [{src0_start}..], [{src1_start}..], [{src2_start}..]}}" @@ -1791,7 +1843,7 @@ impl LogicalFlagsMOpImm { src2_start, dest_start, dest_count, - } = this.into_sim_value(); + } = this; Self::flags_operation_impl( src0_start, src1_start, @@ -1966,7 +2018,7 @@ common_mop_struct! { write!(f, "LogicalFlags {common}, {:?}", lut.lut) })] #[mapped( LogicalFlagsMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] /// Operation: /// ``` /// # // set up a bunch of mock types and variables -- they don't necessarily match the real types @@ -2130,7 +2182,7 @@ common_mop_struct! { write!(f, "Logical {alu_common}, {:?}", lut.lut) })] #[mapped( LogicalMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct LogicalMOp { #[common] pub alu_common: AluCommonMOp>, @@ -2202,7 +2254,7 @@ impl LogicalMOp for ShiftRotateMode { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned())) + == SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned())) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + impl ShiftRotateMode { #[hdl] fn debug_str(this: &SimValue) -> &'static str { @@ -2321,7 +2407,7 @@ impl ShiftRotateDestLogicOp { } /// immediate values for [`ShiftRotateMOp`]. -#[hdl(cmp_eq, custom_debug(sim))] +#[hdl(cmp_eq)] pub struct ShiftRotateMOpImm { /// taken from `src2` if this is [`HdlNone`] pub shift_rotate_amount: HdlOption>, @@ -2330,18 +2416,15 @@ pub struct ShiftRotateMOpImm { pub dest_logic_op: HdlOption, } -impl SimValueDebug for ShiftRotateMOpImm { +impl MOpImmDebug for ShiftRotateMOpImm { #[hdl] - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - type SimValueT = ::SimValue; - let SimValueT:: { + fn mop_imm_debug(this: &SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result { + #[hdl(sim)] + let Self { shift_rotate_amount, shift_rotate_right, dest_logic_op, - } = value; + } = this; let shift_op = if **shift_rotate_right { ">>" } else { "<<" }; #[hdl(sim)] match shift_rotate_amount { @@ -2382,7 +2465,7 @@ common_mop_struct! { write!(f, "ShiftRotate {alu_common}, {:?}", ShiftRotateMode::debug_str(mode)) })] #[mapped( ShiftRotateMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct ShiftRotateMOp { #[common] pub alu_common: AluCommonMOp, ShiftRotateMOpImm>, @@ -2422,7 +2505,7 @@ impl ShiftRotateMOp { } } -#[hdl(cmp_eq)] +#[hdl] pub enum CompareMode { U64, S64, @@ -2440,6 +2523,40 @@ pub enum CompareMode { CmpEqB, } +impl HdlPartialEqImpl for CompareMode { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned())) + == SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned())) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + impl CompareMode { #[hdl] fn debug_str(this: &SimValue) -> &'static str { @@ -2472,7 +2589,7 @@ common_mop_struct! { write!(f, "Compare {common}, {}", CompareMode::debug_str(compare_mode)) })] #[mapped( CompareMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct CompareMOp { #[common] pub common: CommonMOp, DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm>, @@ -2535,7 +2652,7 @@ impl CompareMOp for ConditionMode { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned())) + == SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned())) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + impl ConditionMode { #[hdl] fn debug_str(this: &SimValue, inverted: bool) -> &'static str { @@ -2585,7 +2736,7 @@ common_mop_struct! { maybe_write_comma_flag!(f, is_ret, **is_ret) })] #[mapped( BranchMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] /// `src0` is the value used for reading flags from. /// `src1 + imm + if pc_relative { pc } else { 0 }` is the target address. /// `src2` (if present) is the counter to compare against zero. @@ -2741,12 +2892,63 @@ impl BranchMOp for ReadSpecialMOpImm { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned())) + == SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned())) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + +impl MOpImmDebug for ReadSpecialMOpImm { + fn mop_imm_debug(this: &SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(Self::debug_str(this)) + } +} + +impl ReadSpecialMOpImm { + #[hdl] + fn debug_str(this: &SimValue) -> &'static str { + #[hdl(sim)] + match this { + Self::PowerIsaTimeBase => "PowerIsaTimeBase", + Self::PowerIsaTimeBaseU => "PowerIsaTimeBaseU", + } + } +} + common_mop_struct! { #[debug(#[hdl] |this, f| { #[hdl(sim)] @@ -2757,7 +2959,7 @@ common_mop_struct! { write!(f, "ReadSpecial {common}") })] #[mapped( ReadSpecialMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct ReadSpecialMOp { #[common] pub common: CommonMOp, DestReg, SrcRegWidth, ConstUsize<0>, ReadSpecialMOpImm>, @@ -2791,7 +2993,7 @@ impl ReadSpecialMOp { mop_enum! { #[impl_mop_into = true] - #[hdl(custom_debug(sim))] + #[hdl] pub enum AluBranchMOp { AddSub(AddSubMOp>), AddSubI(AddSubMOp>), @@ -2807,7 +3009,7 @@ mop_enum! { } } -#[hdl(custom_debug(sim))] +#[hdl] pub struct L2RegNum { pub value: UInt<{ MOpRegNum::WIDTH }>, } @@ -2826,14 +3028,14 @@ impl L2RegNum { value: u8::try_from(value).expect("value must fit"), } } + pub fn debug_sim(this: &SimValue) -> impl fmt::Debug { + fmt::from_fn(move |f| write!(f, "l2r{:#x}", Self::value_sim(this))) + } } -impl SimValueDebug for L2RegNum { - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(f, "l2r{:#x}", value.value.as_int()) +impl MOpImmDebug for L2RegNum { + fn mop_imm_debug(this: &SimValue, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&Self::debug_sim(this), f) } } @@ -2847,7 +3049,7 @@ common_mop_struct! { write!(f, "ReadL2Reg {common}") })] #[mapped( ReadL2RegMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct ReadL2RegMOp { #[common] pub common: CommonMOp, DestReg, SrcRegWidth, ConstUsize<0>, L2RegNum>, @@ -2889,7 +3091,7 @@ common_mop_struct! { write!(f, "WriteL2Reg {common}") })] #[mapped( WriteL2RegMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct WriteL2RegMOp { #[common] pub common: CommonMOp, DestReg, SrcRegWidth, ConstUsize<1>, L2RegNum>, @@ -2923,7 +3125,7 @@ impl WriteL2RegMOp { mop_enum! { #[impl_mop_into = true] - #[hdl(custom_debug(sim))] + #[hdl] pub enum L2RegisterFileMOp { ReadL2Reg(ReadL2RegMOp), WriteL2Reg(WriteL2RegMOp), @@ -2949,7 +3151,7 @@ where } } -#[hdl(cmp_eq)] +#[hdl] pub enum LoadStoreWidth { Width8Bit, Width16Bit, @@ -2957,13 +3159,81 @@ pub enum LoadStoreWidth { Width64Bit, } -#[hdl(cmp_eq)] +impl HdlPartialEqImpl for LoadStoreWidth { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned())) + == SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned())) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + +#[hdl] pub enum LoadStoreConversion { ZeroExt, SignExt, // TODO(FP): add Power ISA's f32 in f64 format and RISC-V's ones-extension of floating-point } +impl HdlPartialEqImpl for LoadStoreConversion { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned())) + == SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned())) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + common_mop_struct! { #[mapped( LoadStoreCommonMOp)] #[hdl(cmp_eq)] @@ -3039,7 +3309,7 @@ common_mop_struct! { write!(f, "Load {load_store_common}") })] #[mapped( LoadMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct LoadMOp { #[common] pub load_store_common: LoadStoreCommonMOp>, @@ -3087,7 +3357,7 @@ common_mop_struct! { write!(f, "Store {load_store_common}") })] #[mapped( StoreMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] /// does `*src0 = convert(src1)` pub struct StoreMOp { #[common] @@ -3128,7 +3398,7 @@ impl StoreMOp { mop_enum! { #[impl_mop_into = true] - #[hdl(custom_debug(sim))] + #[hdl] pub enum LoadStoreMOp { Load(LoadMOp), Store(StoreMOp), @@ -3145,7 +3415,7 @@ common_mop_struct! { write!(f, "MoveReg {common}") })] #[mapped( MoveRegMOp)] - #[hdl(cmp_eq, custom_debug(sim))] + #[hdl(cmp_eq)] pub struct MoveRegMOp { #[common] pub common: CommonMOp, DestReg, SrcRegWidth, ConstUsize<1>, CommonMOpDefaultImm>>, @@ -3195,7 +3465,7 @@ impl MoveRegMOp { } } -#[hdl(cmp_eq, no_static, custom_debug(sim))] +#[hdl(cmp_eq, no_static)] /// there may be more than one unit of a given kind, so UnitNum is not the same as UnitKind. /// zero is used for built-in constants, such as the zero register pub struct UnitNum> { @@ -3203,30 +3473,6 @@ pub struct UnitNum> { pub config: C, } -impl> SimValueDebug for UnitNum { - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - if let Some(index) = Self::index_sim(value) { - write!(f, "u{index}") - } else { - f.write_str("uz") - } - } -} - -impl> UnitNum { - pub fn index_sim(expr: &::SimValue) -> Option { - let adj_value = expr.adj_value.cast_to_static::>().as_int(); - if adj_value == 0 { - None - } else { - Some(adj_value as usize - 1) - } - } -} - impl UnitNum { pub fn const_zero(self) -> Expr { self.const_zero_sim().to_expr() @@ -3254,6 +3500,14 @@ impl UnitNum { let expr = expr.to_expr(); expr.ty().from_index(index).adj_value.cmp_eq(expr.adj_value) } + pub fn index_sim(expr: &SimValue) -> Option { + let adj_value = expr.adj_value.cast_to_static::>().as_int(); + if adj_value == 0 { + None + } else { + Some(adj_value as usize - 1) + } + } #[hdl] pub fn as_index( expr: impl ToExpr, @@ -3271,32 +3525,25 @@ impl UnitNum { } unit_index } + pub fn debug_sim(this: &SimValue) -> impl fmt::Debug { + fmt::from_fn(move |f| { + if let Some(index) = Self::index_sim(this) { + write!(f, "u{index}") + } else { + f.write_str("uz") + } + }) + } } pub const CONST_ZERO_UNIT_NUM: usize = 0; -#[hdl(cmp_eq, no_static, custom_debug(sim))] +#[hdl(cmp_eq, no_static)] pub struct UnitOutRegNum> { pub value: UIntType>, pub config: C, } -impl> SimValueDebug for UnitOutRegNum { - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - let value = Self::value_sim(value); - write!(f, "or{value:#x}") - } -} - -impl> UnitOutRegNum { - pub fn value_sim(this: &::SimValue) -> usize { - this.value.cast_to_static::>().as_int() as usize - } -} - impl UnitOutRegNum { #[hdl] pub fn new_sim(self, value: usize) -> SimValue { @@ -3306,9 +3553,16 @@ impl UnitOutRegNum { config: self.config, } } + pub fn value_sim(this: &SimValue) -> usize { + this.value.cast_to_static::>().as_int() as usize + } + pub fn debug_sim(this: &SimValue) -> impl fmt::Debug { + let value = Self::value_sim(this); + fmt::from_fn(move |f| write!(f, "or{value:#x}")) + } } -#[hdl(cmp_eq, no_static, custom_debug(sim))] +#[hdl(cmp_eq, no_static)] /// Physical Register Number -- registers in the CPU's backend pub struct PRegNum> { pub unit_num: UnitNum, @@ -3328,20 +3582,27 @@ impl PRegNum { }, } } -} - -impl> SimValueDebug for PRegNum { - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - if let (None, 0) = ( - UnitNum::index_sim(&value.unit_num), - UnitOutRegNum::value_sim(&value.unit_out_reg), - ) { - return f.write_str("pzero"); - } - write!(f, "p{:?}_{:?}", &value.unit_num, &value.unit_out_reg) + #[hdl] + pub fn debug_sim(this: &SimValue) -> impl fmt::Debug { + fmt::from_fn(move |f| { + #[hdl(sim)] + let Self { + unit_num, + unit_out_reg, + } = this; + if let (None, 0) = ( + UnitNum::index_sim(unit_num), + UnitOutRegNum::value_sim(unit_out_reg), + ) { + return f.write_str("pzero"); + } + write!( + f, + "p{:?}_{:?}", + UnitNum::debug_sim(unit_num), + UnitOutRegNum::debug_sim(unit_out_reg), + ) + }) } } @@ -3383,7 +3644,7 @@ impl MOpRegNum { Self::CONST_ZERO_REG_NUM + 1..Self::SPECIAL_REG_NUMS.start; } -#[hdl(cmp_eq, custom_debug(sim))] +#[hdl(cmp_eq)] /// all the registers this instruction will write to, they are all renamed to the same physical register. pub struct MOpDestReg { /// some instructions have multiple destination registers, e.g. x86 div @@ -3395,33 +3656,6 @@ pub struct MOpDestReg { pub flag_regs: Array, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>, } -impl SimValueDebug for MOpDestReg { - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - if f.alternate() { - type SimValueT = ::SimValue; - let SimValueT:: { - normal_regs, - flag_regs, - } = value; - f.debug_struct("MOpDestReg") - .field("normal_regs", normal_regs) - .field("flag_regs", flag_regs) - .finish() - } else { - f.debug_set() - .entries( - Self::regs_sim(value) - .into_iter() - .filter(|&v| v != MOpRegNum::CONST_ZERO_REG_NUM), - ) - .finish() - } - } -} - impl MOpDestReg { #[hdl] #[track_caller] @@ -3656,7 +3890,8 @@ impl MOpDestReg { }) } #[hdl] - pub fn regs_sim(this: &::SimValue) -> [u32; Self::REG_COUNT] { + pub fn regs_sim(this: &SimValue) -> [u32; Self::REG_COUNT] { + let this = this.into_sim_value(); std::array::from_fn(|index| match Self::REG_KINDS[index] { MOpDestRegKind::NormalReg { dest_reg_index } => this.normal_regs[dest_reg_index] .value diff --git a/crates/cpu/src/next_pc.rs b/crates/cpu/src/next_pc.rs index 7a0d063..fcc5286 100644 --- a/crates/cpu/src/next_pc.rs +++ b/crates/cpu/src/next_pc.rs @@ -23,13 +23,14 @@ use crate::{ util::array_vec::ArrayVec, }; use fayalite::{ + expr::HdlPartialEqImpl, int::{UIntInRange, UIntInRangeInclusive, UIntInRangeInclusiveType, UIntInRangeType}, prelude::*, sim::value::SimOnlyValueTrait, ty::StaticType, util::{DebugAsDisplay, ready_valid::ReadyValid}, }; -use std::fmt; +use std::{borrow::Cow, fmt}; pub const FETCH_BLOCK_ID_WIDTH: usize = FetchBlockIdInt::BITS as usize; type FetchBlockIdInt = u8; @@ -52,7 +53,7 @@ pub struct NextPcToFetchInterface> { pub config: C, } -#[hdl(cmp_eq)] +#[hdl] /// WIP version of decoded instruction just good enough to represent stuff needed for [`next_pc()`] /// since the actual instruction definition isn't finalized yet. /// This will be replaced at a later point. @@ -92,6 +93,101 @@ impl WipDecodedInsnKind { } } +// TODO: replace with #[hdl(cmp_eq)] when that's implemented for enums +impl HdlPartialEqImpl for WipDecodedInsnKind { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + *Self::cmp_sim_value_eq( + Cow::Owned(SimValue::from_value(lhs, lhs_value.into_owned())), + Cow::Owned(SimValue::from_value(rhs, rhs_value.into_owned())), + ) + } + + #[hdl] + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + let clear_unused_bits = |v: Cow<'_, SimValue>| { + #[hdl(sim)] + match &*v { + Self::NonBranch => + { + #[hdl(sim)] + Self::NonBranch() + } + Self::Branch(target) => + { + #[hdl(sim)] + Self::Branch(target) + } + Self::BranchCond(target) => + { + #[hdl(sim)] + Self::BranchCond(target) + } + Self::IndirectBranch => + { + #[hdl(sim)] + Self::IndirectBranch() + } + Self::Call(target) => + { + #[hdl(sim)] + Self::Call(target) + } + Self::CallCond(target) => + { + #[hdl(sim)] + Self::CallCond(target) + } + Self::IndirectCall => + { + #[hdl(sim)] + Self::IndirectCall() + } + Self::Ret => + { + #[hdl(sim)] + Self::Ret() + } + Self::RetCond => + { + #[hdl(sim)] + Self::RetCond() + } + Self::Interrupt(target) => + { + #[hdl(sim)] + Self::Interrupt(target) + } + Self::Unknown => v.into_owned(), + } + }; + (SimValue::bits(&clear_unused_bits(lhs)) == SimValue::bits(&clear_unused_bits(rhs))) + .to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + !Self::cmp_sim_value_eq(lhs, rhs) + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + todo!() + } +} + #[hdl(cmp_eq)] /// WIP version of decoded instruction just good enough to represent stuff needed for [`next_pc()`] /// since the actual instruction definition isn't finalized yet. @@ -2685,10 +2781,8 @@ impl SimValueDefault for ArrayType { } impl SimValueDefault for HdlOption { - #[hdl] fn sim_value_default(self) -> SimValue { - #[hdl(sim)] - self.HdlNone() + self.HdlNone().to_sim_value_with_type(self) } } @@ -2817,13 +2911,50 @@ impl ResetSteps for CallStack { } } -#[hdl(cmp_eq)] +#[hdl] enum BTBEntryInsnKind { Branch, Call, Ret, } +// TODO: replace with #[hdl(cmp_eq)] when that's implemented for enums +impl HdlPartialEqImpl for BTBEntryInsnKind { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + *Self::cmp_sim_value_eq( + Cow::Owned(SimValue::from_value(lhs, lhs_value.into_owned())), + Cow::Owned(SimValue::from_value(rhs, rhs_value.into_owned())), + ) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::bits(&*lhs) == SimValue::bits(&*rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::bits(&*lhs) != SimValue::bits(&*rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + impl BTBEntryInsnKind { #[hdl] fn try_from_decoded_insn_kind(kind: &SimValue) -> Option> { @@ -2852,7 +2983,7 @@ impl BTBEntryInsnKind { } } -#[hdl(cmp_eq)] +#[hdl] enum BTBEntryAddrKind { Unconditional, Indirect, @@ -2860,6 +2991,43 @@ enum BTBEntryAddrKind { CondNotTaken, } +// TODO: replace with #[hdl(cmp_eq)] when that's implemented for enums +impl HdlPartialEqImpl for BTBEntryAddrKind { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: Self, + rhs_value: Cow<'_, Self::SimValue>, + ) -> bool { + *Self::cmp_sim_value_eq( + Cow::Owned(SimValue::from_value(lhs, lhs_value.into_owned())), + Cow::Owned(SimValue::from_value(rhs, rhs_value.into_owned())), + ) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::bits(&*lhs) == SimValue::bits(&*rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>, + ) -> SimValue { + (SimValue::bits(&*lhs) != SimValue::bits(&*rhs)).to_sim_value() + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr) -> Expr { + lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) + } +} + impl BTBEntryAddrKind { #[hdl] fn taken(this: &SimValue) -> bool { diff --git a/crates/cpu/src/rename_execute_retire.rs b/crates/cpu/src/rename_execute_retire.rs index fe7b7db..602d113 100644 --- a/crates/cpu/src/rename_execute_retire.rs +++ b/crates/cpu/src/rename_execute_retire.rs @@ -10,8 +10,8 @@ use crate::{ CpuConfigRobSize, CpuConfigUnitCount, PhantomConstCpuConfig, TwiceCpuConfigFetchWidth, }, instruction::{ - COMMON_MOP_SRC_LEN, L2RegNum, L2RegisterFileMOp, MOp, MOpDestReg, MOpRegNum, MOpTrait, - PRegNum, ReadL2RegMOp, UnitNum, UnitOutRegNum, + COMMON_MOP_SRC_LEN, L2RegNum, L2RegisterFileMOp, MOp, MOpDebug, MOpDestReg, MOpRegNum, + MOpTrait, PRegNum, ReadL2RegMOp, UnitNum, UnitOutRegNum, }, next_pc::{CallStackOp, SimValueDefault}, register::PRegValue, @@ -22,7 +22,7 @@ use crate::{ use fayalite::{ int::UIntInRangeInclusiveType, prelude::*, - ty::{OpaqueSimValue, SimValueDebug, StaticType}, + ty::{OpaqueSimValue, StaticType}, util::ready_valid::ReadyValid, }; use std::{collections::VecDeque, fmt, mem, num::NonZero}; @@ -33,7 +33,7 @@ pub const MOP_ID_WIDTH: usize = 16; #[hdl] pub type MOpId = UInt<{ MOP_ID_WIDTH }>; -#[hdl(custom_debug(sim))] +#[hdl] /// A µOp along with the state needed for this instance of the µOp. pub struct MOpInstance { pub fetch_block_id: UInt<8>, @@ -50,29 +50,6 @@ pub struct MOpInstance { pub mop: MOp, } -impl SimValueDebug for MOpInstance { - #[hdl] - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - #[hdl(sim)] - let Self { - fetch_block_id, - id, - pc, - predicted_next_pc, - size_in_bytes, - is_first_mop_in_insn, - mop, - } = value; - write!( - f, - "fid={fetch_block_id:?} id={id:?} pc={pc:?} pn_pc={predicted_next_pc:?} sz={size_in_bytes:?} first={is_first_mop_in_insn}: {mop:?}" - ) - } -} - #[hdl(no_static)] /// TODO: merge with [`crate::next_pc::PostDecodeOutputInterface`] pub struct PostDecodeOutputInterface> { @@ -256,6 +233,16 @@ impl RenameTableEntry { #[hdl(sim)] self.L1(self.L1.const_zero()) } + #[hdl] + fn debug_sim(this: &SimValue) -> impl fmt::Debug { + fmt::from_fn(move |f| { + #[hdl(sim)] + match this { + Self::L1(v) => write!(f, "L1({:?})", PRegNum::debug_sim(v)), + Self::L2(v) => write!(f, "L2({:?})", L2RegNum::debug_sim(v)), + } + }) + } } /// make arrays dynamically-sized to avoid putting large types on the stack @@ -333,7 +320,10 @@ impl RenameTable { // writing to const zero reg does nothing return; } - println!("{rename_table_name}: Write: {unrenamed_reg_num:#x} <- {new:?}"); + println!( + "{rename_table_name}: Write: {unrenamed_reg_num:#x} <- {:?}", + RenameTableEntry::debug_sim(new), + ); self.entries[*unrenamed_reg_num as usize] = new.clone(); } RenameTableUpdate::UpdateForReadL2Reg { dest, src } => { @@ -346,8 +336,9 @@ impl RenameTable { RenameTableEntry::<_>::L2(l2) => { if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) { println!( - "{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \ - updating from {entry:?} to {new:?}", + "{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} updating from {:?} to {:?}", + RenameTableEntry::debug_sim(&entry), + RenameTableEntry::debug_sim(&new), ); *entry = new.clone(); } @@ -364,8 +355,9 @@ impl RenameTable { RenameTableEntry::<_>::L1(l1) => { if l1 == src { println!( - "{rename_table_name}: UpdateForWriteL2Reg: {unrenamed_reg_num:#x} \ - updating from {entry:?} to {new:?}", + "{rename_table_name}: UpdateForWriteL2Reg: {unrenamed_reg_num:#x} updating from {:?} to {:?}", + RenameTableEntry::debug_sim(&entry), + RenameTableEntry::debug_sim(&new), ); *entry = new.clone(); } @@ -643,8 +635,20 @@ impl RobEntry { mop, mop_in_unit_state: SimOnlyValue::new(*mop_in_unit_state), is_speculative, - finished: finished.into_sim_value_with_type(ret_ty.finished), - caused_cancel: caused_cancel.into_sim_value_with_type(ret_ty.caused_cancel), + finished: if let Some(finished) = finished { + #[hdl(sim)] + (ret_ty.finished).HdlSome(finished) + } else { + #[hdl(sim)] + (ret_ty.finished).HdlNone() + }, + caused_cancel: if let Some(caused_cancel) = caused_cancel { + #[hdl(sim)] + (ret_ty.caused_cancel).HdlSome(caused_cancel) + } else { + #[hdl(sim)] + (ret_ty.caused_cancel).HdlNone() + }, } } } @@ -809,7 +813,13 @@ impl ReorderBuffer { entries.iter().map(RobEntries::debug_state), ) .expect("known to fit"), - incomplete_back_entry: incomplete_back_entry.as_ref().map(|v| v.debug_state()), + incomplete_back_entry: if let Some(incomplete_back_entry) = incomplete_back_entry { + #[hdl(sim)] + HdlSome(incomplete_back_entry.debug_state()) + } else { + #[hdl(sim)] + HdlNone() + }, renamed: ty .renamed .from_iter_sim( @@ -1026,15 +1036,15 @@ impl RenameExecuteRetireState { } write!( f, - ": {:#x}{}: {:?}", + ": {:#x}{}: ", rob.mop.pc.as_int(), if *rob.mop.is_first_mop_in_insn { "" } else { ".." }, - rob.mop.mop, - ) + )?; + MOpDebug::mop_debug(&rob.mop.mop, f) }) .to_string(); // TODO @@ -1075,7 +1085,18 @@ impl RenameExecuteRetireState { l1_reg_file: SimValue::from_array_elements( state_for_debug.ty().l1_reg_file, l1_reg_file.iter().map(|v| { - SimValue::from_array_elements(state_for_debug.ty().l1_reg_file.element(), v) + SimValue::from_array_elements( + state_for_debug.ty().l1_reg_file.element(), + v.iter().map(|v| { + if let Some(v) = v { + #[hdl(sim)] + HdlSome(v) + } else { + #[hdl(sim)] + HdlNone() + } + }), + ) }), ), per_insn_timeline: self.per_insn_timeline(), @@ -1228,7 +1249,10 @@ impl RenameExecuteRetireState { }); let [src_reg] = src_regs; let renamed_reg = self.rename_table.entries[src_reg as usize].clone(); - println!("moving from {src_reg:#x} renamed: {renamed_reg:?}"); + println!( + "moving from {src_reg:#x} renamed: {:?}", + RenameTableEntry::debug_sim(&renamed_reg), + ); let unrenamed_dest_regs = MOpDestReg::regs_sim(MOpTrait::dest_reg_sim_ref(move_reg_mop)); assert!(self.rob.incomplete_back_entry.is_none()); @@ -1326,7 +1350,10 @@ impl RenameExecuteRetireState { CpuConfigPRegNumWidth[self.config], &mut |src_reg, index| { let renamed = &self.rename_table.entries[src_reg.as_int() as usize]; - println!("renaming src[{index}] from {src_reg:?} to {renamed:?}"); + println!( + "renaming src[{index}] from {src_reg:?} to {:?}", + RenameTableEntry::debug_sim(renamed), + ); #[hdl(sim)] match renamed { RenameTableEntry::<_>::L1(v) => v.cast_to_bits(), diff --git a/crates/cpu/src/rename_execute_retire/to_unit_interfaces.rs b/crates/cpu/src/rename_execute_retire/to_unit_interfaces.rs index d3ec39a..2709083 100644 --- a/crates/cpu/src/rename_execute_retire/to_unit_interfaces.rs +++ b/crates/cpu/src/rename_execute_retire/to_unit_interfaces.rs @@ -7,10 +7,7 @@ use fayalite::{ expr::ops::FieldAccess, intern::{Intern, Interned, Memoize}, prelude::*, - ty::{ - OpaqueSimValue, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, - SimValueDebug, - }, + ty::{OpaqueSimValue, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten}, }; use std::{fmt, marker::PhantomData, ops::Index}; @@ -119,15 +116,6 @@ impl> Index for ExecuteToUnitInterfacesW } } -impl> SimValueDebug for ExecuteToUnitInterfaces { - fn sim_value_debug( - value: &::SimValue, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - fmt::Debug::fmt(value, f) - } -} - impl> Type for ExecuteToUnitInterfaces { type BaseType = Bundle; type MaskType = Bundle; diff --git a/crates/cpu/src/unit.rs b/crates/cpu/src/unit.rs index 79f03bf..e249b38 100644 --- a/crates/cpu/src/unit.rs +++ b/crates/cpu/src/unit.rs @@ -26,7 +26,7 @@ macro_rules! all_units { ( #[hdl_unit_kind = $HdlUnitKind:ident] #[unit_kind = $UnitKind:ident] - #[hdl(custom_debug(sim))] + #[hdl] $(#[$enum_meta:meta])* $vis:vis enum $UnitMOpEnum:ident<$DestReg:ident: Type, $SrcRegWidth:ident: Size, #[MOp(get_ty = $transformed_move_op_get_ty:expr)] $TransformedMoveOp:ident: Type> { $( @@ -82,8 +82,9 @@ macro_rules! all_units { } mop_enum! { + #[debug(where $TransformedMoveOp: crate::instruction::MOpDebug)] #[impl_mop_into = false] - #[hdl(custom_debug(sim))] + #[hdl] $(#[$enum_meta])* $vis enum $UnitMOpEnum< $DestReg: Type, @@ -321,7 +322,7 @@ macro_rules! all_units { all_units! { #[hdl_unit_kind = HdlUnitKind] #[unit_kind = UnitKind] - #[hdl(custom_debug(sim))] + #[hdl] pub enum UnitMOp< DestReg: Type, SrcRegWidth: Size, diff --git a/crates/cpu/tests/next_pc.rs b/crates/cpu/tests/next_pc.rs index 2046a26..e17a8bd 100644 --- a/crates/cpu/tests/next_pc.rs +++ b/crates/cpu/tests/next_pc.rs @@ -1163,7 +1163,13 @@ impl MockExecuteState { id: &insn.id, next_pc, call_stack_op: mock_insn.call_stack_op(pc), - cond_br_taken, + cond_br_taken: if let Some(cond_br_taken) = cond_br_taken { + #[hdl(sim)] + HdlSome(cond_br_taken) + } else { + #[hdl(sim)] + HdlNone() + }, config: self.config, }, ) diff --git a/crates/cpu/tests/rename_execute_retire.rs b/crates/cpu/tests/rename_execute_retire.rs index 3a02f22..fb4b14b 100644 --- a/crates/cpu/tests/rename_execute_retire.rs +++ b/crates/cpu/tests/rename_execute_retire.rs @@ -9,8 +9,8 @@ use cpu::{ instruction::{ AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp, CompareMOp, CompareMode, ConditionMode, L2RegisterFileMOp, LoadMOp, LoadStoreCommonMOp, - LoadStoreConversion, LoadStoreMOp, LoadStoreWidth, MOp, MOpDestReg, MOpRegNum, MOpTrait, - MoveRegMOp, OutputIntegerMode, PRegNum, StoreMOp, UnitNum, + LoadStoreConversion, LoadStoreMOp, LoadStoreWidth, MOp, MOpDebug, MOpDestReg, MOpRegNum, + MOpTrait, MoveRegMOp, OutputIntegerMode, PRegNum, StoreMOp, UnitNum, }, next_pc::CallStackOp, register::{PRegFlags, PRegFlagsPowerISA, PRegValue}, @@ -1817,8 +1817,20 @@ impl MockUnitOp { mop, src_values, sent_cant_cause_cancel, - output_ready: output_ready.into_sim_value_with_type(output_ready_ty), - caused_cancel: caused_cancel.into_sim_value_with_type(caused_cancel_ty), + output_ready: if let Some(output_ready) = output_ready { + #[hdl(sim)] + output_ready_ty.HdlSome(output_ready) + } else { + #[hdl(sim)] + output_ready_ty.HdlNone() + }, + caused_cancel: if let Some(caused_cancel) = caused_cancel { + #[hdl(sim)] + caused_cancel_ty.HdlSome(caused_cancel) + } else { + #[hdl(sim)] + caused_cancel_ty.HdlNone() + }, config, } } @@ -1830,7 +1842,11 @@ impl MockUnitOp { let (output, caused_cancel) = execution_state.run_mop(&self.mop, &self.src_values, self.config); assert!(output.is_some() || caused_cancel.is_some()); - println!("try_run: {:#x}: {:?}", self.mop.pc.as_int(), self.mop.mop); + println!( + "try_run: {:#x}: {}", + self.mop.pc.as_int(), + fmt::from_fn(|f| MOpDebug::mop_debug(&self.mop.mop, f)), + ); println!( "<- {:?}", self.src_values @@ -1969,8 +1985,20 @@ impl MockUnitState { if op.output_ready.is_none() && op.caused_cancel.is_none() { continue; } - let output_ready = op.output_ready.to_sim_value_with_type(output_ready_ty); - let caused_cancel = op.caused_cancel.to_sim_value_with_type(caused_cancel_ty); + let output_ready = if let Some(output_ready) = &op.output_ready { + #[hdl(sim)] + output_ready_ty.HdlSome(output_ready) + } else { + #[hdl(sim)] + output_ready_ty.HdlNone() + }; + let caused_cancel = if let Some(caused_cancel) = &op.caused_cancel { + #[hdl(sim)] + caused_cancel_ty.HdlSome(caused_cancel) + } else { + #[hdl(sim)] + caused_cancel_ty.HdlNone() + }; // TODO: add delay return ( output_ready, @@ -2273,8 +2301,20 @@ impl MockLoadStoreOp { MockLoadStoreOpDebugState::<_> { mop, is_speculative, - src_values, - dest_value, + src_values: if let Some(v) = src_values { + #[hdl(sim)] + HdlSome(v) + } else { + #[hdl(sim)] + HdlNone() + }, + dest_value: if let Some(v) = dest_value { + #[hdl(sim)] + HdlSome(v) + } else { + #[hdl(sim)] + HdlNone() + }, ran_nonspeculatively, sent_cant_cause_cancel, sent_output_ready, diff --git a/crates/cpu/tests/simple_power_isa_decoder/main.rs b/crates/cpu/tests/simple_power_isa_decoder/main.rs index a345f44..9fa5d3c 100644 --- a/crates/cpu/tests/simple_power_isa_decoder/main.rs +++ b/crates/cpu/tests/simple_power_isa_decoder/main.rs @@ -152,7 +152,16 @@ fn test_decode_insn() { } in test_cases::test_cases() { sim.write(sim.io().first_input, first_input); - sim.write(sim.io().second_input, second_input); + sim.write( + sim.io().second_input, + if let Some(v) = second_input { + #[hdl(sim)] + HdlSome(v) + } else { + #[hdl(sim)] + HdlNone() + }, + ); sim.advance_time(SimDuration::from_micros(1)); let second_input_used = sim.read_bool(sim.io().second_input_used); let is_illegal = sim.read_bool(sim.io().is_illegal); diff --git a/crates/cpu/tests/simple_power_isa_decoder/test_cases/fixed_point_rotate_and_shift.rs b/crates/cpu/tests/simple_power_isa_decoder/test_cases/fixed_point_rotate_and_shift.rs index 6195154..29f84b4 100644 --- a/crates/cpu/tests/simple_power_isa_decoder/test_cases/fixed_point_rotate_and_shift.rs +++ b/crates/cpu/tests/simple_power_isa_decoder/test_cases/fixed_point_rotate_and_shift.rs @@ -30,7 +30,13 @@ fn rotate_imm( ) -> SimValue { #[hdl(sim)] ShiftRotateMOpImm { - shift_rotate_amount: amount.map(|amount| amount.cast_to_static::>()), + shift_rotate_amount: if let Some(amount) = amount { + #[hdl(sim)] + HdlSome(amount.cast_to_static::>()) + } else { + #[hdl(sim)] + HdlNone() + }, shift_rotate_right: false, dest_logic_op: if let Some((rotated_output_start, rotated_output_len)) = rotated_output_start_and_len