formal proof works! also add test_power_isa_add_sim
Some checks failed
/ test (pull_request) Failing after 22m21s
Some checks failed
/ test (pull_request) Failing after 22m21s
This commit is contained in:
parent
1bc59716c5
commit
ef30d325d5
9 changed files with 28747 additions and 211 deletions
|
|
@ -2745,8 +2745,35 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
|||
|
||||
const MAX_MOPS_PER_INSN: usize = 3;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DecodeFilterArgs<'a> {
|
||||
mnemonic: &'a str,
|
||||
}
|
||||
|
||||
impl DecodeFilterArgs<'_> {
|
||||
pub fn mnemonic(&self) -> &str {
|
||||
self.mnemonic
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DecodeFilter {
|
||||
fn should_include(&mut self, args: &DecodeFilterArgs<'_>) -> bool;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + FnMut(&DecodeFilterArgs<'_>) -> bool> DecodeFilter for T {
|
||||
fn should_include(&mut self, args: &DecodeFilterArgs<'_>) -> bool {
|
||||
self(args)
|
||||
}
|
||||
}
|
||||
|
||||
impl DecodeFilter for () {
|
||||
fn should_include(&mut self, _args: &DecodeFilterArgs<'_>) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn decode_one_insn() {
|
||||
pub fn decode_one_insn(mut filter: impl DecodeFilter) {
|
||||
#[hdl]
|
||||
let output: ArrayVec<TraceAsString<MOp>, ConstUsize<{ MAX_MOPS_PER_INSN }>> = m.output();
|
||||
#[hdl]
|
||||
|
|
@ -2816,20 +2843,22 @@ pub fn decode_one_insn() {
|
|||
let Some(decode_fn) = decode_fns.get(mnemonic) else {
|
||||
panic!("unhandled mnemonic: {mnemonic:?}");
|
||||
};
|
||||
decode_fn(&mut DecodeState {
|
||||
mnemonic,
|
||||
arguments,
|
||||
conditions,
|
||||
header,
|
||||
insn,
|
||||
output,
|
||||
is_illegal,
|
||||
first_input,
|
||||
has_second_input,
|
||||
second_input_value,
|
||||
second_input_used,
|
||||
field_wires: &mut field_wires,
|
||||
});
|
||||
if filter.should_include(&DecodeFilterArgs { mnemonic }) {
|
||||
decode_fn(&mut DecodeState {
|
||||
mnemonic,
|
||||
arguments,
|
||||
conditions,
|
||||
header,
|
||||
insn,
|
||||
output,
|
||||
is_illegal,
|
||||
first_input,
|
||||
has_second_input,
|
||||
second_input_value,
|
||||
second_input_used,
|
||||
field_wires: &mut field_wires,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ impl<T: MOpTrait> MOpInto<T> for T {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait MOpLeaf<Target: MOpTrait>: MOpInto<Target> {}
|
||||
|
||||
pub trait MOpVariantVisitOps {
|
||||
type MOp: MOpTrait<
|
||||
DestReg = <Self::Target as MOpTrait>::DestReg,
|
||||
|
|
@ -714,6 +716,35 @@ pub const COMMON_MOP_2_IMM_WIDTH: usize = common_mop_max_imm_size(2);
|
|||
pub const COMMON_MOP_3_IMM_WIDTH: usize = common_mop_max_imm_size(3);
|
||||
|
||||
macro_rules! common_mop_struct {
|
||||
(
|
||||
#[leaf]
|
||||
$(#[debug($($debug:tt)*)])?
|
||||
#[mapped(<$NewDestReg:ident, $NewSrcReg:ident> $mapped_ty:ty)]
|
||||
$(#[$struct_meta:meta])*
|
||||
$vis:vis struct $MOp:ident<$DestReg:ident: $DestRegBound:ident, $SrcReg:ident: $SrcRegBound:ident $(, $Generic:ident: $GenericBound:ident)* $(,)?> {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
common_mop_struct! {
|
||||
$(#[debug($($debug)*)])?
|
||||
#[mapped(<$NewDestReg, $NewSrcReg> $mapped_ty)]
|
||||
$(#[$struct_meta])*
|
||||
$vis struct $MOp<$DestReg: $DestRegBound, $SrcReg: $SrcRegBound $(, $Generic: $GenericBound)*> {
|
||||
$($body)*
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
$DestReg: $DestRegBound,
|
||||
$SrcReg: $SrcRegBound,
|
||||
$($Generic: $GenericBound,)*
|
||||
Target: MOpTrait,
|
||||
> MOpLeaf<Target> for $MOp<$DestReg, $SrcReg, $($Generic),*>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
}
|
||||
};
|
||||
(
|
||||
#[debug($(#[$debug_hdl:ident])? |$debug_value:ident, $debug_f:ident| $debug_block:block $(where $($debug_where:tt)*)?)]
|
||||
#[mapped(<$NewDestReg:ident, $SrcReg:ident> $mapped_ty:ty)]
|
||||
|
|
@ -1322,6 +1353,7 @@ macro_rules! maybe_write_comma_flag {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let AddSubMOp::<_, _, _> {
|
||||
|
|
@ -1909,6 +1941,7 @@ impl LogicalFlagsMOpImm {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let LogicalFlagsMOp::<_, _> {
|
||||
|
|
@ -2073,6 +2106,7 @@ impl<DestReg: Type, SrcReg: Type> LogicalFlagsMOp<DestReg, SrcReg> {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let LogicalMOp::<_, _, _> {
|
||||
|
|
@ -2350,6 +2384,7 @@ impl SimValueDebug for ShiftRotateMOpImm {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let ShiftRotateMOp::<_, _> {
|
||||
|
|
@ -2465,6 +2500,7 @@ impl CompareMode {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let CompareMOp::<_, _, _> {
|
||||
|
|
@ -2569,6 +2605,7 @@ impl ConditionMode {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let BranchMOp::<_, _, _> {
|
||||
|
|
@ -2736,6 +2773,7 @@ pub enum ReadSpecialMOpImm {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let ReadSpecialMOp::<_, _> {
|
||||
|
|
@ -2826,6 +2864,7 @@ impl SimValueDebug for L2RegNum {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let ReadL2RegMOp::<_, _> {
|
||||
|
|
@ -2868,6 +2907,7 @@ impl<DestReg: Type, SrcReg: Type> ReadL2RegMOp<DestReg, SrcReg> {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let WriteL2RegMOp::<_, _> {
|
||||
|
|
@ -3014,6 +3054,7 @@ impl<DestReg: Type, SrcReg: Type, SrcCount: KnownSize>
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let LoadMOp::<_, _> {
|
||||
|
|
@ -3062,6 +3103,7 @@ impl<DestReg: Type, SrcReg: Type> LoadMOp<DestReg, SrcReg> {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let StoreMOp::<_, _> {
|
||||
|
|
@ -3120,6 +3162,7 @@ mop_enum! {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let MoveRegMOp::<_, _> {
|
||||
|
|
|
|||
|
|
@ -937,6 +937,7 @@ pub fn decode_and_run_single_insn<C: Type + PhantomConstCpuConfig, D: Type + Dec
|
|||
connect(output.data, output.ty().data.HdlNone());
|
||||
#[hdl]
|
||||
if let HdlSome(input) = input.data {
|
||||
connect(decoder_input, input.decoder_input);
|
||||
connect(
|
||||
state_reg,
|
||||
HdlSome(DecodeAndRunSingleInsnState::new(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpLeaf, MOpRegNum, MOpTrait,
|
||||
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, mop_enum,
|
||||
},
|
||||
rename_execute_retire::ExecuteToUnitInterface,
|
||||
|
|
@ -45,9 +45,9 @@ macro_rules! all_units {
|
|||
}
|
||||
|
||||
impl $UnitKind {
|
||||
pub fn unit(self, config: PhantomConst<CpuConfig>, unit_index: usize) -> DynUnit {
|
||||
pub fn unit(self, config: PhantomConst<CpuConfig>, unit_index: usize, filter: &mut impl RenamedMOpFilter) -> DynUnit {
|
||||
match self {
|
||||
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)*
|
||||
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index, filter),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -326,19 +326,67 @@ all_units! {
|
|||
this.TransformedMove.mapped_ty(new_dest_reg, new_src_reg)
|
||||
})] TransformedMoveOp: Type
|
||||
> {
|
||||
#[create_dyn_unit_fn = |config, unit_index| alu_branch::AluBranch::new(config, unit_index).to_dyn()]
|
||||
#[create_dyn_unit_fn = |config, unit_index, filter| alu_branch::AluBranch::new(config, unit_index, filter).to_dyn()]
|
||||
#[extract(alu_branch_mop, alu_branch_mop_sim, alu_branch_mop_sim_ref, alu_branch_mop_sim_mut)]
|
||||
AluBranch(AluBranchMOp<DestReg, SrcReg>),
|
||||
#[transformed_move]
|
||||
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
||||
#[create_dyn_unit_fn = |config, unit_index, filter| todo!()]
|
||||
#[extract(transformed_move_mop, transformed_move_mop_sim, transformed_move_mop_sim_ref, transformed_move_mop_sim_mut)]
|
||||
TransformedMove(TransformedMoveOp),
|
||||
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
||||
#[create_dyn_unit_fn = |config, unit_index, filter| todo!()]
|
||||
#[extract(load_store_mop, load_store_mop_sim, load_store_mop_sim_ref, load_store_mop_sim_mut)]
|
||||
LoadStore(LoadStoreMOp<DestReg, SrcReg>),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RenamedMOpFilter {
|
||||
fn should_include(
|
||||
&mut self,
|
||||
mop: &SimValue<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>,
|
||||
) -> bool;
|
||||
fn should_include_ty<
|
||||
T: MOpLeaf<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>,
|
||||
>(
|
||||
&mut self,
|
||||
ty: T,
|
||||
) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.should_include(
|
||||
&T::mop_into(
|
||||
UInt::new_dyn(ty.canonical().bit_width())
|
||||
.zero()
|
||||
.to_expr()
|
||||
.cast_bits_to(ty),
|
||||
)
|
||||
.to_sim_value(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
T: ?Sized
|
||||
+ FnMut(&SimValue<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>) -> bool,
|
||||
> RenamedMOpFilter for T
|
||||
{
|
||||
fn should_include(
|
||||
&mut self,
|
||||
mop: &SimValue<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>,
|
||||
) -> bool {
|
||||
self(mop)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenamedMOpFilter for () {
|
||||
fn should_include(
|
||||
&mut self,
|
||||
_mop: &SimValue<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>,
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UnitTrait:
|
||||
'static + Send + Sync + std::fmt::Debug + fayalite::intern::SupportsPtrEqWithTypeId
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::{
|
|||
ExecuteToUnitInterface, GlobalState, NextPcPredictorOp, RenamedMOp, UnitCausedCancel,
|
||||
UnitFinishCauseCancel, UnitInputsReady, UnitOutputReady,
|
||||
},
|
||||
unit::{DynUnit, DynUnitWrapper, UnitKind, UnitTrait},
|
||||
unit::{DynUnit, DynUnitWrapper, RenamedMOpFilter, UnitKind, UnitTrait},
|
||||
};
|
||||
use fayalite::{
|
||||
expr::CastToImpl,
|
||||
|
|
@ -1235,7 +1235,11 @@ fn read_special<C: Type + PhantomConstCpuConfig>(config: C) {
|
|||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
|
||||
pub fn alu_branch(
|
||||
config: PhantomConst<CpuConfig>,
|
||||
unit_index: usize,
|
||||
filter: &mut impl RenamedMOpFilter,
|
||||
) {
|
||||
#[hdl]
|
||||
let from_execute: ExecuteToUnitInterface<PhantomConst<CpuConfig>> =
|
||||
m.input(ExecuteToUnitInterface[config]);
|
||||
|
|
@ -1294,193 +1298,237 @@ pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
|
|||
#[hdl]
|
||||
match mop {
|
||||
AluBranchMOp::<_, _>::AddSub(mop) => {
|
||||
#[hdl]
|
||||
let add_sub = instance(add_sub(config));
|
||||
#[hdl]
|
||||
let add_sub::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = add_sub;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc, mop_instance.pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let add_sub = instance(add_sub(config));
|
||||
#[hdl]
|
||||
let add_sub::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = add_sub;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc, mop_instance.pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::AddSubI(mop) => {
|
||||
#[hdl]
|
||||
let add_sub_i = instance(add_sub(config));
|
||||
#[hdl]
|
||||
let add_sub::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = add_sub_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc, mop_instance.pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let add_sub_i = instance(add_sub(config));
|
||||
#[hdl]
|
||||
let add_sub::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = add_sub_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc, mop_instance.pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::LogicalFlags(mop) => {
|
||||
#[hdl]
|
||||
let logical_flags = instance(logical_flags(config));
|
||||
#[hdl]
|
||||
let logical_flags::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical_flags;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let logical_flags = instance(logical_flags(config));
|
||||
#[hdl]
|
||||
let logical_flags::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical_flags;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::Logical(mop) => {
|
||||
#[hdl]
|
||||
let logical = instance(logical(config));
|
||||
#[hdl]
|
||||
let logical::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let logical = instance(logical(config));
|
||||
#[hdl]
|
||||
let logical::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::LogicalI(mop) => {
|
||||
#[hdl]
|
||||
let logical_i = instance(logical(config));
|
||||
#[hdl]
|
||||
let logical::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let logical_i = instance(logical(config));
|
||||
#[hdl]
|
||||
let logical::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::ShiftRotate(mop) => {
|
||||
#[hdl]
|
||||
let shift_rotate = instance(shift_rotate(config));
|
||||
#[hdl]
|
||||
let shift_rotate::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = shift_rotate;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let shift_rotate = instance(shift_rotate(config));
|
||||
#[hdl]
|
||||
let shift_rotate::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = shift_rotate;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::Compare(mop) => {
|
||||
#[hdl]
|
||||
let compare = instance(compare(config));
|
||||
#[hdl]
|
||||
let compare::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = compare;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let compare = instance(compare(config));
|
||||
#[hdl]
|
||||
let compare::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = compare;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::CompareI(mop) => {
|
||||
#[hdl]
|
||||
let compare_i = instance(compare(config));
|
||||
#[hdl]
|
||||
let compare::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = compare_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let compare_i = instance(compare(config));
|
||||
#[hdl]
|
||||
let compare::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = compare_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::Branch(mop) => {
|
||||
#[hdl]
|
||||
let branch = instance(branch(config));
|
||||
#[hdl]
|
||||
let branch::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc: pc_,
|
||||
fallthrough_pc: fallthrough_pc_,
|
||||
predicted_next_pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
predictor_op: predictor_op_,
|
||||
caused_cancel: caused_cancel_,
|
||||
} = branch;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc_, mop_instance.pc);
|
||||
connect(fallthrough_pc_, fallthrough_pc);
|
||||
connect(predicted_next_pc, mop_instance.predicted_next_pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let branch = instance(branch(config));
|
||||
#[hdl]
|
||||
let branch::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc: pc_,
|
||||
fallthrough_pc: fallthrough_pc_,
|
||||
predicted_next_pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
predictor_op: predictor_op_,
|
||||
caused_cancel: caused_cancel_,
|
||||
} = branch;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc_, mop_instance.pc);
|
||||
connect(fallthrough_pc_, fallthrough_pc);
|
||||
connect(predicted_next_pc, mop_instance.predicted_next_pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::BranchI(mop) => {
|
||||
#[hdl]
|
||||
let branch_i = instance(branch(config));
|
||||
#[hdl]
|
||||
let branch::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc: pc_,
|
||||
fallthrough_pc: fallthrough_pc_,
|
||||
predicted_next_pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
predictor_op: predictor_op_,
|
||||
caused_cancel: caused_cancel_,
|
||||
} = branch_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc_, mop_instance.pc);
|
||||
connect(fallthrough_pc_, fallthrough_pc);
|
||||
connect(predicted_next_pc, mop_instance.predicted_next_pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let branch_i = instance(branch(config));
|
||||
#[hdl]
|
||||
let branch::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc: pc_,
|
||||
fallthrough_pc: fallthrough_pc_,
|
||||
predicted_next_pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
predictor_op: predictor_op_,
|
||||
caused_cancel: caused_cancel_,
|
||||
} = branch_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc_, mop_instance.pc);
|
||||
connect(fallthrough_pc_, fallthrough_pc);
|
||||
connect(predicted_next_pc, mop_instance.predicted_next_pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::ReadSpecial(mop) => {
|
||||
#[hdl]
|
||||
let read_special = instance(read_special(config));
|
||||
#[hdl]
|
||||
let read_special::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = read_special;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let read_special = instance(read_special(config));
|
||||
#[hdl]
|
||||
let read_special::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = read_special;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
}
|
||||
connect(
|
||||
|
|
@ -1530,10 +1578,14 @@ pub struct AluBranch {
|
|||
}
|
||||
|
||||
impl AluBranch {
|
||||
pub fn new(config: PhantomConst<CpuConfig>, unit_index: usize) -> Self {
|
||||
pub fn new(
|
||||
config: PhantomConst<CpuConfig>,
|
||||
unit_index: usize,
|
||||
filter: &mut impl RenamedMOpFilter,
|
||||
) -> Self {
|
||||
Self {
|
||||
config,
|
||||
module: alu_branch(config, unit_index),
|
||||
module: alu_branch(config, unit_index, filter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
28278
crates/cpu/tests/expected/units_formal_power_isa_add_sim.vcd
generated
Normal file
28278
crates/cpu/tests/expected/units_formal_power_isa_add_sim.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -4079,7 +4079,7 @@ fn rename_execute_retire_test_harness<#[hdl(skip)] MI: MakeInsns>(
|
|||
AluBranchKind::Real => {
|
||||
let unit = instance_with_loc(
|
||||
&dut.ty().to_units.unit_field_name(unit_index),
|
||||
cpu::unit::alu_branch::alu_branch(config, unit_index),
|
||||
cpu::unit::alu_branch::alu_branch(config, unit_index, &mut ()),
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
connect(unit.from_execute, to_unit);
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ fn test_test_cases_assembly() -> std::io::Result<()> {
|
|||
#[test]
|
||||
fn test_decode_insn() {
|
||||
let _n = SourceLocation::normalize_files_for_tests();
|
||||
let m = decode_one_insn();
|
||||
let m = decode_one_insn(());
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output = checked_vcd_output!(
|
||||
&mut sim,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
use cpu::{
|
||||
config::{CpuConfig, UnitConfig},
|
||||
decoder::simple_power_isa,
|
||||
instruction::MOpRegNum,
|
||||
decoder::simple_power_isa::{self, DecodeFilter, DecodeFilterArgs},
|
||||
instruction::{AluBranchMOp, MOpRegNum},
|
||||
next_pc::CallStackOp,
|
||||
register::{FlagsMode, PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegValue},
|
||||
rename_execute_retire::{
|
||||
|
|
@ -14,7 +14,7 @@ use cpu::{
|
|||
DecodeAndRunSingleInsnInput, DecodeAndRunSingleInsnOutput, DecodeOneInsnInput,
|
||||
DecodeOneInsnMaxMOpCount, decode_and_run_single_insn,
|
||||
},
|
||||
unit::{UnitKind, UnitTrait},
|
||||
unit::{RenamedMOpFilter, UnitKind, UnitMOp, UnitTrait},
|
||||
util::array_vec::ArrayVec,
|
||||
};
|
||||
use fayalite::{
|
||||
|
|
@ -26,7 +26,11 @@ use fayalite::{
|
|||
use std::num::NonZero;
|
||||
|
||||
#[hdl_module]
|
||||
fn formal_harness(config: PhantomConst<CpuConfig>) {
|
||||
fn formal_harness(
|
||||
config: PhantomConst<CpuConfig>,
|
||||
decode_filter: impl DecodeFilter,
|
||||
renamed_mop_filter: &mut impl RenamedMOpFilter,
|
||||
) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
|
||||
|
|
@ -47,7 +51,7 @@ fn formal_harness(config: PhantomConst<CpuConfig>) {
|
|||
#[hdl]
|
||||
let decode_and_run = instance(decode_and_run_single_insn(
|
||||
config,
|
||||
simple_power_isa::decode_one_insn(),
|
||||
simple_power_isa::decode_one_insn(decode_filter),
|
||||
));
|
||||
connect(decode_and_run.cd, cd);
|
||||
#[hdl]
|
||||
|
|
@ -78,7 +82,7 @@ fn formal_harness(config: PhantomConst<CpuConfig>) {
|
|||
connect(decode_and_run.output.ready, true);
|
||||
connect(output, decode_and_run.output.data);
|
||||
for (unit_index, unit) in config.get().units.iter().enumerate() {
|
||||
let dyn_unit = unit.kind.unit(config, unit_index);
|
||||
let dyn_unit = unit.kind.unit(config, unit_index, renamed_mop_filter);
|
||||
let unit = instance_with_loc(
|
||||
&decode_and_run.ty().to_units.unit_field_name(unit_index),
|
||||
dyn_unit.module(),
|
||||
|
|
@ -95,24 +99,70 @@ fn formal_harness(config: PhantomConst<CpuConfig>) {
|
|||
hdl_assert(cd.clk, !decode_and_run.error, "");
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct R3R4AnyConst {
|
||||
r3_any_const: Expr<UInt<64>>,
|
||||
r4_any_const: Expr<UInt<64>>,
|
||||
}
|
||||
|
||||
impl R3R4AnyConst {
|
||||
#[track_caller]
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
r3_any_const: any_const(StaticType::TYPE),
|
||||
r4_any_const: any_const(StaticType::TYPE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
fn check_power_isa_add_formal(config: PhantomConst<CpuConfig>) {
|
||||
#[hdl]
|
||||
let clk: Clock = m.input();
|
||||
fn check_power_isa_add_formal(
|
||||
config: PhantomConst<CpuConfig>,
|
||||
r3_r4_any_const: Option<R3R4AnyConst>,
|
||||
) {
|
||||
#[hdl]
|
||||
let cd = wire();
|
||||
connect(
|
||||
cd,
|
||||
#[hdl]
|
||||
ClockDomain {
|
||||
clk,
|
||||
clk: formal_global_clock(),
|
||||
rst: formal_reset().to_reset(),
|
||||
},
|
||||
);
|
||||
#[hdl]
|
||||
let harness = instance(formal_harness(config));
|
||||
let harness = instance(formal_harness(
|
||||
config,
|
||||
|args: &DecodeFilterArgs<'_>| args.mnemonic() == "add",
|
||||
&mut |mop: &SimValue<_>| -> bool {
|
||||
#[hdl(sim)]
|
||||
match mop {
|
||||
UnitMOp::<_, _, _>::AluBranch(mop) =>
|
||||
{
|
||||
#[hdl(sim)]
|
||||
match mop {
|
||||
AluBranchMOp::<_, _>::AddSub(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
));
|
||||
connect(harness.cd, cd);
|
||||
#[hdl]
|
||||
let ran: Bool = m.output();
|
||||
#[hdl]
|
||||
let ran_reg = reg_builder().clock_domain(cd).reset(false);
|
||||
connect(ran, ran_reg);
|
||||
#[hdl]
|
||||
let cycle_count = reg_builder().clock_domain(cd).reset(0u32);
|
||||
connect_any(cycle_count, cycle_count + 1u32);
|
||||
#[hdl]
|
||||
if cycle_count.cmp_ge(5u32) {
|
||||
hdl_assert(cd.clk, ran, "");
|
||||
}
|
||||
#[hdl]
|
||||
let DecodeAndRunSingleInsnInput::<_, _> {
|
||||
decoder_input,
|
||||
fetch_block_id,
|
||||
|
|
@ -135,12 +185,16 @@ fn check_power_isa_add_formal(config: PhantomConst<CpuConfig>) {
|
|||
1 << MOpRegNum::WIDTH,
|
||||
),
|
||||
);
|
||||
let R3R4AnyConst {
|
||||
r3_any_const,
|
||||
r4_any_const,
|
||||
} = r3_r4_any_const.unwrap_or_else(|| R3R4AnyConst::new());
|
||||
#[hdl]
|
||||
let input_r3 = wire();
|
||||
connect(input_r3, any_const(StaticType::TYPE));
|
||||
connect(input_r3, r3_any_const);
|
||||
#[hdl]
|
||||
let input_r4 = wire();
|
||||
connect(input_r4, any_const(StaticType::TYPE));
|
||||
connect(input_r4, r4_any_const);
|
||||
connect(
|
||||
input_regs.regs[MOpRegNum::power_isa_gpr_reg_imm(3).value].int_fp,
|
||||
input_r3,
|
||||
|
|
@ -151,6 +205,7 @@ fn check_power_isa_add_formal(config: PhantomConst<CpuConfig>) {
|
|||
);
|
||||
#[hdl]
|
||||
if let HdlSome(output) = harness.output {
|
||||
connect(ran_reg, true);
|
||||
#[hdl]
|
||||
let DecodeAndRunSingleInsnOutput::<_, _> {
|
||||
regs,
|
||||
|
|
@ -218,13 +273,12 @@ fn test_power_isa_add_formal() {
|
|||
vec![UnitConfig::new(UnitKind::AluBranch)],
|
||||
NonZero::new(20).unwrap(),
|
||||
));
|
||||
let m = check_power_isa_add_formal(config);
|
||||
println!("starting assert formal");
|
||||
let m = check_power_isa_add_formal(config, None);
|
||||
assert_formal(
|
||||
"test_power_isa_add_formal",
|
||||
m,
|
||||
FormalMode::Prove,
|
||||
10,
|
||||
FormalMode::BMC,
|
||||
7,
|
||||
None,
|
||||
ExportOptions {
|
||||
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
|
||||
|
|
@ -232,3 +286,34 @@ fn test_power_isa_add_formal() {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[test]
|
||||
fn test_power_isa_add_sim() {
|
||||
let config = PhantomConst::new_sized(CpuConfig::new(
|
||||
vec![UnitConfig::new(UnitKind::AluBranch)],
|
||||
NonZero::new(20).unwrap(),
|
||||
));
|
||||
let r3_r4_any_const = R3R4AnyConst::new();
|
||||
let m = check_power_isa_add_formal(config, Some(r3_r4_any_const));
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output = cpu::checked_vcd_output!(
|
||||
&mut sim,
|
||||
"tests/expected/units_formal_power_isa_add_sim.vcd",
|
||||
);
|
||||
sim.write(r3_r4_any_const.r3_any_const, 0x1234u64);
|
||||
sim.write(r3_r4_any_const.r4_any_const, 0x2345u64);
|
||||
let clk = formal_global_clock();
|
||||
let rst = formal_reset();
|
||||
sim.write_clock(clk, false);
|
||||
sim.write_reset(rst, true);
|
||||
for cycle in 0..10 {
|
||||
sim.advance_time(SimDuration::from_nanos(500));
|
||||
println!("clock tick: {cycle}");
|
||||
sim.write_clock(clk, true);
|
||||
sim.advance_time(SimDuration::from_nanos(500));
|
||||
sim.write_clock(clk, false);
|
||||
sim.write_reset(rst, false);
|
||||
}
|
||||
assert!(sim.read_bool(sim.io().ran));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue