diff options
author | iximeow <me@iximeow.net> | 2025-04-06 17:02:31 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2025-04-06 17:02:31 -0700 |
commit | dc1fb4bde1ea601e8be3a7ce3f4244344d1f8e3c (patch) | |
tree | 2b25540802492e9d3ecb963941c5da03d96ff826 | |
parent | 1e3e699c38ad919946a5352b6c3d0ff7fe977624 (diff) |
gross hacks for AddAsl, fix AddMpyi decoding
-rw-r--r-- | src/display.rs | 70 | ||||
-rw-r--r-- | src/lib.rs | 46 | ||||
-rw-r--r-- | tests/from_brain.rs | 56 |
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") }, @@ -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] |