refactor: Refactor instruction decoding to panic instead of returning a Result

flamegraph shows too much time is being spent 'unwraping' decoded
instructions


Former-commit-id: e89072e6cf648e83f87d8c01891f50474246a36b
This commit is contained in:
Michel Heily 2020-02-14 13:05:14 +02:00
parent 69aadb9d92
commit 0c2da2ae46
5 changed files with 63 additions and 112 deletions

View file

@ -110,65 +110,56 @@ pub struct ArmInstruction {
impl InstructionDecoder for ArmInstruction { impl InstructionDecoder for ArmInstruction {
type IntType = u32; type IntType = u32;
fn decode(raw: u32, addr: Addr) -> Result<Self, InstructionDecoderError> { fn decode(raw: u32, addr: Addr) -> Self {
use ArmFormat::*; use ArmFormat::*;
let cond_code = raw.bit_range(28..32) as u8; let cond_code = raw.bit_range(28..32) as u8;
let cond = match ArmCond::from_u8(cond_code) { let cond = ArmCond::from_u8(cond_code).expect("invalid arm condition");
Some(cond) => Ok(cond),
None => Err(ArmDecodeError::new(
UndefinedConditionCode(cond_code as u32),
raw,
addr,
)),
}?;
let fmt = if (0x0fff_fff0 & raw) == 0x012f_ff10 { let fmt = if (0x0fff_fff0 & raw) == 0x012f_ff10 {
Ok(BX) BX
} else if (0x0e00_0000 & raw) == 0x0a00_0000 { } else if (0x0e00_0000 & raw) == 0x0a00_0000 {
Ok(B_BL) B_BL
} else if (0xe000_0010 & raw) == 0x0600_0000 { } else if (0xe000_0010 & raw) == 0x0600_0000 {
Err(ArmDecodeError::new(UnknownInstructionFormat, raw, addr)) panic!("unknown instruction {:#x} at @{:#x}", raw, addr);
} else if (0x0fb0_0ff0 & raw) == 0x0100_0090 { } else if (0x0fb0_0ff0 & raw) == 0x0100_0090 {
Ok(SWP) SWP
} else if (0x0fc0_00f0 & raw) == 0x0000_0090 { } else if (0x0fc0_00f0 & raw) == 0x0000_0090 {
Ok(MUL_MLA) MUL_MLA
} else if (0x0f80_00f0 & raw) == 0x0080_0090 { } else if (0x0f80_00f0 & raw) == 0x0080_0090 {
Ok(MULL_MLAL) MULL_MLAL
} else if (0x0fbf_0fff & raw) == 0x010f_0000 { } else if (0x0fbf_0fff & raw) == 0x010f_0000 {
Ok(MRS) MRS
} else if (0x0fbf_fff0 & raw) == 0x0129_f000 { } else if (0x0fbf_fff0 & raw) == 0x0129_f000 {
Ok(MSR_REG) MSR_REG
} else if (0x0dbf_f000 & raw) == 0x0128_f000 { } else if (0x0dbf_f000 & raw) == 0x0128_f000 {
Ok(MSR_FLAGS) MSR_FLAGS
} else if (0x0c00_0000 & raw) == 0x0400_0000 { } else if (0x0c00_0000 & raw) == 0x0400_0000 {
Ok(LDR_STR) LDR_STR
} else if (0x0e40_0F90 & raw) == 0x0000_0090 { } else if (0x0e40_0F90 & raw) == 0x0000_0090 {
Ok(LDR_STR_HS_REG) LDR_STR_HS_REG
} else if (0x0e40_0090 & raw) == 0x0040_0090 { } else if (0x0e40_0090 & raw) == 0x0040_0090 {
Ok(LDR_STR_HS_IMM) LDR_STR_HS_IMM
} else if (0x0e00_0000 & raw) == 0x0800_0000 { } else if (0x0e00_0000 & raw) == 0x0800_0000 {
Ok(LDM_STM) LDM_STM
} else if (0x0f00_0000 & raw) == 0x0f00_0000 { } else if (0x0f00_0000 & raw) == 0x0f00_0000 {
Ok(SWI) SWI
} else if (0x0c00_0000 & raw) == 0x0000_0000 { } else if (0x0c00_0000 & raw) == 0x0000_0000 {
Ok(DP) DP
} else { } else {
Err(ArmDecodeError::new(UnknownInstructionFormat, raw, addr)) panic!("unknown arm instruction {:#x} at @{:#x}", raw, addr);
}?; };
Ok(ArmInstruction { ArmInstruction {
cond: cond, cond: cond,
fmt: fmt, fmt: fmt,
raw: raw, raw: raw,
pc: addr, pc: addr,
}) }
} }
fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Result<Self, InstructionDecoderError> { fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Self {
let mut rdr = std::io::Cursor::new(bytes); let mut rdr = std::io::Cursor::new(bytes);
let raw = rdr let raw = rdr.read_u32::<LittleEndian>().unwrap();
.read_u32::<LittleEndian>()
.map_err(|e| InstructionDecoderError::IoError(e.kind()))?;
Self::decode(raw, addr) Self::decode(raw, addr)
} }

View file

@ -293,25 +293,8 @@ impl Core {
} }
} }
// fn handle_exec_result(&mut self, sb: &mut SysBus, exec_result: CpuAction) {
// match self.cpsr.state() {
// CpuState::ARM => {
// match exec_result {
// CpuAction::AdvancePC => self.advance_arm(),
// CpuAction::FlushPipeline => self.reload_pipeline32(sb),
// }
// }
// CpuState::THUMB => {
// match exec_result {
// CpuAction::AdvancePC => self.advance_thumb(),
// CpuAction::FlushPipeline => self.reload_pipeline16(sb),
// }
// }
// }
// }
fn step_arm_exec(&mut self, insn: u32, sb: &mut SysBus) { fn step_arm_exec(&mut self, insn: u32, sb: &mut SysBus) {
let decoded_arm = ArmInstruction::decode(insn, self.pc.wrapping_sub(8)).unwrap(); let decoded_arm = ArmInstruction::decode(insn, self.pc.wrapping_sub(8));
#[cfg(feature = "debugger")] #[cfg(feature = "debugger")]
{ {
self.gpr_previous = self.get_registers(); self.gpr_previous = self.get_registers();
@ -320,12 +303,12 @@ impl Core {
let result = self.exec_arm(sb, decoded_arm); let result = self.exec_arm(sb, decoded_arm);
match result { match result {
CpuAction::AdvancePC => self.advance_arm(), CpuAction::AdvancePC => self.advance_arm(),
CpuAction::FlushPipeline => {}, CpuAction::FlushPipeline => {}
} }
} }
fn step_thumb_exec(&mut self, insn: u16, sb: &mut SysBus) { fn step_thumb_exec(&mut self, insn: u16, sb: &mut SysBus) {
let decoded_thumb = ThumbInstruction::decode(insn, self.pc.wrapping_sub(4)).unwrap(); let decoded_thumb = ThumbInstruction::decode(insn, self.pc.wrapping_sub(4));
#[cfg(feature = "debugger")] #[cfg(feature = "debugger")]
{ {
self.gpr_previous = self.get_registers(); self.gpr_previous = self.get_registers();
@ -334,7 +317,7 @@ impl Core {
let result = self.exec_thumb(sb, decoded_thumb); let result = self.exec_thumb(sb, decoded_thumb);
match result { match result {
CpuAction::AdvancePC => self.advance_thumb(), CpuAction::AdvancePC => self.advance_thumb(),
CpuAction::FlushPipeline => {}, CpuAction::FlushPipeline => {}
} }
} }
@ -358,14 +341,6 @@ impl Core {
self.advance_arm(); self.advance_arm();
} }
#[inline]
pub(super) fn reload_pipeline(&mut self, sb: &mut SysBus) {
match self.cpsr.state() {
CpuState::THUMB => self.reload_pipeline16(sb),
CpuState::ARM => self.reload_pipeline32(sb),
}
}
#[inline] #[inline]
pub(super) fn advance_thumb(&mut self) { pub(super) fn advance_thumb(&mut self) {
self.pc = self.pc.wrapping_add(2) self.pc = self.pc.wrapping_add(2)

View file

@ -75,9 +75,9 @@ impl From<ThumbDecodeError> for InstructionDecoderError {
pub trait InstructionDecoder: Sized { pub trait InstructionDecoder: Sized {
type IntType: Num; type IntType: Num;
fn decode(n: Self::IntType, addr: Addr) -> Result<Self, InstructionDecoderError>; fn decode(n: Self::IntType, addr: Addr) -> Self;
/// Helper functions for the Disassembler /// Helper functions for the Disassembler
fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Result<Self, InstructionDecoderError>; fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Self;
fn get_raw(&self) -> Self::IntType; fn get_raw(&self) -> Self::IntType;
} }

View file

@ -87,63 +87,61 @@ pub struct ThumbInstruction {
impl InstructionDecoder for ThumbInstruction { impl InstructionDecoder for ThumbInstruction {
type IntType = u16; type IntType = u16;
fn decode(raw: u16, addr: Addr) -> Result<Self, InstructionDecoderError> { fn decode(raw: u16, addr: Addr) -> Self {
use self::ThumbFormat::*; use self::ThumbFormat::*;
let fmt = if raw & 0xf800 == 0x1800 { let fmt = if raw & 0xf800 == 0x1800 {
Ok(AddSub) AddSub
} else if raw & 0xe000 == 0x0000 { } else if raw & 0xe000 == 0x0000 {
Ok(MoveShiftedReg) MoveShiftedReg
} else if raw & 0xe000 == 0x2000 { } else if raw & 0xe000 == 0x2000 {
Ok(DataProcessImm) DataProcessImm
} else if raw & 0xfc00 == 0x4000 { } else if raw & 0xfc00 == 0x4000 {
Ok(AluOps) AluOps
} else if raw & 0xfc00 == 0x4400 { } else if raw & 0xfc00 == 0x4400 {
Ok(HiRegOpOrBranchExchange) HiRegOpOrBranchExchange
} else if raw & 0xf800 == 0x4800 { } else if raw & 0xf800 == 0x4800 {
Ok(LdrPc) LdrPc
} else if raw & 0xf200 == 0x5000 { } else if raw & 0xf200 == 0x5000 {
Ok(LdrStrRegOffset) LdrStrRegOffset
} else if raw & 0xf200 == 0x5200 { } else if raw & 0xf200 == 0x5200 {
Ok(LdrStrSHB) LdrStrSHB
} else if raw & 0xe000 == 0x6000 { } else if raw & 0xe000 == 0x6000 {
Ok(LdrStrImmOffset) LdrStrImmOffset
} else if raw & 0xf000 == 0x8000 { } else if raw & 0xf000 == 0x8000 {
Ok(LdrStrHalfWord) LdrStrHalfWord
} else if raw & 0xf000 == 0x9000 { } else if raw & 0xf000 == 0x9000 {
Ok(LdrStrSp) LdrStrSp
} else if raw & 0xf000 == 0xa000 { } else if raw & 0xf000 == 0xa000 {
Ok(LoadAddress) LoadAddress
} else if raw & 0xff00 == 0xb000 { } else if raw & 0xff00 == 0xb000 {
Ok(AddSp) AddSp
} else if raw & 0xf600 == 0xb400 { } else if raw & 0xf600 == 0xb400 {
Ok(PushPop) PushPop
} else if raw & 0xf000 == 0xc000 { } else if raw & 0xf000 == 0xc000 {
Ok(LdmStm) LdmStm
} else if raw & 0xff00 == 0xdf00 { } else if raw & 0xff00 == 0xdf00 {
Ok(Swi) Swi
} else if raw & 0xf000 == 0xd000 { } else if raw & 0xf000 == 0xd000 {
Ok(BranchConditional) BranchConditional
} else if raw & 0xf800 == 0xe000 { } else if raw & 0xf800 == 0xe000 {
Ok(Branch) Branch
} else if raw & 0xf000 == 0xf000 { } else if raw & 0xf000 == 0xf000 {
Ok(BranchLongWithLink) BranchLongWithLink
} else { } else {
Err(ThumbDecodeError::new(UnknownInstructionFormat, raw, addr)) panic!("unknown thumb instruction {:#x} at @{:#x}", raw, addr);
}?; };
Ok(ThumbInstruction { ThumbInstruction {
fmt: fmt, fmt: fmt,
raw: raw, raw: raw,
pc: addr, pc: addr,
}) }
} }
fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Result<Self, InstructionDecoderError> { fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Self {
let mut rdr = std::io::Cursor::new(bytes); let mut rdr = std::io::Cursor::new(bytes);
let raw = rdr let raw = rdr.read_u16::<LittleEndian>().unwrap();
.read_u16::<LittleEndian>()
.map_err(|e| InstructionDecoderError::IoError(e.kind()))?;
Self::decode(raw, addr) Self::decode(raw, addr)
} }

View file

@ -42,27 +42,14 @@ where
let mut line = String::new(); let mut line = String::new();
let addr = self.base + self.pos as Addr; let addr = self.base + self.pos as Addr;
let decoded: Option<D> = let decoded: D = D::decode_from_bytes(&self.bytes[(self.pos as usize)..], addr);
match D::decode_from_bytes(&self.bytes[(self.pos as usize)..], addr) {
Ok(decoded) => {
self.pos += self.word_size; self.pos += self.word_size;
Some(decoded) line.push_str(&format!(
} "{:8x}:\t{:08x} \t{}",
Err(InstructionDecoderError::IoError(ErrorKind::UnexpectedEof)) => { addr,
return None; decoded.get_raw(),
} decoded
_ => { ));
self.pos += self.word_size;
None
}
};
match decoded {
Some(insn) => {
line.push_str(&format!("{:8x}:\t{:08x} \t{}", addr, insn.get_raw(), insn))
}
_ => line.push_str(&format!("{:8x}:\t \t<UNDEFINED>", addr)),
};
Some((self.pos as Addr, line)) Some((self.pos as Addr, line))
} }