decode all fixed-point add/sub instructions other than addex

This commit is contained in:
Jacob Lifshay 2026-01-18 15:02:15 -08:00
parent 62512960c3
commit a4b052f5f3
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
3 changed files with 2112 additions and 281 deletions

View file

@ -185,6 +185,10 @@ impl_fields! {
struct FieldRT(FieldGpr);
#[name = "SI"]
struct FieldSI(SInt<16>);
#[name = "si0"]
struct FieldSi0(SInt<18>);
#[name = "si1"]
struct FieldSi1(UInt<16>);
#[name = "d0"]
struct FieldAddPcISD0(SInt<10>);
#[name = "d1"]
@ -193,6 +197,8 @@ impl_fields! {
struct FieldAddPcISD2(UInt<1>);
#[name = "OE"]
struct FieldOE(Bool);
#[name = "R"]
struct FieldR(Bool);
#[name = "Rc"]
struct FieldRc(Bool);
}
@ -388,17 +394,17 @@ impl DecodeState {
}
if let Some(prefix) = self.header.bit_fields().prefix() {
#[hdl]
if let HdlSome(prefix_word) = self.second_input {
if let HdlSome(suffix_word) = self.second_input {
self.decode_word(
&mut matches,
&mut fields,
prefix_word,
self.first_input,
prefix.fields_inner(),
);
self.decode_word(
&mut matches,
&mut fields,
self.first_input,
suffix_word,
self.header.bit_fields().fields_inner(),
);
run(self, matches, &mut fields, &mut f);
@ -442,7 +448,28 @@ impl DecodeState {
});
}
"paddi" => {
// TODO
self.decode_scope(
|this, (FieldRT(rt), FieldRA(ra), FieldSi0(si0), FieldSi1(si1), FieldR(r))| {
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
AddSubMOp::add_sub_i(
MOpDestReg::new([gpr(rt)], []),
#[hdl]
[gpr_or_zero(ra).value, MOpRegNum::const_zero().value],
((si0 << 16) + si1.cast_to(SInt[34])).cast_to_static(),
OutputIntegerMode.Full64(),
false,
false,
false,
r,
),
);
},
);
}
_ => unreachable!("{:?}", self.mnemonic),
}
@ -561,14 +588,74 @@ impl DecodeState {
);
});
}
/// for `subf[o][.]`
/// for `subf[c][o][.]`
#[hdl]
fn decode_subf(&mut self) {
// TODO
fn decode_subf_subfc(&mut self) {
self.decode_scope(
|this, (FieldRT(rt), FieldRA(ra), FieldRB(rb), FieldOE(oe), FieldRc(rc))| {
// TODO: handle SO propagation
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
AddSubMOp::add_sub(
MOpDestReg::new(
[
gpr(rt),
if this.mnemonic.contains('c') {
MOpRegNum::power_isa_xer_ca_ca32_reg()
} else {
MOpRegNum::const_zero()
},
],
[
(MOpRegNum::POWER_ISA_XER_SO_OV_OV32_REG_NUM, oe),
(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc),
],
),
#[hdl]
[gpr(ra).value, gpr(rb).value, MOpRegNum::const_zero().value],
0i8.cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(),
true,
false,
true,
false,
),
);
},
);
}
#[hdl]
fn decode_subfic(&mut self) {
// TODO
self.decode_scope(|this, (FieldRT(rt), FieldRA(ra), FieldSI(si))| {
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
AddSubMOp::add_sub_i(
MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
[(
MOpRegNum::POWER_ISA_CR_0_REG_NUM,
self.mnemonic.ends_with('.').to_expr(),
)],
),
#[hdl]
[gpr(ra).value, MOpRegNum::const_zero().value],
si.cast_to_static(),
OutputIntegerMode.Full64(),
true,
false,
true,
false,
),
);
});
}
/// for `addc[o][.]`
#[hdl]
@ -603,11 +690,6 @@ impl DecodeState {
},
);
}
/// for `subfc[o][.]`
#[hdl]
fn decode_subfc(&mut self) {
// TODO
}
/// for `adde[o][.]`
#[hdl]
fn decode_adde(&mut self) {
@ -645,6 +727,118 @@ impl DecodeState {
},
);
}
/// for `subfe[o][.]`
#[hdl]
fn decode_subfe(&mut self) {
self.decode_scope(
|this, (FieldRT(rt), FieldRA(ra), FieldRB(rb), FieldOE(oe), FieldRc(rc))| {
// TODO: handle SO propagation
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
AddSubMOp::add_sub(
MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
[
(MOpRegNum::POWER_ISA_XER_SO_OV_OV32_REG_NUM, oe),
(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc),
],
),
#[hdl]
[
gpr(ra).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
gpr(rb).value,
],
0i8.cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(),
true,
true,
false,
false,
),
);
},
);
}
/// for `addme[o][.]` and `subfme[o][.]` and `addze[o][.]` and `subfze[o][.]`
#[hdl]
fn decode_addme_subfme_addze_subfze(&mut self) {
self.decode_scope(
|this, (FieldRT(rt), FieldRA(ra), FieldOE(oe), FieldRc(rc))| {
// TODO: handle SO propagation
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
AddSubMOp::add_sub(
MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
[
(MOpRegNum::POWER_ISA_XER_SO_OV_OV32_REG_NUM, oe),
(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc),
],
),
#[hdl]
[
gpr(ra).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
if this.mnemonic.contains('m') { -1i8 } else { 0 }
.cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(),
this.mnemonic.contains("subf"),
true,
false,
false,
),
);
},
);
}
/// for `neg[o][.]`
#[hdl]
fn decode_neg(&mut self) {
self.decode_scope(
|this, (FieldRT(rt), FieldRA(ra), FieldOE(oe), FieldRc(rc))| {
// TODO: handle SO propagation
connect(
ArrayVec::len(this.output),
1usize.cast_to_static::<Length<_>>(),
);
connect(
this.output[0],
AddSubMOp::add_sub(
MOpDestReg::new(
[gpr(rt)],
[
(MOpRegNum::POWER_ISA_XER_SO_OV_OV32_REG_NUM, oe),
(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc),
],
),
#[hdl]
[
gpr(ra).value,
MOpRegNum::const_zero().value,
MOpRegNum::const_zero().value,
],
0i8.cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(),
true,
false,
true,
false,
),
);
},
);
}
}
type DecodeFn = fn(&mut DecodeState);
@ -718,7 +912,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
(&["addic", "addic."], DecodeState::decode_addic),
(
&["subf", "subf.", "subfo", "subfo."],
DecodeState::decode_subf,
DecodeState::decode_subf_subfc,
),
(&["subfic"], DecodeState::decode_subfic),
(
@ -727,33 +921,27 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
),
(
&["subfc", "subfc.", "subfco", "subfco."],
DecodeState::decode_subfc,
DecodeState::decode_subf_subfc,
),
(
&["adde", "adde.", "addeo", "addeo."],
DecodeState::decode_adde,
),
(&["subfe", "subfe.", "subfeo", "subfeo."], |_state| {
// TODO
}),
(&["addme", "addme.", "addmeo", "addmeo."], |_state| {
// TODO
}),
(&["addze", "addze.", "addzeo", "addzeo."], |_state| {
// TODO
}),
(&["subfme", "subfme.", "subfmeo", "subfmeo."], |_state| {
// TODO
}),
(&["subfze", "subfze.", "subfzeo", "subfzeo."], |_state| {
// TODO
}),
(
&["subfe", "subfe.", "subfeo", "subfeo."],
DecodeState::decode_subfe,
),
(
&[
"addme", "addme.", "addmeo", "addmeo.", "addze", "addze.", "addzeo", "addzeo.",
"subfme", "subfme.", "subfmeo", "subfmeo.", "subfze", "subfze.", "subfzeo", "subfzeo.",
],
DecodeState::decode_addme_subfme_addze_subfze,
),
(&["addex"], |_state| {
// TODO
}),
(&["neg", "neg.", "nego", "nego."], |_state| {
// TODO
}),
(&["neg", "neg.", "nego", "nego."], DecodeState::decode_neg),
(
&[
"mulli", "mullw", "mullw.", "mullwo", "mullwo.", "mulhw", "mulhw.", "mulhwu", "mulhwu.",

File diff suppressed because it is too large Load diff

View file

@ -89,6 +89,41 @@ fn test_cases() -> Vec<TestCase> {
false,
),
));
retval.push(insn_single(
"paddi 3, 4, 0x123456789, 0",
0x06012345,
Some(0x38646789),
AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::const_zero().value,
],
0x123456789i64.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
false,
false,
false,
false,
),
));
retval.push(insn_single(
"paddi 3, 0, 0x123456789, 1",
0x06112345,
Some(0x38606789),
AddSubMOp::add_sub_i(
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(),
false,
false,
false,
true,
),
));
retval.push(insn_single(
"addis 3, 4, 0x1234",
0x3C641234,
@ -172,6 +207,54 @@ fn test_cases() -> Vec<TestCase> {
false,
),
));
retval.push(insn_single(
"subf. 3, 4, 5",
0x7c642851,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[MOpRegNum::power_isa_gpr_reg_num(3)],
&[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::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
true,
false,
true,
false,
),
));
retval.push(insn_single(
"subfic 3, 4, 0x1234",
0x20641234,
None,
AddSubMOp::add_sub_i(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num(3),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::const_zero().value,
],
0x1234.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
true,
false,
true,
false,
),
));
retval.push(insn_single(
"addc. 3, 4, 5",
0x7c642815,
@ -198,6 +281,211 @@ fn test_cases() -> Vec<TestCase> {
false,
),
));
retval.push(insn_single(
"subfc. 3, 4, 5",
0x7c642811,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num(3),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[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::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
true,
false,
true,
false,
),
));
retval.push(insn_single(
"adde. 3, 4, 5",
0x7c642915,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num(3),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
false,
true,
false,
false,
),
));
retval.push(insn_single(
"subfe. 3, 4, 5",
0x7c642911,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num(3),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::power_isa_gpr_reg(5_hdl_u5).value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
true,
true,
false,
false,
),
));
retval.push(insn_single(
"addme. 3, 4",
0x7c6401d5,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num(3),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
(-1i8).cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
false,
true,
false,
false,
),
));
retval.push(insn_single(
"subfme. 3, 4",
0x7c6401d1,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num(3),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
(-1i8).cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
true,
true,
false,
false,
),
));
retval.push(insn_single(
"addze. 3, 4",
0x7c640195,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num(3),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
false,
true,
false,
false,
),
));
retval.push(insn_single(
"subfze. 3, 4",
0x7c640191,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[
MOpRegNum::power_isa_gpr_reg_num(3),
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
true,
true,
false,
false,
),
));
retval.push(insn_single(
"neg. 3, 4",
0x7c6400d1,
None,
AddSubMOp::add_sub(
MOpDestReg::new_sim(
&[MOpRegNum::power_isa_gpr_reg_num(3)],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg(4_hdl_u5).value,
MOpRegNum::const_zero().value,
MOpRegNum::const_zero().value,
],
0.cast_to_static::<SInt<_>>(),
#[hdl(sim)]
OutputIntegerMode::Full64(),
true,
false,
true,
false,
),
));
retval
}
@ -349,7 +637,7 @@ fn test_decode_insn() {
);
assert!(
expected == output,
"test_case={test_case:#?}\noutput={output}"
"test_case={test_case:#?}\noutput={output}\nexpected={expected}"
);
}
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();