This repository has been archived on 2024-12-14. You can view files and clone it, but cannot push or open issues or pull requests.
rustboyadvance-ng/src/arm7tdmi/thumb/display.rs
Michel Heily 0c50209735 Fix wrong calculation of conditional branch offset in Thumb mode
Former-commit-id: 4cc28b13b19b2bf45e2b0e34d9a9dc0f83f82b01
2019-07-05 16:01:16 +03:00

227 lines
7.2 KiB
Rust

use std::fmt;
use crate::bit::BitIndex;
use super::*;
use crate::arm7tdmi::*;
impl ThumbInstruction {
fn fmt_thumb_move_shifted_reg(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{op}\t{Rd}, {Rs}, #{Offset5}",
op = self.format1_op(),
Rd = reg_string(self.rd()),
Rs = reg_string(self.rs()),
Offset5 = self.offset5()
)
}
fn fmt_thumb_data_process_imm(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{op}\t{Rd}, #{Offset8:#x}",
op = self.format3_op(),
Rd = reg_string(self.rd()),
Offset8 = self.offset8()
)
}
fn fmt_thumb_mul(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"mul\t{Rd}, {Rs}",
Rd = reg_string(self.rd()),
Rs = reg_string(self.rs())
)
}
fn fmt_thumb_alu_ops(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{op}\t{Rd}, {Rs}",
op = self.alu_opcode(),
Rd = reg_string(self.rd()),
Rs = reg_string(self.rs())
)
}
fn fmt_thumb_high_reg_op_or_bx(&self, f: &mut fmt::Formatter) -> fmt::Result {
let op = self.format5_op();
let dst_reg = if self.flag(ThumbInstruction::FLAG_H1) {
self.rd() + 8
} else {
self.rd()
};
let src_reg = if self.flag(ThumbInstruction::FLAG_H2) {
self.rs() + 8
} else {
self.rs()
};
write!(f, "{}\t", op)?;
match op {
OpFormat5::BX => write!(f, "{}", reg_string(src_reg)),
_ => write!(
f,
"{dst}, {src}",
dst = reg_string(dst_reg),
src = reg_string(src_reg)
),
}
}
fn fmt_thumb_ldr_pc(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"ldr\t{Rd}, [pc, #{Imm:#x}] ; = #{effective:#x}",
Rd = reg_string(self.rd()),
Imm = self.word8(),
effective = (self.pc + 4 & !0b10) + (self.word8() as Addr)
)
}
fn fmt_thumb_ldr_str_reg_offset(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{op}{b}\t{Rd}, [{Rb}, {Ro}]",
op = if self.is_load() { "ldr" } else { "str" },
b = if self.is_transfering_bytes() { "b" } else { "" },
Rd = reg_string(self.rd()),
Rb = reg_string(self.rb()),
Ro = reg_string(self.ro()),
)
}
fn fmt_thumb_ldr_str_halfword(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{op}\t{Rd}, [{Rb}, #{imm:#x}]",
op = if self.is_load() { "ldrh" } else { "strh" },
Rd = reg_string(self.rd()),
Rb = reg_string(self.rb()),
imm = self.offset5() << 1
)
}
fn fmt_thumb_ldr_str_sp(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{op}\t{Rd}, [sp, #{Imm:#x}]",
op = if self.is_load() { "ldr" } else { "str" },
Rd = reg_string(self.rd()),
Imm = self.word8(),
)
}
fn fmt_thumb_add_sub(&self, f: &mut fmt::Formatter) -> fmt::Result {
let operand = if self.is_immediate_operand() {
format!("#{:x}", self.raw.bit_range(6..9))
} else {
String::from(reg_string(self.rn()))
};
write!(
f,
"{op}\t{Rd}, [{Rs}, {operand}]",
op = if self.is_subtract() { "sub" } else { "add" },
Rd = reg_string(self.rd()),
Rs = reg_string(self.rs()),
operand = operand
)
}
fn fmt_thumb_add_sp(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "add\tsp, #{imm:x}", imm = self.sword7())
}
fn fmt_thumb_push_pop(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}\t{{", if self.is_load() { "pop" } else { "push" })?;
let mut register_list = self.register_list().into_iter();
let mut has_reg = false;
if let Some(reg) = register_list.next() {
write!(f, "{}", reg_string(reg))?;
has_reg = true;
}
for reg in register_list {
has_reg = true;
write!(f, ", {}", reg_string(reg))?;
}
if self.flag(ThumbInstruction::FLAG_R) {
let r = if self.is_load() { "pc" } else { "lr" };
if has_reg {
write!(f, ", {}", r)?;
} else {
write!(f, "{}", r)?;
}
}
write!(f, "}}")
}
fn fmt_thumb_branch_with_cond(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"b{cond}\t{addr:#x}",
cond = self.cond(),
addr = {
let offset = ((self.offset8() as i8) << 1) as i32;
(self.pc as i32 + 4).wrapping_add(offset) as Addr
}
)
}
fn fmt_thumb_branch_long_with_link(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "bl\t#0x{:08x}", {
let offset11 = self.offset11();
if self.flag(ThumbInstruction::FLAG_LOW_OFFSET) {
(offset11 << 1) as i32
} else {
((offset11 << 21) >> 9) as i32
}
})
}
}
impl fmt::Display for ThumbInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.fmt {
ThumbFormat::MoveShiftedReg => self.fmt_thumb_move_shifted_reg(f),
ThumbFormat::AddSub => self.fmt_thumb_add_sub(f),
ThumbFormat::DataProcessImm => self.fmt_thumb_data_process_imm(f),
ThumbFormat::Mul => self.fmt_thumb_mul(f),
ThumbFormat::AluOps => self.fmt_thumb_alu_ops(f),
ThumbFormat::HiRegOpOrBranchExchange => self.fmt_thumb_high_reg_op_or_bx(f),
ThumbFormat::LdrPc => self.fmt_thumb_ldr_pc(f),
ThumbFormat::LdrStrRegOffset => self.fmt_thumb_ldr_str_reg_offset(f),
ThumbFormat::LdrStrHalfWord => self.fmt_thumb_ldr_str_halfword(f),
ThumbFormat::LdrStrSp => self.fmt_thumb_ldr_str_sp(f),
ThumbFormat::AddSp => self.fmt_thumb_add_sp(f),
ThumbFormat::PushPop => self.fmt_thumb_push_pop(f),
ThumbFormat::BranchConditional => self.fmt_thumb_branch_with_cond(f),
ThumbFormat::BranchLongWithLink => self.fmt_thumb_branch_long_with_link(f),
_ => write!(f, "({:?})", self),
}
}
}
impl fmt::Display for OpFormat3 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OpFormat3::MOV => write!(f, "mov"),
OpFormat3::CMP => write!(f, "cmp"),
OpFormat3::ADD => write!(f, "add"),
OpFormat3::SUB => write!(f, "sub"),
}
}
}
impl fmt::Display for OpFormat5 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OpFormat5::ADD => write!(f, "add"),
OpFormat5::CMP => write!(f, "cmp"),
OpFormat5::MOV => write!(f, "mov"),
OpFormat5::BX => write!(f, "bx"),
}
}
}