diff --git a/src/arm7tdmi/arm/display.rs b/src/arm7tdmi/arm/display.rs index 2d3e4e8..4926206 100644 --- a/src/arm7tdmi/arm/display.rs +++ b/src/arm7tdmi/arm/display.rs @@ -1,8 +1,8 @@ use std::fmt; use super::{ - ArmCond, ArmHalfwordTransferType, ArmInstruction, ArmFormat, ArmOpCode, - ArmRegisterShift, ArmShiftType, ArmShiftedValue, + ArmCond, ArmFormat, ArmHalfwordTransferType, ArmInstruction, ArmOpCode, ArmRegisterShift, + ArmShiftType, ArmShiftedValue, }; use crate::arm7tdmi::{reg_string, Addr, REG_PC}; diff --git a/src/arm7tdmi/arm/exec.rs b/src/arm7tdmi/arm/exec.rs index 61419b6..3453bdb 100644 --- a/src/arm7tdmi/arm/exec.rs +++ b/src/arm7tdmi/arm/exec.rs @@ -3,14 +3,13 @@ use crate::bit::BitIndex; use crate::arm7tdmi::bus::{Bus, MemoryAccessType::*, MemoryAccessWidth::*}; use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction}; use crate::arm7tdmi::exception::Exception; -use crate::arm7tdmi::{Addr, CpuError, CpuInstruction, CpuResult, CpuState, REG_PC}; use crate::arm7tdmi::psr::RegPSR; +use crate::arm7tdmi::{Addr, CpuError, CpuResult, CpuState, DecodedInstruction, REG_PC}; use crate::sysbus::SysBus; use super::{ - ArmCond, ArmInstruction, ArmFormat, ArmOpCode, ArmRegisterShift, ArmShiftType, - ArmShiftedValue, + ArmFormat, ArmInstruction, ArmOpCode, ArmRegisterShift, ArmShiftType, ArmShiftedValue, }; impl Core { @@ -31,7 +30,11 @@ impl Core { ArmFormat::SWI => self.exec_swi(sysbus, insn), ArmFormat::LDR_STR => self.exec_ldr_str(sysbus, insn), ArmFormat::MSR_REG => self.exec_msr_reg(sysbus, insn), - _ => Err(CpuError::UnimplementedCpuInstruction(CpuInstruction::Arm(insn))), + _ => Err(CpuError::UnimplementedCpuInstruction( + insn.pc, + insn.raw, + DecodedInstruction::Arm(insn), + )), } } diff --git a/src/arm7tdmi/arm/mod.rs b/src/arm7tdmi/arm/mod.rs index 334d0fa..9d86caf 100644 --- a/src/arm7tdmi/arm/mod.rs +++ b/src/arm7tdmi/arm/mod.rs @@ -1,11 +1,14 @@ pub mod display; pub mod exec; -use crate::arm7tdmi::Addr; +use crate::arm7tdmi::{Addr, InstructionDecoder, InstructionDecoderError}; use crate::bit::BitIndex; -use crate::num_traits::FromPrimitive; +use crate::byteorder::{LittleEndian, ReadBytesExt}; +use crate::num::FromPrimitive; + use std::convert::TryFrom; +use std::io; #[derive(Debug, PartialEq)] pub enum ArmDecodeErrorKind { @@ -14,6 +17,7 @@ pub enum ArmDecodeErrorKind { UndefinedConditionCode(u32), InvalidShiftType(u32), InvalidHSBits(u32), + IoError(io::ErrorKind), } use ArmDecodeErrorKind::*; @@ -130,13 +134,11 @@ pub struct ArmInstruction { pub pc: Addr, } -impl TryFrom<(u32, Addr)> for ArmInstruction { - type Error = ArmDecodeError; +impl InstructionDecoder for ArmInstruction { + type IntType = u32; - fn try_from(value: (u32, Addr)) -> Result { + fn decode(raw: u32, addr: Addr) -> Result { use ArmFormat::*; - let (raw, addr) = value; - let cond_code = raw.bit_range(28..32) as u8; let cond = match ArmCond::from_u8(cond_code) { Some(cond) => Ok(cond), @@ -188,13 +190,17 @@ impl TryFrom<(u32, Addr)> for ArmInstruction { pc: addr, }) } -} -impl TryFrom for ArmInstruction { - type Error = ArmDecodeError; + fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Result { + let mut rdr = std::io::Cursor::new(bytes); + let raw = rdr + .read_u32::() + .map_err(|e| InstructionDecoderError::IoError(e.kind()))?; + Self::decode(raw, addr) + } - fn try_from(value: u32) -> Result { - ArmInstruction::try_from((value, 0)) + fn get_raw(&self) -> u32 { + self.raw } } @@ -440,7 +446,7 @@ mod tests { #[test] fn test_decode_swi() { // swi #0x1337 - let decoded = ArmInstruction::try_from(0xef001337).unwrap(); + let decoded = ArmInstruction::decode(0xef001337, 0).unwrap(); assert_eq!(decoded.fmt, ArmFormat::SWI); assert_eq!(decoded.swi_comment(), 0x1337); assert_eq!(format!("{}", decoded), "swi\t#0x1337"); @@ -449,7 +455,7 @@ mod tests { #[test] fn test_decode_branch_forwards() { // 0x20: b 0x30 - let decoded = ArmInstruction::try_from((0xea_00_00_02, 0x20)).unwrap(); + let decoded = ArmInstruction::decode(0xea_00_00_02, 0x20).unwrap(); assert_eq!(decoded.fmt, ArmFormat::B_BL); assert_eq!(decoded.link_flag(), false); assert_eq!( @@ -462,7 +468,7 @@ mod tests { #[test] fn test_decode_branch_link_backwards() { // 0x20: bl 0x10 - let decoded = ArmInstruction::try_from((0xeb_ff_ff_fa, 0x20)).unwrap(); + let decoded = ArmInstruction::decode(0xeb_ff_ff_fa, 0x20).unwrap(); assert_eq!(decoded.fmt, ArmFormat::B_BL); assert_eq!(decoded.link_flag(), true); assert_eq!( @@ -473,9 +479,9 @@ mod tests { } #[test] - fn test_decode_ldr_preindex() { + fn test_decode_ldr_pre_index() { // ldreq r2, [r5, -r6, lsl #5] - let decoded = ArmInstruction::try_from(0x07_15_22_86).unwrap(); + let decoded = ArmInstruction::decode(0x07_15_22_86, 0).unwrap(); assert_eq!(decoded.fmt, ArmFormat::LDR_STR); assert_eq!(decoded.cond, ArmCond::Equal); assert_eq!(decoded.load_flag(), true); @@ -496,9 +502,9 @@ mod tests { } #[test] - fn test_decode_str_postindex() { + fn test_decode_str_post_index() { // strteq r2, [r4], -r7, lsl #8 - let decoded = ArmInstruction::try_from(0x06_24_24_47).unwrap(); + let decoded = ArmInstruction::decode(0x06_24_24_47, 0).unwrap(); assert_eq!(decoded.fmt, ArmFormat::LDR_STR); assert_eq!(decoded.cond, ArmCond::Equal); assert_eq!(decoded.load_flag(), false); diff --git a/src/arm7tdmi/bus.rs b/src/arm7tdmi/bus.rs index 7f0427b..6bdf703 100644 --- a/src/arm7tdmi/bus.rs +++ b/src/arm7tdmi/bus.rs @@ -27,35 +27,33 @@ pub struct MemoryAccess(pub MemoryAccessType, pub MemoryAccessWidth); pub trait Bus { fn read_32(&self, addr: Addr) -> u32 { - self.get_bytes(addr, 4).read_u32::().unwrap() + self.get_bytes(addr).read_u32::().unwrap() } fn read_16(&self, addr: Addr) -> u16 { - self.get_bytes(addr, 2).read_u16::().unwrap() + self.get_bytes(addr).read_u16::().unwrap() } fn read_8(&self, addr: Addr) -> u8 { - self.get_bytes(addr, 1)[0] + self.get_bytes(addr)[0] } fn write_32(&mut self, addr: Addr, value: u32) -> Result<(), io::Error> { - self.get_bytes_mut(addr, 4).write_u32::(value) + self.get_bytes_mut(addr).write_u32::(value) } fn write_16(&mut self, addr: Addr, value: u16) -> Result<(), io::Error> { - self.get_bytes_mut(addr, 2).write_u16::(value) + self.get_bytes_mut(addr).write_u16::(value) } fn write_8(&mut self, addr: Addr, value: u8) -> Result<(), io::Error> { - self.get_bytes_mut(addr, 1).write_u8(value) + self.get_bytes_mut(addr).write_u8(value) } /// Return a slice of bytes - /// Will panic if requested range is out of bounds - fn get_bytes(&self, addr: Addr, len: usize) -> &[u8]; + fn get_bytes(&self, addr: Addr) -> &[u8]; /// Return a mutable slice of bytes - /// Will panic if requested range is out of bounds - fn get_bytes_mut(&mut self, addr: Addr, len: usize) -> &mut [u8]; + fn get_bytes_mut(&mut self, addr: Addr) -> &mut [u8]; /// returns the number of cycles needed for this memory access fn get_cycles(&self, addr: Addr, access: MemoryAccess) -> usize; diff --git a/src/arm7tdmi/cpu.rs b/src/arm7tdmi/cpu.rs index e61c992..6d493b3 100644 --- a/src/arm7tdmi/cpu.rs +++ b/src/arm7tdmi/cpu.rs @@ -3,6 +3,7 @@ use std::fmt; use std::ops::Add; use ansi_term::{Colour, Style}; +use num_traits::Num; use crate::sysbus::SysBus; @@ -11,16 +12,44 @@ use super::{ arm::*, bus::{Bus, MemoryAccess, MemoryAccessType::*, MemoryAccessWidth::*}, psr::RegPSR, - reg_string, Addr, CpuMode, CpuResult, CpuState, + reg_string, + thumb::ThumbInstruction, + Addr, CpuMode, CpuResult, CpuState, DecodedInstruction, InstructionDecoder, }; -#[derive(Debug, Default)] -pub struct PipelineContext { - fetched: Option<(Addr, u32)>, - decoded: Option, +#[derive(Debug)] +pub struct PipelineContext +where + D: InstructionDecoder, + N: Num, +{ + fetched: Option<(Addr, N)>, + decoded: Option, } -impl PipelineContext { +impl Default for PipelineContext +where + D: InstructionDecoder, + N: Num, +{ + fn default() -> PipelineContext { + PipelineContext { + fetched: None, + decoded: None, + } + } +} + +impl PipelineContext +where + D: InstructionDecoder, + N: Num, +{ + fn flush(&mut self) { + self.fetched = None; + self.decoded = None; + } + fn is_flushed(&self) -> bool { self.fetched.is_none() && self.decoded.is_none() } @@ -48,7 +77,8 @@ pub struct Core { pub cpsr: RegPSR, pub spsr: [RegPSR; 5], - pub pipeline: PipelineContext, + pub pipeline_arm: PipelineContext, + pub pipeline_thumb: PipelineContext, cycles: usize, // store the gpr before executing an instruction to show diff in the Display impl @@ -178,32 +208,69 @@ impl Core { } } - fn step_arm( + fn step_thumb( &mut self, sysbus: &mut SysBus, - ) -> CpuResult<(Option, CpuPipelineAction)> { + ) -> CpuResult<(Option, CpuPipelineAction)> { // fetch - let new_fetched = sysbus.read_32(self.pc); + let new_fetched = sysbus.read_16(self.pc); // decode - let new_decoded = match self.pipeline.fetched { - Some((addr, i)) => Some(ArmInstruction::try_from((i, addr)).unwrap()), + let new_decoded = match self.pipeline_thumb.fetched { + Some((addr, i)) => { + let insn = ThumbInstruction::decode(i, addr)?; + Some(insn) + } None => None, }; // exec - let result = match self.pipeline.decoded { + let result = match self.pipeline_thumb.decoded { Some(d) => { self.gpr_previous = self.get_registers(); - let action = self.exec_arm(sysbus, d)?; - Ok((Some(d), action)) + let action = self.exec_thumb(sysbus, d)?; + Ok((Some(DecodedInstruction::Thumb(d)), action)) } None => Ok((None, CpuPipelineAction::IncPC)), }; - self.pipeline.fetched = Some((self.pc, new_fetched)); + self.pipeline_thumb.fetched = Some((self.pc, new_fetched)); if let Some(d) = new_decoded { - self.pipeline.decoded = Some(d); + self.pipeline_thumb.decoded = Some(d); + } + + result + } + + fn step_arm( + &mut self, + sysbus: &mut SysBus, + ) -> CpuResult<(Option, CpuPipelineAction)> { + // fetch + let new_fetched = sysbus.read_32(self.pc); + + // decode + let new_decoded = match self.pipeline_arm.fetched { + Some((addr, i)) => { + let insn = ArmInstruction::decode(i, addr)?; + Some(insn) + } + None => None, + }; + + // exec + let result = match self.pipeline_arm.decoded { + Some(d) => { + self.gpr_previous = self.get_registers(); + let action = self.exec_arm(sysbus, d)?; + Ok((Some(DecodedInstruction::Arm(d)), action)) + } + None => Ok((None, CpuPipelineAction::IncPC)), + }; + + self.pipeline_arm.fetched = Some((self.pc, new_fetched)); + if let Some(d) = new_decoded { + self.pipeline_arm.decoded = Some(d); } result @@ -211,17 +278,17 @@ impl Core { /// Perform a pipeline step /// If an instruction was executed in this step, return it. - pub fn step(&mut self, sysbus: &mut SysBus) -> CpuResult> { + pub fn step(&mut self, sysbus: &mut SysBus) -> CpuResult> { let (executed_instruction, pipeline_action) = match self.cpsr.state() { CpuState::ARM => self.step_arm(sysbus), - CpuState::THUMB => unimplemented!("thumb not implemented :("), + CpuState::THUMB => self.step_thumb(sysbus), }?; match pipeline_action { CpuPipelineAction::IncPC => self.advance_pc(), CpuPipelineAction::Flush => { - self.pipeline.fetched = None; - self.pipeline.decoded = None; + self.pipeline_arm.flush(); + self.pipeline_thumb.flush(); } } @@ -230,21 +297,36 @@ impl Core { /// Get's the address of the next instruction that is going to be executed pub fn get_next_pc(&self) -> Addr { - if self.pipeline.is_flushed() { - self.pc as Addr - } else if self.pipeline.is_only_fetched() { - self.pipeline.fetched.unwrap().0 - } else if self.pipeline.is_ready_to_execute() { - self.pipeline.decoded.unwrap().pc - } else { - unreachable!() + match self.cpsr.state() { + CpuState::ARM => { + if self.pipeline_arm.is_flushed() { + self.pc as Addr + } else if self.pipeline_arm.is_only_fetched() { + self.pipeline_arm.fetched.unwrap().0 + } else if self.pipeline_arm.is_ready_to_execute() { + self.pipeline_arm.decoded.unwrap().pc + } else { + unreachable!() + } + } + CpuState::THUMB => { + if self.pipeline_thumb.is_flushed() { + self.pc as Addr + } else if self.pipeline_thumb.is_only_fetched() { + self.pipeline_thumb.fetched.unwrap().0 + } else if self.pipeline_thumb.is_ready_to_execute() { + self.pipeline_thumb.decoded.unwrap().pc + } else { + unreachable!() + } + } } } /// A step that returns only once an instruction was executed. /// Returns the address of PC before executing an instruction, /// and the address of the next instruction to be executed; - pub fn step_debugger(&mut self, sysbus: &mut SysBus) -> CpuResult { + pub fn step_debugger(&mut self, sysbus: &mut SysBus) -> CpuResult { loop { if let Some(i) = self.step(sysbus)? { return Ok(i); diff --git a/src/arm7tdmi/mod.rs b/src/arm7tdmi/mod.rs index 160c3ea..a42d491 100644 --- a/src/arm7tdmi/mod.rs +++ b/src/arm7tdmi/mod.rs @@ -3,7 +3,10 @@ use std::fmt; use num::Num; pub mod arm; +pub mod thumb; + use arm::{ArmDecodeError, ArmInstruction}; +use thumb::{ThumbDecodeError, ThumbInstruction}; pub mod cpu; pub use cpu::*; @@ -18,6 +21,57 @@ pub const REG_SP: usize = 13; pub type Addr = u32; +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum DecodedInstruction { + Arm(ArmInstruction), + Thumb(ThumbInstruction), +} + +impl DecodedInstruction { + pub fn get_pc(&self) -> Addr { + match self { + DecodedInstruction::Arm(a) => a.pc, + DecodedInstruction::Thumb(t) => t.pc, + } + } +} +impl fmt::Display for DecodedInstruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + DecodedInstruction::Arm(a) => write!(f, "{}", a), + DecodedInstruction::Thumb(t) => write!(f, "{:#?}", t), + } + } +} + +#[derive(Debug, PartialEq)] +pub enum InstructionDecoderError { + ArmDecodeError(ArmDecodeError), + ThumbDecodeError(ThumbDecodeError), + IoError(std::io::ErrorKind), +} + +impl From for InstructionDecoderError { + fn from(e: ArmDecodeError) -> InstructionDecoderError { + InstructionDecoderError::ArmDecodeError(e) + } +} + +impl From for InstructionDecoderError { + fn from(e: ThumbDecodeError) -> InstructionDecoderError { + InstructionDecoderError::ThumbDecodeError(e) + } +} + +pub trait InstructionDecoder: Sized + fmt::Display { + type IntType: Num; + + fn decode(n: Self::IntType, addr: Addr) -> Result; + /// Helper functions for the Disassembler + fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Result; + fn get_raw(&self) -> Self::IntType; +} + pub fn reg_string(reg: usize) -> &'static str { let reg_names = &[ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "fp", "ip", "sp", "lr", @@ -26,12 +80,6 @@ pub fn reg_string(reg: usize) -> &'static str { reg_names[reg] } -#[derive(Debug, PartialEq)] -pub enum CpuInstruction { - Arm(ArmInstruction), - Thumb, -} - #[derive(Debug, PartialEq, Primitive, Copy, Clone)] #[repr(u8)] pub enum CpuState { @@ -101,29 +149,46 @@ impl fmt::Display for CpuMode { #[derive(Debug, PartialEq)] pub enum CpuError { - ArmDecodeError(ArmDecodeError), + DecodeError(InstructionDecoderError), IllegalInstruction, - UnimplementedCpuInstruction(CpuInstruction), + UnimplementedCpuInstruction(Addr, u32, DecodedInstruction), +} + +impl From for CpuError { + fn from(e: InstructionDecoderError) -> CpuError { + CpuError::DecodeError(e) + } } impl From for CpuError { fn from(e: ArmDecodeError) -> CpuError { - CpuError::ArmDecodeError(e) + CpuError::DecodeError(InstructionDecoderError::ArmDecodeError(e)) + } +} + +impl From for CpuError { + fn from(e: ThumbDecodeError) -> CpuError { + CpuError::DecodeError(InstructionDecoderError::ThumbDecodeError(e)) } } impl fmt::Display for CpuError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - CpuError::ArmDecodeError(e) => write!( + CpuError::DecodeError(InstructionDecoderError::ArmDecodeError(e)) => write!( f, "arm decoding error at address @0x{:08x} (instruction 0x{:08x}): {:?}", e.addr, e.insn, e.kind ), - CpuError::UnimplementedCpuInstruction(CpuInstruction::Arm(insn)) => write!( + CpuError::DecodeError(InstructionDecoderError::ThumbDecodeError(e)) => write!( f, - "unimplemented instruction: 0x{:08x}:\t0x{:08x}\t{}", - insn.pc, insn.raw, insn + "thumb decoding error at address @0x{:08x} (instruction 0x{:08x}): {:?}", + e.addr, e.insn, e.kind + ), + CpuError::UnimplementedCpuInstruction(addr, raw, d) => write!( + f, + "unimplemented instruction: 0x{:08x}:\t0x{:08x}\t{:?}", + addr, raw, d ), CpuError::IllegalInstruction => write!(f, "illegal instruction"), e => write!(f, "error: {:#x?}", e), diff --git a/src/arm7tdmi/thumb/display.rs b/src/arm7tdmi/thumb/display.rs new file mode 100644 index 0000000..1eed6e3 --- /dev/null +++ b/src/arm7tdmi/thumb/display.rs @@ -0,0 +1,142 @@ +use std::fmt; + +use crate::bit::BitIndex; + +use super::*; +use crate::arm7tdmi::reg_string; + +impl ThumbInstruction { + fn fmt_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_data_process_imm(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{op}\t{Rd}, #{Offset8}", + op = self.format3_op(), + Rd = reg_string(self.rd()), + Offset8 = self.offset8() + ) + } + + fn fmt_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_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 + 2 + (self.word8() as Addr) + ) + } + + fn fmt_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_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_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 as i32; + (self.pc as i32).wrapping_add(offset) as Addr + } + ) + } +} + +impl fmt::Display for ThumbInstruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.fmt { + ThumbFormat::MoveShiftedReg => self.fmt_move_shifted_reg(f), + ThumbFormat::AddSub => self.fmt_add_sub(f), + ThumbFormat::DataProcessImm => self.fmt_data_process_imm(f), + ThumbFormat::HiRegOpOrBranchExchange => self.fmt_high_reg_op_or_bx(f), + ThumbFormat::LdrPc => self.fmt_ldr_pc(f), + ThumbFormat::LdrStrRegOffset => self.fmt_ldr_str_reg_offset(f), + ThumbFormat::BranchConditional => self.fmt_branch_with_cond(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"), + } + } +} diff --git a/src/arm7tdmi/thumb/exec.rs b/src/arm7tdmi/thumb/exec.rs new file mode 100644 index 0000000..63b8d97 --- /dev/null +++ b/src/arm7tdmi/thumb/exec.rs @@ -0,0 +1,9 @@ +use super::super::super::sysbus::SysBus; +use super::super::cpu::{Core, CpuExecResult}; +use super::ThumbInstruction; + +impl Core { + pub fn exec_thumb(&mut self, sysbus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { + unimplemented!("thumb not implemented {:#}", insn) + } +} diff --git a/src/arm7tdmi/thumb/mod.rs b/src/arm7tdmi/thumb/mod.rs new file mode 100644 index 0000000..2ab3905 --- /dev/null +++ b/src/arm7tdmi/thumb/mod.rs @@ -0,0 +1,241 @@ +use std::io; + +use crate::bit::BitIndex; +use crate::byteorder::{LittleEndian, ReadBytesExt}; +use crate::num::FromPrimitive; + +use super::arm::{ArmCond, ArmShiftType}; +use super::{Addr, InstructionDecoder, InstructionDecoderError}; + +pub mod display; +pub mod exec; + +#[derive(Debug, PartialEq)] +pub enum ThumbDecodeErrorKind { + UnknownInstructionFormat, + IoError(io::ErrorKind), +} +use ThumbDecodeErrorKind::*; + +#[derive(Debug, PartialEq)] +pub struct ThumbDecodeError { + pub kind: ThumbDecodeErrorKind, + pub insn: u16, + pub addr: Addr, +} + +impl ThumbDecodeError { + fn new(kind: ThumbDecodeErrorKind, insn: u16, addr: Addr) -> ThumbDecodeError { + ThumbDecodeError { + kind: kind, + insn: insn, + addr: addr, + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum ThumbFormat { + /// Format 1 + MoveShiftedReg, + /// Format 2 + AddSub, + /// Format 3 + DataProcessImm, + /// Format 4 + AluOps, + /// Format 5 + HiRegOpOrBranchExchange, + /// Format 6 + LdrPc, + /// Format 7 + LdrStrRegOffset, + /// Format 8 + LdrStrSHB, + /// Format 9 + LdrStrImmOffset, + /// Format 10 + LdrStrHalfWord, + /// Format 11 + LdrStrSp, + /// Format 12 + LdrAddress, + /// Format 13 + AddSp, + /// Format 14 + PushPop, + /// Format 15 + LdmStm, + /// Format 16 + BranchConditional, + /// Format 17 + Swi, + /// Format 18 + Branch, + /// Format 19 + BranchLongWithLink, +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct ThumbInstruction { + pub fmt: ThumbFormat, + pub raw: u16, + pub pc: Addr, +} + +impl InstructionDecoder for ThumbInstruction { + type IntType = u16; + + fn decode(raw: u16, addr: Addr) -> Result { + use self::ThumbFormat::*; + + let fmt = if raw & 0xf800 == 0x1800 { + Ok(AddSub) + } else if raw & 0xe000 == 0x0000 { + Ok(MoveShiftedReg) + } else if raw & 0xe000 == 0x2000 { + Ok(DataProcessImm) + } else if raw & 0xfc00 == 0x4000 { + Ok(AluOps) + } else if raw & 0xfc00 == 0x4400 { + Ok(HiRegOpOrBranchExchange) + } else if raw & 0xf800 == 0x4800 { + Ok(LdrPc) + } else if raw & 0xf200 == 0x5000 { + Ok(LdrStrRegOffset) + } else if raw & 0xf200 == 0x5200 { + Ok(LdrStrSHB) + } else if raw & 0xe000 == 0x6000 { + Ok(LdrStrImmOffset) + } else if raw & 0xf000 == 0x8000 { + Ok(LdrStrHalfWord) + } else if raw & 0xf000 == 0x9000 { + Ok(LdrStrSp) + } else if raw & 0xf000 == 0xa000 { + Ok(LdrAddress) + } else if raw & 0xff00 == 0xb000 { + Ok(AddSp) + } else if raw & 0xf600 == 0xb400 { + Ok(PushPop) + } else if raw & 0xf000 == 0xc000 { + Ok(LdmStm) + } else if raw & 0xf000 == 0xd000 { + Ok(BranchConditional) + } else if raw & 0xff00 == 0xdf00 { + Ok(Swi) + } else if raw & 0xf800 == 0xe000 { + Ok(Branch) + } else if raw & 0xf000 == 0xf000 { + Ok(BranchLongWithLink) + } else { + Err(ThumbDecodeError::new(UnknownInstructionFormat, raw, addr)) + }?; + + Ok(ThumbInstruction { + fmt: fmt, + raw: raw, + pc: addr, + }) + } + + fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Result { + let mut rdr = std::io::Cursor::new(bytes); + let raw = rdr + .read_u16::() + .map_err(|e| InstructionDecoderError::IoError(e.kind()))?; + Self::decode(raw, addr) + } + + fn get_raw(&self) -> u16 { + self.raw + } +} + +#[derive(Debug, Primitive)] +pub enum OpFormat3 { + MOV = 0, + CMP = 1, + ADD = 2, + SUB = 3, +} + +#[derive(Debug, Primitive)] +pub enum OpFormat5 { + ADD = 0, + CMP = 1, + MOV = 2, + BX = 3, +} + +impl ThumbInstruction { + const FLAG_H1: usize = 7; + const FLAG_H2: usize = 6; + + pub fn rd(&self) -> usize { + (self.raw & 0b111) as usize + } + + pub fn rs(&self) -> usize { + self.raw.bit_range(3..6) as usize + } + + pub fn rb(&self) -> usize { + self.raw.bit_range(3..6) as usize + } + + pub fn ro(&self) -> usize { + self.raw.bit_range(6..9) as usize + } + + pub fn rn(&self) -> usize { + self.raw.bit_range(6..9) as usize + } + + pub fn format1_op(&self) -> ArmShiftType { + ArmShiftType::from_u8(self.raw.bit_range(11..13) as u8).unwrap() + } + + pub fn format3_op(&self) -> OpFormat3 { + OpFormat3::from_u8(self.raw.bit_range(11..13) as u8).unwrap() + } + + pub fn format5_op(&self) -> OpFormat5 { + OpFormat5::from_u8(self.raw.bit_range(8..10) as u8).unwrap() + } + + pub fn offset5(&self) -> i8 { + self.raw.bit_range(6..11) as i8 + } + + pub fn offset8(&self) -> i8 { + self.raw.bit_range(0..8) as i8 + } + + pub fn word8(&self) -> u16 { + self.raw.bit_range(0..8) << 2 + } + + pub fn is_transfering_bytes(&self) -> bool { + self.raw.bit(10) + } + + pub fn is_load(&self) -> bool { + self.raw.bit(11) + } + + pub fn is_subtract(&self) -> bool { + self.raw.bit(9) + } + + pub fn is_immediate_operand(&self) -> bool { + self.raw.bit(10) + } + + pub fn cond(&self) -> ArmCond { + ArmCond::from_u8(self.raw.bit_range(8..12) as u8).unwrap() + } + + pub fn flag(&self, bit: usize) -> bool { + self.raw.bit(bit) + } +} diff --git a/src/bin/cli.yml b/src/bin/cli.yml index e69866b..86245da 100644 --- a/src/bin/cli.yml +++ b/src/bin/cli.yml @@ -15,12 +15,4 @@ subcommands: long: game-rom takes_value: true help: Sets the game-rom file to use - required: true - - disass: - about: disassemble an arm binary file - args: - - INPUT: - help: Sets the input file to use - required: true - index: 1 - + required: true \ No newline at end of file diff --git a/src/bin/main.rs b/src/bin/main.rs index 3704a60..4569e89 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -9,7 +9,6 @@ extern crate rustboyadvance_ng; use rustboyadvance_ng::arm7tdmi; use rustboyadvance_ng::debugger::{Debugger, DebuggerError}; -use rustboyadvance_ng::disass::Disassembler; use rustboyadvance_ng::sysbus::SysBus; use rustboyadvance_ng::util::read_bin_file; @@ -47,17 +46,6 @@ impl From for GBAError { } } -fn run_disass(matches: &ArgMatches) -> GBAResult<()> { - let input = matches.value_of("INPUT").unwrap(); - let bin = read_bin_file(&input)?; - - let disassembler = Disassembler::new(0, &bin); - for (_, line) in disassembler { - println!("{}", line) - } - Ok(()) -} - fn run_debug(matches: &ArgMatches) -> GBAResult<()> { let bios_bin = read_bin_file(matches.value_of("bios").unwrap_or_default())?; let rom_bin = read_bin_file(matches.value_of("game_rom").unwrap())?; @@ -81,7 +69,6 @@ fn main() { let result = match matches.subcommand() { ("debug", Some(m)) => run_debug(m), - ("disass", Some(m)) => run_disass(m), _ => Ok(()), }; diff --git a/src/debugger/command.rs b/src/debugger/command.rs index bef1139..30e5944 100644 --- a/src/debugger/command.rs +++ b/src/debugger/command.rs @@ -1,5 +1,5 @@ use crate::arm7tdmi::bus::Bus; -use crate::arm7tdmi::{reg_string, Addr, REG_PC}; +use crate::arm7tdmi::{Addr, CpuState}; use crate::disass::Disassembler; use super::{parser::Value, Debugger, DebuggerError, DebuggerResult}; @@ -9,15 +9,21 @@ use ansi_term::Colour; use colored::*; use hexdump; +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum DisassMode { + ModeArm, + ModeThumb, +} + #[derive(Debug, PartialEq, Clone)] pub enum Command { Info, SingleStep(bool), Continue, - HexDump(u32, usize), - Disass(u32, usize), - AddBreakpoint(u32), - DelBreakpoint(u32), + HexDump(Addr, usize), + Disass(DisassMode, Addr, usize), + AddBreakpoint(Addr), + DelBreakpoint(Addr), ClearBreakpoints, ListBreakpoints, Reset, @@ -38,8 +44,8 @@ impl Command { Ok(insn) => { println!("{}\n", debugger.cpu); println!( - "Executed at @0x{:08x}:\n\t{}", - insn.pc, + "Executed at @0x{:08x}:\t{}", + insn.get_pc(), Colour::Yellow.italic().paint(format!("{} ", insn)) ); println!("Next instruction at @0x{:08x}", debugger.cpu.get_next_pc()) @@ -60,8 +66,8 @@ impl Command { match debugger.cpu.step_debugger(&mut debugger.sysbus) { Ok(insn) => { println!( - "@0x{:08x}:\n\t{}", - insn.pc, + "@0x{:08x}:\t{}", + insn.get_pc(), Colour::Yellow.italic().paint(format!("{} ", insn)) ); } @@ -73,15 +79,28 @@ impl Command { }; }, HexDump(addr, nbytes) => { - let bytes = debugger.sysbus.get_bytes(addr, nbytes); - hexdump::hexdump(bytes); + let bytes = debugger.sysbus.get_bytes(addr); + hexdump::hexdump(&bytes[0..nbytes]); } - Disass(addr, n) => { - let bytes = debugger.sysbus.get_bytes(addr, 4 * n); - let disass = Disassembler::new(addr, bytes); - for (_, line) in disass { - println!("{}", line) - } + Disass(mode, addr, n) => { + use crate::arm7tdmi::arm::ArmInstruction; + use crate::arm7tdmi::thumb::ThumbInstruction; + + let bytes = debugger.sysbus.get_bytes(addr); + match mode { + DisassMode::ModeArm => { + let disass = Disassembler::::new(addr, bytes); + for (_, line) in disass.take(n) { + println!("{}", line) + } + } + DisassMode::ModeThumb => { + let disass = Disassembler::::new(addr, bytes); + for (_, line) in disass.take(n) { + println!("{}", line) + } + } + }; } Quit => { print!("Quitting!"); @@ -114,9 +133,37 @@ impl Command { } impl Debugger { + fn get_disassembler_args(&self, args: Vec) -> DebuggerResult<(Addr, usize)> { + match args.len() { + 2 => { + let addr = self.val_address(&args[0])?; + let n = self.val_number(&args[1])?; + + Ok((addr, n as usize)) + } + 1 => { + let addr = self.val_address(&args[0])?; + + Ok((addr, 10)) + } + 0 => { + if let Some(Command::Disass(_mode, addr, n)) = &self.previous_command { + Ok((*addr + (4 * (*n as u32)), 10)) + } else { + Ok((self.cpu.get_next_pc(), 10)) + } + } + _ => { + return Err(DebuggerError::InvalidCommandFormat( + "disass [addr] [n]".to_string(), + )) + } + } + } + pub fn eval_command(&self, command: Value, args: Vec) -> DebuggerResult { let command = match command { - Value::Name(command) => command, + Value::Identifier(command) => command, _ => { return Err(DebuggerError::InvalidCommand("expected a name".to_string())); } @@ -156,33 +203,23 @@ impl Debugger { Ok(Command::HexDump(addr, n)) } "d" | "disass" => { - let (addr, n) = match args.len() { - 2 => { - let addr = self.val_address(&args[0])?; - let n = self.val_number(&args[1])?; + let (addr, n) = self.get_disassembler_args(args)?; - (addr, n as usize) - } - 1 => { - let addr = self.val_address(&args[0])?; - - (addr, 10) - } - 0 => { - if let Some(Command::Disass(addr, n)) = self.previous_command { - (addr + (4 * n as u32), 10) - } else { - (self.cpu.get_next_pc(), 10) - } - } - _ => { - return Err(DebuggerError::InvalidCommandFormat( - "disass [addr] [n]".to_string(), - )) - } + let m = match self.cpu.cpsr.state() { + CpuState::ARM => DisassMode::ModeArm, + CpuState::THUMB => DisassMode::ModeThumb, }; + Ok(Command::Disass(m, addr, n)) + } + "da" | "disass-arm" => { + let (addr, n) = self.get_disassembler_args(args)?; - Ok(Command::Disass(addr, n)) + Ok(Command::Disass(DisassMode::ModeArm, addr, n)) + } + "dt" | "disass-thumb" => { + let (addr, n) = self.get_disassembler_args(args)?; + + Ok(Command::Disass(DisassMode::ModeThumb, addr, n)) } "b" | "break" => { if args.len() != 1 { diff --git a/src/debugger/mod.rs b/src/debugger/mod.rs index e3441b3..6a7b7cb 100644 --- a/src/debugger/mod.rs +++ b/src/debugger/mod.rs @@ -82,7 +82,7 @@ impl Debugger { fn val_reg(&self, arg: &Value) -> DebuggerResult { match arg { - Value::Name(reg) => self.decode_reg(®), + Value::Identifier(reg) => self.decode_reg(®), v => Err(DebuggerError::InvalidArgument(format!( "expected a number, got {:?}", v @@ -103,7 +103,7 @@ impl Debugger { fn val_address(&self, arg: &Value) -> DebuggerResult { match arg { Value::Num(n) => Ok(*n), - Value::Name(reg) => { + Value::Identifier(reg) => { let reg = self.decode_reg(®)?; Ok(self.cpu.get_reg(reg)) } @@ -167,7 +167,7 @@ impl Debugger { println!("Welcome to rustboyadvance-NG debugger 😎!\n"); self.running = true; let mut rl = Editor::<()>::new(); - rl.load_history(".rustboyadvance_history"); + rl.load_history(".rustboyadvance_history").unwrap(); while self.running { let readline = rl.readline(&format!("({}) ᐅ ", "rustboyadvance-dbg".bold().cyan())); match readline { diff --git a/src/debugger/parser.rs b/src/debugger/parser.rs index 1fe73e7..0ef87e1 100644 --- a/src/debugger/parser.rs +++ b/src/debugger/parser.rs @@ -4,8 +4,8 @@ use crate::arm7tdmi::Addr; use nom; use nom::branch::alt; -use nom::bytes::complete::{tag, take_while_m_n}; -use nom::character::complete::{alphanumeric1, char, digit1, multispace0, multispace1}; +use nom::bytes::complete::{tag, take_while1, take_while_m_n}; +use nom::character::complete::{char, digit1, multispace0, multispace1}; use nom::combinator::{cut, map, map_res, opt}; use nom::error::{context, convert_error, ParseError, VerboseError}; use nom::multi::separated_list; @@ -25,7 +25,7 @@ pub enum DerefType { pub enum Value { Num(u32), Boolean(bool), - Name(String), + Identifier(String), Deref(Box, DerefType), } @@ -63,8 +63,11 @@ fn parse_boolean<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Val )(i) } -fn parse_name<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Value, E> { - map(alphanumeric1, |s: &str| Value::Name(String::from(s)))(i) +fn parse_identifier<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Value, E> { + map( + take_while1(|c: char| c.is_alphanumeric() || c == '_' || c == '-'), + |s: &str| Value::Identifier(String::from(s)), + )(i) } fn parse_deref_type<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, DerefType, E> { @@ -90,7 +93,7 @@ fn parse_deref<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Value Some(t) => t, None => DerefType::Word, }), - alt((parse_num, parse_name)), + alt((parse_num, parse_identifier)), )), |(t, v)| Value::Deref(Box::new(v), t), )), @@ -101,7 +104,7 @@ fn parse_deref<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Value fn parse_value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Value, E> { context( "argument", - alt((parse_boolean, parse_deref, parse_num, parse_name)), + alt((parse_boolean, parse_deref, parse_num, parse_identifier)), )(i) } @@ -110,7 +113,7 @@ fn parse_command<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&str, Expr, "command", map( tuple(( - terminated(parse_name, multispace0), + terminated(parse_identifier, multispace0), separated_list(multispace1, parse_value), )), |(cmd, args)| Expr::Command(cmd, args), @@ -169,14 +172,17 @@ mod tests { fn test_parse_command_expr() { assert_eq!( parse_expr("command"), - Ok(Expr::Command(Value::Name("command".to_string()), vec![])) + Ok(Expr::Command( + Value::Identifier("command".to_string()), + vec![] + )) ); assert_eq!( parse_expr("command arg0 0x1337 true "), Ok(Expr::Command( - Value::Name("command".to_string()), + Value::Identifier("command".to_string()), vec![ - Value::Name("arg0".to_string()), + Value::Identifier("arg0".to_string()), Value::Num(0x1337), Value::Boolean(true) ] @@ -189,22 +195,22 @@ mod tests { assert_eq!( parse_expr(" pc = 0x1337 "), Ok(Expr::Assignment( - Value::Name("pc".to_string()), + Value::Identifier("pc".to_string()), Value::Num(0x1337) )) ); assert_eq!( parse_expr("aaa = false "), Ok(Expr::Assignment( - Value::Name("aaa".to_string()), + Value::Identifier("aaa".to_string()), Value::Boolean(false) )) ); assert_eq!( parse_expr(" pc = lr "), Ok(Expr::Assignment( - Value::Name("pc".to_string()), - Value::Name("lr".to_string()) + Value::Identifier("pc".to_string()), + Value::Identifier("lr".to_string()) )) ); } @@ -222,7 +228,10 @@ mod tests { parse_deref::>("*r10"), Ok(( "", - Value::Deref(Box::new(Value::Name("r10".to_string())), DerefType::Word) + Value::Deref( + Box::new(Value::Identifier("r10".to_string())), + DerefType::Word + ) )) ); } diff --git a/src/disass.rs b/src/disass.rs index c3107dd..70e799d 100644 --- a/src/disass.rs +++ b/src/disass.rs @@ -1,55 +1,69 @@ use std::convert::TryFrom; +use std::marker::PhantomData; +use super::arm7tdmi::{Addr, InstructionDecoder, InstructionDecoderError}; +use std::io; use std::io::ErrorKind; -use std::io::{Cursor, Seek, SeekFrom}; -use byteorder::{LittleEndian, ReadBytesExt}; - -use super::arm7tdmi::arm; - -pub struct Disassembler<'a> { - base: u32, - rdr: Cursor<&'a [u8]>, +pub struct Disassembler<'a, D> +where + D: InstructionDecoder, +{ + base: Addr, + pos: usize, + bytes: &'a [u8], + pub word_size: usize, + instruction_decoder: PhantomData, } -impl<'a> Disassembler<'a> { - pub fn new(base: u32, bin: &'a [u8]) -> Disassembler { +impl<'a, D> Disassembler<'a, D> +where + D: InstructionDecoder, +{ + pub fn new(base: Addr, bytes: &'a [u8]) -> Disassembler { Disassembler { - base: base, - rdr: Cursor::new(bin), + base: base as Addr, + pos: 0, + bytes: bytes, + word_size: std::mem::size_of::(), + instruction_decoder: PhantomData, } } } -impl<'a> Seek for Disassembler<'a> { - fn seek(&mut self, pos: SeekFrom) -> std::io::Result { - self.rdr.seek(pos) - } -} - -impl<'a> Iterator for Disassembler<'a> { - type Item = (u32, String); +impl<'a, D> Iterator for Disassembler<'a, D> +where + D: InstructionDecoder, + ::IntType: std::fmt::LowerHex, +{ + type Item = (Addr, String); fn next(&mut self) -> Option { let mut line = String::new(); - let value: u32 = match self.rdr.read_u32::() { - Ok(value) => value, - Err(e) => match e.kind() { - ErrorKind::UnexpectedEof => { + + let addr = self.base + self.pos as Addr; + let decoded: Option = + match D::decode_from_bytes(&self.bytes[(self.pos as usize)..], addr) { + Ok(decoded) => { + self.pos += self.word_size; + Some(decoded) + } + Err(InstructionDecoderError::IoError(ErrorKind::UnexpectedEof)) => { return None; } - _ => panic!("unexpected error"), - }, + _ => { + 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", addr)), }; - let addr = self.base + (self.rdr.position() - 4) as u32; - line.push_str(&format!("{:8x}:\t{:08x} \t", addr, value)); - - match arm::ArmInstruction::try_from((value, addr)) { - Ok(insn) => line.push_str(&format!("{}", insn)), - Err(_) => line.push_str(""), - }; - - Some((addr, line)) + Some((self.pos as Addr, line)) } } diff --git a/src/lib.rs b/src/lib.rs index 0a6e3c9..5c893e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,11 +11,11 @@ extern crate rustyline; extern crate nom; -extern crate colored; // not needed in Rust 2018 extern crate ansi_term; +extern crate colored; // not needed in Rust 2018 -pub mod sysbus; pub mod arm7tdmi; pub mod debugger; pub mod disass; -pub mod util; \ No newline at end of file +pub mod sysbus; +pub mod util; diff --git a/src/sysbus.rs b/src/sysbus.rs index f2b4c9e..c56db7c 100644 --- a/src/sysbus.rs +++ b/src/sysbus.rs @@ -36,14 +36,12 @@ impl Default for WaitState { } impl Bus for BoxedMemory { - fn get_bytes(&self, addr: Addr, size: usize) -> &[u8] { - let addr = addr as usize; - &self.0[addr..addr + size] + fn get_bytes(&self, addr: Addr) -> &[u8] { + &self.0[addr as usize..] } - fn get_bytes_mut(&mut self, addr: Addr, size: usize) -> &mut [u8] { - let addr = addr as usize; - &mut self.0[addr..addr + size] + fn get_bytes_mut(&mut self, addr: Addr) -> &mut [u8] { + &mut self.0[addr as usize..] } fn get_cycles(&self, _addr: Addr, access: MemoryAccess) -> usize { @@ -149,12 +147,12 @@ impl Bus for SysBus { self.map_mut(addr).write_8(addr & 0xff_ffff, value) } - fn get_bytes(&self, addr: Addr, size: usize) -> &[u8] { - self.map(addr).get_bytes(addr & 0xff_ffff, size) + fn get_bytes(&self, addr: Addr) -> &[u8] { + self.map(addr).get_bytes(addr & 0xff_ffff) } - fn get_bytes_mut(&mut self, addr: Addr, size: usize) -> &mut [u8] { - self.map_mut(addr).get_bytes_mut(addr & 0xff_ffff, size) + fn get_bytes_mut(&mut self, addr: Addr) -> &mut [u8] { + self.map_mut(addr).get_bytes_mut(addr & 0xff_ffff) } fn get_cycles(&self, addr: Addr, access: MemoryAccess) -> usize {