Finish disassembler for now
This commit is contained in:
parent
377f350e12
commit
dffb739d47
|
@ -9,6 +9,7 @@ pub enum ArmError {
|
||||||
UnknownInstructionFormat(u32),
|
UnknownInstructionFormat(u32),
|
||||||
UndefinedConditionCode(u32),
|
UndefinedConditionCode(u32),
|
||||||
InvalidShiftType(u32),
|
InvalidShiftType(u32),
|
||||||
|
InvalidHSBits(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Primitive)]
|
#[derive(Debug, Copy, Clone, PartialEq, Primitive)]
|
||||||
|
@ -81,6 +82,13 @@ pub enum ArmOpCode {
|
||||||
MVN = 0b1111,
|
MVN = 0b1111,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Primitive)]
|
||||||
|
pub enum ArmHalfwordTransferType {
|
||||||
|
UnsignedHalfwords = 0b01,
|
||||||
|
SignedByte = 0b10,
|
||||||
|
SignedHalfwords = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct ArmInstruction {
|
pub struct ArmInstruction {
|
||||||
pub cond: ArmCond,
|
pub cond: ArmCond,
|
||||||
|
@ -106,10 +114,20 @@ impl TryFrom<(u32, u32)> for ArmInstruction {
|
||||||
Ok(BX)
|
Ok(BX)
|
||||||
} else if (0x0e00_0000 & raw) == 0x0a00_0000 {
|
} else if (0x0e00_0000 & raw) == 0x0a00_0000 {
|
||||||
Ok(B_BL)
|
Ok(B_BL)
|
||||||
|
} else if (0xe000_0010 & raw) == 0x0600_0000 {
|
||||||
|
Err(ArmError::UnknownInstructionFormat(raw))
|
||||||
|
} else if (0x0fb0_0ff0 & raw) == 0x0100_0090 {
|
||||||
|
Ok(SWP)
|
||||||
} else if (0x0fc0_00f0 & raw) == 0x0000_0090 {
|
} else if (0x0fc0_00f0 & raw) == 0x0000_0090 {
|
||||||
Ok(MUL_MLA)
|
Ok(MUL_MLA)
|
||||||
} else if (0x0f80_00f0 & raw) == 0x0080_0090 {
|
} else if (0x0f80_00f0 & raw) == 0x0080_0090 {
|
||||||
Ok(MULL_MLAL)
|
Ok(MULL_MLAL)
|
||||||
|
} else if (0x0fbf_0fff & raw) == 0x010f_0000 {
|
||||||
|
Ok(MRS)
|
||||||
|
} else if (0x0fbf_fff0 & raw) == 0x0129_f000 {
|
||||||
|
Ok(MSR_REG)
|
||||||
|
} else if (0x0dbf_f000 & raw) == 0x0128_f000 {
|
||||||
|
Ok(MSR_FLAGS)
|
||||||
} else if (0x0c00_0000 & raw) == 0x0400_0000 {
|
} else if (0x0c00_0000 & raw) == 0x0400_0000 {
|
||||||
Ok(LDR_STR)
|
Ok(LDR_STR)
|
||||||
} else if (0x0e40_0F90 & raw) == 0x0000_0090 {
|
} else if (0x0e40_0F90 & raw) == 0x0000_0090 {
|
||||||
|
@ -118,16 +136,6 @@ impl TryFrom<(u32, u32)> for ArmInstruction {
|
||||||
Ok(LDR_STR_HS_IMM)
|
Ok(LDR_STR_HS_IMM)
|
||||||
} else if (0x0e00_0000 & raw) == 0x0800_0000 {
|
} else if (0x0e00_0000 & raw) == 0x0800_0000 {
|
||||||
Ok(LDM_STM)
|
Ok(LDM_STM)
|
||||||
} else if (0x0fb0_0ff0 & raw) == 0x0100_0090 {
|
|
||||||
Ok(SWP)
|
|
||||||
} else if (0x0fbf_0fff & raw) == 0x010f_0000 {
|
|
||||||
Ok(MRS)
|
|
||||||
} else if (0x0fbf_fff0 & raw) == 0x0129_f000 {
|
|
||||||
Ok(MSR_REG)
|
|
||||||
} else if (0x0dbf_f000 & raw) == 0x0128_f000 {
|
|
||||||
Ok(MSR_FLAGS)
|
|
||||||
} else if (0x0fb0_0ff0 & raw) == 0x0100_0090 {
|
|
||||||
Ok(SWP)
|
|
||||||
} else if (0x0c00_0000 & raw) == 0x0000_0000 {
|
} else if (0x0c00_0000 & raw) == 0x0000_0000 {
|
||||||
Ok(DP)
|
Ok(DP)
|
||||||
} else {
|
} else {
|
||||||
|
@ -176,16 +184,20 @@ impl TryFrom<u32> for ArmShift {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum ArmInstructionShiftValue {
|
pub enum ArmShiftedValue {
|
||||||
ImmediateValue(u32),
|
ImmediateValue(i32),
|
||||||
RotatedImmediate(u32, u32),
|
RotatedImmediate(u32, u32),
|
||||||
ShiftedRegister(usize, ArmShift),
|
ShiftedRegister {
|
||||||
|
reg: usize,
|
||||||
|
shift: ArmShift,
|
||||||
|
added: Option<bool>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArmInstructionShiftValue {
|
impl ArmShiftedValue {
|
||||||
/// Decode operand2 as an immediate value
|
/// Decode operand2 as an immediate value
|
||||||
pub fn decode_rotated_immediate(&self) -> Option<i32> {
|
pub fn decode_rotated_immediate(&self) -> Option<i32> {
|
||||||
if let ArmInstructionShiftValue::RotatedImmediate(immediate, rotate) = self {
|
if let ArmShiftedValue::RotatedImmediate(immediate, rotate) = self {
|
||||||
return Some(immediate.rotate_right(*rotate) as i32);
|
return Some(immediate.rotate_right(*rotate) as i32);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -212,7 +224,19 @@ impl ArmInstruction {
|
||||||
pub fn rm(&self) -> usize {
|
pub fn rm(&self) -> usize {
|
||||||
self.raw.bit_range(0..4) as usize
|
self.raw.bit_range(0..4) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rs(&self) -> usize {
|
||||||
|
self.raw.bit_range(8..12) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rd_lo(&self) -> usize {
|
||||||
|
self.raw.bit_range(12..16) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rd_hi(&self) -> usize {
|
||||||
|
self.raw.bit_range(16..20) as usize
|
||||||
|
}
|
||||||
|
|
||||||
pub fn opcode(&self) -> Option<ArmOpCode> {
|
pub fn opcode(&self) -> Option<ArmOpCode> {
|
||||||
ArmOpCode::from_u32(self.raw.bit_range(21..25))
|
ArmOpCode::from_u32(self.raw.bit_range(21..25))
|
||||||
}
|
}
|
||||||
|
@ -221,18 +245,33 @@ impl ArmInstruction {
|
||||||
((((self.raw << 8) as i32) >> 8) << 2) + 8
|
((((self.raw << 8) as i32) >> 8) << 2) + 8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_load(&self) -> bool {
|
pub fn load_flag(&self) -> bool {
|
||||||
self.raw.bit(20)
|
self.raw.bit(20)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_set_cond(&self) -> bool {
|
pub fn set_cond_flag(&self) -> bool {
|
||||||
self.raw.bit(20)
|
self.raw.bit(20)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_write_back(&self) -> bool {
|
pub fn write_back_flag(&self) -> bool {
|
||||||
self.raw.bit(21)
|
self.raw.bit(21)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn accumulate_flag(&self) -> bool {
|
||||||
|
self.raw.bit(21)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u_flag(&self) -> bool {
|
||||||
|
self.raw.bit(22)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn halfword_data_transfer_type(&self) -> Result<ArmHalfwordTransferType, ArmError> {
|
||||||
|
match ArmHalfwordTransferType::from_u32((self.raw & 0b1100000) >> 5) {
|
||||||
|
Some(x) => Ok(x),
|
||||||
|
None => Err(ArmError::InvalidHSBits(self.raw)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn transfer_size(&self) -> usize {
|
pub fn transfer_size(&self) -> usize {
|
||||||
if self.raw.bit(22) {
|
if self.raw.bit(22) {
|
||||||
1
|
1
|
||||||
|
@ -245,43 +284,79 @@ impl ArmInstruction {
|
||||||
self.raw.bit(22)
|
self.raw.bit(22)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_spsr(&self) -> bool {
|
pub fn spsr_flag(&self) -> bool {
|
||||||
self.raw.bit(22)
|
self.raw.bit(22)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ofs_added(&self) -> bool {
|
pub fn add_offset_flag(&self) -> bool {
|
||||||
self.raw.bit(23)
|
self.raw.bit(23)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_pre_indexing(&self) -> bool {
|
pub fn pre_index_flag(&self) -> bool {
|
||||||
self.raw.bit(24)
|
self.raw.bit(24)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_linked_branch(&self) -> bool {
|
pub fn link_flag(&self) -> bool {
|
||||||
self.raw.bit(24)
|
self.raw.bit(24)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset(&self) -> ArmInstructionShiftValue {
|
/// gets offset used by ldr/str instructions
|
||||||
|
pub fn ldr_str_offset(&self) -> ArmShiftedValue {
|
||||||
let ofs = self.raw.bit_range(0..12);
|
let ofs = self.raw.bit_range(0..12);
|
||||||
if self.raw.bit(25) {
|
if self.raw.bit(25) {
|
||||||
let rm = ofs & 0xf;
|
let rm = ofs & 0xf;
|
||||||
let shift = ArmShift::try_from(ofs).unwrap();
|
let shift = ArmShift::try_from(ofs).unwrap();
|
||||||
ArmInstructionShiftValue::ShiftedRegister(rm as usize, shift)
|
ArmShiftedValue::ShiftedRegister {
|
||||||
|
reg: rm as usize,
|
||||||
|
shift: shift,
|
||||||
|
added: Some(self.add_offset_flag()),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ArmInstructionShiftValue::ImmediateValue(ofs)
|
let ofs = if self.add_offset_flag() {
|
||||||
|
ofs as i32
|
||||||
|
} else {
|
||||||
|
-(ofs as i32)
|
||||||
|
};
|
||||||
|
ArmShiftedValue::ImmediateValue(ofs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operand2(&self) -> ArmInstructionShiftValue {
|
pub fn ldr_str_hs_offset(&self) -> Option<ArmShiftedValue> {
|
||||||
|
match self.fmt {
|
||||||
|
ArmInstructionFormat::LDR_STR_HS_IMM => {
|
||||||
|
let offset8 = (self.raw.bit_range(8..12) << 4) + self.raw.bit_range(0..4);
|
||||||
|
let offset8 = if self.add_offset_flag() {
|
||||||
|
offset8 as i32
|
||||||
|
} else {
|
||||||
|
-(offset8 as i32)
|
||||||
|
};
|
||||||
|
Some(ArmShiftedValue::ImmediateValue(offset8))
|
||||||
|
},
|
||||||
|
ArmInstructionFormat::LDR_STR_HS_REG => {
|
||||||
|
Some(ArmShiftedValue::ShiftedRegister {
|
||||||
|
reg: (self.raw & 0xf) as usize,
|
||||||
|
shift: ArmShift::ImmediateShift(0, ArmShiftType::LSL),
|
||||||
|
added: Some(self.add_offset_flag())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operand2(&self) -> ArmShiftedValue {
|
||||||
let op2 = self.raw.bit_range(0..12);
|
let op2 = self.raw.bit_range(0..12);
|
||||||
if self.raw.bit(25) {
|
if self.raw.bit(25) {
|
||||||
let immediate = op2 & 0xff;
|
let immediate = op2 & 0xff;
|
||||||
let rotate = 2 * op2.bit_range(8..12);
|
let rotate = 2 * op2.bit_range(8..12);
|
||||||
ArmInstructionShiftValue::RotatedImmediate(immediate, rotate)
|
ArmShiftedValue::RotatedImmediate(immediate, rotate)
|
||||||
} else {
|
} else {
|
||||||
let reg = op2 & 0xf;
|
let reg = op2 & 0xf;
|
||||||
let shift = ArmShift::try_from(op2).unwrap(); // TODO error handling
|
let shift = ArmShift::try_from(op2).unwrap(); // TODO error handling
|
||||||
ArmInstructionShiftValue::ShiftedRegister(reg as usize, shift)
|
ArmShiftedValue::ShiftedRegister {
|
||||||
|
reg: reg as usize,
|
||||||
|
shift: shift,
|
||||||
|
added: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::super::reg_string;
|
use super::super::{reg_string, REG_PC};
|
||||||
use super::arm_isa::{
|
use super::arm_isa::{
|
||||||
ArmCond, ArmInstruction, ArmInstructionFormat, ArmInstructionShiftValue, ArmOpCode, ArmShift,
|
ArmCond, ArmInstruction, ArmInstructionFormat, ArmShiftedValue, ArmOpCode, ArmShift,
|
||||||
ArmShiftType,
|
ArmShiftType, ArmHalfwordTransferType
|
||||||
};
|
};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
@ -64,6 +64,17 @@ impl fmt::Display for ArmShiftType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ArmHalfwordTransferType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use ArmHalfwordTransferType::*;
|
||||||
|
match self {
|
||||||
|
UnsignedHalfwords => write!(f, "h"),
|
||||||
|
SignedHalfwords => write!(f, "sh"),
|
||||||
|
SignedByte => write!(f, "sb"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_shift(shift: &ArmShift) -> bool {
|
fn is_shift(shift: &ArmShift) -> bool {
|
||||||
if let ArmShift::ImmediateShift(val, typ) = shift {
|
if let ArmShift::ImmediateShift(val, typ) = shift {
|
||||||
return !(*val == 0 && *typ == ArmShiftType::LSL);
|
return !(*val == 0 && *typ == ArmShiftType::LSL);
|
||||||
|
@ -92,98 +103,127 @@ impl ArmInstruction {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"b{link}{cond}\t{ofs:#x}",
|
"b{link}{cond}\t{ofs:#x}",
|
||||||
link = if self.is_linked_branch() { "l" } else { "" },
|
link = if self.link_flag() { "l" } else { "" },
|
||||||
cond = self.cond,
|
cond = self.cond,
|
||||||
ofs = self.pc.wrapping_add(self.branch_offset() as u32) as u32
|
ofs = self.pc.wrapping_add(self.branch_offset() as u32) as u32
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_cond_mark(&self) -> &str {
|
||||||
|
if self.set_cond_flag() { "s" } else { "" }
|
||||||
|
}
|
||||||
|
|
||||||
fn fmt_data_processing(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_data_processing(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use ArmOpCode::*;
|
use ArmOpCode::*;
|
||||||
|
|
||||||
let opcode = self.opcode().unwrap();
|
let opcode = self.opcode().unwrap();
|
||||||
let rd = reg_string(self.rd());
|
|
||||||
|
|
||||||
match opcode {
|
match opcode {
|
||||||
// <opcode>{cond}{S} Rd,<Op2>
|
|
||||||
MOV | MVN => write!(
|
MOV | MVN => write!(
|
||||||
f,
|
f,
|
||||||
"{opcode}{cond}{S}\t{Rd}",
|
"{opcode}{S}{cond}\t{Rd}, ",
|
||||||
opcode = opcode,
|
opcode = opcode,
|
||||||
cond = self.cond,
|
cond = self.cond,
|
||||||
S = if self.is_set_cond() { "s" } else { "" },
|
S = self.set_cond_mark(),
|
||||||
Rd = rd
|
Rd = reg_string(self.rd())
|
||||||
|
),
|
||||||
|
CMP | CMN | TEQ | TST => write!(
|
||||||
|
f,
|
||||||
|
"{opcode}{cond}\t{Rn}, ",
|
||||||
|
opcode = opcode,
|
||||||
|
cond = self.cond,
|
||||||
|
Rn = reg_string(self.rn())
|
||||||
),
|
),
|
||||||
// <opcode>{cond}{S} Rd,Rn,<Op2>
|
|
||||||
_ => write!(
|
_ => write!(
|
||||||
f,
|
f,
|
||||||
"{opcode}{cond}\t{Rd}, {Rn}",
|
"{opcode}{S}{cond}\t{Rd}, {Rn}, ",
|
||||||
opcode = opcode,
|
opcode = opcode,
|
||||||
cond = self.cond,
|
cond = self.cond,
|
||||||
Rd = rd,
|
S = self.set_cond_mark(),
|
||||||
|
Rd = reg_string(self.rd()),
|
||||||
Rn = reg_string(self.rn())
|
Rn = reg_string(self.rn())
|
||||||
),
|
),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
let operand2 = self.operand2();
|
let operand2 = self.operand2();
|
||||||
match operand2 {
|
match operand2 {
|
||||||
ArmInstructionShiftValue::RotatedImmediate(_, _) => {
|
ArmShiftedValue::RotatedImmediate(_, _) => {
|
||||||
write!(f, ", #{:#x}", operand2.decode_rotated_immediate().unwrap())
|
let value = operand2.decode_rotated_immediate().unwrap();
|
||||||
|
write!(f, "#{}\t; {:#x}", value, value)
|
||||||
}
|
}
|
||||||
ArmInstructionShiftValue::ShiftedRegister(reg, shift) => {
|
ArmShiftedValue::ShiftedRegister{reg, shift, added: _} => {
|
||||||
write!(f, ", {}", self.make_shifted_reg_string(reg, shift))
|
write!(f, "{}", self.make_shifted_reg_string(reg, shift))
|
||||||
}
|
}
|
||||||
_ => write!(f, "RegisterNotImpl"),
|
_ => write!(f, "RegisterNotImpl"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <LDR|STR>{cond}{B}{T} Rd,<Address>
|
fn auto_incremenet_mark(&self) -> &str {
|
||||||
|
if self.write_back_flag() { "!" } else { "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_rn_offset(&self, f: &mut fmt::Formatter, offset: ArmShiftedValue) -> fmt::Result {
|
||||||
|
write!(f, "[{Rn}", Rn = reg_string(self.rn()))?;
|
||||||
|
let (ofs_string, comment) = match offset {
|
||||||
|
ArmShiftedValue::ImmediateValue(value) => {
|
||||||
|
let value_for_commnet = if self.rn() == REG_PC {
|
||||||
|
value + (self.pc as i32) + 8 // account for pipelining
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
};
|
||||||
|
(
|
||||||
|
format!("#{}", value),
|
||||||
|
Some(format!("\t; {:#x}", value_for_commnet)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ArmShiftedValue::ShiftedRegister{reg, shift, added: Some(added)} => (
|
||||||
|
format!("{}{}", if added { "" } else { "-" }, self.make_shifted_reg_string(reg, shift)),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
_ => panic!("bad barrel shifter"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.pre_index_flag() {
|
||||||
|
write!(f, ", {}]{}", ofs_string, self.auto_incremenet_mark())?;
|
||||||
|
} else {
|
||||||
|
write!(f, "], {}", ofs_string)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(comment) = comment {
|
||||||
|
write!(f, "{}", comment)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fmt_ldr_str(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_ldr_str(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{mnem}{B}{cond}{T}\t{Rd}, [{Rn}",
|
"{mnem}{B}{cond}{T}\t{Rd}, ",
|
||||||
mnem = if self.is_load() { "ldr" } else { "str" },
|
mnem = if self.load_flag() { "ldr" } else { "str" },
|
||||||
B = if self.transfer_size() == 1 { "b" } else { "" },
|
B = if self.transfer_size() == 1 { "b" } else { "" },
|
||||||
cond = self.cond,
|
cond = self.cond,
|
||||||
T = if !self.is_pre_indexing() && self.is_write_back() {
|
T = if !self.pre_index_flag() && self.write_back_flag() {
|
||||||
"t"
|
"t"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
Rd = reg_string(self.rd()),
|
Rd = reg_string(self.rd()),
|
||||||
Rn = reg_string(self.rn())
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let offset = self.offset();
|
self.fmt_rn_offset(f, self.ldr_str_offset())
|
||||||
let auto_incremenet_mark = if self.is_write_back() { "!" } else { "" };
|
|
||||||
let sign_mark = if self.is_ofs_added() { '+' } else { '-' };
|
|
||||||
|
|
||||||
let ofs_string = match offset {
|
|
||||||
ArmInstructionShiftValue::ImmediateValue(value) => format!("#{:+}", value),
|
|
||||||
ArmInstructionShiftValue::ShiftedRegister(reg, shift) => {
|
|
||||||
format!("{}{}", sign_mark, self.make_shifted_reg_string(reg, shift))
|
|
||||||
}
|
|
||||||
_ => panic!("bad barrel shifter"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.is_pre_indexing() {
|
|
||||||
write!(f, ", {}]{}", ofs_string, auto_incremenet_mark)
|
|
||||||
} else {
|
|
||||||
write!(f, "], {}", ofs_string)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <LDM|STM>{cond}<FD|ED|FA|EA|IA|IB|DA|DB> Rn{!},<Rlist>{^}
|
|
||||||
fn fmt_ldm_stm(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_ldm_stm(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{mnem}{inc_dec}{pre_post}{cond}\t{Rn}{auto_inc}, {{",
|
"{mnem}{inc_dec}{pre_post}{cond}\t{Rn}{auto_inc}, {{",
|
||||||
mnem = if self.is_load() { "ldm" } else { "stm" },
|
mnem = if self.load_flag() { "ldm" } else { "stm" },
|
||||||
inc_dec = if self.is_ofs_added() { 'i' } else { 'd' },
|
inc_dec = if self.add_offset_flag() { 'i' } else { 'd' },
|
||||||
pre_post = if self.is_pre_indexing() { 'b' } else { 'a' },
|
pre_post = if self.pre_index_flag() { 'b' } else { 'a' },
|
||||||
cond = self.cond,
|
cond = self.cond,
|
||||||
Rn = reg_string(self.rn()),
|
Rn = reg_string(self.rn()),
|
||||||
auto_inc = if self.is_write_back() { "!" } else { "" }
|
auto_inc = if self.write_back_flag() { "!" } else { "" }
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut register_list = self.register_list().into_iter();
|
let mut register_list = self.register_list().into_iter();
|
||||||
|
@ -197,29 +237,98 @@ impl ArmInstruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MRS - transfer PSR contents to a register
|
/// MRS - transfer PSR contents to a register
|
||||||
/// MRS{cond} Rd,<psr>
|
|
||||||
fn fmt_mrs(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_mrs(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"mrs{cond}\t{Rd}, {psr}",
|
"mrs{cond}\t{Rd}, {psr}",
|
||||||
cond = self.cond,
|
cond = self.cond,
|
||||||
Rd = reg_string(self.rd()),
|
Rd = reg_string(self.rd()),
|
||||||
psr = if self.is_spsr() { "SPSR" } else { "CPSR" }
|
psr = if self.spsr_flag() { "SPSR" } else { "CPSR" }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MSR - transfer register contents to PSR
|
/// MSR - transfer register contents to PSR
|
||||||
/// MSR{cond} <psr>,Rm
|
|
||||||
fn fmt_msr_reg(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_msr_reg(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"msr{cond}\t{psr}, {Rm}",
|
"msr{cond}\t{psr}, {Rm}",
|
||||||
cond = self.cond,
|
cond = self.cond,
|
||||||
psr = if self.is_spsr() { "SPSR" } else { "CPSR" },
|
psr = if self.spsr_flag() { "SPSR" } else { "CPSR" },
|
||||||
Rm = reg_string(self.rm()),
|
Rm = reg_string(self.rm()),
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fmt_mul_mla(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.accumulate_flag() {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"mla{S}{cond}\t{Rd}, {Rm}, {Rs}, {Rn}",
|
||||||
|
S = self.set_cond_mark(),
|
||||||
|
cond = self.cond,
|
||||||
|
Rd = reg_string(self.rd()),
|
||||||
|
Rm = reg_string(self.rm()),
|
||||||
|
Rs = reg_string(self.rs()),
|
||||||
|
Rn = reg_string(self.rn()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"mul{S}{cond}\t{Rd}, {Rm}, {Rs}",
|
||||||
|
S = self.set_cond_mark(),
|
||||||
|
cond = self.cond,
|
||||||
|
Rd = reg_string(self.rd()),
|
||||||
|
Rm = reg_string(self.rm()),
|
||||||
|
Rs = reg_string(self.rs()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_mark(&self) -> &str {
|
||||||
|
if self.u_flag() { "s" } else { "u" }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_mull_mlal(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.accumulate_flag() {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{sign}mlal{S}{cond}\t{RdLo}, {RdHi}, {Rm}, {Rs}",
|
||||||
|
sign = self.sign_mark(),
|
||||||
|
S = self.set_cond_mark(),
|
||||||
|
cond = self.cond,
|
||||||
|
RdLo = reg_string(self.rd_lo()),
|
||||||
|
RdHi = reg_string(self.rd_hi()),
|
||||||
|
Rm = reg_string(self.rm()),
|
||||||
|
Rs = reg_string(self.rs()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{sign}mull{S}{cond}\t{RdLo}, {RdHi}, {Rm}",
|
||||||
|
sign = self.sign_mark(),
|
||||||
|
S = self.set_cond_mark(),
|
||||||
|
cond = self.cond,
|
||||||
|
RdLo = reg_string(self.rd_lo()),
|
||||||
|
RdHi = reg_string(self.rd_hi()),
|
||||||
|
Rm = reg_string(self.rm())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_ldr_str_hs(&self, f: &mut fmt::Formatter) -> fmt::Result{
|
||||||
|
if let Ok(transfer_type) = self.halfword_data_transfer_type() {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{mnem}{type}{cond}\t{Rd}, ",
|
||||||
|
mnem = if self.load_flag() { "ldr" } else { "str" },
|
||||||
|
cond = self.cond,
|
||||||
|
type = transfer_type,
|
||||||
|
Rd = reg_string(self.rd()),
|
||||||
|
)?;
|
||||||
|
self.fmt_rn_offset(f, self.ldr_str_hs_offset().unwrap())
|
||||||
|
} else {
|
||||||
|
write!(f, "<undefined>")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ArmInstruction {
|
impl fmt::Display for ArmInstruction {
|
||||||
|
@ -233,6 +342,10 @@ impl fmt::Display for ArmInstruction {
|
||||||
LDM_STM => self.fmt_ldm_stm(f),
|
LDM_STM => self.fmt_ldm_stm(f),
|
||||||
MRS => self.fmt_mrs(f),
|
MRS => self.fmt_mrs(f),
|
||||||
MSR_REG => self.fmt_msr_reg(f),
|
MSR_REG => self.fmt_msr_reg(f),
|
||||||
|
MUL_MLA => self.fmt_mul_mla(f),
|
||||||
|
MULL_MLAL => self.fmt_mull_mlal(f),
|
||||||
|
LDR_STR_HS_IMM => self.fmt_ldr_str_hs(f),
|
||||||
|
LDR_STR_HS_REG => self.fmt_ldr_str_hs(f),
|
||||||
_ => write!(f, "({:?})", self),
|
_ => write!(f, "({:?})", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ extern crate bit;
|
||||||
|
|
||||||
pub mod arm;
|
pub mod arm;
|
||||||
|
|
||||||
|
pub const REG_PC: usize = 15;
|
||||||
|
|
||||||
pub fn reg_string(reg: usize) -> &'static str {
|
pub fn reg_string(reg: usize) -> &'static str {
|
||||||
let reg_names = &[
|
let reg_names = &[
|
||||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "fp", "ip", "sp",
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "fp", "ip", "sp",
|
||||||
|
|
|
@ -55,7 +55,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let addr = (rdr.position() - 4) as u32;
|
let addr = (rdr.position() - 4) as u32;
|
||||||
print!("{:08x}: <{:08x}>\t", addr, value);
|
print!("{:8x}:\t{:08x} \t", addr, value);
|
||||||
match ArmInstruction::try_from((value, addr)) {
|
match ArmInstruction::try_from((value, addr)) {
|
||||||
Ok(insn) => println!("{}", insn),
|
Ok(insn) => println!("{}", insn),
|
||||||
Err(_) => println!("<UNDEFINED>")
|
Err(_) => println!("<UNDEFINED>")
|
||||||
|
|
Reference in a new issue