Compare commits

...

3 commits

7 changed files with 74572 additions and 50159 deletions

View file

@ -4,8 +4,8 @@
use crate::{
config::CpuConfig,
instruction::{
AddSubMOp, CompareMOp, CompareMode, LogicalMOp, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
OutputIntegerMode,
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LogicalMOp, MOp, MOpDestReg,
MOpRegNum, MoveRegMOp, OutputIntegerMode,
},
powerisa_instructions_xml::{
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
@ -179,6 +179,8 @@ macro_rules! impl_fields {
impl_fields! {
#[name = "BF"]
struct FieldBF(FieldCrf);
#[name = "BI"]
struct FieldBI(FieldCrBit);
#[name = "RA"]
struct FieldRA(FieldGpr);
#[name = "RB"]
@ -187,6 +189,10 @@ impl_fields! {
struct FieldRS(FieldGpr);
#[name = "RT"]
struct FieldRT(FieldGpr);
#[name = "BD"]
struct FieldBD(SInt<14>);
#[name = "LI"]
struct FieldLI(SInt<24>);
#[name = "SI"]
struct FieldSI(SInt<16>);
#[name = "si0"]
@ -201,8 +207,16 @@ impl_fields! {
struct FieldAddPcISD1(UInt<5>);
#[name = "d2"]
struct FieldAddPcISD2(UInt<1>);
#[name = "BH"]
struct FieldBH(UInt<2>);
#[name = "BO"]
struct FieldBO(UInt<5>);
#[name = "AA"]
struct FieldAA(Bool);
#[name = "L"]
struct FieldL(Bool);
#[name = "LK"]
struct FieldLK(Bool);
#[name = "OE"]
struct FieldOE(Bool);
#[name = "R"]
@ -223,6 +237,12 @@ struct FieldCrf {
reg_num: UInt<3>,
}
/// condition register bit
#[hdl]
struct FieldCrBit {
bit_num: UInt<5>,
}
fn gpr(this: impl ToExpr<Type = FieldGpr>) -> Expr<MOpRegNum> {
MOpRegNum::power_isa_gpr_reg(this.to_expr().reg_num)
}
@ -235,6 +255,26 @@ fn crf(this: impl ToExpr<Type = FieldCrf>) -> Expr<MOpRegNum> {
MOpRegNum::power_isa_cr_reg(this.to_expr().reg_num)
}
#[hdl]
fn cr_bit(cr_bit: impl ToExpr<Type = FieldCrBit>) -> (Expr<MOpRegNum>, Expr<ConditionMode>) {
let cr_bit = cr_bit.to_expr();
#[hdl]
let condition_mode = wire();
let field_bit = cr_bit.bit_num.cast_to_static::<UInt<2>>();
let field_num = (cr_bit.bit_num >> 2).cast_to_static::<UInt<3>>();
#[hdl]
if field_bit.cmp_eq(0_hdl_u2) {
connect(condition_mode, ConditionMode.SLt());
} else if field_bit.cmp_eq(1_hdl_u2) {
connect(condition_mode, ConditionMode.SGt());
} else if field_bit.cmp_eq(2_hdl_u2) {
connect(condition_mode, ConditionMode.Eq());
} else {
connect(condition_mode, ConditionMode.Overflow());
}
(MOpRegNum::power_isa_cr_reg(field_num), condition_mode)
}
impl DecodeState {
fn form(&self) -> &'static str {
let mut title_words = self
@ -439,7 +479,160 @@ impl DecodeState {
}
}
fn decode_b_ba_bl_bla(&mut self) {
// TODO
self.decode_scope(|this, (FieldLI(li), FieldAA(aa), FieldLK(lk))| {
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
BranchMOp::branch_i(
MOpDestReg::new(
[if this.mnemonic.contains('l') {
MOpRegNum::power_isa_lr_reg()
} else {
MOpRegNum::const_zero()
}],
[],
),
MOpRegNum::const_zero().value,
(li << 2).cast_to_static(),
!aa,
lk,
false,
),
);
});
}
#[hdl]
fn decode_bc_bclr_bcctr_bctar(&mut self) {
let addr_reg = match self.mnemonic {
"bc" | "bca" | "bcl" | "bcla" => None,
"bclr" | "bclrl" => Some(MOpRegNum::power_isa_lr_reg()),
"bcctr" | "bcctrl" => Some(MOpRegNum::power_isa_ctr_reg()),
"bctar" | "bctarl" => Some(MOpRegNum::power_isa_tar_reg()),
_ => unreachable!(),
};
let body = |this: &mut DecodeState,
bo: Expr<UInt<5>>,
bi: Expr<FieldCrBit>,
is_ret: Expr<Bool>,
bd: Option<Expr<SInt<14>>>,
aa: Option<Expr<Bool>>,
lk: Expr<Bool>| {
let use_eq_for_ctr_compare = bo[1]; // BO_3 in specification
let no_ctr = bo[2]; // BO_2 in specification
let expected_cr_bit_value = bo[3]; // BO_1 in specification
let no_cr_bit = bo[4]; // BO_0 in specification
let (cr_field, condition_mode) = cr_bit(bi);
#[hdl]
let branch_mop = wire();
#[hdl]
let branch_lr_dest_reg = wire();
connect(branch_lr_dest_reg, MOpRegNum::const_zero());
#[hdl]
if lk {
connect(branch_lr_dest_reg, MOpRegNum::power_isa_lr_reg());
}
#[hdl]
let branch_ctr_reg: MOpRegNum = wire();
let dest = MOpDestReg::new([branch_lr_dest_reg], []);
let src1 = addr_reg.unwrap_or_else(|| MOpRegNum::const_zero()).value;
let imm = (bd.unwrap_or(0_hdl_i14) << 2).cast_to_static();
let invert_src2_eq_zero = !use_eq_for_ctr_compare;
let pc_relative = match aa {
Some(aa) => !aa,
None => addr_reg.is_none().to_expr(),
};
#[hdl]
if no_cr_bit {
connect(
branch_mop,
BranchMOp::branch_ctr(
dest,
src1,
branch_ctr_reg.value,
imm,
invert_src2_eq_zero,
pc_relative,
lk,
is_ret,
),
);
} else {
connect(
branch_mop,
BranchMOp::branch_cond_ctr(
dest,
[cr_field.value, src1, branch_ctr_reg.value],
imm,
!expected_cr_bit_value,
condition_mode,
invert_src2_eq_zero,
pc_relative,
lk,
is_ret,
),
);
}
#[hdl]
if no_ctr {
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(this.output[0], branch_mop);
connect(branch_ctr_reg, MOpRegNum::const_zero());
} else {
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
AddSubMOp::add_sub_i(
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
[
MOpRegNum::power_isa_ctr_reg().value,
MOpRegNum::const_zero().value,
],
(-1).cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(),
false,
false,
false,
false,
),
);
connect(this.output[1], branch_mop);
connect(branch_ctr_reg, MOpRegNum::power_isa_ctr_reg());
}
};
if addr_reg.is_some() {
self.decode_scope(
|this, (FieldBO(bo), FieldBI(bi), FieldBH(bh), FieldLK(lk))| {
body(
this,
bo,
bi,
if this.mnemonic.starts_with("bclr") {
bh.cmp_eq(0u8)
} else {
false.to_expr()
},
None,
None,
lk,
)
},
);
} else {
self.decode_scope(
|this, (FieldBO(bo), FieldBI(bi), FieldBD(bd), FieldAA(aa), FieldLK(lk))| {
body(this, bo, bi, false.to_expr(), Some(bd), Some(aa), lk)
},
);
}
}
#[hdl]
fn decode_addi_paddi(&mut self) {
@ -1121,24 +1314,56 @@ impl DecodeState {
},
);
}
/// for `extsb[.]/extsh[.]/extsw[.]`
#[hdl]
fn decode_extsb_extsh_extsw(&mut self) {
assert_eq!(self.arguments, Some("RA,RS"));
let output_integer_mode = match self.mnemonic.trim_end_matches('.') {
"extsb" => OutputIntegerMode.SignExt8(),
"extsh" => OutputIntegerMode.SignExt16(),
"extsw" => OutputIntegerMode.SignExt32(),
_ => unreachable!(),
};
self.decode_scope(|this, (FieldRA(ra), FieldRS(rs), FieldRc(rc))| {
// TODO: handle SO propagation
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
LogicalMOp::logical_i(
MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]),
[gpr(rs).value],
0.cast_to_static::<SInt<_>>(),
output_integer_mode,
LogicalMOp::lut_from_fn(|[a, b]| a | b),
),
);
});
}
/// for `pnop`
#[hdl]
fn decode_pnop(&mut self) {
self.decode_scope(|this, ()| {
connect(
ArrayVec::len(this.output),
0usize.cast_to_static::<Length<_>>(),
);
});
}
}
type DecodeFn = fn(&mut DecodeState);
const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
(&["b", "ba", "bl", "bla"], DecodeState::decode_b_ba_bl_bla),
(&["bc", "bca", "bcl", "bcla"], |_state| {
// TODO
}),
(&["bclr", "bclrl"], |_state| {
// TODO
}),
(&["bcctr", "bcctrl"], |_state| {
// TODO
}),
(&["bctar", "bctarl"], |_state| {
// TODO
}),
(
&[
"bc", "bca", "bcl", "bcla", "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl",
],
DecodeState::decode_bc_bclr_bcctr_bctar,
),
(
&[
"crand", "crnand", "cror", "crxor", "crnor", "creqv", "crandc", "crorc",
@ -1287,9 +1512,10 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
],
DecodeState::decode_and_xor_nand_or_orc_nor_eqv_andc,
),
(&["extsb", "extsb.", "extsh", "extsh."], |_state| {
// TODO
}),
(
&["extsb", "extsb.", "extsh", "extsh.", "extsw", "extsw."],
DecodeState::decode_extsb_extsh_extsw,
),
(&["cmpb"], |_state| {
// TODO
}),
@ -1303,9 +1529,6 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
// TODO
},
),
(&["extsw", "extsw."], |_state| {
// TODO
}),
(
&[
"rlwinm", "rlwinm.", "rlwnm", "rlwnm.", "rlwimi", "rlwimi.", "rldicl", "rldicl.",
@ -1360,9 +1583,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
// TODO
},
),
(&["pnop"], |_state| {
// TODO
}),
(&["pnop"], DecodeState::decode_pnop),
(FP_MNEMONICS, |_state| {
// TODO(FP)
}),

View file

@ -3,7 +3,7 @@
use crate::{unit::UnitMOp, util::range_u32_len};
use fayalite::{
expr::{HdlPartialEqImpl, ops::ArrayLiteral},
intern::Interned,
intern::{Intern, InternSlice, Interned},
module::wire_with_loc,
prelude::*,
ty::StaticType,
@ -1101,13 +1101,195 @@ impl<DestReg: Type, SrcRegWidth: Size> CompareMOp<DestReg, SrcRegWidth, ConstUsi
}
}
#[hdl]
pub enum ConditionMode {
Eq,
ULt,
UGt,
SLt,
SGt,
Sign,
Overflow,
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())
}
}
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth>)]
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
#[hdl(cmp_eq)]
pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size> {
/// `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.
/// The branch is taken only if all of `src2` (if present) and `src0`'s conditions pass
/// The output value is the next instruction's address used for a return address when this is a call.
pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
pub lut: UInt<4>,
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>,
pub invert_src0_cond: Bool,
pub src0_cond_mode: ConditionMode,
/// `src2`'s condition passes if `src2`'s value `== 0`.
/// However, if `invert_src2_eq_zero` is set, then the comparison is instead `!= 0`.
pub invert_src2_eq_zero: Bool,
pub pc_relative: Bool,
pub is_call: Bool,
pub is_ret: Bool,
}
}
impl<DestReg: Type, SrcRegWidth: Size> BranchMOp<DestReg, SrcRegWidth, ConstUsize<2>> {
#[hdl]
pub fn branch_cond_i<Target: MOpTrait>(
dest: impl ToExpr<Type = DestReg>,
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 2>>,
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_2_IMM_WIDTH }>>,
invert_src0_cond: impl ToExpr<Type = Bool>,
src0_cond_mode: impl ToExpr<Type = ConditionMode>,
pc_relative: impl ToExpr<Type = Bool>,
is_call: impl ToExpr<Type = Bool>,
is_ret: impl ToExpr<Type = Bool>,
) -> Expr<Target>
where
Self: MOpInto<Target>,
{
MOpInto::mop_into(
#[hdl]
BranchMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
invert_src0_cond,
src0_cond_mode,
invert_src2_eq_zero: false,
pc_relative,
is_call,
is_ret,
},
)
}
#[hdl]
pub fn branch_i<Target: MOpTrait>(
dest: impl ToExpr<Type = DestReg>,
src1: impl ToExpr<Type = UIntType<SrcRegWidth>>,
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_2_IMM_WIDTH }>>,
pc_relative: impl ToExpr<Type = Bool>,
is_call: impl ToExpr<Type = Bool>,
is_ret: impl ToExpr<Type = Bool>,
) -> Expr<Target>
where
Self: MOpInto<Target>,
{
let src1 = src1.to_expr();
Self::branch_cond_i(
dest,
ArrayLiteral::new(
src1.ty(),
[src1.ty().zero().to_expr(), src1]
.into_iter()
.map(Expr::canonical)
.collect(),
),
imm,
true,
ConditionMode.ULt(),
pc_relative,
is_call,
is_ret,
)
}
}
impl<DestReg: Type, SrcRegWidth: Size> BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>> {
#[hdl]
pub fn branch_cond_ctr<Target: MOpTrait>(
dest: impl ToExpr<Type = DestReg>,
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 3>>,
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_3_IMM_WIDTH }>>,
invert_src0_cond: impl ToExpr<Type = Bool>,
src0_cond_mode: impl ToExpr<Type = ConditionMode>,
invert_src2_eq_zero: impl ToExpr<Type = Bool>,
pc_relative: impl ToExpr<Type = Bool>,
is_call: impl ToExpr<Type = Bool>,
is_ret: impl ToExpr<Type = Bool>,
) -> Expr<Target>
where
Self: MOpInto<Target>,
{
MOpInto::mop_into(
#[hdl]
BranchMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
invert_src0_cond,
src0_cond_mode,
invert_src2_eq_zero,
pc_relative,
is_call,
is_ret,
},
)
}
#[hdl]
pub fn branch_ctr<Target: MOpTrait>(
dest: impl ToExpr<Type = DestReg>,
src1: impl ToExpr<Type = UIntType<SrcRegWidth>>,
src2: impl ToExpr<Type = UIntType<SrcRegWidth>>,
imm: impl ToExpr<Type = SInt<{ COMMON_MOP_3_IMM_WIDTH }>>,
invert_src2_eq_zero: impl ToExpr<Type = Bool>,
pc_relative: impl ToExpr<Type = Bool>,
is_call: impl ToExpr<Type = Bool>,
is_ret: impl ToExpr<Type = Bool>,
) -> Expr<Target>
where
Self: MOpInto<Target>,
{
let src1 = src1.to_expr();
Self::branch_cond_ctr(
dest,
ArrayLiteral::new(
src1.ty(),
[src1.ty().zero().to_expr(), src1, src2.to_expr()]
.into_iter()
.map(Expr::canonical)
.collect(),
),
imm,
true,
ConditionMode.ULt(),
invert_src2_eq_zero,
pc_relative,
is_call,
is_ret,
)
}
}
@ -1121,6 +1303,8 @@ mop_enum! {
LogicalI(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
Compare(CompareMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
Branch(BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
BranchI(BranchMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
}
}

View file

@ -27,8 +27,29 @@ pub struct PowerIsaCrBitNum {
impl MOpRegNum {
pub const POWER_ISA_LR_REG_NUM: u32 = 1;
#[hdl]
pub fn power_isa_lr_reg() -> Expr<Self> {
#[hdl]
Self {
value: Self::POWER_ISA_LR_REG_NUM.cast_to_static::<UInt<_>>(),
}
}
pub const POWER_ISA_CTR_REG_NUM: u32 = 2;
#[hdl]
pub fn power_isa_ctr_reg() -> Expr<Self> {
#[hdl]
Self {
value: Self::POWER_ISA_CTR_REG_NUM.cast_to_static::<UInt<_>>(),
}
}
pub const POWER_ISA_TAR_REG_NUM: u32 = 3;
#[hdl]
pub fn power_isa_tar_reg() -> Expr<Self> {
#[hdl]
Self {
value: Self::POWER_ISA_TAR_REG_NUM.cast_to_static::<UInt<_>>(),
}
}
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
///
@ -122,6 +143,13 @@ impl MOpRegNum {
}
}
#[hdl]
pub fn power_isa_gpr_reg_imm(index: usize) -> Expr<Self> {
#[hdl]
Self {
value: Self::power_isa_gpr_reg_num(index).cast_to_static::<UInt<_>>(),
}
}
#[hdl]
pub fn power_isa_gpr_reg_sim(reg_num: &SimValue<UInt<5>>) -> SimValue<Self> {
#[hdl(sim)]
Self {

View file

@ -4,8 +4,8 @@
use crate::{
config::CpuConfig,
instruction::{
AddSubMOp, AluBranchMOp, AluCommonMOp, COMMON_MOP_SRC_LEN, CommonMOp, CompareMOp,
LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp, UnitOutRegNum,
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
CompareMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp, UnitOutRegNum,
},
register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue},
unit::{
@ -272,6 +272,21 @@ fn compare<SrcCount: KnownSize>(
}
}
#[hdl]
fn branch<SrcCount: KnownSize>(
mop: Expr<BranchMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
pc: Expr<UInt<64>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
// TODO: finish
#[hdl]
UnitResultCompleted::<_> {
value: PRegValue::zeroed(),
extra_out: (),
}
}
#[hdl_module]
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
#[hdl]
@ -415,6 +430,42 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
},
),
),
AluBranchMOp::<_, _>::Branch(mop) => connect(
unit_base.execute_end,
HdlSome(
#[hdl]
ExecuteEnd::<_, _> {
unit_output: #[hdl]
UnitOutput::<_, _> {
which: MOpTrait::dest_reg(mop),
result: UnitResult[()].Completed(branch(
mop,
pc,
global_state.flags_mode,
src_values,
)),
},
},
),
),
AluBranchMOp::<_, _>::BranchI(mop) => connect(
unit_base.execute_end,
HdlSome(
#[hdl]
ExecuteEnd::<_, _> {
unit_output: #[hdl]
UnitOutput::<_, _> {
which: MOpTrait::dest_reg(mop),
result: UnitResult[()].Completed(branch(
mop,
pc,
global_state.flags_mode,
src_values,
)),
},
},
),
),
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -49,7 +49,6 @@ impl fmt::Debug for TestCase {
}
}
#[hdl]
fn test_cases() -> Vec<TestCase> {
let mut retval = Vec::new();
#[track_caller]
@ -93,12 +92,11 @@ fn test_cases() -> Vec<TestCase> {
AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::const_zero().value,
],
0x1234.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
false,
false,
@ -112,12 +110,11 @@ fn test_cases() -> Vec<TestCase> {
AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::const_zero().value,
],
0x123456789i64.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
false,
false,
@ -132,8 +129,7 @@ fn test_cases() -> Vec<TestCase> {
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[MOpRegNum::const_zero().value, MOpRegNum::const_zero().value],
0x123456789i64.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
false,
false,
@ -147,12 +143,11 @@ fn test_cases() -> Vec<TestCase> {
AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::const_zero().value,
],
0x12340000.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
false,
false,
@ -167,8 +162,7 @@ fn test_cases() -> Vec<TestCase> {
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[MOpRegNum::const_zero().value; _],
0x12340004.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
false,
false,
@ -185,13 +179,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
false,
false,
@ -211,12 +204,11 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::const_zero().value,
],
0x1234.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
false,
false,
@ -233,13 +225,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
true,
false,
true,
@ -259,12 +250,11 @@ fn test_cases() -> Vec<TestCase> {
&[],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::const_zero().value,
],
0x1234.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
true,
false,
true,
@ -284,13 +274,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
false,
false,
@ -310,13 +299,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
true,
false,
true,
@ -336,13 +324,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
true,
false,
@ -362,13 +349,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
true,
true,
false,
@ -388,13 +374,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
(-1i8).cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
true,
false,
@ -414,13 +399,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
(-1i8).cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
true,
true,
false,
@ -440,13 +424,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
false,
true,
false,
@ -466,13 +449,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
true,
true,
false,
@ -489,13 +471,12 @@ fn test_cases() -> Vec<TestCase> {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::const_zero().value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
OutputIntegerMode.Full64(),
true,
false,
true,
@ -508,12 +489,10 @@ fn test_cases() -> Vec<TestCase> {
None,
CompareMOp::compare_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value],
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
0x1234.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::S32(),
OutputIntegerMode.Full64(),
CompareMode.S32(),
),
));
retval.push(insn_single(
@ -522,12 +501,10 @@ fn test_cases() -> Vec<TestCase> {
None,
CompareMOp::compare_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value],
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
(0x89abu16 as i16).cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::S64(),
OutputIntegerMode.Full64(),
CompareMode.S64(),
),
));
retval.push(insn_single(
@ -537,14 +514,12 @@ fn test_cases() -> Vec<TestCase> {
CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::S32(),
OutputIntegerMode.Full64(),
CompareMode.S32(),
),
));
retval.push(insn_single(
@ -554,14 +529,12 @@ fn test_cases() -> Vec<TestCase> {
CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::S64(),
OutputIntegerMode.Full64(),
CompareMode.S64(),
),
));
retval.push(insn_single(
@ -570,12 +543,10 @@ fn test_cases() -> Vec<TestCase> {
None,
CompareMOp::compare_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value],
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
0x1234.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::U32(),
OutputIntegerMode.Full64(),
CompareMode.U32(),
),
));
retval.push(insn_single(
@ -584,12 +555,10 @@ fn test_cases() -> Vec<TestCase> {
None,
CompareMOp::compare_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value],
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
0x89ab.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::U64(),
OutputIntegerMode.Full64(),
CompareMode.U64(),
),
));
retval.push(insn_single(
@ -599,14 +568,12 @@ fn test_cases() -> Vec<TestCase> {
CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::U32(),
OutputIntegerMode.Full64(),
CompareMode.U32(),
),
));
retval.push(insn_single(
@ -616,14 +583,12 @@ fn test_cases() -> Vec<TestCase> {
CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::U64(),
OutputIntegerMode.Full64(),
CompareMode.U64(),
),
));
retval.push(insn_single(
@ -633,14 +598,12 @@ fn test_cases() -> Vec<TestCase> {
CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::CmpRBOne(),
OutputIntegerMode.Full64(),
CompareMode.CmpRBOne(),
),
));
retval.push(insn_single(
@ -650,14 +613,12 @@ fn test_cases() -> Vec<TestCase> {
CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::CmpRBTwo(),
OutputIntegerMode.Full64(),
CompareMode.CmpRBTwo(),
),
));
retval.push(insn_single(
@ -667,14 +628,12 @@ fn test_cases() -> Vec<TestCase> {
CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
MOpRegNum::power_isa_gpr_reg_imm(4).value,
MOpRegNum::power_isa_gpr_reg_imm(5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
#[hdl(sim)]
CompareMode::CmpEqB(),
OutputIntegerMode.Full64(),
CompareMode.CmpEqB(),
),
));
macro_rules! insn_logic_i {
@ -704,10 +663,7 @@ fn test_cases() -> Vec<TestCase> {
&[]
},
),
[MOpRegNum::power_isa_gpr_reg(
($src as u8).cast_to_static::<UInt<_>>().to_expr(),
)
.value],
[MOpRegNum::power_isa_gpr_reg_imm($src).value],
(($imm as u32) << if $mnemonic.contains('s') { 16 } else { 0 })
.cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(),
@ -781,14 +737,8 @@ fn test_cases() -> Vec<TestCase> {
},
),
[
MOpRegNum::power_isa_gpr_reg(
($src0 as u8).cast_to_static::<UInt<_>>().to_expr(),
)
.value,
MOpRegNum::power_isa_gpr_reg(
($src1 as u8).cast_to_static::<UInt<_>>().to_expr(),
)
.value,
MOpRegNum::power_isa_gpr_reg_imm($src0).value,
MOpRegNum::power_isa_gpr_reg_imm($src1).value,
],
0.cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(),
@ -838,7 +788,7 @@ fn test_cases() -> Vec<TestCase> {
None,
MoveRegMOp::move_reg(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value],
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
0.cast_to_static::<SInt<_>>(),
),
));
@ -892,6 +842,71 @@ fn test_cases() -> Vec<TestCase> {
0x7c832879;
|[a, b]| a & !b;
}
macro_rules! insn_exts {
(
$mnemonic:literal $dest:literal, $src:literal;
$encoding:literal;
$OutputIntegerMode:ident;
) => {
retval.push(insn_single(
concat!($mnemonic, " ", stringify!($dest), ", ", stringify!($src)),
$encoding,
None,
LogicalMOp::logical_i(
MOpDestReg::new_sim(
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
if $mnemonic.contains('.') {
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
} else {
&[]
},
),
[MOpRegNum::power_isa_gpr_reg_imm($src).value],
0.cast_to_static::<SInt<_>>(),
OutputIntegerMode.$OutputIntegerMode(),
LogicalMOp::lut_from_fn(|[a, b]| a | b),
),
));
};
}
insn_exts! {
"extsb" 3, 4;
0x7c830774;
SignExt8;
}
insn_exts! {
"extsb." 3, 4;
0x7c830775;
SignExt8;
}
insn_exts! {
"extsh" 3, 4;
0x7c830734;
SignExt16;
}
insn_exts! {
"extsh." 3, 4;
0x7c830735;
SignExt16;
}
insn_exts! {
"extsw" 3, 4;
0x7c8307b4;
SignExt32;
}
insn_exts! {
"extsw." 3, 4;
0x7c8307b5;
SignExt32;
}
// ensure pnop decodes to zero instructions
retval.push(insn_empty(
// LLVM doesn't support the pnop instruction:
// https://github.com/llvm/llvm-project/issues/176831
".long 0x07000000, 0 # pnop",
0x07000000,
Some(0),
));
retval
}
@ -950,6 +965,24 @@ fn test_test_cases_assembly() -> std::io::Result<()> {
let Some(line) = lines.next() else {
panic!("output missing line for: {test_case:?}");
};
if line.starts_with("\t.long") {
assert_eq!(
line,
format!("\t.long\t{first_input}"),
"test_case={test_case:?}\nline:\n{line}"
);
if let Some(second_input) = second_input {
let Some(line) = lines.next() else {
panic!("output missing line for: {test_case:?}");
};
assert_eq!(
line,
format!("\t.long\t{second_input}"),
"test_case={test_case:?}\nline:\n{line}"
);
}
continue;
}
let Some((_, comment)) = line.split_once('#') else {
panic!("output line missing comment. test_case={test_case:?}\nline:\n{line}");
};