From 79d220ce177833f7dd80e15e1094bbfbf4c6f8b1 Mon Sep 17 00:00:00 2001
From: iximeow <me@iximeow.net>
Date: Sun, 17 Mar 2024 02:34:27 +0000
Subject: system instruction and register improvements

* cN instead of crN for control registers
* # for immediates in sys/sysl instructions
* write out ARM system register names in the way the ARM reference manual says
---
 src/armv8/a64.rs   | 30 ++++++++++++++++++++----------
 tests/armv8/a64.rs | 20 ++++++++++++++++++++
 2 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs
index de7a743..19440ba 100644
--- a/src/armv8/a64.rs
+++ b/src/armv8/a64.rs
@@ -600,20 +600,20 @@ impl Display for Instruction {
                 }
             },
             Opcode::SYS(ops) => {
-                return write!(fmt, "sys {:#x}, {}, {}, {:#x}, {}",
+                return write!(fmt, "sys #{:#x}, {}, {}, #{:#x}, {}",
                     ops.op1(),
-                    self.operands[0],
                     self.operands[1],
-                    ops.op2(),
                     self.operands[2],
+                    ops.op2(),
+                    self.operands[0],
                 );
             }
             Opcode::SYSL(ops) => {
-                return write!(fmt, "sysl {}, {:#x}, {}, {}, {:#x}",
-                    self.operands[0],
+                return write!(fmt, "sysl {}, #{:#x}, {}, {}, #{:#x}",
+                    self.operands[2],
                     ops.op1(),
+                    self.operands[0],
                     self.operands[1],
-                    self.operands[2],
                     ops.op2(),
                 );
             }
@@ -2910,7 +2910,7 @@ impl Display for Operand {
                 write!(fmt, "{}, {}", Operand::Register(*size, *reg), Operand::Register(*size, *reg + 1))
             },
             Operand::ControlReg(reg) => {
-                write!(fmt, "cr{}", reg)
+                write!(fmt, "c{}", reg)
             },
             Operand::PrefetchOp(op) => {
                 let ty = (op >> 3) & 0b11;
@@ -2933,7 +2933,17 @@ impl Display for Operand {
                     0x4000 => fmt.write_str("midr_el1"),
                     0x5e82 => fmt.write_str("tpidr_el0"),
                     0x5f02 => fmt.write_str("cntvct_el0"),
-                    _ => write!(fmt, "sysreg:{:x}", reg),
+                    _ => {
+                        // syntax for otherwise-undescribed system register names is described in
+                        // MRS or similar, S<op0>_<op1>_<Cn>_<Cm>_<op2>
+                        // ... but that "op0" is `o0` + 2.
+                        let op2 = reg & 0b111;
+                        let CRm = (reg >> 3) & 0b1111;
+                        let CRn = (reg >> 7) & 0b1111;
+                        let op1 = (reg >> 11) & 0b111;
+                        let op0 = ((reg >> 14) & 0b1) + 2;
+                        write!(fmt, "s{op0}_{op1}_c{CRn}_c{CRm}_{op2}")
+                    },
                 }
             }
             Operand::PstateField(reg) => {
@@ -10418,7 +10428,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                     }
                                 }
                                 0b001 => {
-                                    let Rt = word & 0b1111;
+                                    let Rt = word & 0b11111;
                                     let op2 = (word >> 5) & 0b111;
                                     let CRm = (word >> 8) & 0b1111;
                                     let CRn = (word >> 12) & 0b1111;
@@ -10447,7 +10457,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                     inst.opcode = Opcode::Invalid;
                                 }
                                 0b101 => {
-                                    let Rt = word & 0b1111;
+                                    let Rt = word & 0b11111;
                                     let op2 = (word >> 5) & 0b111;
                                     let CRm = (word >> 8) & 0b1111;
                                     let CRn = (word >> 12) & 0b1111;
diff --git a/tests/armv8/a64.rs b/tests/armv8/a64.rs
index 1d04a76..a3ec96e 100644
--- a/tests/armv8/a64.rs
+++ b/tests/armv8/a64.rs
@@ -4753,6 +4753,26 @@ fn test_vec_shift() {
 }
 
 #[test]
+fn test_system() {
+    const TESTS: &[([u8; 4], &'static str)] = &[
+        ([0x00, 0x00, 0x08, 0xd5], "sys #0x0, c0, c0, #0x0, x0"),
+        ([0x00, 0x00, 0x28, 0xd5], "sysl x0, #0x0, c0, c0, #0x0"),
+        ([0x10, 0x00, 0x08, 0xd5], "sys #0x0, c0, c0, #0x0, x16"),
+        ([0x10, 0x00, 0x28, 0xd5], "sysl x16, #0x0, c0, c0, #0x0"),
+        ([0xab, 0x03, 0x08, 0xd5], "sys #0x0, c0, c3, #0x5, x11"),
+        ([0xab, 0x03, 0x28, 0xd5], "sysl x11, #0x0, c0, c3, #0x5"),
+        ([0x00, 0x00, 0x30, 0xd5], "mrs x0, s2_0_c0_c0_0"),
+    ];
+    let errs = run_tests(TESTS);
+
+    for err in errs.iter() {
+        println!("{}", err);
+    }
+
+    assert!(errs.is_empty());
+}
+
+#[test]
 fn test_pac() {
     const TESTS: &[([u8; 4], &'static str)] = &[
         ([0x00, 0x04, 0xc1, 0xda], "pacib x0, x0"),
-- 
cgit v1.1