forked from libre-chip/cpu
Compare commits
1 commit
83b3f7bac9
...
ac99caa3b6
| Author | SHA1 | Date | |
|---|---|---|---|
| ac99caa3b6 |
11 changed files with 755 additions and 258 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ impl<C: PhantomConstCpuConfig> L1ICacheStateSim<C> {
|
|||
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<C: PhantomConstCpuConfig> L1ICacheStateSim<C> {
|
|||
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<C: PhantomConstCpuConfig> L1ICacheStateSim<C> {
|
|||
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<CpuConfig>) {
|
|||
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<CpuConfig>) {
|
|||
.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
|
||||
|
|
|
|||
|
|
@ -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<DestReg = Self::DestReg, SrcRegWidth = Self::SrcRegWidth>;
|
||||
}
|
||||
|
||||
pub trait MOpDebug: MOpTrait {
|
||||
fn mop_debug(this: &SimValue<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
|
||||
}
|
||||
|
||||
pub trait MOpImmDebug: Type {
|
||||
fn mop_imm_debug(this: &SimValue<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
|
||||
}
|
||||
|
||||
pub trait MOpTrait: Type {
|
||||
type Mapped<NewDestReg: Type, NewSrcRegWidth: Size>: MOpTrait<DestReg = NewDestReg, SrcRegWidth = NewSrcRegWidth>;
|
||||
type DestReg: Type;
|
||||
|
|
@ -373,7 +381,7 @@ impl<T: CommonMOpTrait> MOpVisitVariants for T {
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
#[hdl]
|
||||
pub enum OutputIntegerMode {
|
||||
Full64,
|
||||
DupLow32,
|
||||
|
|
@ -402,6 +410,40 @@ impl OutputIntegerMode {
|
|||
}
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
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<SrcCount: KnownSize> fmt::Debug for CommonMOpDefaultImm<SrcCount> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<SrcCount: KnownSize> SimValueDebug for CommonMOpDefaultImm<SrcCount> {
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::SimValue,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
<SIntValue as fmt::Display>::fmt(value, f)
|
||||
impl<SrcCount: KnownSize> MOpImmDebug for CommonMOpDefaultImm<SrcCount> {
|
||||
fn mop_imm_debug(this: &SimValue<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
<SIntValue as fmt::Display>::fmt(this, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -586,7 +625,7 @@ impl<SrcCount: KnownSize> HdlPartialEqImpl<Self> for CommonMOpDefaultImm<SrcCoun
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct CommonMOp<
|
||||
PrefixPad: KnownSize,
|
||||
DestReg: Type,
|
||||
|
|
@ -600,17 +639,6 @@ pub struct CommonMOp<
|
|||
pub imm: Imm,
|
||||
}
|
||||
|
||||
impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize, Imm: Type>
|
||||
SimValueDebug for CommonMOp<PrefixPad, DestReg, SrcRegWidth, SrcCount, Imm>
|
||||
{
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::SimValue,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
fmt::Display::fmt(&Self::mop_debug(value, true), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize, Imm: Type>
|
||||
CommonMOp<PrefixPad, DestReg, SrcRegWidth, SrcCount, Imm>
|
||||
{
|
||||
|
|
@ -624,11 +652,32 @@ impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize
|
|||
// we should probably add padding to `CommonMOp` after `src` to compensate
|
||||
// assert!(self.src.element().width() >= MOP_MIN_REG_WIDTH, "{self:#?}");
|
||||
}
|
||||
fn debug_sources(
|
||||
this: &<Self as Type>::SimValue,
|
||||
is_first: bool,
|
||||
is_last: bool,
|
||||
) -> impl fmt::Display {
|
||||
fn debug_dest(this: &SimValue<Self>) -> impl fmt::Debug {
|
||||
use std::any::Any;
|
||||
fmt::from_fn(move |f| {
|
||||
if let Some(dest) = <dyn Any>::downcast_ref::<SimValue<MOpDestReg>>(&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) =
|
||||
<dyn Any>::downcast_ref::<SimValue<PRegNum<PhantomConst<CpuConfig>>>>(&this.dest)
|
||||
{
|
||||
fmt::Debug::fmt(&PRegNum::debug_sim(dest), f)
|
||||
} else if let Some(dest) = <dyn Any>::downcast_ref::<
|
||||
SimValue<UnitOutRegNum<PhantomConst<CpuConfig>>>,
|
||||
>(&this.dest)
|
||||
{
|
||||
fmt::Debug::fmt(&UnitOutRegNum::debug_sim(dest), f)
|
||||
} else {
|
||||
fmt::Debug::fmt(&this.dest, f)
|
||||
}
|
||||
})
|
||||
}
|
||||
fn debug_sources(this: &SimValue<Self>, 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<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize
|
|||
}
|
||||
})
|
||||
}
|
||||
fn mop_debug(this: &<Self as Type>::SimValue, debug_imm: bool) -> impl fmt::Display {
|
||||
fn mop_debug(this: &SimValue<Self>, 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: &<Self as Type>::SimValue, $debug_f: &mut fmt::Formatter<'_>) -> fmt::Result $debug_block
|
||||
$(#[$hdl])?
|
||||
fn mop_debug($debug_this: &SimValue<Self>, $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<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,)*
|
||||
$($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: &<Self as Type>::SimValue, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn mop_debug(this: &SimValue<Self>, 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<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize, Imm: Type>
|
||||
impl<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize, Imm: MOpImmDebug>
|
||||
AluCommonMOp<DestReg, SrcRegWidth, SrcCount, Imm>
|
||||
{
|
||||
#[hdl]
|
||||
|
|
@ -1386,7 +1441,7 @@ common_mop_struct! {
|
|||
maybe_write_comma_flag!(f, add_pc, **add_pc)
|
||||
})]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> AddSubMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct AddSubMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm<SrcCount>>,
|
||||
|
|
@ -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: &<Self as Type>::SimValue,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
type SimValueT<T> = <T as Type>::SimValue;
|
||||
let SimValueT::<Self> {
|
||||
fn mop_imm_debug(this: &SimValue<Self>, 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(<NewDestReg, NewSrcRegWidth> LogicalFlagsMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[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(<NewDestReg, NewSrcRegWidth> LogicalMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct LogicalMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm<SrcCount>>,
|
||||
|
|
@ -2202,7 +2254,7 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsi
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
#[hdl]
|
||||
pub enum ShiftRotateMode {
|
||||
/// like `llvm.fsh[lr].i8(src0, src1, shift_rotate_amount.unwrap_or(src2))`
|
||||
FunnelShift2x8Bit,
|
||||
|
|
@ -2222,6 +2274,40 @@ pub enum ShiftRotateMode {
|
|||
ShiftSigned64,
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl ShiftRotateMode {
|
||||
#[hdl]
|
||||
fn debug_str(this: &SimValue<Self>) -> &'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<UInt<6>>,
|
||||
|
|
@ -2330,18 +2416,15 @@ pub struct ShiftRotateMOpImm {
|
|||
pub dest_logic_op: HdlOption<ShiftRotateDestLogicOp>,
|
||||
}
|
||||
|
||||
impl SimValueDebug for ShiftRotateMOpImm {
|
||||
impl MOpImmDebug for ShiftRotateMOpImm {
|
||||
#[hdl]
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::SimValue,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
type SimValueT<T> = <T as Type>::SimValue;
|
||||
let SimValueT::<Self> {
|
||||
fn mop_imm_debug(this: &SimValue<Self>, 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(<NewDestReg, NewSrcRegWidth> ShiftRotateMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct ShiftRotateMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<3>, ShiftRotateMOpImm>,
|
||||
|
|
@ -2422,7 +2505,7 @@ impl<DestReg: Type, SrcRegWidth: Size> ShiftRotateMOp<DestReg, SrcRegWidth> {
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
#[hdl]
|
||||
pub enum CompareMode {
|
||||
U64,
|
||||
S64,
|
||||
|
|
@ -2440,6 +2523,40 @@ pub enum CompareMode {
|
|||
CmpEqB,
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl CompareMode {
|
||||
#[hdl]
|
||||
fn debug_str(this: &SimValue<Self>) -> &'static str {
|
||||
|
|
@ -2472,7 +2589,7 @@ common_mop_struct! {
|
|||
write!(f, "Compare {common}, {}", CompareMode::debug_str(compare_mode))
|
||||
})]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> CompareMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct CompareMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm<SrcCount>>,
|
||||
|
|
@ -2535,7 +2652,7 @@ impl<DestReg: Type, SrcRegWidth: Size> CompareMOp<DestReg, SrcRegWidth, ConstUsi
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
#[hdl]
|
||||
pub enum ConditionMode {
|
||||
Eq,
|
||||
ULt,
|
||||
|
|
@ -2547,6 +2664,40 @@ pub enum ConditionMode {
|
|||
Parity,
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl ConditionMode {
|
||||
#[hdl]
|
||||
fn debug_str(this: &SimValue<Self>, inverted: bool) -> &'static str {
|
||||
|
|
@ -2585,7 +2736,7 @@ common_mop_struct! {
|
|||
maybe_write_comma_flag!(f, is_ret, **is_ret)
|
||||
})]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[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<DestReg: Type, SrcRegWidth: Size> BranchMOp<DestReg, SrcRegWidth, ConstUsiz
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
#[hdl]
|
||||
pub enum ReadSpecialMOpImm {
|
||||
PowerIsaTimeBase,
|
||||
PowerIsaTimeBaseU,
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl MOpImmDebug for ReadSpecialMOpImm {
|
||||
fn mop_imm_debug(this: &SimValue<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(Self::debug_str(this))
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadSpecialMOpImm {
|
||||
#[hdl]
|
||||
fn debug_str(this: &SimValue<Self>) -> &'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(<NewDestReg, NewSrcRegWidth> ReadSpecialMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct ReadSpecialMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, ConstUsize<0>, ReadSpecialMOpImm>,
|
||||
|
|
@ -2791,7 +2993,7 @@ impl<DestReg: Type, SrcRegWidth: Size> ReadSpecialMOp<DestReg, SrcRegWidth> {
|
|||
|
||||
mop_enum! {
|
||||
#[impl_mop_into = true]
|
||||
#[hdl(custom_debug(sim))]
|
||||
#[hdl]
|
||||
pub enum AluBranchMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
AddSub(AddSubMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
|
||||
AddSubI(AddSubMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||
|
|
@ -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<Self>) -> 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: &<Self as Type>::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<Self>, 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(<NewDestReg, NewSrcRegWidth> ReadL2RegMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct ReadL2RegMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, ConstUsize<0>, L2RegNum>,
|
||||
|
|
@ -2889,7 +3091,7 @@ common_mop_struct! {
|
|||
write!(f, "WriteL2Reg {common}")
|
||||
})]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> WriteL2RegMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct WriteL2RegMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, ConstUsize<1>, L2RegNum>,
|
||||
|
|
@ -2923,7 +3125,7 @@ impl<DestReg: Type, SrcRegWidth: Size> WriteL2RegMOp<DestReg, SrcRegWidth> {
|
|||
|
||||
mop_enum! {
|
||||
#[impl_mop_into = true]
|
||||
#[hdl(custom_debug(sim))]
|
||||
#[hdl]
|
||||
pub enum L2RegisterFileMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
ReadL2Reg(ReadL2RegMOp<DestReg, SrcRegWidth>),
|
||||
WriteL2Reg(WriteL2RegMOp<DestReg, SrcRegWidth>),
|
||||
|
|
@ -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<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
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<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> LoadStoreCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl(cmp_eq)]
|
||||
|
|
@ -3039,7 +3309,7 @@ common_mop_struct! {
|
|||
write!(f, "Load {load_store_common}")
|
||||
})]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> LoadMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct LoadMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<1>>,
|
||||
|
|
@ -3087,7 +3357,7 @@ common_mop_struct! {
|
|||
write!(f, "Store {load_store_common}")
|
||||
})]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> StoreMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
/// does `*src0 = convert(src1)`
|
||||
pub struct StoreMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
|
|
@ -3128,7 +3398,7 @@ impl<DestReg: Type, SrcRegWidth: Size> StoreMOp<DestReg, SrcRegWidth> {
|
|||
|
||||
mop_enum! {
|
||||
#[impl_mop_into = true]
|
||||
#[hdl(custom_debug(sim))]
|
||||
#[hdl]
|
||||
pub enum LoadStoreMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
Load(LoadMOp<DestReg, SrcRegWidth>),
|
||||
Store(StoreMOp<DestReg, SrcRegWidth>),
|
||||
|
|
@ -3145,7 +3415,7 @@ common_mop_struct! {
|
|||
write!(f, "MoveReg {common}")
|
||||
})]
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> MoveRegMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct MoveRegMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<4>, DestReg, SrcRegWidth, ConstUsize<1>, CommonMOpDefaultImm<ConstUsize<1>>>,
|
||||
|
|
@ -3195,7 +3465,7 @@ impl<DestReg: Type, SrcRegWidth: Size> MoveRegMOp<DestReg, SrcRegWidth> {
|
|||
}
|
||||
}
|
||||
|
||||
#[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<C: PhantomConstGet<CpuConfig>> {
|
||||
|
|
@ -3203,30 +3473,6 @@ pub struct UnitNum<C: PhantomConstGet<CpuConfig>> {
|
|||
pub config: C,
|
||||
}
|
||||
|
||||
impl<C: Type + PhantomConstGet<CpuConfig>> SimValueDebug for UnitNum<C> {
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::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<C: Type + PhantomConstGet<CpuConfig>> UnitNum<C> {
|
||||
pub fn index_sim(expr: &<Self as Type>::SimValue) -> Option<usize> {
|
||||
let adj_value = expr.adj_value.cast_to_static::<UInt<32>>().as_int();
|
||||
if adj_value == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(adj_value as usize - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PhantomConstCpuConfig> UnitNum<C> {
|
||||
pub fn const_zero(self) -> Expr<Self> {
|
||||
self.const_zero_sim().to_expr()
|
||||
|
|
@ -3254,6 +3500,14 @@ impl<C: PhantomConstCpuConfig> UnitNum<C> {
|
|||
let expr = expr.to_expr();
|
||||
expr.ty().from_index(index).adj_value.cmp_eq(expr.adj_value)
|
||||
}
|
||||
pub fn index_sim(expr: &SimValue<Self>) -> Option<usize> {
|
||||
let adj_value = expr.adj_value.cast_to_static::<UInt<32>>().as_int();
|
||||
if adj_value == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(adj_value as usize - 1)
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
pub fn as_index(
|
||||
expr: impl ToExpr<Type = Self>,
|
||||
|
|
@ -3271,32 +3525,25 @@ impl<C: PhantomConstCpuConfig> UnitNum<C> {
|
|||
}
|
||||
unit_index
|
||||
}
|
||||
pub fn debug_sim(this: &SimValue<Self>) -> 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<C: PhantomConstGet<CpuConfig>> {
|
||||
pub value: UIntType<CpuConfigOutRegNumWidth<C>>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
impl<C: Type + PhantomConstGet<CpuConfig>> SimValueDebug for UnitOutRegNum<C> {
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::SimValue,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
let value = Self::value_sim(value);
|
||||
write!(f, "or{value:#x}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Type + PhantomConstGet<CpuConfig>> UnitOutRegNum<C> {
|
||||
pub fn value_sim(this: &<Self as Type>::SimValue) -> usize {
|
||||
this.value.cast_to_static::<UInt<64>>().as_int() as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: PhantomConstCpuConfig> UnitOutRegNum<C> {
|
||||
#[hdl]
|
||||
pub fn new_sim(self, value: usize) -> SimValue<Self> {
|
||||
|
|
@ -3306,9 +3553,16 @@ impl<C: PhantomConstCpuConfig> UnitOutRegNum<C> {
|
|||
config: self.config,
|
||||
}
|
||||
}
|
||||
pub fn value_sim(this: &SimValue<Self>) -> usize {
|
||||
this.value.cast_to_static::<UInt<64>>().as_int() as usize
|
||||
}
|
||||
pub fn debug_sim(this: &SimValue<Self>) -> 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<C: PhantomConstGet<CpuConfig>> {
|
||||
pub unit_num: UnitNum<C>,
|
||||
|
|
@ -3328,20 +3582,27 @@ impl<C: PhantomConstCpuConfig> PRegNum<C> {
|
|||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Type + PhantomConstGet<CpuConfig>> SimValueDebug for PRegNum<C> {
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::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<Self>) -> 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<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>,
|
||||
}
|
||||
|
||||
impl SimValueDebug for MOpDestReg {
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::SimValue,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
if f.alternate() {
|
||||
type SimValueT<T> = <T as Type>::SimValue;
|
||||
let SimValueT::<Self> {
|
||||
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: &<Self as Type>::SimValue) -> [u32; Self::REG_COUNT] {
|
||||
pub fn regs_sim(this: &SimValue<Self>) -> [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
|
||||
|
|
|
|||
|
|
@ -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<C: PhantomConstGet<CpuConfig>> {
|
|||
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<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
let clear_unused_bits = |v: Cow<'_, SimValue<Self>>| {
|
||||
#[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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
!Self::cmp_sim_value_eq(lhs, rhs)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
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<T: SimValueDefault, N: Size> SimValueDefault for ArrayType<T, N> {
|
|||
}
|
||||
|
||||
impl<T: Type> SimValueDefault for HdlOption<T> {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
#[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<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::bits(&*lhs) == SimValue::bits(&*rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::bits(&*lhs) != SimValue::bits(&*rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl BTBEntryInsnKind {
|
||||
#[hdl]
|
||||
fn try_from_decoded_insn_kind(kind: &SimValue<WipDecodedInsnKind>) -> Option<SimValue<Self>> {
|
||||
|
|
@ -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<Self> 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<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::bits(&*lhs) == SimValue::bits(&*rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::bits(&*lhs) != SimValue::bits(&*rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl BTBEntryAddrKind {
|
||||
#[hdl]
|
||||
fn taken(this: &SimValue<Self>) -> bool {
|
||||
|
|
|
|||
|
|
@ -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<MOp> {
|
||||
pub fetch_block_id: UInt<8>,
|
||||
|
|
@ -50,29 +50,6 @@ pub struct MOpInstance<MOp> {
|
|||
pub mop: MOp,
|
||||
}
|
||||
|
||||
impl<MOp: Type> SimValueDebug for MOpInstance<MOp> {
|
||||
#[hdl]
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::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<C: PhantomConstGet<CpuConfig>> {
|
||||
|
|
@ -256,6 +233,16 @@ impl<C: PhantomConstCpuConfig> RenameTableEntry<C> {
|
|||
#[hdl(sim)]
|
||||
self.L1(self.L1.const_zero())
|
||||
}
|
||||
#[hdl]
|
||||
fn debug_sim(this: &SimValue<Self>) -> 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<C: PhantomConstCpuConfig> RenameTable<C> {
|
|||
// 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<C: PhantomConstCpuConfig> RenameTable<C> {
|
|||
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<C: PhantomConstCpuConfig> RenameTable<C> {
|
|||
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<C: PhantomConstCpuConfig> RobEntry<C> {
|
|||
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<C: PhantomConstCpuConfig> ReorderBuffer<C> {
|
|||
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<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
|
|||
}
|
||||
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<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
|
|||
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<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
|
|||
});
|
||||
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<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
|
|||
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(),
|
||||
|
|
|
|||
|
|
@ -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<C: Type + PhantomConstGet<CpuConfig>> Index<C> for ExecuteToUnitInterfacesW
|
|||
}
|
||||
}
|
||||
|
||||
impl<C: Type + PhantomConstGet<CpuConfig>> SimValueDebug for ExecuteToUnitInterfaces<C> {
|
||||
fn sim_value_debug(
|
||||
value: &<Self as Type>::SimValue,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
fmt::Debug::fmt(value, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Type + PhantomConstGet<CpuConfig>> Type for ExecuteToUnitInterfaces<C> {
|
||||
type BaseType = Bundle;
|
||||
type MaskType = Bundle;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<C: PhantomConstCpuConfig> MockUnitOp<C> {
|
|||
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<C: PhantomConstCpuConfig> MockUnitOp<C> {
|
|||
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<C: PhantomConstCpuConfig, E: MockExecutionStateTrait> MockUnitState<C, E> {
|
|||
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<C: PhantomConstCpuConfig> MockLoadStoreOp<C> {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,13 @@ fn rotate_imm(
|
|||
) -> SimValue<ShiftRotateMOpImm> {
|
||||
#[hdl(sim)]
|
||||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: amount.map(|amount| amount.cast_to_static::<UInt<_>>()),
|
||||
shift_rotate_amount: if let Some(amount) = amount {
|
||||
#[hdl(sim)]
|
||||
HdlSome(amount.cast_to_static::<UInt<_>>())
|
||||
} 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue