diff options
| author | iximeow <me@iximeow.net> | 2021-10-21 13:54:40 -0700 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2021-10-21 13:54:40 -0700 | 
| commit | eadc1ab0ceb5b3cd5f88b696d72b5c0592a63da5 (patch) | |
| tree | 1cfcb78315648b467d9f6a146dc0f57cd043e1cf | |
| parent | 80737e150dbc143e95b2b1c995d087822dda9a0b (diff) | |
ccm{n,p}
| -rw-r--r-- | src/armv8/a64.rs | 49 | ||||
| -rw-r--r-- | test/armv8/a64.rs | 8 | 
2 files changed, 56 insertions, 1 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 453778e..16a4116 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -641,6 +641,12 @@ impl Display for Instruction {              Opcode::PACIZA => {                  write!(fmt, "paciza")?;              } +            Opcode::CCMN => { +                write!(fmt, "ccmn")?; +            } +            Opcode::CCMP => { +                write!(fmt, "ccmp")?; +            }          };          if self.operands[0] != Operand::Nothing { @@ -808,6 +814,8 @@ pub enum Opcode {      CSINV,      PACIA,      PACIZA, +    CCMN, +    CCMP,  }  #[derive(Copy, Clone, Debug, PartialEq)] @@ -1175,7 +1183,46 @@ impl Decoder<ARMv8> for InstDecoder {                          },                          0b001 => {                              // Conditional compare (register/immediate) -                            return Err(DecodeError::IncompleteDecoder); +                            let imm_or_reg = (word >> 11) & 0x01; + +                            let o3 = (word >> 4) & 0x01; +                            let o2 = (word >> 10) & 0x01; +                            let S = (word >> 29) & 0x01; +                            let op = (word >> 30) & 0x01; +                            let sf = (word >> 31) & 0x01; + +                            if S != 1 || o2 != 0 || o3 != 0 { +                                inst.opcode = Opcode::Invalid; +                                return Err(DecodeError::InvalidOpcode); +                            } + +                            let size = if sf == 1 { +                                SizeCode::X +                            } else { +                                SizeCode::W +                            }; + +                            inst.opcode = if op == 1 { +                                Opcode::CCMP +                            } else { +                                Opcode::CCMN +                            }; + +                            let Rn = ((word >> 5) & 0x1f) as u16; +                            let Rm = ((word >> 16) & 0x1f) as u16; +                            let cond = ((word >> 12) & 0x0f) as u8; +                            let nzcv = (word & 0x0f) as u8; + +                            inst.operands = [ +                                Operand::Register(size, Rn), +                                if imm_or_reg == 1 { +                                    Operand::Immediate(Rm as u32) +                                } else { +                                    Operand::Register(size, Rm) +                                }, +                                Operand::Immediate(nzcv as u32), +                                Operand::ConditionCode(cond), +                            ]                          },                          0b010 => {                              // Conditional select diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs index 0e25c93..5b480df 100644 --- a/test/armv8/a64.rs +++ b/test/armv8/a64.rs @@ -287,6 +287,14 @@ fn test_decode_mul() {  }  #[test] +fn test_decode_ccm() { +    test_display([0x00, 0xa8, 0x42, 0x3a], "ccmn w0, 0x2, 0x0, ge"); +    test_display([0x00, 0xa8, 0x42, 0xfa], "ccmp x0, 0x2, 0x0, ge"); +    test_display([0x00, 0xa0, 0x42, 0xfa], "ccmp x0, x2, 0x0, ge"); +    test_display([0x85, 0x80, 0x42, 0xfa], "ccmp x4, x2, 0x5, hi"); +} + +#[test]  fn test_decode_chrome_entrypoint() {      // 1400 instructions from the entrypoint of a chrome binary, sorted by      // instruction word for no good reason.  | 
