summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/display.rs6
-rw-r--r--src/lib.rs45
-rw-r--r--tests/from_brain.rs90
3 files changed, 69 insertions, 72 deletions
diff --git a/src/display.rs b/src/display.rs
index e730cee..eb19107 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -932,7 +932,11 @@ impl fmt::Display for Operand {
f.write_str("BUG (operand)")
}
Operand::PCRel32 { rel } => {
- write!(f, "$+#{}", rel)
+ if *rel >= 0 {
+ write!(f, "$+{:#x}", *rel)
+ } else {
+ write!(f, "$-{:#x}", -*rel)
+ }
}
Operand::Gpr { reg } => {
const NAMES: [&'static str; 32] = [
diff --git a/src/lib.rs b/src/lib.rs
index fc399e3..b74f195 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -171,11 +171,11 @@ pub struct InstructionPacket {
/// between parentheses is recorded as a "source", and operands not in parentheses are recorded as
/// "destination". for the simplest instructions, `opcode(operand)` or `opcode(op0, op1, ...)`,
/// there will be no destination, and all operands are in `sources`. for an instruction like
-/// `R4 = add(R3, R5)`, `R4` is recorded as a destination, with `R3` and `R5` recorded as sources.
+/// `r4 = add(r3, r5)`, `r4` is recorded as a destination, with `r3` and `r5` recorded as sources.
///
/// an exception to the above are stores, which look something like
/// ```text
-/// memh(R4 + R2<<3) = R30
+/// memh(r4 + r2<<3) = r30
/// ```
/// in these cases the the operands are an `Operand::RegShiftedReg` describing the operand in
/// parentheses, and an `Operand::Gpr` describing the source of the store on the right-hand side.
@@ -184,11 +184,11 @@ pub struct InstructionPacket {
/// branches set a predicate, while others only compare with a new register value and leave
/// predicate registers unaffected. the former look like
/// ```text
-/// p0 = cmp.gtu(R15, #40); if (!p0.new) jump:t #354
+/// p0 = cmp.gtu(r15, #40); if (!p0.new) jump:t #354
/// ```
/// while the latter look like
/// ```text
-/// if (cmp.eq(R4.new, R2)) jump:t #812
+/// if (cmp.eq(r4.new, r2)) jump:t #812
/// ```
///
/// in the former case, there are two "destinations", `p0` and `PCRel32` for the jump target. `p0`
@@ -238,7 +238,7 @@ pub struct InstructionPacket {
/// ```text
/// | Symbol | Meaning |
/// |--------|---------|
-/// | .sN | Bits `[N-1:0]` are treated as an N-bit signed number. For example, R0.s16 means the least significant 16 bits of R0 are treated as a 16-bit signed number. |
+/// | .sN | Bits `[N-1:0]` are treated as an N-bit signed number. For example, r0.s16 means the least significant 16 bits of r0 are treated as a 16-bit signed number. |
/// | .uN | Bits `[N-1:0]` are treated as an N-bit unsigned number. |
/// | .H | The most significant 16 bits of a 32-bit register. |
/// | .L | The least significant 16 bits of a 32-bit register. |
@@ -1078,22 +1078,15 @@ impl yaxpeax_arch::Instruction for InstructionPacket {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Operand {
Nothing,
- /*
- /// one of the 16 32-bit general purpose registers: `R0 (sp)` through `R15`.
- Register { num: u8 },
- /// one of the 16 32-bit general purpose registers, but a smaller part of it. typically
- /// sign-extended to 32b for processing.
- Subreg { num: u8, width: SizeCode },
- */
PCRel32 { rel: i32 },
- /// `Rn`, a 32-bit register `R<reg>`
+ /// `rR`, a 32-bit register `r<reg>`
///
/// V73 Section 2.1:
- /// > thirty-two 32-bit general-purpose registers (named R0 through R31)
+ /// > thirty-two 32-bit general-purpose registers (named r0 through r31)
///
- /// the last three, `R29, R30, R31` are, when possible, shown as `SP, FR, LR`. they are not
+ /// the last three, `r29, r30, r31` are, when possible, shown as `sp, fr, lr`. they are not
/// necessarily required to serve the purposes of stack pointer, frame register, or link
/// register. they are, however, described as such by the manual and almost certainly used that
/// way by actual code.
@@ -1102,18 +1095,18 @@ pub enum Operand {
Cr { reg: u8 },
/// `Sn`, a 32-bit supervisor register `S<reg>`
Sr { reg: u8 },
- /// `Rn.new`, the version of a 32-bit register `R<reg>` after being written in this instruction
+ /// `rN.new`, the version of a 32-bit register `R<reg>` after being written in this instruction
/// packet.
GprNew { reg: u8 },
- /// `Rn.L`, low 16 bits of `R<reg>`
+ /// `rN.l`, low 16 bits of `r<reg>`
GprLow { reg: u8 },
- /// `Rn.H`, high 16 bits of `R<reg>`
+ /// `rN.h`, high 16 bits of `r<reg>`
GprHigh { reg: u8 },
- /// the complex conjugate of `R<reg>`. this is only used in a few instructions performing
- /// complex multiplies, and is displayed as `Rn*`.
+ /// the complex conjugate of `r<reg>`. this is only used in a few instructions performing
+ /// complex multiplies, and is displayed as `rN*`.
GprConjugate { reg: u8 },
- /// `Rn:m`, register pair forming a 64-bit value
+ /// `rN:M`, register pair forming a 64-bit value
///
/// V73 Section 2.1:
/// > the general registers can be specified as a pair that represent a single 64-bit register.
@@ -1121,18 +1114,18 @@ pub enum Operand {
/// > NOTE: the first register in a register pair must always be odd-numbered, and the second must be
/// > the next lower register.
///
- /// from Table 2-2, note there is an entry of `R31:R30 (LR:FP)`
+ /// from Table 2-2, note there is an entry of `r31:r30 (lr:fp)`
Gpr64b { reg_low: u8 },
- /// `Rn:m*`, a register pair interpreted as a complex number, conjugated
+ /// `rN:M*`, a register pair interpreted as a complex number, conjugated
///
/// this is only used for forms of `cmpy*w`
Gpr64bConjugate { reg_low: u8 },
- /// `Cn:m`, control register pair forming a 64-bit location
+ /// `cN:M`, control register pair forming a 64-bit location
Cr64b { reg_low: u8 },
- /// `Sn:m`, control register pair forming a 64-bit location
+ /// `sN:M`, control register pair forming a 64-bit location
Sr64b { reg_low: u8 },
- /// `Pn`, a predicate register
+ /// `pN`, a predicate register
PredicateReg { reg: u8 },
RegOffset { base: u8, offset: u32 },
diff --git a/tests/from_brain.rs b/tests/from_brain.rs
index f183fc6..3eb7df1 100644
--- a/tests/from_brain.rs
+++ b/tests/from_brain.rs
@@ -69,37 +69,37 @@ fn supervisor() {
#[test]
fn inst_0001() {
- test_display(&0b0001_0110000_01001_11_00_0111_000_00100u32.to_le_bytes(), "{ r17 = #7; jump $+#8 }");
- test_display(&0b0001_0111000_01001_11_00_0111_000_00100u32.to_le_bytes(), "{ r7 = r17; jump $+#8 }");
+ test_display(&0b0001_0110000_01001_11_00_0111_000_00100u32.to_le_bytes(), "{ r17 = #7; jump $+0x8 }");
+ test_display(&0b0001_0111000_01001_11_00_0111_000_00100u32.to_le_bytes(), "{ r7 = r17; jump $+0x8 }");
- test_display(&0b0001_0011011_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ p1 = cmp.gtu(r17, #3); if (!p1.new) jump:nt $+#-508 }");
- test_display(&0b0001_0011101_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ p1 = tstbit(r17, #0x0); if (p1.new) jump:nt $+#-508 }");
- test_display(&0b0001_0011111_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ p1 = tstbit(r17, #0x0); if (!p1.new) jump:nt $+#-508 }");
- test_display(&0b0001_0011111_11001_11_10_0011_000_00010u32.to_le_bytes(), "{ p1 = tstbit(r17, #0x0); if (!p1.new) jump:t $+#-508 }");
+ test_display(&0b0001_0011011_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ p1 = cmp.gtu(r17, #3); if (!p1.new) jump:nt $-0x1fc }");
+ test_display(&0b0001_0011101_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ p1 = tstbit(r17, #0x0); if (p1.new) jump:nt $-0x1fc }");
+ test_display(&0b0001_0011111_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ p1 = tstbit(r17, #0x0); if (!p1.new) jump:nt $-0x1fc }");
+ test_display(&0b0001_0011111_11001_11_10_0011_000_00010u32.to_le_bytes(), "{ p1 = tstbit(r17, #0x0); if (!p1.new) jump:t $-0x1fc }");
- test_display(&0b0001_0101011_11001_11_10_0111_000_00010u32.to_le_bytes(), "{ p0 = cmp.gtu(r17, r7); if (!p0.new) jump:t $+#-508 }");
- test_display(&0b0001_0101011_11001_11_11_0111_000_00010u32.to_le_bytes(), "{ p1 = cmp.gtu(r17, r7); if (!p1.new) jump:t $+#-508 }");
+ test_display(&0b0001_0101011_11001_11_10_0111_000_00010u32.to_le_bytes(), "{ p0 = cmp.gtu(r17, r7); if (!p0.new) jump:t $-0x1fc }");
+ test_display(&0b0001_0101011_11001_11_11_0111_000_00010u32.to_le_bytes(), "{ p1 = cmp.gtu(r17, r7); if (!p1.new) jump:t $-0x1fc }");
}
#[test]
fn inst_0010() {
- test_display(&0b0010_00000001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(r4.new, r2)) jump:nt $+#812 }");
- test_display(&0b0010_00000001_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(r4.new, r2)) jump:t $+#812 }");
- test_display(&0b0010_00000101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.eq(r4.new, r2)) jump:nt $+#812 }");
- test_display(&0b0010_00001001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gt(r4.new, r2)) jump:nt $+#812 }");
- test_display(&0b0010_00001101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gt(r4.new, r2)) jump:nt $+#812 }");
- test_display(&0b0010_00010001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gtu(r4.new, r2)) jump:nt $+#812 }");
- test_display(&0b0010_00010101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(r4.new, r2)) jump:nt $+#812 }");
- test_display(&0b0010_00011001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gt(r2, r4.new)) jump:nt $+#812 }");
- test_display(&0b0010_00100101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(r2, r4.new)) jump:nt $+#812 }");
+ test_display(&0b0010_00000001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(r4.new, r2)) jump:nt $+0x32c }");
+ test_display(&0b0010_00000001_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(r4.new, r2)) jump:t $+0x32c }");
+ test_display(&0b0010_00000101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.eq(r4.new, r2)) jump:nt $+0x32c }");
+ test_display(&0b0010_00001001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gt(r4.new, r2)) jump:nt $+0x32c }");
+ test_display(&0b0010_00001101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gt(r4.new, r2)) jump:nt $+0x32c }");
+ test_display(&0b0010_00010001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gtu(r4.new, r2)) jump:nt $+0x32c }");
+ test_display(&0b0010_00010101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(r4.new, r2)) jump:nt $+0x32c }");
+ test_display(&0b0010_00011001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gt(r2, r4.new)) jump:nt $+0x32c }");
+ test_display(&0b0010_00100101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(r2, r4.new)) jump:nt $+0x32c }");
test_invalid(&0b0010_00101101_0100_11_0_00010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
test_invalid(&0b0010_00110101_0100_11_0_00010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
test_invalid(&0b0010_00111101_0100_11_0_00010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
- test_display(&0b0010_01000001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(r4.new, #2)) jump:nt $+#812 }");
- test_display(&0b0010_01010101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(r4.new, #2)) jump:t $+#812 }");
- test_display(&0b0010_01011001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (tstbit(r4.new, #0)) jump:nt $+#812 }");
- test_display(&0b0010_01011101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!tstbit(r4.new, #0)) jump:t $+#812 }");
- test_display(&0b0010_01101101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gt(r4.new, #-1)) jump:t $+#812 }");
+ test_display(&0b0010_01000001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(r4.new, #2)) jump:nt $+0x32c }");
+ test_display(&0b0010_01010101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(r4.new, #2)) jump:t $+0x32c }");
+ test_display(&0b0010_01011001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (tstbit(r4.new, #0)) jump:nt $+0x32c }");
+ test_display(&0b0010_01011101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!tstbit(r4.new, #0)) jump:t $+0x32c }");
+ test_display(&0b0010_01101101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gt(r4.new, #-1)) jump:t $+0x32c }");
}
#[test]
@@ -298,34 +298,34 @@ fn inst_0101() {
test_display(&0b0101_011_1110_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ isync }");
test_display(&0b0101_011_1111_00000_11_0_10000_000_00010u32.to_le_bytes(), "{ unpause }");
- test_display(&0b0101_100_0000_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ jump $+#4 }");
- test_display(&0b0101_101_0000_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ call $+#4 }");
+ test_display(&0b0101_100_0000_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ jump $+0x4 }");
+ test_display(&0b0101_101_0000_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ call $+0x4 }");
- test_display(&0b0101_110_0000_00000_11_0_00001_000_00010u32.to_le_bytes(), "{ if (p1) jump:nt $+#4 }");
- test_display(&0b0101_110_0001_00000_11_0_01001_000_00010u32.to_le_bytes(), "{ if (!p1.new) jump:nt $+#4 }");
- test_display(&0b0101_110_1001_00000_11_0_00001_000_00010u32.to_le_bytes(), "{ if (!p1) call $+#4 }");
+ test_display(&0b0101_110_0000_00000_11_0_00001_000_00010u32.to_le_bytes(), "{ if (p1) jump:nt $+0x4 }");
+ test_display(&0b0101_110_0001_00000_11_0_01001_000_00010u32.to_le_bytes(), "{ if (!p1.new) jump:nt $+0x4 }");
+ test_display(&0b0101_110_1001_00000_11_0_00001_000_00010u32.to_le_bytes(), "{ if (!p1) call $+0x4 }");
test_invalid(&0b0101_110_1001_00000_11_0_01001_000_00010u32.to_le_bytes(), DecodeError::InvalidOpcode);
}
#[test]
fn inst_0110() {
- test_display(&0b0110_0000000_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ loop0($+#36, r6) }");
- test_display(&0b0110_0000001_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ loop1($+#36, r6) }");
+ test_display(&0b0110_0000000_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ loop0($+0x24, r6) }");
+ test_display(&0b0110_0000001_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ loop1($+0x24, r6) }");
test_invalid(&0b0110_0000010_00110_11_0_00010_000_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
test_invalid(&0b0110_0000011_00110_11_0_00010_000_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
- test_display(&0b0110_0000101_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ p3 = sp1loop0($+#36, r6) }");
- test_display(&0b0110_0000110_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ p3 = sp2loop0($+#36, r6) }");
- test_display(&0b0110_0000111_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ p3 = sp3loop0($+#36, r6) }");
+ test_display(&0b0110_0000101_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ p3 = sp1loop0($+0x24, r6) }");
+ test_display(&0b0110_0000110_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ p3 = sp2loop0($+0x24, r6) }");
+ test_display(&0b0110_0000111_00110_11_0_00010_000_01000u32.to_le_bytes(), "{ p3 = sp3loop0($+0x24, r6) }");
// TODO: test signed (negative) offsets
- test_display(&0b0110_0001001_00110_11_1_000101_00_10110u32.to_le_bytes(), "{ if (r6!=#0) jump:nt $+#-6868 }");
- test_display(&0b0110_0001001_00110_11_1_100101_00_10110u32.to_le_bytes(), "{ if (r6!=#0) jump:t $+#-6868 }");
- test_display(&0b0110_0001011_00110_11_1_000101_00_10110u32.to_le_bytes(), "{ if (r6>=#0) jump:nt $+#-6868 }");
- test_display(&0b0110_0001011_00110_11_1_100101_00_10110u32.to_le_bytes(), "{ if (r6>=#0) jump:t $+#-6868 }");
- test_display(&0b0110_0001101_00110_11_1_000101_00_10110u32.to_le_bytes(), "{ if (r6==#0) jump:nt $+#-6868 }");
- test_display(&0b0110_0001101_00110_11_1_100101_00_10110u32.to_le_bytes(), "{ if (r6==#0) jump:t $+#-6868 }");
- test_display(&0b0110_0001111_00110_11_1_000101_00_10110u32.to_le_bytes(), "{ if (r6<=#0) jump:nt $+#-6868 }");
- test_display(&0b0110_0001111_00110_11_1_100101_00_10110u32.to_le_bytes(), "{ if (r6<=#0) jump:t $+#-6868 }");
+ test_display(&0b0110_0001001_00110_11_1_000101_00_10110u32.to_le_bytes(), "{ if (r6!=#0) jump:nt $-0x1ad4 }");
+ test_display(&0b0110_0001001_00110_11_1_100101_00_10110u32.to_le_bytes(), "{ if (r6!=#0) jump:t $-0x1ad4 }");
+ test_display(&0b0110_0001011_00110_11_1_000101_00_10110u32.to_le_bytes(), "{ if (r6>=#0) jump:nt $-0x1ad4 }");
+ test_display(&0b0110_0001011_00110_11_1_100101_00_10110u32.to_le_bytes(), "{ if (r6>=#0) jump:t $-0x1ad4 }");
+ test_display(&0b0110_0001101_00110_11_1_000101_00_10110u32.to_le_bytes(), "{ if (r6==#0) jump:nt $-0x1ad4 }");
+ test_display(&0b0110_0001101_00110_11_1_100101_00_10110u32.to_le_bytes(), "{ if (r6==#0) jump:t $-0x1ad4 }");
+ test_display(&0b0110_0001111_00110_11_1_000101_00_10110u32.to_le_bytes(), "{ if (r6<=#0) jump:nt $-0x1ad4 }");
+ test_display(&0b0110_0001111_00110_11_1_100101_00_10110u32.to_le_bytes(), "{ if (r6<=#0) jump:t $-0x1ad4 }");
test_display(&0b0110_0010001_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ c22 = r6 }");
test_display(&0b0110_0010010_00110_11_0_00000_000_01000u32.to_le_bytes(), "{ trace(r6) }");
@@ -337,11 +337,11 @@ fn inst_0110() {
test_display(&0b0110_1000000_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ r23:22 = c7:6 }");
- test_display(&0b0110_1001000_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ loop0($+#36, #0xd2) }");
- test_display(&0b0110_1001001_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ loop1($+#36, #0xd2) }");
- test_display(&0b0110_1001101_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ p3 = sp1loop0($+#36, #0xd2) }");
- test_display(&0b0110_1001110_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ p3 = sp2loop0($+#36, #0xd2) }");
- test_display(&0b0110_1001111_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ p3 = sp3loop0($+#36, #0xd2) }");
+ test_display(&0b0110_1001000_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ loop0($+0x24, #0xd2) }");
+ test_display(&0b0110_1001001_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ loop1($+0x24, #0xd2) }");
+ test_display(&0b0110_1001101_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ p3 = sp1loop0($+0x24, #0xd2) }");
+ test_display(&0b0110_1001110_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ p3 = sp2loop0($+0x24, #0xd2) }");
+ test_display(&0b0110_1001111_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ p3 = sp3loop0($+0x24, #0xd2) }");
test_display(&0b0110_1010000_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ r22 = m0 }");
test_display(&0b0110_1010010_01001_11_0_000101_00_10110u32.to_le_bytes(), "{ r22 = add(pc, #0x5) }");