diff --git a/src/bin/main.rs b/src/bin/main.rs index 6599576..ea34086 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -38,7 +38,6 @@ fn run_emulator(matches: &ArgMatches) -> GBAResult<()> { println!("loaded rom: {:#?}", gamepak.header); let mut core = Core::new(); - core.reset(); if skip_bios { core.gpr[13] = 0x0300_7f00; core.gpr_banked_r13[0] = 0x0300_7f00; // USR/SYS diff --git a/src/core/arm7tdmi/alu.rs b/src/core/arm7tdmi/alu.rs index 1723ad4..1276e55 100644 --- a/src/core/arm7tdmi/alu.rs +++ b/src/core/arm7tdmi/alu.rs @@ -240,6 +240,7 @@ impl Core { Ok(result) } ShiftRegisterBy::ByRegister(rs) => { + self.add_cycle(); // +1I if shift.reg == REG_PC { val = val + 4; // PC prefetching } diff --git a/src/core/arm7tdmi/arm/exec.rs b/src/core/arm7tdmi/arm/exec.rs index 540cade..4c101b0 100644 --- a/src/core/arm7tdmi/arm/exec.rs +++ b/src/core/arm7tdmi/arm/exec.rs @@ -4,25 +4,27 @@ use super::super::alu::*; use crate::core::arm7tdmi::bus::Bus; use crate::core::arm7tdmi::cpu::{Core, CpuExecResult}; use crate::core::arm7tdmi::psr::RegPSR; -use crate::core::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, REG_PC}; +use crate::core::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, REG_LR, REG_PC}; +use crate::core::sysbus::SysBus; use super::*; impl Core { - pub fn exec_arm(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + pub fn exec_arm(&mut self, bus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { if !self.check_arm_cond(insn.cond) { + self.S_cycle32(bus, self.pc); return Ok(()); } match insn.fmt { ArmFormat::BX => self.exec_bx(bus, insn), ArmFormat::B_BL => self.exec_b_bl(bus, insn), ArmFormat::DP => self.exec_data_processing(bus, insn), - ArmFormat::SWI => self.exec_swi(), + ArmFormat::SWI => self.exec_swi(bus), ArmFormat::LDR_STR => self.exec_ldr_str(bus, insn), ArmFormat::LDR_STR_HS_IMM => self.exec_ldr_str_hs(bus, insn), ArmFormat::LDR_STR_HS_REG => self.exec_ldr_str_hs(bus, insn), ArmFormat::LDM_STM => self.exec_ldm_stm(bus, insn), - ArmFormat::MRS => self.exec_mrs(insn), + ArmFormat::MRS => self.exec_mrs(bus, insn), ArmFormat::MSR_REG => self.exec_msr_reg(bus, insn), ArmFormat::MSR_FLAGS => self.exec_msr_flags(bus, insn), ArmFormat::MUL_MLA => self.exec_mul_mla(bus, insn), @@ -32,18 +34,23 @@ impl Core { } /// Cycles 2S+1N - fn exec_b_bl(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_b_bl(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + self.S_cycle32(sb, self.pc); if insn.link_flag() { - self.set_reg(14, (insn.pc + (self.word_size() as u32)) & !0b1); + self.set_reg(REG_LR, (insn.pc + (self.word_size() as u32)) & !0b1); } self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32 & !1; - self.flush_pipeline(); + self.flush_pipeline(sb); Ok(()) } - pub fn branch_exchange(&mut self, mut addr: Addr) -> CpuExecResult { + pub fn branch_exchange(&mut self, sb: &mut SysBus, mut addr: Addr) -> CpuExecResult { + match self.cpsr.state() { + CpuState::ARM => self.S_cycle32(sb, self.pc), + CpuState::THUMB => self.S_cycle16(sb, self.pc), + } if addr.bit(0) { addr = addr & !0x1; self.cpsr.set_state(CpuState::THUMB); @@ -53,17 +60,17 @@ impl Core { } self.pc = addr; - self.flush_pipeline(); + self.flush_pipeline(sb); // +1S+1N Ok(()) } /// Cycles 2S+1N - fn exec_bx(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { - self.branch_exchange(self.get_reg(insn.rn())) + fn exec_bx(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + self.branch_exchange(sb, self.get_reg(insn.rn())) } - fn exec_mrs(&mut self, insn: ArmInstruction) -> CpuExecResult { + fn exec_mrs(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { let mode = self.cpsr.mode(); let result = if insn.spsr_flag() { if let Some(index) = mode.spsr_index() { @@ -75,14 +82,15 @@ impl Core { self.cpsr.get() }; self.set_reg(insn.rd(), result); + self.S_cycle32(sb, self.pc); Ok(()) } - fn exec_msr_reg(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { - self.exec_msr(insn, self.get_reg(insn.rm())) + fn exec_msr_reg(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + self.exec_msr(sb, insn, self.get_reg(insn.rm())) } - fn exec_msr(&mut self, insn: ArmInstruction, value: u32) -> CpuExecResult { + fn exec_msr(&mut self, sb: &mut SysBus, insn: ArmInstruction, value: u32) -> CpuExecResult { let new_psr = RegPSR::new(value); let old_mode = self.cpsr.mode(); if insn.spsr_flag() { @@ -97,10 +105,12 @@ impl Core { } self.cpsr = new_psr; } + self.S_cycle32(sb, self.pc); Ok(()) } - fn exec_msr_flags(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_msr_flags(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + self.S_cycle32(sb, self.pc); let op = insn.operand2()?; let op = self.decode_operand2(op, false)?; @@ -124,8 +134,6 @@ impl Core { Ok(result) } BarrelShifterValue::ShiftedRegister(x) => { - // +1I - self.add_cycle(); let result = self.register_shift(x)?; if set_flags { self.cpsr.set_C(self.bs_carry_out); @@ -151,7 +159,8 @@ impl Core { /// /// Cycles: 1S+x+y (from GBATEK) /// Add x=1I cycles if Op2 shifted-by-register. Add y=1S+1N cycles if Rd=R15. - fn exec_data_processing(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_data_processing(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { + self.S_cycle32(sb, self.pc); let op1 = if insn.rn() == REG_PC { self.pc as i32 } else { @@ -167,9 +176,9 @@ impl Core { if !s_flag { match opcode { AluOpCode::TEQ | AluOpCode::CMN => { - return self.exec_msr(insn, op2 as u32); + return self.exec_msr(sb, insn, op2 as u32); } - AluOpCode::TST | AluOpCode::CMP => return self.exec_mrs(insn), + AluOpCode::TST | AluOpCode::CMP => return self.exec_mrs(sb, insn), _ => (), } } @@ -185,7 +194,7 @@ impl Core { if let Some(result) = alu_res { if rd == REG_PC { self.transfer_spsr_mode(); - self.flush_pipeline(); + self.flush_pipeline(sb); } self.set_reg(rd, result as u32); } @@ -200,16 +209,13 @@ impl Core { /// STR{cond}{B}{T} Rd,
| 2N | ---- | [Rn+/-]=Rd /// ------------------------------------------------------------------------------ /// For LDR, add y=1S+1N if Rd=R15. - fn exec_ldr_str(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_ldr_str(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { let mut writeback = insn.write_back_flag(); - let mut addr = self.get_reg(insn.rn()); if insn.rn() == REG_PC { addr = insn.pc + 8; // prefetching } - let offset = self.get_barrel_shifted_value(insn.ldr_str_offset()); - let effective_addr = (addr as i32).wrapping_add(offset) as Addr; addr = if insn.pre_index_flag() { effective_addr @@ -220,12 +226,14 @@ impl Core { if writeback && insn.rd() == insn.rn() { writeback = false; } - if insn.load_flag() { + self.S_cycle32(sb, self.pc); let data = if insn.transfer_size() == 1 { - self.load_8(addr, bus) as u32 + self.N_cycle8(sb, addr); + sb.read_8(addr) as u32 } else { - self.ldr_word(addr, bus) + self.N_cycle32(sb, addr); + self.ldr_word(addr, sb) }; self.set_reg(insn.rd(), data); @@ -234,7 +242,7 @@ impl Core { self.add_cycle(); if insn.rd() == REG_PC { - self.flush_pipeline(); + self.flush_pipeline(sb); } } else { let value = if insn.rd() == REG_PC { @@ -243,10 +251,13 @@ impl Core { self.get_reg(insn.rd()) }; if insn.transfer_size() == 1 { - self.store_8(addr, value as u8, bus); + self.N_cycle8(sb, addr); + sb.write_8(addr, value as u8); } else { - self.store_32(addr & !0x3, value, bus); + self.N_cycle32(sb, addr); + sb.write_32(addr & !0x3, value); }; + self.N_cycle32(sb, self.pc); } if writeback { @@ -256,7 +267,7 @@ impl Core { Ok(()) } - fn exec_ldr_str_hs(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_ldr_str_hs(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { let mut writeback = insn.write_back_flag(); let mut addr = self.get_reg(insn.rn()); @@ -277,10 +288,20 @@ impl Core { writeback = false; } if insn.load_flag() { + self.S_cycle32(sb, self.pc); let data = match insn.halfword_data_transfer_type().unwrap() { - ArmHalfwordTransferType::SignedByte => self.load_8(addr, bus) as u8 as i8 as u32, - ArmHalfwordTransferType::SignedHalfwords => self.ldr_sign_half(addr, bus), - ArmHalfwordTransferType::UnsignedHalfwords => self.ldr_half(addr, bus), + ArmHalfwordTransferType::SignedByte => { + self.N_cycle8(sb, addr); + sb.read_8(addr) as u8 as i8 as u32 + } + ArmHalfwordTransferType::SignedHalfwords => { + self.N_cycle16(sb, addr); + self.ldr_sign_half(addr, sb) + } + ArmHalfwordTransferType::UnsignedHalfwords => { + self.N_cycle16(sb, addr); + self.ldr_half(addr, sb) + } }; self.set_reg(insn.rd(), data); @@ -289,7 +310,7 @@ impl Core { self.add_cycle(); if insn.rd() == REG_PC { - self.flush_pipeline(); + self.flush_pipeline(sb); } } else { let value = if insn.rd() == REG_PC { @@ -300,7 +321,9 @@ impl Core { match insn.halfword_data_transfer_type().unwrap() { ArmHalfwordTransferType::UnsignedHalfwords => { - self.store_16(addr, value as u16, bus) + self.N_cycle32(sb, addr); + sb.write_16(addr, value as u16); + self.N_cycle32(sb, self.pc); } _ => panic!("invalid HS flags for L=0"), }; @@ -313,7 +336,7 @@ impl Core { Ok(()) } - fn exec_ldm_stm(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_ldm_stm(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { let full = insn.pre_index_flag(); let ascending = insn.add_offset_flag(); let psr_user_flag = insn.psr_and_force_user_flag(); @@ -347,6 +370,8 @@ impl Core { let psr_transfer = psr_user_flag & is_load & rlist.bit(REG_PC); if is_load { + self.add_cycle(); + self.N_cycle32(sb, self.pc); for r in 0..16 { let r = if ascending { r } else { 15 - r }; if rlist.bit(r) { @@ -357,8 +382,8 @@ impl Core { addr = addr.wrapping_add(step); } - self.add_cycle(); - let val = self.load_32(addr as Addr, bus); + let val = sb.read_32(addr as Addr); + self.S_cycle32(sb, self.pc); if user_bank_transfer { self.set_reg_user(r, val); } else { @@ -369,7 +394,7 @@ impl Core { if psr_transfer { self.transfer_spsr_mode(); } - self.flush_pipeline(); + self.flush_pipeline(sb); } if !full { @@ -378,6 +403,7 @@ impl Core { } } } else { + let mut first = true; for r in 0..16 { let r = if ascending { r } else { 15 - r }; if rlist.bit(r) { @@ -394,13 +420,20 @@ impl Core { self.get_reg(r) } }; - self.store_32(addr as Addr, val, bus); + if first { + self.N_cycle32(sb, addr as u32); + first = false; + } else { + self.S_cycle32(sb, addr as u32); + } + sb.write_32(addr as Addr, val); if !full { addr = addr.wrapping_add(step); } } } + self.N_cycle32(sb, self.pc); } if writeback { @@ -410,7 +443,7 @@ impl Core { Ok(()) } - fn exec_mul_mla(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_mul_mla(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { let (rd, rn, rs, rm) = (insn.rd(), insn.rn(), insn.rs(), insn.rm()); // check validity @@ -444,10 +477,11 @@ impl Core { self.cpsr.set_V(false); } + self.S_cycle32(sb, self.pc); Ok(()) } - fn exec_mull_mlal(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_mull_mlal(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { let (rd_hi, rd_lo, rn, rs, rm) = (insn.rd_hi(), insn.rd_lo(), insn.rn(), insn.rs(), insn.rm()); @@ -491,21 +525,27 @@ impl Core { self.cpsr.set_V(false); } + self.S_cycle32(sb, self.pc); Ok(()) } - fn exec_arm_swp(&mut self, sb: &mut Bus, insn: ArmInstruction) -> CpuExecResult { + fn exec_arm_swp(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { let base_addr = self.get_reg(insn.rn()); + self.add_cycle(); if insn.transfer_size() == 1 { - let t = self.load_8(base_addr, sb); - self.store_8(base_addr, self.get_reg(insn.rm()) as u8, sb); + let t = sb.read_8(base_addr); + self.N_cycle8(sb, base_addr); + sb.write_8(base_addr, self.get_reg(insn.rm()) as u8); + self.S_cycle8(sb, base_addr); self.set_reg(insn.rd(), t as u32); } else { - let t = self.load_32(base_addr, sb); - self.store_32(base_addr, self.get_reg(insn.rm()), sb); + let t = sb.read_32(base_addr); + self.N_cycle32(sb, base_addr); + sb.write_32(base_addr, self.get_reg(insn.rm())); + self.S_cycle32(sb, base_addr); self.set_reg(insn.rd(), t as u32); } - + self.N_cycle32(sb, self.pc); Ok(()) } } diff --git a/src/core/arm7tdmi/cpu.rs b/src/core/arm7tdmi/cpu.rs index 4d3cfdb..7f8072b 100644 --- a/src/core/arm7tdmi/cpu.rs +++ b/src/core/arm7tdmi/cpu.rs @@ -4,12 +4,12 @@ use ansi_term::{Colour, Style}; pub use super::exception::Exception; use super::{ - arm::*, - bus::{Bus, MemoryAccess, MemoryAccessType, MemoryAccessType::*, MemoryAccessWidth::*}, - psr::RegPSR, - reg_string, - thumb::ThumbInstruction, - Addr, CpuMode, CpuResult, CpuState, DecodedInstruction, InstructionDecoder, + arm::*, bus::Bus, psr::RegPSR, reg_string, thumb::ThumbInstruction, Addr, CpuMode, CpuResult, + CpuState, DecodedInstruction, InstructionDecoder, +}; + +use super::super::sysbus::{ + MemoryAccess, MemoryAccessType, MemoryAccessType::*, MemoryAccessWidth::*, SysBus, }; #[derive(Debug, PartialEq)] @@ -125,33 +125,33 @@ impl Core { } /// Helper function for "ldr" instruction that handles misaligned addresses - pub fn ldr_word(&mut self, addr: Addr, bus: &Bus) -> u32 { + pub fn ldr_word(&mut self, addr: Addr, bus: &SysBus) -> u32 { if addr & 0x3 != 0 { let rotation = (addr & 0x3) << 3; - let value = self.load_32(addr & !0x3, bus); + let value = bus.read_32(addr & !0x3); self.ror(value, rotation, self.cpsr.C(), false, false) } else { - self.load_32(addr, bus) + bus.read_32(addr) } } /// Helper function for "ldrh" instruction that handles misaligned addresses - pub fn ldr_half(&mut self, addr: Addr, bus: &Bus) -> u32 { + pub fn ldr_half(&mut self, addr: Addr, bus: &SysBus) -> u32 { if addr & 0x1 != 0 { let rotation = (addr & 0x1) << 3; - let value = self.load_16(addr & !0x1, bus); + let value = bus.read_16(addr & !0x1); self.ror(value as u32, rotation, self.cpsr.C(), false, false) } else { - self.load_16(addr, bus) as u32 + bus.read_16(addr) as u32 } } /// Helper function for "ldrsh" instruction that handles misaligned addresses - pub fn ldr_sign_half(&mut self, addr: Addr, bus: &Bus) -> u32 { + pub fn ldr_sign_half(&mut self, addr: Addr, bus: &SysBus) -> u32 { if addr & 0x1 != 0 { - self.load_8(addr, bus) as i8 as i32 as u32 + bus.read_8(addr) as i8 as i32 as u32 } else { - self.load_16(addr, bus) as i16 as i32 as u32 + bus.read_16(addr) as i16 as i32 as u32 } } @@ -194,8 +194,8 @@ impl Core { } /// Resets the cpu - pub fn reset(&mut self) { - self.exception(Exception::Reset); + pub fn reset(&mut self, sb: &mut SysBus) { + self.exception(sb, Exception::Reset); } pub fn word_size(&self) -> usize { @@ -214,9 +214,10 @@ impl Core { self.cycles += 1; } - pub fn add_cycles(&mut self, addr: Addr, bus: &Bus, access: MemoryAccess) { - // println!(" total: {}", addr, access, self.cycles); - self.cycles += bus.get_cycles(addr, access); + pub fn add_cycles(&mut self, addr: Addr, bus: &SysBus, access: MemoryAccess) { + let cycles_to_add = 1 + bus.get_cycles(addr, access); + // println!(" took: {}", addr, access, cycles_to_add); + self.cycles += cycles_to_add; } pub fn cycle_type(&self, addr: Addr) -> MemoryAccessType { @@ -239,45 +240,40 @@ impl Core { } } - pub fn load_32(&mut self, addr: Addr, bus: &Bus) -> u32 { - self.add_cycles(addr, bus, self.cycle_type(addr) + MemoryAccess32); - self.memreq = addr; - bus.read_32(addr) + #[allow(non_snake_case)] + pub fn S_cycle32(&mut self, sb: &SysBus, addr: u32) { + self.cycles += 1; + self.cycles += sb.get_cycles(addr, Seq + MemoryAccess32); } - pub fn load_16(&mut self, addr: Addr, bus: &Bus) -> u16 { - let cycle_type = self.cycle_type(addr); - self.add_cycles(addr, bus, cycle_type + MemoryAccess16); - self.memreq = addr; - bus.read_16(addr) + #[allow(non_snake_case)] + pub fn S_cycle16(&mut self, sb: &SysBus, addr: u32) { + self.cycles += 1; + self.cycles += sb.get_cycles(addr, Seq + MemoryAccess16); } - pub fn load_8(&mut self, addr: Addr, bus: &Bus) -> u8 { - let cycle_type = self.cycle_type(addr); - self.add_cycles(addr, bus, cycle_type + MemoryAccess8); - self.memreq = addr; - bus.read_8(addr) + #[allow(non_snake_case)] + pub fn S_cycle8(&mut self, sb: &SysBus, addr: u32) { + self.cycles += 1; + self.cycles += sb.get_cycles(addr, Seq + MemoryAccess8); } - pub fn store_32(&mut self, addr: Addr, value: u32, bus: &mut Bus) { - let cycle_type = self.cycle_type(addr); - self.add_cycles(addr, bus, cycle_type + MemoryAccess32); - self.memreq = addr; - bus.write_32(addr, value); + #[allow(non_snake_case)] + pub fn N_cycle32(&mut self, sb: &SysBus, addr: u32) { + self.cycles += 1; + self.cycles += sb.get_cycles(addr, NonSeq + MemoryAccess32); } - pub fn store_16(&mut self, addr: Addr, value: u16, bus: &mut Bus) { - let cycle_type = self.cycle_type(addr); - self.add_cycles(addr, bus, cycle_type + MemoryAccess16); - self.memreq = addr; - bus.write_16(addr, value); + #[allow(non_snake_case)] + pub fn N_cycle16(&mut self, sb: &SysBus, addr: u32) { + self.cycles += 1; + self.cycles += sb.get_cycles(addr, NonSeq + MemoryAccess16); } - pub fn store_8(&mut self, addr: Addr, value: u8, bus: &mut Bus) { - let cycle_type = self.cycle_type(addr); - self.add_cycles(addr, bus, cycle_type + MemoryAccess8); - self.memreq = addr; - bus.write_8(addr, value); + #[allow(non_snake_case)] + pub fn N_cycle8(&mut self, sb: &SysBus, addr: u32) { + self.cycles += 1; + self.cycles += sb.get_cycles(addr, NonSeq + MemoryAccess8); } pub fn check_arm_cond(&self, cond: ArmCond) -> bool { @@ -301,13 +297,16 @@ impl Core { } } - pub fn exec_swi(&mut self) -> CpuExecResult { - self.exception(Exception::SoftwareInterrupt); - self.flush_pipeline(); + pub fn exec_swi(&mut self, sb: &mut SysBus) -> CpuExecResult { + match self.cpsr.state() { + CpuState::ARM => self.N_cycle32(sb, self.pc), + CpuState::THUMB => self.N_cycle16(sb, self.pc), + }; + self.exception(sb, Exception::SoftwareInterrupt); Ok(()) } - fn step_arm_exec(&mut self, insn: u32, sb: &mut Bus) -> CpuResult<()> { + fn step_arm_exec(&mut self, insn: u32, sb: &mut SysBus) -> CpuResult<()> { let pc = self.pc; match self.pipeline_state { PipelineState::Refill1 => { @@ -331,11 +330,11 @@ impl Core { Ok(()) } - fn arm(&mut self, sb: &mut Bus) -> CpuResult<()> { + fn arm(&mut self, sb: &mut SysBus) -> CpuResult<()> { let pc = self.pc; // fetch - let fetched_now = self.load_32(pc, sb); + let fetched_now = sb.read_32(pc); let executed_now = self.decoded_arm; // decode @@ -351,7 +350,7 @@ impl Core { self.pipeline_state == PipelineState::Refill1 } - fn step_thumb_exec(&mut self, insn: u16, sb: &mut Bus) -> CpuResult<()> { + fn step_thumb_exec(&mut self, insn: u16, sb: &mut SysBus) -> CpuResult<()> { let pc = self.pc; match self.pipeline_state { PipelineState::Refill1 => { @@ -375,11 +374,11 @@ impl Core { Ok(()) } - fn thumb(&mut self, sb: &mut Bus) -> CpuResult<()> { + fn thumb(&mut self, sb: &mut SysBus) -> CpuResult<()> { let pc = self.pc; // fetch - let fetched_now = self.load_16(pc, sb); + let fetched_now = sb.read_16(pc); let executed_now = self.decoded_thumb; // decode @@ -391,13 +390,23 @@ impl Core { Ok(()) } - pub fn flush_pipeline(&mut self) { + pub fn flush_pipeline(&mut self, sb: &mut SysBus) { self.pipeline_state = PipelineState::Refill1; + match self.cpsr.state() { + CpuState::ARM => { + self.N_cycle32(sb, self.pc); + self.S_cycle32(sb, self.pc + 4); + } + CpuState::THUMB => { + self.N_cycle16(sb, self.pc); + self.S_cycle16(sb, self.pc + 2); + } + } } /// Perform a pipeline step /// If an instruction was executed in this step, return it. - pub fn step(&mut self, bus: &mut Bus) -> CpuResult<()> { + pub fn step(&mut self, bus: &mut SysBus) -> CpuResult<()> { match self.cpsr.state() { CpuState::ARM => self.arm(bus), CpuState::THUMB => self.thumb(bus), @@ -417,7 +426,7 @@ impl Core { /// 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_one(&mut self, bus: &mut Bus) -> CpuResult { + pub fn step_one(&mut self, bus: &mut SysBus) -> CpuResult { loop { match self.pipeline_state { PipelineState::Execute => { diff --git a/src/core/arm7tdmi/exception.rs b/src/core/arm7tdmi/exception.rs index aedfc25..9ee9a39 100644 --- a/src/core/arm7tdmi/exception.rs +++ b/src/core/arm7tdmi/exception.rs @@ -1,5 +1,7 @@ +use super::super::sysbus::SysBus; +use super::cpu::Core; use super::REG_LR; -use super::{cpu::Core, CpuMode, CpuState}; +use super::{CpuMode, CpuState}; use colored::*; #[derive(Debug, Clone, Copy, PartialEq)] @@ -31,7 +33,7 @@ impl From for CpuMode { } impl Core { - pub fn exception(&mut self, e: Exception) { + pub fn exception(&mut self, sb: &mut SysBus, e: Exception) { let vector = e as u32; let new_mode = CpuMode::from(e); if self.verbose { @@ -58,6 +60,6 @@ impl Core { // Set PC to vector address self.pc = vector; - self.flush_pipeline(); + self.flush_pipeline(sb); } } diff --git a/src/core/arm7tdmi/thumb/exec.rs b/src/core/arm7tdmi/thumb/exec.rs index 896df06..5e77ff7 100644 --- a/src/core/arm7tdmi/thumb/exec.rs +++ b/src/core/arm7tdmi/thumb/exec.rs @@ -1,16 +1,17 @@ use crate::core::arm7tdmi::bus::Bus; use crate::core::arm7tdmi::cpu::{Core, CpuExecResult}; use crate::core::arm7tdmi::*; +use crate::core::sysbus::SysBus; use super::*; -fn push(cpu: &mut Core, bus: &mut Bus, r: usize) { +fn push(cpu: &mut Core, bus: &mut SysBus, r: usize) { cpu.gpr[REG_SP] -= 4; let stack_addr = cpu.gpr[REG_SP]; - cpu.store_32(stack_addr, cpu.get_reg(r), bus) + bus.write_32(stack_addr, cpu.get_reg(r)) } -fn pop(cpu: &mut Core, bus: &mut Bus, r: usize) { +fn pop(cpu: &mut Core, bus: &mut SysBus, r: usize) { let stack_addr = cpu.gpr[REG_SP]; - let val = cpu.load_32(stack_addr, bus); + let val = bus.read_32(stack_addr); cpu.set_reg(r, val); cpu.gpr[REG_SP] = stack_addr + 4; } @@ -18,7 +19,7 @@ fn pop(cpu: &mut Core, bus: &mut Bus, r: usize) { impl Core { fn exec_thumb_move_shifted_reg( &mut self, - _bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, ) -> CpuExecResult { let op2 = self @@ -37,11 +38,11 @@ impl Core { if let Some(result) = result { self.set_reg(rd, result as u32); } - + self.S_cycle16(sb, self.pc + 2); Ok(()) } - fn exec_thumb_add_sub(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_add_sub(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let op1 = self.get_reg(insn.rs()) as i32; let op2 = if insn.is_immediate_operand() { insn.rn() as u32 as i32 @@ -58,13 +59,13 @@ impl Core { if let Some(result) = result { self.set_reg(insn.rd(), result as u32); } - + self.S_cycle16(sb, self.pc + 2); Ok(()) } fn exec_thumb_data_process_imm( &mut self, - _bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, ) -> CpuExecResult { let arm_alu_op: AluOpCode = insn.format3_op().into(); @@ -74,11 +75,11 @@ impl Core { if let Some(result) = result { self.set_reg(insn.rd(), result as u32); } - + self.S_cycle16(sb, self.pc + 2); Ok(()) } - fn exec_thumb_mul(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_mul(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let op1 = self.get_reg(insn.rd()) as i32; let op2 = self.get_reg(insn.rs()) as i32; let m = self.get_required_multipiler_array_cycles(op2); @@ -89,10 +90,11 @@ impl Core { self.cpsr.set_N((result as i32) < 0); self.cpsr.set_Z(result == 0); self.gpr[insn.rd()] = result; + self.S_cycle16(sb, self.pc + 2); Ok(()) } - fn exec_thumb_alu_ops(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_alu_ops(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let rd = insn.rd(); let (arm_alu_op, shft) = insn.alu_opcode(); @@ -107,27 +109,27 @@ impl Core { if let Some(result) = result { self.set_reg(rd, result as u32); } - + self.S_cycle16(sb, self.pc + 2); Ok(()) } /// Cycles 2S+1N - fn exec_thumb_bx(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_bx(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let src_reg = if insn.flag(ThumbInstruction::FLAG_H2) { insn.rs() + 8 } else { insn.rs() }; - self.branch_exchange(self.get_reg(src_reg)) + self.branch_exchange(sb, self.get_reg(src_reg)) } fn exec_thumb_hi_reg_op_or_bx( &mut self, - bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, ) -> CpuExecResult { if OpFormat5::BX == insn.format5_op() { - self.exec_thumb_bx(bus, insn) + self.exec_thumb_bx(sb, insn) } else { let dst_reg = if insn.flag(ThumbInstruction::FLAG_H1) { insn.rd() + 8 @@ -151,16 +153,19 @@ impl Core { if let Some(result) = alu_res { self.set_reg(dst_reg, result as u32); if dst_reg == REG_PC { - self.flush_pipeline(); + self.flush_pipeline(sb); } } + self.S_cycle16(sb, self.pc + 2); Ok(()) } } - fn exec_thumb_ldr_pc(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_ldr_pc(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let addr = (insn.pc & !0b10) + 4 + (insn.word8() as Addr); - let data = self.load_32(addr, bus); + self.S_cycle16(sb, self.pc + 2); + let data = sb.read_32(addr); + self.N_cycle16(sb, addr); self.set_reg(insn.rd(), data); // +1I @@ -171,15 +176,17 @@ impl Core { fn do_exec_thumb_ldr_str( &mut self, - bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, addr: Addr, ) -> CpuExecResult { if insn.is_load() { let data = if insn.is_transferring_bytes() { - self.load_8(addr, bus) as u32 + self.S_cycle8(sb, addr); + sb.read_8(addr) as u32 } else { - self.ldr_word(addr, bus) + self.S_cycle32(sb, addr); + self.ldr_word(addr, sb) }; self.set_reg(insn.rd(), data); @@ -189,18 +196,21 @@ impl Core { } else { let value = self.get_reg(insn.rd()); if insn.is_transferring_bytes() { - self.store_8(addr, value as u8, bus); + self.N_cycle8(sb, addr); + sb.write_8(addr, value as u8); } else { - self.store_32(addr, value, bus); + self.N_cycle32(sb, addr); + sb.write_32(addr, value); }; } + self.N_cycle16(sb, self.pc + 2); Ok(()) } fn exec_thumb_ldr_str_reg_offset( &mut self, - bus: &mut Bus, + bus: &mut SysBus, insn: ThumbInstruction, ) -> CpuExecResult { let addr = self @@ -209,7 +219,7 @@ impl Core { self.do_exec_thumb_ldr_str(bus, insn, addr) } - fn exec_thumb_ldr_str_shb(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_ldr_str_shb(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let addr = self .get_reg(insn.rb()) .wrapping_add(self.get_reg(insn.ro())); @@ -221,33 +231,41 @@ impl Core { (false, false) => /* strh */ { - self.store_16(addr, self.gpr[rd] as u16, bus) + sb.write_16(addr, self.gpr[rd] as u16); + self.N_cycle16(sb, addr); } (false, true) => /* ldrh */ { - self.gpr[rd] = self.ldr_half(addr, bus) + self.gpr[rd] = self.ldr_half(addr, sb); + self.S_cycle16(sb, addr); + self.add_cycle(); } (true, false) => /* ldsb */ { - let val = self.load_8(addr, bus) as i8 as i32 as u32; + let val = sb.read_8(addr) as i8 as i32 as u32; self.gpr[rd] = val; + self.S_cycle8(sb, addr); + self.add_cycle(); } (true, true) => /* ldsh */ { - let val = self.ldr_sign_half(addr, bus); + let val = self.ldr_sign_half(addr, sb); self.gpr[rd] = val; + self.S_cycle16(sb, addr); + self.add_cycle(); } } + self.N_cycle16(sb, self.pc + 2); Ok(()) } fn exec_thumb_ldr_str_imm_offset( &mut self, - bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, ) -> CpuExecResult { let offset = if insn.is_transferring_bytes() { @@ -256,92 +274,115 @@ impl Core { (insn.offset5() << 3) >> 1 }; let addr = self.get_reg(insn.rb()).wrapping_add(offset as u32); - self.do_exec_thumb_ldr_str(bus, insn, addr) + self.do_exec_thumb_ldr_str(sb, insn, addr) } fn exec_thumb_ldr_str_halfword( &mut self, - bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, ) -> CpuExecResult { let base = self.gpr[insn.rb()] as i32; let addr = base.wrapping_add((insn.offset5() << 1) as i32) as Addr; if insn.is_load() { - let data = self.ldr_half(addr, bus); + let data = self.ldr_half(addr, sb); + self.S_cycle16(sb, addr); self.add_cycle(); self.gpr[insn.rd()] = data as u32; } else { - self.store_16(addr, self.gpr[insn.rd()] as u16, bus); + sb.write_16(addr, self.gpr[insn.rd()] as u16); + self.N_cycle16(sb, addr); } + self.N_cycle16(sb, self.pc + 2); Ok(()) } - fn exec_thumb_ldr_str_sp(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_ldr_str_sp(&mut self, bus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let addr = self.gpr[REG_SP] + (insn.word8() as Addr); self.do_exec_thumb_ldr_str_with_addr(bus, insn, addr) } - fn exec_thumb_load_address(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_load_address( + &mut self, + sb: &mut SysBus, + insn: ThumbInstruction, + ) -> CpuExecResult { let result = if insn.flag(ThumbInstruction::FLAG_SP) { self.gpr[REG_SP] + (insn.word8() as Addr) } else { (insn.pc & !0b10) + 4 + (insn.word8() as Addr) }; self.gpr[insn.rd()] = result; - + self.S_cycle16(sb, self.pc + 2); Ok(()) } fn do_exec_thumb_ldr_str_with_addr( &mut self, - bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, addr: Addr, ) -> CpuExecResult { if insn.is_load() { - let data = self.load_32(addr, bus); + let data = sb.read_32(addr); + self.S_cycle16(sb, addr); self.add_cycle(); self.gpr[insn.rd()] = data; } else { - self.store_32(addr, self.gpr[insn.rd()], bus); + sb.write_32(addr, self.gpr[insn.rd()]); + self.N_cycle16(sb, addr); } + self.N_cycle16(sb, self.pc + 2); Ok(()) } - fn exec_thumb_add_sp(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_add_sp(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let op1 = self.gpr[REG_SP] as i32; let op2 = insn.sword7(); let arm_alu_op = AluOpCode::ADD; self.gpr[REG_SP] = self.alu(arm_alu_op, op1, op2) as u32; - + self.S_cycle16(sb, self.pc + 2); Ok(()) } - fn exec_thumb_push_pop(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_push_pop(&mut self, sb: &mut SysBus, 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 pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R); let rlist = insn.register_list(); + self.N_cycle16(sb, self.pc); + let mut first = true; if is_pop { for r in 0..8 { if rlist.bit(r) { - pop(self, bus, r); + pop(self, sb, r); + if first { + self.add_cycle(); + first = false; + } else { + self.S_cycle16(sb, self.gpr[REG_SP]); + } } } if pc_lr_flag { - pop(self, bus, REG_PC); + pop(self, sb, REG_PC); self.pc = self.pc & !1; - self.flush_pipeline(); + self.flush_pipeline(sb); } - self.add_cycle(); + self.S_cycle16(sb, self.pc + 2); } else { if pc_lr_flag { - push(self, bus, REG_LR); + push(self, sb, REG_LR); } for r in (0..8).rev() { if rlist.bit(r) { - push(self, bus, r); + push(self, sb, r); + if first { + first = false; + } else { + self.S_cycle16(sb, self.gpr[REG_SP]); + } } } } @@ -349,7 +390,7 @@ impl Core { Ok(()) } - fn exec_thumb_ldm_stm(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_ldm_stm(&mut self, sb: &mut SysBus, 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_load = insn.is_load(); @@ -357,19 +398,33 @@ impl Core { let mut addr = self.gpr[rb]; let rlist = insn.register_list(); + self.N_cycle16(sb, self.pc); + let mut first = true; if is_load { for r in 0..8 { if rlist.bit(r) { - let val = self.load_32(addr, bus); + let val = sb.read_32(addr); + if first { + first = false; + self.add_cycle(); + } else { + self.S_cycle16(sb, addr); + } addr += 4; self.add_cycle(); self.set_reg(r, val); } } + self.S_cycle16(sb, self.pc + 2); } else { for r in 0..8 { if rlist.bit(r) { - self.store_32(addr, self.gpr[r], bus); + if first { + first = false; + } else { + self.S_cycle16(sb, addr); + } + sb.write_32(addr, self.gpr[r]); addr += 4; } } @@ -382,49 +437,53 @@ impl Core { fn exec_thumb_branch_with_cond( &mut self, - _bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, ) -> CpuExecResult { if !self.check_arm_cond(insn.cond()) { + self.S_cycle16(sb, self.pc + 2); Ok(()) } else { let offset = insn.bcond_offset(); + self.S_cycle16(sb, self.pc); self.pc = (self.pc as i32).wrapping_add(offset) as u32; - self.flush_pipeline(); + self.flush_pipeline(sb); Ok(()) } } - fn exec_thumb_branch(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + fn exec_thumb_branch(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { let offset = ((insn.offset11() << 21) >> 20) as i32; self.pc = (self.pc as i32).wrapping_add(offset) as u32; - self.flush_pipeline(); + self.S_cycle16(sb, self.pc); + self.flush_pipeline(sb); Ok(()) } fn exec_thumb_branch_long_with_link( &mut self, - _bus: &mut Bus, + sb: &mut SysBus, insn: ThumbInstruction, ) -> CpuExecResult { let mut off = insn.offset11(); if insn.flag(ThumbInstruction::FLAG_LOW_OFFSET) { + self.S_cycle16(sb, self.pc); off = off << 1; let next_pc = (self.pc - 2) | 1; self.pc = ((self.gpr[REG_LR] & !1) as i32).wrapping_add(off) as u32; self.gpr[REG_LR] = next_pc; - self.flush_pipeline(); + self.flush_pipeline(sb); Ok(()) } else { off = (off << 21) >> 9; self.gpr[REG_LR] = (self.pc as i32).wrapping_add(off) as u32; - + self.S_cycle16(sb, self.pc); Ok(()) } } - pub fn exec_thumb(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { + pub fn exec_thumb(&mut self, bus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { match insn.fmt { ThumbFormat::MoveShiftedReg => self.exec_thumb_move_shifted_reg(bus, insn), ThumbFormat::AddSub => self.exec_thumb_add_sub(bus, insn), @@ -443,7 +502,7 @@ impl Core { ThumbFormat::PushPop => self.exec_thumb_push_pop(bus, insn), ThumbFormat::LdmStm => self.exec_thumb_ldm_stm(bus, insn), ThumbFormat::BranchConditional => self.exec_thumb_branch_with_cond(bus, insn), - ThumbFormat::Swi => self.exec_swi(), + ThumbFormat::Swi => self.exec_swi(bus), ThumbFormat::Branch => self.exec_thumb_branch(bus, insn), ThumbFormat::BranchLongWithLink => self.exec_thumb_branch_long_with_link(bus, insn), } diff --git a/src/core/gba.rs b/src/core/gba.rs index 3eefd16..8fd4359 100644 --- a/src/core/gba.rs +++ b/src/core/gba.rs @@ -93,7 +93,7 @@ impl GameBoyAdvance { if !self.cpu.cpsr.irq_disabled() { io.intc.request_irqs(irqs); if io.intc.irq_pending() { - self.cpu.exception(Exception::Irq); + self.cpu.exception(&mut self.sysbus, Exception::Irq); } } } @@ -105,7 +105,7 @@ impl GameBoyAdvance { self.emulate_peripherals(cycles); - if self.io.borrow().gpu.state == GpuState::HBlank { + if self.io.borrow().gpu.state == GpuState::VBlank { self.backend.render(self.io.borrow().gpu.render()); } diff --git a/src/core/gpu.rs b/src/core/gpu.rs index 114c664..51d2e26 100644 --- a/src/core/gpu.rs +++ b/src/core/gpu.rs @@ -350,8 +350,8 @@ impl Gpu { } } BGMode::BGMode2 => { - self.scanline_mode0(2, sb); self.scanline_mode0(3, sb); + self.scanline_mode0(2, sb); } BGMode::BGMode3 => { self.scanline_mode3(2, sb); diff --git a/src/core/ioregs.rs b/src/core/ioregs.rs index a168a3c..dc55b6c 100644 --- a/src/core/ioregs.rs +++ b/src/core/ioregs.rs @@ -3,8 +3,8 @@ use std::rc::Rc; use super::arm7tdmi::{Addr, Bus}; use super::gba::IoDevices; -use super::sysbus::BoxedMemory; use super::keypad; +use super::sysbus::BoxedMemory; pub mod consts { use super::*; @@ -188,9 +188,7 @@ impl Bus for IoRegs { REG_POSTFLG => self.post_boot_flag as u16, REG_HALTCNT => 0, REG_KEYINPUT => self.keyinput as u16, - _ => { - self.mem.read_16(addr) - } + _ => self.mem.read_16(addr), } } diff --git a/src/core/sysbus.rs b/src/core/sysbus.rs index 0ef4358..e96f82c 100644 --- a/src/core/sysbus.rs +++ b/src/core/sysbus.rs @@ -232,39 +232,33 @@ impl SysBus { // TODO handle EWRAM accesses match addr & 0xff000000 { - EWRAM_ADDR => { - match access.1 { - MemoryAccessWidth::MemoryAccess32 => cycles += 6, - _ => cycles += 3 - } - } + EWRAM_ADDR => match access.1 { + MemoryAccessWidth::MemoryAccess32 => cycles += 6, + _ => cycles += 3, + }, OAM_ADDR | VRAM_ADDR | PALRAM_ADDR => { match access.1 { MemoryAccessWidth::MemoryAccess32 => cycles += 2, - _ => cycles += 1 + _ => cycles += 1, } if self.io.borrow().gpu.state == GpuState::HDraw { cycles += 1; } } - GAMEPAK_WS0_ADDR => { - match access.0 { - MemoryAccessType::NonSeq => { - match access.1 { - MemoryAccessWidth::MemoryAccess32 => { - cycles += nonseq_cycles[self.ioregs.waitcnt.ws0_first_access() as usize]; - cycles += seq_cycles[self.ioregs.waitcnt.ws0_second_access() as usize]; - } - _ => { - cycles += nonseq_cycles[self.ioregs.waitcnt.ws0_first_access() as usize]; - } - } - } - MemoryAccessType::Seq => { + GAMEPAK_WS0_ADDR => match access.0 { + MemoryAccessType::NonSeq => match access.1 { + MemoryAccessWidth::MemoryAccess32 => { + cycles += nonseq_cycles[self.ioregs.waitcnt.ws0_first_access() as usize]; + cycles += seq_cycles[self.ioregs.waitcnt.ws0_second_access() as usize]; + } + _ => { + cycles += nonseq_cycles[self.ioregs.waitcnt.ws0_first_access() as usize]; + } + }, + MemoryAccessType::Seq => { + cycles += seq_cycles[self.ioregs.waitcnt.ws0_second_access() as usize]; + if access.1 == MemoryAccessWidth::MemoryAccess32 { cycles += seq_cycles[self.ioregs.waitcnt.ws0_second_access() as usize]; - if access.1 == MemoryAccessWidth::MemoryAccess32 { - cycles += seq_cycles[self.ioregs.waitcnt.ws0_second_access() as usize]; - } } } }, diff --git a/src/debugger/command.rs b/src/debugger/command.rs index 3322900..6cd2ca0 100644 --- a/src/debugger/command.rs +++ b/src/debugger/command.rs @@ -49,61 +49,61 @@ impl Command { DisplayInfo => println!("GPU: {:#?}", debugger.gba.io.borrow().gpu), Step(count) => { for _ in 0..count { - if let Some(bp) = debugger.check_breakpoint() { - println!("hit breakpoint #0x{:08x}!", bp); - debugger.delete_breakpoint(bp); - } else { - match debugger.gba.step() { - Ok(insn) => { - print!( - "{}\t{}", - Colour::Black - .bold() - .italic() - .on(Colour::White) - .paint(format!("Executed at @0x{:08x}:", insn.get_pc(),)), - insn - ); - println!( - "{}", - Colour::Purple.dimmed().italic().paint(format!( - "\t\t/// Next instruction at @0x{:08x}", - debugger.gba.cpu.get_next_pc() - )) - ) - } - Err(GBAError::CpuError(e)) => { - println!("{}: {}", "cpu encountered an error".red(), e); - println!("cpu: {:x?}", debugger.gba.cpu) - } - _ => unreachable!(), + match debugger.gba.step() { + Ok(insn) => { + print!( + "{}\t{}", + Colour::Black + .bold() + .italic() + .on(Colour::White) + .paint(format!("Executed at @0x{:08x}:", insn.get_pc(),)), + insn + ); + println!( + "{}", + Colour::Purple.dimmed().italic().paint(format!( + "\t\t/// Next instruction at @0x{:08x}", + debugger.gba.cpu.get_next_pc() + )) + ) } + Err(GBAError::CpuError(e)) => { + println!("{}: {}", "cpu encountered an error".red(), e); + println!("cpu: {:x?}", debugger.gba.cpu) + } + _ => unreachable!(), } } println!("{}\n", debugger.gba.cpu); } - Continue => loop { - if let Some(bp) = debugger.check_breakpoint() { - println!("hit breakpoint #0x{:08x}!", bp); - debugger.delete_breakpoint(bp); - break; - } - match debugger.gba.step() { - // Ok(insn) => { - // println!( - // "@0x{:08x}:\t{}", - // insn.get_pc(), - // Colour::Yellow.italic().paint(format!("{} ", insn)) - // ); - // } - Err(GBAError::CpuError(e)) => { - println!("{}: {}", "cpu encountered an error".red(), e); - println!("cpu: {:x?}", debugger.gba.cpu); + Continue => { + let start_cycles = debugger.gba.cpu.cycles(); + loop { + if let Some(bp) = debugger.check_breakpoint() { + match debugger.gba.step() { + Err(GBAError::CpuError(e)) => { + println!("{}: {}", "cpu encountered an error".red(), e); + println!("cpu: {:x?}", debugger.gba.cpu); + break; + } + _ => (), + }; + let num_cycles = debugger.gba.cpu.cycles() - start_cycles; + println!("hit breakpoint #0x{:08x} after {} cycles !", bp, num_cycles); break; + } else { + match debugger.gba.step() { + Err(GBAError::CpuError(e)) => { + println!("{}: {}", "cpu encountered an error".red(), e); + println!("cpu: {:x?}", debugger.gba.cpu); + break; + } + _ => (), + }; } - _ => (), - }; - }, + } + } Frame(count) => { use super::time::PreciseTime; let start = PreciseTime::now(); @@ -160,7 +160,7 @@ impl Command { TileView(bg) => create_tile_view(bg, &debugger.gba), Reset => { println!("resetting cpu..."); - debugger.gba.cpu.reset(); + debugger.gba.cpu.reset(&mut debugger.gba.sysbus); println!("cpu is restarted!") } }