summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2025-04-06 17:02:31 -0700
committeriximeow <me@iximeow.net>2025-04-06 17:02:31 -0700
commitdc1fb4bde1ea601e8be3a7ce3f4244344d1f8e3c (patch)
tree2b25540802492e9d3ecb963941c5da03d96ff826
parent1e3e699c38ad919946a5352b6c3d0ff7fe977624 (diff)
gross hacks for AddAsl, fix AddMpyi decoding
-rw-r--r--src/display.rs70
-rw-r--r--src/lib.rs46
-rw-r--r--tests/from_brain.rs56
3 files changed, 131 insertions, 41 deletions
diff --git a/src/display.rs b/src/display.rs
index 1d1e1ae..f2b0e51 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -107,6 +107,14 @@ impl fmt::Display for Instruction {
return write!(f, "{} = or({}, asl({}, {}))", self.dest.as_ref().unwrap(),
self.sources[0], self.sources[1], self.sources[2]);
},
+ Opcode::AddAdd => {
+ return write!(f, "{} = add({}, add({}, {}))", self.dest.as_ref().unwrap(),
+ self.sources[0], self.sources[1], self.sources[2]);
+ },
+ Opcode::AddSub => {
+ return write!(f, "{} = add({}, sub({}, {}))", self.dest.as_ref().unwrap(),
+ self.sources[0], self.sources[1], self.sources[2]);
+ },
Opcode::AddMpyi => {
return write!(f, "{} = add({}, mpyi({}, {}))", self.dest.as_ref().unwrap(),
self.sources[0], self.sources[1], self.sources[2]);
@@ -341,24 +349,46 @@ impl fmt::Display for Instruction {
if needs_parens { f.write_str(")")?; }
// ... vxaddsubh has the right shift after round, but cmpyiwh and friends have the left
- // shift before round.
- if let Some(shift) = self.flags.shift_left {
- write!(f, ":<<{}", shift)?;
- }
- if let Some(mode) = self.flags.rounded {
- write!(f, "{}", mode.as_label())?;
- }
- if self.flags.chop {
- f.write_str(":chop")?;
- }
- if let Some(shift) = self.flags.shift_right {
- write!(f, ":>>{}", shift)?;
- }
- if self.flags.carry {
- f.write_str(":carry")?;
- }
- if self.flags.saturate {
- f.write_str(":sat")?;
+ // shift before round. cmpyiwh and add/sub `:sat:<<16` forms have the shift in different
+ // positions. awful awful awful.
+ if self.opcode == Opcode::Add || self.opcode == Opcode::Sub {
+ if let Some(mode) = self.flags.rounded {
+ write!(f, "{}", mode.as_label())?;
+ }
+ if self.flags.chop {
+ f.write_str(":chop")?;
+ }
+ if self.flags.carry {
+ f.write_str(":carry")?;
+ }
+ if self.flags.saturate {
+ f.write_str(":sat")?;
+ }
+ if let Some(shift) = self.flags.shift_right {
+ write!(f, ":>>{}", shift)?;
+ }
+ if let Some(shift) = self.flags.shift_left {
+ write!(f, ":<<{}", shift)?;
+ }
+ } else {
+ if let Some(shift) = self.flags.shift_left {
+ write!(f, ":<<{}", shift)?;
+ }
+ if let Some(mode) = self.flags.rounded {
+ write!(f, "{}", mode.as_label())?;
+ }
+ if self.flags.chop {
+ f.write_str(":chop")?;
+ }
+ if let Some(shift) = self.flags.shift_right {
+ write!(f, ":>>{}", shift)?;
+ }
+ if self.flags.carry {
+ f.write_str(":carry")?;
+ }
+ if self.flags.saturate {
+ f.write_str(":sat")?;
+ }
}
if self.flags.deprecated {
f.write_str(":deprecated")?;
@@ -683,6 +713,10 @@ impl fmt::Display for Opcode {
Opcode::SubLsr => { f.write_str("sublsr") },
Opcode::AddLsl => { f.write_str("addlsl") },
Opcode::AddAsl => { f.write_str("addasl") },
+ // this is the form shown literally as `addasl`, in contrast to the form above which
+ // shouldn't ever really be printed as `addasl` (instruction display has more complex
+ // rules here.
+ Opcode::AddAslRegReg => { f.write_str("addasl") },
Opcode::SubAsl => { f.write_str("subasl") },
Opcode::AndAsl => { f.write_str("andasl") },
Opcode::AddClb => { f.write_str("addclb") },
diff --git a/src/lib.rs b/src/lib.rs
index 7f95ad6..fc82124 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -822,9 +822,9 @@ pub enum Opcode {
Vrmpyu,
Vrmpysu,
- // `Rd=addasl(Rt,Rs,#u3)` sure makes this look like it should not have special
- // display rules. but wth?
- AddAsl,
+ // `Rd=addasl(Rt,Rs,#u3)` wants the "typical" operand rending rules, rather than
+ // `add(x, asl(y, z))` that would be used below. terrible.
+ AddAslRegReg,
AndAnd = 0x8000,
AndOr,
@@ -841,6 +841,7 @@ pub enum Opcode {
AddLsr,
SubLsr,
AddLsl,
+ AddAsl,
SubAsl,
AndAsl,
OrAsl,
@@ -4634,7 +4635,7 @@ fn decode_instruction<
opcode_check!(minbits == 0b000);
operand_check!(inst & 0b0010_0000_0000_0000 == 0);
- handler.on_opcode_decoded(Opcode::AddAsl)?;
+ handler.on_opcode_decoded(Opcode::AddAslRegReg)?;
handler.on_dest_decoded(Operand::gpr(ddddd))?;
handler.on_source_decoded(Operand::gpr(ttttt))?;
handler.on_source_decoded(Operand::gpr(sssss))?;
@@ -5439,15 +5440,15 @@ fn decode_instruction<
let i9 = (inst >> 5) & 0b1_1111_1111;
let i_hi = (inst >> 21) & 1;
let i10 = i9 | (i_hi << 9);
- let i = (i10 as i16) << 6 >> 6;
+ let i = (i10 as u16) << 6 >> 6;
- let op = (inst >> 23) & 1;
+ let op = (inst >> 22) & 0b11;
opcode_check!(op & 0b10 == 0);
handler.on_dest_decoded(Operand::gpr(ddddd))?;
handler.on_opcode_decoded(Opcode::DfMake)?;
- handler.on_source_decoded(Operand::imm_i16(i))?;
+ handler.on_source_decoded(Operand::imm_u16(i))?;
if op == 0 {
handler.rounded(RoundingMode::Pos)?;
} else {
@@ -5479,9 +5480,9 @@ fn decode_instruction<
let i10 = i9 | (i_hi << 9);
let i = (i10 as i16) << 6 >> 6;
handler.on_opcode_decoded(Opcode::OrAnd)?;
- handler.on_dest_decoded(Operand::gpr(sssss))?;
- handler.on_source_decoded(Operand::gpr(uuuuu))?;
- handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_dest_decoded(Operand::gpr(reg_b16(inst)))?;
+ handler.on_source_decoded(Operand::gpr(reg_b0(inst)))?;
+ handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?;
handler.on_source_decoded(Operand::imm_i16(i))?;
}
0b10 => {
@@ -5544,18 +5545,17 @@ fn decode_instruction<
}
handler.on_source_decoded(Operand::imm_u8(imm as u8))?;
- const OPCODES: [Option<Opcode>; 64] = [
- Some(Opcode::VcmpbEq), Some(Opcode::VcmpbEq), Some(Opcode::VcmpbEq), None,
+ const OPCODES: [Option<Opcode>; 32] = [
+ Some(Opcode::VcmpbEq), Some(Opcode::VcmphEq), Some(Opcode::VcmpwEq), None,
+ Some(Opcode::VcmpbGt), Some(Opcode::VcmphGt), Some(Opcode::VcmpwGt), None,
+ // 0b01000
+ Some(Opcode::VcmpbGtu), Some(Opcode::VcmphGtu), Some(Opcode::VcmpwGtu), None,
+ None, None, None, None,
+ // 0b10000
+ None, None, Some(DfClass), None,
None, None, None, None,
- Some(Opcode::VcmpbGt), Some(Opcode::VcmpbGt), Some(Opcode::VcmpbGt), None,
None, None, None, None,
- Some(Opcode::VcmpbGtu), Some(Opcode::VcmpbGtu), Some(Opcode::VcmpbGtu), None,
None, None, None, None,
- None, None, None, None, Some(DfClass), None, None, None,
- None, None, None, None, None, None, None, None,
- None, None, None, None, None, None, None, None,
- None, None, None, None, None, None, None, None,
- None, None, None, None, None, None, None, None,
];
handler.on_opcode_decoded(decode_opcode!(OPCODES[opc as usize]))?;
@@ -5598,7 +5598,7 @@ fn decode_instruction<
handler.on_dest_decoded(Operand::gpr(xxxxx))?;
handler.on_source_decoded(Operand::imm_u8(i as u8))?;
- handler.on_dest_decoded(Operand::gpr(xxxxx))?;
+ handler.on_source_decoded(Operand::gpr(xxxxx))?;
handler.on_source_decoded(Operand::imm_u8(u5))?;
const OPCODES: [Opcode; 8] = [
@@ -5611,10 +5611,10 @@ fn decode_instruction<
handler.on_opcode_decoded(OPCODES[opc as usize])?;
}
0b1111 => {
- let order = (inst >> 24) & 1;
+ let order = (inst >> 23) & 1;
let uuuuu = reg_b0(inst);
- let ddddd = reg_b0(inst);
- let sssss = reg_b0(inst);
+ let ddddd = reg_b8(inst);
+ let sssss = reg_b16(inst);
let i_lo = (inst >> 5) & 0b111;
let i_mid = (inst >> 13) & 0b1;
let i_hi = (inst >> 21) & 0b11;
diff --git a/tests/from_brain.rs b/tests/from_brain.rs
index 5be4a5c..abaef4f 100644
--- a/tests/from_brain.rs
+++ b/tests/from_brain.rs
@@ -1358,6 +1358,62 @@ fn inst_1101() {
test_invalid(&0b1101_0111_110_10100_11_100110_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
test_display(&0b1101_1000_110_10100_11_100110_100_10110u32.to_le_bytes(), "{ R6 = add(#0x2c, mpyi(R20, #0x36)) }");
+
+ test_display(&0b1101_1001_001_10100_11_100110_100_10110u32.to_le_bytes(), "{ R22 = dfmake(#0x334):pos }");
+ test_display(&0b1101_1001_011_10100_11_100110_100_10110u32.to_le_bytes(), "{ R22 = dfmake(#0x334):neg }");
+ test_invalid(&0b1101_1001_101_10100_11_100110_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b1101_1001_111_10100_11_100110_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b1101_1010_001_10100_11_100110_100_10110u32.to_le_bytes(), "{ R22 |= and(R20, #-204) }");
+ test_display(&0b1101_1010_011_10100_11_100110_100_10110u32.to_le_bytes(), "{ R20 = or(R22, and(R20, #-204)) }");
+ test_display(&0b1101_1010_101_10100_11_100110_100_10110u32.to_le_bytes(), "{ R22 |= or(R20, #-204) }");
+ test_invalid(&0b1101_1010_111_10100_11_100110_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b1101_1011_001_10100_11_100110_100_10110u32.to_le_bytes(), "{ R6 = add(R20, add(R22, #28)) }");
+ test_display(&0b1101_1011_101_10100_11_100110_100_10110u32.to_le_bytes(), "{ R6 = add(R20, sub(#28, R22)) }");
+
+ test_display(&0b1101_1100_000_10100_11_100110_100_00110u32.to_le_bytes(), "{ P2 = vcmpb.eq(R21:20, #0x34) }");
+ test_display(&0b1101_1100_000_10100_11_100110_100_01110u32.to_le_bytes(), "{ P2 = vcmph.eq(R21:20, #0x34) }");
+ test_display(&0b1101_1100_000_10100_11_100110_100_10110u32.to_le_bytes(), "{ P2 = vcmpw.eq(R21:20, #0x34) }");
+ test_invalid(&0b1101_1100_000_10100_11_100110_100_11110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b1101_1100_001_10100_11_100110_100_00110u32.to_le_bytes(), "{ P2 = vcmpb.gt(R21:20, #0x34) }");
+ test_display(&0b1101_1100_001_10100_11_100110_100_01110u32.to_le_bytes(), "{ P2 = vcmph.gt(R21:20, #0x34) }");
+ test_display(&0b1101_1100_001_10100_11_100110_100_10110u32.to_le_bytes(), "{ P2 = vcmpw.gt(R21:20, #0x34) }");
+ test_invalid(&0b1101_1100_001_10100_11_100110_100_11110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b1101_1100_010_10100_11_100110_100_00110u32.to_le_bytes(), "{ P2 = vcmpb.gtu(R21:20, #0x34) }");
+ test_display(&0b1101_1100_010_10100_11_100110_100_01110u32.to_le_bytes(), "{ P2 = vcmph.gtu(R21:20, #0x34) }");
+ test_display(&0b1101_1100_010_10100_11_100110_100_10110u32.to_le_bytes(), "{ P2 = vcmpw.gtu(R21:20, #0x34) }");
+ test_invalid(&0b1101_1100_010_10100_11_100110_100_11110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ // top bit of the immediate must be 0
+ test_invalid(&0b1101_1100_010_10100_11_110110_100_00110u32.to_le_bytes(), DecodeError::InvalidOperand);
+ test_invalid(&0b1101_1100_010_10100_11_110110_100_01110u32.to_le_bytes(), DecodeError::InvalidOperand);
+ test_invalid(&0b1101_1100_010_10100_11_110110_100_10110u32.to_le_bytes(), DecodeError::InvalidOperand);
+ test_invalid(&0b1101_1100_010_10100_11_110110_100_11110u32.to_le_bytes(), DecodeError::InvalidOperand);
+
+ test_display(&0b1101_1100_100_10100_11_100010_100_10110u32.to_le_bytes(), "{ P2 = dfclass(R21:20, #0x14) }");
+
+ test_display(&0b1101_1101_000_10100_11_100110_100_00110u32.to_le_bytes(), "{ P2 = cmpb.gt(R20, #0x34) }");
+ test_display(&0b1101_1101_000_10100_11_100110_100_01110u32.to_le_bytes(), "{ P2 = cmph.gt(R20, #0x34) }");
+ test_display(&0b1101_1101_001_10100_11_100110_100_00110u32.to_le_bytes(), "{ P2 = cmpb.eq(R20, #0x34) }");
+ test_display(&0b1101_1101_001_10100_11_100110_100_01110u32.to_le_bytes(), "{ P2 = cmph.eq(R20, #0x34) }");
+ test_display(&0b1101_1101_010_10100_11_100110_100_00110u32.to_le_bytes(), "{ P2 = cmpb.gtu(R20, #0x34) }");
+ test_display(&0b1101_1101_010_10100_11_100110_100_01110u32.to_le_bytes(), "{ P2 = cmph.gtu(R20, #0x34) }");
+ test_invalid(&0b1101_1101_010_10100_11_110110_100_00110u32.to_le_bytes(), DecodeError::InvalidOperand);
+ test_invalid(&0b1101_1101_010_10100_11_110110_100_01110u32.to_le_bytes(), DecodeError::InvalidOperand);
+ test_invalid(&0b1101_1101_011_10100_11_110110_100_00110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b1101_1101_011_10100_11_110110_100_01110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b1101_1110_010_10100_11_100110_100_00000u32.to_le_bytes(), "{ R20 = and(#0x98, asl(R20, #0x6)) }");
+ test_display(&0b1101_1110_010_10100_11_100110_100_00010u32.to_le_bytes(), "{ R20 = or(#0x98, asl(R20, #0x6)) }");
+ test_display(&0b1101_1110_010_10100_11_100110_100_00100u32.to_le_bytes(), "{ R20 = add(#0x98, asl(R20, #0x6)) }");
+ test_display(&0b1101_1110_010_10100_11_100110_100_00110u32.to_le_bytes(), "{ R20 = sub(#0x98, asl(R20, #0x6)) }");
+ test_display(&0b1101_1110_010_10100_11_100110_100_10000u32.to_le_bytes(), "{ R20 = and(#0x98, lsr(R20, #0x6)) }");
+ test_display(&0b1101_1110_010_10100_11_100110_100_10010u32.to_le_bytes(), "{ R20 = or(#0x98, lsr(R20, #0x6)) }");
+ test_display(&0b1101_1110_010_10100_11_100110_100_10100u32.to_le_bytes(), "{ R20 = add(#0x98, lsr(R20, #0x6)) }");
+ test_display(&0b1101_1110_010_10100_11_100110_100_10110u32.to_le_bytes(), "{ R20 = sub(#0x98, lsr(R20, #0x6)) }");
+
+ test_display(&0b1101_1111_010_10100_11_100110_100_10110u32.to_le_bytes(), "{ R6 = add(R22, mpyi(#0xb0, R20)) }");
+ test_display(&0b1101_1111_110_10100_11_100110_100_10110u32.to_le_bytes(), "{ R6 = add(R22, mpyi(R20, #0xb0)) }");
}
#[test]