aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/armv8/a64.rs49
-rw-r--r--test/armv8/a64.rs8
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.