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] | 
