From 7119ba2451aa50701ca81c005a2e48709851351a Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Sat, 20 Jul 2019 14:44:49 +0300 Subject: [PATCH] Cpu: Rewrite pipeline code. Pipeline code was unreadable up until now, this also fixes a bug: * Some roms have illegal instructions right after branch instructions, and the cpu would error trying to decode them because of pipelining. Former-commit-id: e3201c7b0d2adfc772231a3e2d5909f43c17b50f --- src/arm7tdmi/arm/exec.rs | 43 ++++--- src/arm7tdmi/arm/mod.rs | 33 ++--- src/arm7tdmi/cpu.rs | 249 ++++++++++++++++--------------------- src/arm7tdmi/exception.rs | 3 +- src/arm7tdmi/thumb/exec.rs | 50 ++++---- src/arm7tdmi/thumb/mod.rs | 30 +---- src/gba.rs | 2 +- src/lib.rs | 2 +- 8 files changed, 171 insertions(+), 241 deletions(-) diff --git a/src/arm7tdmi/arm/exec.rs b/src/arm7tdmi/arm/exec.rs index ced7088..85acbec 100644 --- a/src/arm7tdmi/arm/exec.rs +++ b/src/arm7tdmi/arm/exec.rs @@ -2,7 +2,7 @@ use crate::bit::BitIndex; use crate::arm7tdmi::alu::*; use crate::arm7tdmi::bus::Bus; -use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction}; +use crate::arm7tdmi::cpu::{Core, CpuExecResult}; use crate::arm7tdmi::exception::Exception; use crate::arm7tdmi::psr::RegPSR; use crate::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, DecodedInstruction, REG_PC}; @@ -12,7 +12,7 @@ use super::*; impl Core { pub fn exec_arm(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { if !self.check_arm_cond(insn.cond) { - return Ok(CpuPipelineAction::IncPC); + return Ok(()); } match insn.fmt { ArmFormat::BX => self.exec_bx(bus, insn), @@ -43,8 +43,9 @@ impl Core { } self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32 & !1; + self.flush_pipeline(); - Ok(CpuPipelineAction::Flush) + Ok(()) } pub fn branch_exchange(&mut self, mut addr: Addr) -> CpuExecResult { @@ -57,8 +58,9 @@ impl Core { } self.pc = addr; + self.flush_pipeline(); - Ok(CpuPipelineAction::Flush) + Ok(()) } /// Cycles 2S+1N @@ -68,7 +70,8 @@ impl Core { fn exec_swi(&mut self, _bus: &mut Bus, _insn: ArmInstruction) -> CpuExecResult { self.exception(Exception::SoftwareInterrupt); - Ok(CpuPipelineAction::Flush) + self.flush_pipeline(); + Ok(()) } fn exec_mrs(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { @@ -83,7 +86,7 @@ impl Core { self.cpsr.get() }; self.set_reg(insn.rd(), result); - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_msr_reg(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { @@ -105,7 +108,7 @@ impl Core { } self.cpsr = new_psr; } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_msr_flags(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { @@ -122,7 +125,7 @@ impl Core { } else { self.cpsr.set_flag_bits(op); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn decode_operand2(&mut self, op2: BarrelShifterValue, set_flags: bool) -> CpuResult { @@ -155,7 +158,6 @@ impl Core { fn exec_data_processing(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { // TODO handle carry flag - let mut pipeline_action = CpuPipelineAction::IncPC; let op1 = if insn.rn() == REG_PC { self.pc as i32 // prefething @@ -186,11 +188,11 @@ impl Core { if let Some(result) = self.alu(opcode, op1, op2, set_flags) { self.set_reg(rd, result as u32); if rd == REG_PC { - pipeline_action = CpuPipelineAction::Flush; + self.flush_pipeline(); } } - Ok(pipeline_action) + Ok(()) } /// Memory Load/Store @@ -206,7 +208,6 @@ impl Core { if writeback && insn.rd() == insn.rn() { return Err(CpuError::IllegalInstruction); } - let mut pipeline_action = CpuPipelineAction::IncPC; let mut addr = self.get_reg(insn.rn()); if insn.rn() == REG_PC { @@ -236,7 +237,7 @@ impl Core { self.add_cycle(); if insn.rd() == REG_PC { - pipeline_action = CpuPipelineAction::Flush; + self.flush_pipeline(); } } else { let value = if insn.rd() == REG_PC { @@ -255,7 +256,7 @@ impl Core { self.set_reg(insn.rn(), effective_addr as u32) } - Ok(pipeline_action) + Ok(()) } fn exec_ldr_str_hs(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { @@ -264,7 +265,6 @@ impl Core { return Err(CpuError::IllegalInstruction); } - let mut pipeline_action = CpuPipelineAction::IncPC; let mut addr = self.get_reg(insn.rn()); if insn.rn() == REG_PC { @@ -296,7 +296,7 @@ impl Core { self.add_cycle(); if insn.rd() == REG_PC { - pipeline_action = CpuPipelineAction::Flush; + self.flush_pipeline(); } } else { let value = if insn.rd() == REG_PC { @@ -317,7 +317,7 @@ impl Core { self.set_reg(insn.rn(), effective_addr as u32) } - Ok(pipeline_action) + Ok(()) } fn exec_ldm_stm(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { @@ -326,7 +326,6 @@ impl Core { let psr_user = insn.psr_and_force_user_flag(); let is_load = insn.load_flag(); let mut writeback = insn.write_back_flag(); - let mut pipeline_action = CpuPipelineAction::IncPC; let rn = insn.rn(); let mut addr = self.gpr[rn] as i32; @@ -357,7 +356,7 @@ impl Core { self.set_reg(r, val); if r == REG_PC { - pipeline_action = CpuPipelineAction::Flush; + self.flush_pipeline(); } if !full { @@ -387,7 +386,7 @@ impl Core { self.set_reg(rn, addr as u32); } - Ok(pipeline_action) + Ok(()) } fn exec_mul_mla(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { @@ -422,7 +421,7 @@ impl Core { self.cpsr.set_Z(result == 0); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_mull_mlal(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { @@ -465,6 +464,6 @@ impl Core { self.cpsr.set_Z(result == 0); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } } diff --git a/src/arm7tdmi/arm/mod.rs b/src/arm7tdmi/arm/mod.rs index c226898..990901b 100644 --- a/src/arm7tdmi/arm/mod.rs +++ b/src/arm7tdmi/arm/mod.rs @@ -374,10 +374,8 @@ mod tests { assert_eq!(decoded.swi_comment(), 0x1337); assert_eq!(format!("{}", decoded), "swi\t#0x1337"); - assert_eq!( - core.exec_arm(&mut mem, decoded), - Ok(CpuPipelineAction::Flush) - ); + core.exec_arm(&mut mem, decoded).unwrap(); + assert_eq!(core.did_pipeline_flush(), true); assert_eq!(core.cpsr.mode(), CpuMode::Supervisor); assert_eq!(core.pc, Exception::SoftwareInterrupt as u32); @@ -401,10 +399,8 @@ mod tests { let bytes = vec![]; let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); - assert_eq!( - core.exec_arm(&mut mem, decoded), - Ok(CpuPipelineAction::Flush) - ); + core.exec_arm(&mut mem, decoded).unwrap(); + assert_eq!(core.did_pipeline_flush(), true); assert_eq!(core.pc, 0x30); } @@ -426,10 +422,8 @@ mod tests { let bytes = vec![]; let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); - assert_eq!( - core.exec_arm(&mut mem, decoded), - Ok(CpuPipelineAction::Flush) - ); + core.exec_arm(&mut mem, decoded).unwrap(); + assert_eq!(core.did_pipeline_flush(), true); assert_eq!(core.pc, 0x10); } @@ -470,10 +464,7 @@ mod tests { ]; let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); - assert_eq!( - core.exec_arm(&mut mem, decoded), - Ok(CpuPipelineAction::IncPC) - ); + core.exec_arm(&mut mem, decoded).unwrap(); assert_eq!(core.gpr[2], 0x1337); } @@ -514,10 +505,7 @@ mod tests { ]; let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); - assert_eq!( - core.exec_arm(&mut mem, decoded), - Ok(CpuPipelineAction::IncPC) - ); + core.exec_arm(&mut mem, decoded).unwrap(); assert_eq!(mem.read_32(0), 0xabababab); } @@ -543,10 +531,7 @@ mod tests { let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); assert_ne!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678); - assert_eq!( - core.exec_arm(&mut mem, decoded), - Ok(CpuPipelineAction::IncPC) - ); + core.exec_arm(&mut mem, decoded).unwrap(); assert_eq!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678); } } diff --git a/src/arm7tdmi/cpu.rs b/src/arm7tdmi/cpu.rs index 3d15949..e4856cf 100644 --- a/src/arm7tdmi/cpu.rs +++ b/src/arm7tdmi/cpu.rs @@ -13,49 +13,16 @@ use super::{ Addr, CpuMode, CpuResult, CpuState, DecodedInstruction, InstructionDecoder, }; -#[derive(Debug)] -pub struct PipelineContext -where - D: InstructionDecoder, - N: Num, -{ - fetched: Option<(Addr, N)>, - decoded: Option, +#[derive(Debug, PartialEq)] +enum PipelineState { + Refill1, + Refill2, + Execute, } -impl Default for PipelineContext -where - D: InstructionDecoder, - N: Num, -{ - fn default() -> PipelineContext { - PipelineContext { - fetched: None, - decoded: None, - } - } -} - -impl PipelineContext -where - D: InstructionDecoder, - N: Num, -{ - pub fn flush(&mut self) { - self.fetched = None; - self.decoded = None; - } - - pub fn is_flushed(&self) -> bool { - self.fetched.is_none() && self.decoded.is_none() - } - - pub fn is_only_fetched(&self) -> bool { - self.fetched.is_some() && self.decoded.is_none() - } - - pub fn is_ready_to_execute(&self) -> bool { - self.fetched.is_some() && self.decoded.is_some() +impl Default for PipelineState { + fn default() -> PipelineState { + PipelineState::Refill1 } } @@ -73,8 +40,13 @@ pub struct Core { pub cpsr: RegPSR, pub spsr: [RegPSR; 5], - pub pipeline_arm: PipelineContext, - pub pipeline_thumb: PipelineContext, + pipeline_state: PipelineState, + fetched_arm: u32, + decoded_arm: u32, + fetched_thumb: u16, + decoded_thumb: u16, + last_executed: Option, + pub cycles: usize, // store the gpr before executing an instruction to show diff in the Display impl @@ -85,13 +57,7 @@ pub struct Core { pub verbose: bool, } -#[derive(Debug, PartialEq)] -pub enum CpuPipelineAction { - IncPC, - Flush, -} - -pub type CpuExecResult = CpuResult; +pub type CpuExecResult = CpuResult<()>; impl Core { pub fn new() -> Core { @@ -274,119 +240,110 @@ impl Core { } } - fn step_thumb( - &mut self, - bus: &mut Bus, - ) -> CpuResult<(Option, CpuPipelineAction)> { - // fetch - // let new_fetched = bus.read_16(self.pc); - let new_fetched = self.load_16(self.pc, bus); - - // decode - let new_decoded = match self.pipeline_thumb.fetched { - Some((addr, i)) => { - let insn = ThumbInstruction::decode(i, addr)?; - Some(insn) + fn step_arm_exec(&mut self, insn: u32, sb: &mut Bus) -> CpuResult<()> { + let pc = self.pc; + match self.pipeline_state { + PipelineState::Refill1 => { + self.pc = pc.wrapping_add(4); + self.pipeline_state = PipelineState::Refill2; } - None => None, - }; - - // exec - let result = match self.pipeline_thumb.decoded { - Some(d) => { + PipelineState::Refill2 => { + self.pc = pc.wrapping_add(4); + self.pipeline_state = PipelineState::Execute; + } + PipelineState::Execute => { + let insn = ArmInstruction::decode(insn, self.pc.wrapping_sub(8))?; self.gpr_previous = self.get_registers(); - let action = self.exec_thumb(bus, d)?; - Ok((Some(DecodedInstruction::Thumb(d)), action)) + self.exec_arm(sb, insn)?; + if !self.did_pipeline_flush() { + self.pc = pc.wrapping_add(4); + } + self.last_executed = Some(DecodedInstruction::Arm(insn)); } - None => Ok((None, CpuPipelineAction::IncPC)), - }; - - self.pipeline_thumb.fetched = Some((self.pc, new_fetched)); - if let Some(d) = new_decoded { - self.pipeline_thumb.decoded = Some(d); } - - result + Ok(()) } - fn step_arm( - &mut self, - bus: &mut Bus, - ) -> CpuResult<(Option, CpuPipelineAction)> { - // let new_fetched = bus.read_32(self.pc); - let new_fetched = self.load_32(self.pc, bus); + fn arm(&mut self, sb: &mut Bus) -> CpuResult<()> { + let pc = self.pc; + + // fetch + let fetched_now = self.load_32(pc, sb); + let executed_now = self.decoded_arm; // decode - let new_decoded = match self.pipeline_arm.fetched { - Some((addr, i)) => { - let insn = ArmInstruction::decode(i, addr)?; - Some(insn) - } - None => None, - }; + self.decoded_arm = self.fetched_arm; + self.fetched_arm = fetched_now; - // exec - let result = match self.pipeline_arm.decoded { - Some(d) => { + // execute + self.step_arm_exec(executed_now, sb)?; + Ok(()) + } + + pub fn did_pipeline_flush(&self) -> bool { + self.pipeline_state == PipelineState::Refill1 + } + + fn step_thumb_exec(&mut self, insn: u16, sb: &mut Bus) -> CpuResult<()> { + let pc = self.pc; + match self.pipeline_state { + PipelineState::Refill1 => { + self.pc = pc.wrapping_add(2); + self.pipeline_state = PipelineState::Refill2; + } + PipelineState::Refill2 => { + self.pc = pc.wrapping_add(2); + self.pipeline_state = PipelineState::Execute; + } + PipelineState::Execute => { + let insn = ThumbInstruction::decode(insn, self.pc.wrapping_sub(4))?; self.gpr_previous = self.get_registers(); - let action = self.exec_arm(bus, d)?; - Ok((Some(DecodedInstruction::Arm(d)), action)) + self.exec_thumb(sb, insn)?; + if !self.did_pipeline_flush() { + self.pc = pc.wrapping_add(2); + } + self.last_executed = Some(DecodedInstruction::Thumb(insn)); } - 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); } + Ok(()) + } - result + fn thumb(&mut self, sb: &mut Bus) -> CpuResult<()> { + let pc = self.pc; + + // fetch + let fetched_now = self.load_16(pc, sb); + let executed_now = self.decoded_thumb; + + // decode + self.decoded_thumb = self.fetched_thumb; + self.fetched_thumb = fetched_now; + + // execute + self.step_thumb_exec(executed_now, sb)?; + Ok(()) + } + + pub fn flush_pipeline(&mut self) { + self.pipeline_state = PipelineState::Refill1; } /// Perform a pipeline step /// If an instruction was executed in this step, return it. - pub fn step(&mut self, bus: &mut Bus) -> CpuResult> { - let (executed_instruction, pipeline_action) = match self.cpsr.state() { - CpuState::ARM => self.step_arm(bus), - CpuState::THUMB => self.step_thumb(bus), - }?; - - match pipeline_action { - CpuPipelineAction::IncPC => self.advance_pc(), - CpuPipelineAction::Flush => { - self.pipeline_arm.flush(); - self.pipeline_thumb.flush(); - } + pub fn step(&mut self, bus: &mut Bus) -> CpuResult<()> { + match self.cpsr.state() { + CpuState::ARM => self.arm(bus), + CpuState::THUMB => self.thumb(bus), } - - Ok(executed_instruction) } /// Get's the address of the next instruction that is going to be executed pub fn get_next_pc(&self) -> Addr { - 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!() - } - } + let insn_size = self.word_size() as u32; + match self.pipeline_state { + PipelineState::Refill1 => self.pc, + PipelineState::Refill2 => self.pc - insn_size, + PipelineState::Execute => self.pc - 2 * insn_size, } } @@ -395,8 +352,14 @@ impl Core { /// and the address of the next instruction to be executed; pub fn step_one(&mut self, bus: &mut Bus) -> CpuResult { loop { - if let Some(i) = self.step(bus)? { - return Ok(i); + match self.pipeline_state { + PipelineState::Execute => { + self.step(bus)?; + return Ok(self.last_executed.unwrap()); + } + _ => { + self.step(bus)?; + } } } } diff --git a/src/arm7tdmi/exception.rs b/src/arm7tdmi/exception.rs index 0dacfb4..dd7a258 100644 --- a/src/arm7tdmi/exception.rs +++ b/src/arm7tdmi/exception.rs @@ -49,7 +49,6 @@ impl Core { // Set PC to vector address self.pc = vector; - self.pipeline_arm.flush(); - self.pipeline_thumb.flush(); + self.flush_pipeline(); } } diff --git a/src/arm7tdmi/thumb/exec.rs b/src/arm7tdmi/thumb/exec.rs index 07f8339..e63335b 100644 --- a/src/arm7tdmi/thumb/exec.rs +++ b/src/arm7tdmi/thumb/exec.rs @@ -1,5 +1,5 @@ use crate::arm7tdmi::bus::Bus; -use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction}; +use crate::arm7tdmi::cpu::{Core, CpuExecResult}; use crate::arm7tdmi::*; use super::*; @@ -35,7 +35,7 @@ impl Core { self.set_reg(rd, result as u32); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_add_sub(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { @@ -56,7 +56,7 @@ impl Core { self.set_reg(insn.rd(), result as u32); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_data_process_imm( @@ -72,7 +72,7 @@ impl Core { self.set_reg(insn.rd(), result as u32); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_mul(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { @@ -83,7 +83,7 @@ impl Core { self.add_cycle(); } self.gpr[insn.rd()] = op1.wrapping_mul(op2) as u32; - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_alu_ops(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { @@ -102,7 +102,7 @@ impl Core { self.set_reg(rd, result as u32); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } /// Cycles 2S+1N @@ -141,10 +141,10 @@ impl Core { if let Some(result) = result { self.set_reg(dst_reg, result as u32); if dst_reg == REG_PC { - return Ok(CpuPipelineAction::Flush); + self.flush_pipeline(); } } - Ok(CpuPipelineAction::IncPC) + Ok(()) } } @@ -156,7 +156,7 @@ impl Core { // +1I self.add_cycle(); - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn do_exec_thumb_ldr_str( @@ -185,7 +185,7 @@ impl Core { }; } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_ldr_str_reg_offset( @@ -232,7 +232,7 @@ impl Core { } } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_ldr_str_imm_offset( @@ -263,7 +263,7 @@ impl Core { } else { self.store_16(addr, self.gpr[insn.rd()] as u16, bus); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_ldr_str_sp(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { @@ -279,7 +279,7 @@ impl Core { }; self.gpr[insn.rd()] = result; - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn do_exec_thumb_ldr_str_with_addr( @@ -295,7 +295,7 @@ impl Core { } else { self.store_32(addr, self.gpr[insn.rd()], bus); } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_add_sp(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { @@ -308,14 +308,13 @@ impl Core { self.gpr[REG_SP] = result as u32; } - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_push_pop(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { // (From GBATEK) Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH). let is_pop = insn.is_load(); - let mut pipeline_action = CpuPipelineAction::IncPC; let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R); let rlist = insn.register_list(); @@ -326,7 +325,7 @@ impl Core { if pc_lr_flag { pop(self, bus, REG_PC); self.pc = self.pc & !1; - pipeline_action = CpuPipelineAction::Flush; + self.flush_pipeline(); } self.add_cycle(); } else { @@ -338,7 +337,7 @@ impl Core { } } - Ok(pipeline_action) + Ok(()) } fn exec_thumb_ldm_stm(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { @@ -365,7 +364,7 @@ impl Core { self.gpr[rb] = addr as u32; - Ok(CpuPipelineAction::IncPC) + Ok(()) } fn exec_thumb_branch_with_cond( @@ -374,18 +373,20 @@ impl Core { insn: ThumbInstruction, ) -> CpuExecResult { if !self.check_arm_cond(insn.cond()) { - Ok(CpuPipelineAction::IncPC) + Ok(()) } else { let offset = ((insn.offset8() as i8) << 1) as i32; self.pc = (self.pc as i32).wrapping_add(offset) as u32; - Ok(CpuPipelineAction::Flush) + self.flush_pipeline(); + Ok(()) } } fn exec_thumb_branch(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { let offset = ((insn.offset11() << 21) >> 20) as i32; self.pc = (self.pc as i32).wrapping_add(offset) as u32; - Ok(CpuPipelineAction::Flush) + self.flush_pipeline(); + Ok(()) } fn exec_thumb_branch_long_with_link( @@ -400,12 +401,13 @@ impl Core { self.pc = (self.gpr[REG_LR] as i32).wrapping_add(off) as u32; self.gpr[REG_LR] = next_pc; - Ok(CpuPipelineAction::Flush) + self.flush_pipeline(); + Ok(()) } else { off = (off << 21) >> 9; self.gpr[REG_LR] = (self.pc as i32).wrapping_add(off) as u32; - Ok(CpuPipelineAction::IncPC) + Ok(()) } } diff --git a/src/arm7tdmi/thumb/mod.rs b/src/arm7tdmi/thumb/mod.rs index 043b295..d52bf6f 100644 --- a/src/arm7tdmi/thumb/mod.rs +++ b/src/arm7tdmi/thumb/mod.rs @@ -355,17 +355,11 @@ impl ThumbInstruction { /// All instructions constants were generated using an ARM assembler. mod tests { use super::*; - use crate::arm7tdmi::{ - cpu::{Core, CpuPipelineAction}, - Bus, - }; + use crate::arm7tdmi::{Core, Bus}; use crate::sysbus::BoxedMemory; #[test] fn mov_low_reg() { - use crate::arm7tdmi::cpu::{Core, CpuPipelineAction}; - use crate::sysbus::BoxedMemory; - let bytes = vec![]; let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); let mut core = Core::new(); @@ -375,10 +369,7 @@ mod tests { let insn = ThumbInstruction::decode(0x2027, 0).unwrap(); assert_eq!(format!("{}", insn), "mov\tr0, #0x27"); - assert_eq!( - core.exec_thumb(&mut mem, insn), - Ok(CpuPipelineAction::IncPC) - ); + core.exec_thumb(&mut mem, insn).unwrap(); assert_eq!(core.get_reg(0), 0x27); } @@ -395,7 +386,7 @@ mod tests { #[rustfmt::skip] let bytes = vec![ - /* 0: */ 0x00, 0x00, + /* 0: */ 0x00, 0x00, /* 2: */ 0x00, 0x00, /* 4: */ 0x00, 0x00, /* 6: */ 0x00, 0x00, @@ -407,10 +398,7 @@ mod tests { core.set_reg(0, 0); assert_eq!(format!("{}", insn), "ldr\tr0, [pc, #0x4] ; = #0xc"); - assert_eq!( - core.exec_thumb(&mut mem, insn), - Ok(CpuPipelineAction::IncPC) - ); + core.exec_thumb(&mut mem, insn).unwrap(); assert_eq!(core.get_reg(0), 0x12345678); } @@ -439,15 +427,9 @@ mod tests { assert_eq!(format!("{}", str_insn), "str\tr0, [r4, r1]"); assert_eq!(format!("{}", ldr_insn), "ldrb\tr2, [r4, r1]"); - assert_eq!( - core.exec_thumb(&mut mem, str_insn), - Ok(CpuPipelineAction::IncPC) - ); + core.exec_thumb(&mut mem, str_insn).unwrap(); assert_eq!(mem.read_32(0x10), 0x12345678); - assert_eq!( - core.exec_thumb(&mut mem, ldr_insn), - Ok(CpuPipelineAction::IncPC) - ); + core.exec_thumb(&mut mem, ldr_insn).unwrap(); assert_eq!(core.get_reg(2), 0x78); } diff --git a/src/gba.rs b/src/gba.rs index 1952c51..e5fcbaf 100644 --- a/src/gba.rs +++ b/src/gba.rs @@ -3,9 +3,9 @@ use super::arm7tdmi::{exception::*, Core, DecodedInstruction}; use super::cartridge::Cartridge; use super::dma::DmaChannel; +use super::gpu::*; use super::interrupt::*; use super::ioregs::consts::*; -use super::gpu::*; use super::sysbus::SysBus; use super::{EmuIoDev, GBAError, GBAResult}; diff --git a/src/lib.rs b/src/lib.rs index b948611..ab58e7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,10 +15,10 @@ extern crate ansi_term; extern crate colored; // not needed in Rust 2018 pub mod arm7tdmi; -pub mod gpu; pub mod cartridge; pub mod debugger; pub mod disass; +pub mod gpu; pub mod sysbus; pub use sysbus::SysBus; pub mod interrupt;