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
This commit is contained in:
Michel Heily 2019-07-20 14:44:49 +03:00
parent 1f074e20ad
commit 7119ba2451
8 changed files with 171 additions and 241 deletions

View file

@ -2,7 +2,7 @@ use crate::bit::BitIndex;
use crate::arm7tdmi::alu::*; use crate::arm7tdmi::alu::*;
use crate::arm7tdmi::bus::Bus; 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::exception::Exception;
use crate::arm7tdmi::psr::RegPSR; use crate::arm7tdmi::psr::RegPSR;
use crate::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, DecodedInstruction, REG_PC}; use crate::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, DecodedInstruction, REG_PC};
@ -12,7 +12,7 @@ use super::*;
impl Core { impl Core {
pub fn exec_arm(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { pub fn exec_arm(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
if !self.check_arm_cond(insn.cond) { if !self.check_arm_cond(insn.cond) {
return Ok(CpuPipelineAction::IncPC); return Ok(());
} }
match insn.fmt { match insn.fmt {
ArmFormat::BX => self.exec_bx(bus, insn), 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.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 { pub fn branch_exchange(&mut self, mut addr: Addr) -> CpuExecResult {
@ -57,8 +58,9 @@ impl Core {
} }
self.pc = addr; self.pc = addr;
self.flush_pipeline();
Ok(CpuPipelineAction::Flush) Ok(())
} }
/// Cycles 2S+1N /// Cycles 2S+1N
@ -68,7 +70,8 @@ impl Core {
fn exec_swi(&mut self, _bus: &mut Bus, _insn: ArmInstruction) -> CpuExecResult { fn exec_swi(&mut self, _bus: &mut Bus, _insn: ArmInstruction) -> CpuExecResult {
self.exception(Exception::SoftwareInterrupt); self.exception(Exception::SoftwareInterrupt);
Ok(CpuPipelineAction::Flush) self.flush_pipeline();
Ok(())
} }
fn exec_mrs(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_mrs(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
@ -83,7 +86,7 @@ impl Core {
self.cpsr.get() self.cpsr.get()
}; };
self.set_reg(insn.rd(), result); self.set_reg(insn.rd(), result);
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_msr_reg(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_msr_reg(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
@ -105,7 +108,7 @@ impl Core {
} }
self.cpsr = new_psr; self.cpsr = new_psr;
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_msr_flags(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_msr_flags(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
@ -122,7 +125,7 @@ impl Core {
} else { } else {
self.cpsr.set_flag_bits(op); self.cpsr.set_flag_bits(op);
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn decode_operand2(&mut self, op2: BarrelShifterValue, set_flags: bool) -> CpuResult<u32> { fn decode_operand2(&mut self, op2: BarrelShifterValue, set_flags: bool) -> CpuResult<u32> {
@ -155,7 +158,6 @@ impl Core {
fn exec_data_processing(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_data_processing(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
// TODO handle carry flag // TODO handle carry flag
let mut pipeline_action = CpuPipelineAction::IncPC;
let op1 = if insn.rn() == REG_PC { let op1 = if insn.rn() == REG_PC {
self.pc as i32 // prefething self.pc as i32 // prefething
@ -186,11 +188,11 @@ impl Core {
if let Some(result) = self.alu(opcode, op1, op2, set_flags) { if let Some(result) = self.alu(opcode, op1, op2, set_flags) {
self.set_reg(rd, result as u32); self.set_reg(rd, result as u32);
if rd == REG_PC { if rd == REG_PC {
pipeline_action = CpuPipelineAction::Flush; self.flush_pipeline();
} }
} }
Ok(pipeline_action) Ok(())
} }
/// Memory Load/Store /// Memory Load/Store
@ -206,7 +208,6 @@ impl Core {
if writeback && insn.rd() == insn.rn() { if writeback && insn.rd() == insn.rn() {
return Err(CpuError::IllegalInstruction); return Err(CpuError::IllegalInstruction);
} }
let mut pipeline_action = CpuPipelineAction::IncPC;
let mut addr = self.get_reg(insn.rn()); let mut addr = self.get_reg(insn.rn());
if insn.rn() == REG_PC { if insn.rn() == REG_PC {
@ -236,7 +237,7 @@ impl Core {
self.add_cycle(); self.add_cycle();
if insn.rd() == REG_PC { if insn.rd() == REG_PC {
pipeline_action = CpuPipelineAction::Flush; self.flush_pipeline();
} }
} else { } else {
let value = if insn.rd() == REG_PC { let value = if insn.rd() == REG_PC {
@ -255,7 +256,7 @@ impl Core {
self.set_reg(insn.rn(), effective_addr as u32) 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 { fn exec_ldr_str_hs(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
@ -264,7 +265,6 @@ impl Core {
return Err(CpuError::IllegalInstruction); return Err(CpuError::IllegalInstruction);
} }
let mut pipeline_action = CpuPipelineAction::IncPC;
let mut addr = self.get_reg(insn.rn()); let mut addr = self.get_reg(insn.rn());
if insn.rn() == REG_PC { if insn.rn() == REG_PC {
@ -296,7 +296,7 @@ impl Core {
self.add_cycle(); self.add_cycle();
if insn.rd() == REG_PC { if insn.rd() == REG_PC {
pipeline_action = CpuPipelineAction::Flush; self.flush_pipeline();
} }
} else { } else {
let value = if insn.rd() == REG_PC { let value = if insn.rd() == REG_PC {
@ -317,7 +317,7 @@ impl Core {
self.set_reg(insn.rn(), effective_addr as u32) 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 { 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 psr_user = insn.psr_and_force_user_flag();
let is_load = insn.load_flag(); let is_load = insn.load_flag();
let mut writeback = insn.write_back_flag(); let mut writeback = insn.write_back_flag();
let mut pipeline_action = CpuPipelineAction::IncPC;
let rn = insn.rn(); let rn = insn.rn();
let mut addr = self.gpr[rn] as i32; let mut addr = self.gpr[rn] as i32;
@ -357,7 +356,7 @@ impl Core {
self.set_reg(r, val); self.set_reg(r, val);
if r == REG_PC { if r == REG_PC {
pipeline_action = CpuPipelineAction::Flush; self.flush_pipeline();
} }
if !full { if !full {
@ -387,7 +386,7 @@ impl Core {
self.set_reg(rn, addr as u32); self.set_reg(rn, addr as u32);
} }
Ok(pipeline_action) Ok(())
} }
fn exec_mul_mla(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_mul_mla(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
@ -422,7 +421,7 @@ impl Core {
self.cpsr.set_Z(result == 0); self.cpsr.set_Z(result == 0);
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_mull_mlal(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_mull_mlal(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
@ -465,6 +464,6 @@ impl Core {
self.cpsr.set_Z(result == 0); self.cpsr.set_Z(result == 0);
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
} }

View file

@ -374,10 +374,8 @@ mod tests {
assert_eq!(decoded.swi_comment(), 0x1337); assert_eq!(decoded.swi_comment(), 0x1337);
assert_eq!(format!("{}", decoded), "swi\t#0x1337"); assert_eq!(format!("{}", decoded), "swi\t#0x1337");
assert_eq!( core.exec_arm(&mut mem, decoded).unwrap();
core.exec_arm(&mut mem, decoded), assert_eq!(core.did_pipeline_flush(), true);
Ok(CpuPipelineAction::Flush)
);
assert_eq!(core.cpsr.mode(), CpuMode::Supervisor); assert_eq!(core.cpsr.mode(), CpuMode::Supervisor);
assert_eq!(core.pc, Exception::SoftwareInterrupt as u32); assert_eq!(core.pc, Exception::SoftwareInterrupt as u32);
@ -401,10 +399,8 @@ mod tests {
let bytes = vec![]; let bytes = vec![];
let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); let mut mem = BoxedMemory::new(bytes.into_boxed_slice());
assert_eq!( core.exec_arm(&mut mem, decoded).unwrap();
core.exec_arm(&mut mem, decoded), assert_eq!(core.did_pipeline_flush(), true);
Ok(CpuPipelineAction::Flush)
);
assert_eq!(core.pc, 0x30); assert_eq!(core.pc, 0x30);
} }
@ -426,10 +422,8 @@ mod tests {
let bytes = vec![]; let bytes = vec![];
let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); let mut mem = BoxedMemory::new(bytes.into_boxed_slice());
assert_eq!( core.exec_arm(&mut mem, decoded).unwrap();
core.exec_arm(&mut mem, decoded), assert_eq!(core.did_pipeline_flush(), true);
Ok(CpuPipelineAction::Flush)
);
assert_eq!(core.pc, 0x10); assert_eq!(core.pc, 0x10);
} }
@ -470,10 +464,7 @@ mod tests {
]; ];
let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); let mut mem = BoxedMemory::new(bytes.into_boxed_slice());
assert_eq!( core.exec_arm(&mut mem, decoded).unwrap();
core.exec_arm(&mut mem, decoded),
Ok(CpuPipelineAction::IncPC)
);
assert_eq!(core.gpr[2], 0x1337); assert_eq!(core.gpr[2], 0x1337);
} }
@ -514,10 +505,7 @@ mod tests {
]; ];
let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); let mut mem = BoxedMemory::new(bytes.into_boxed_slice());
assert_eq!( core.exec_arm(&mut mem, decoded).unwrap();
core.exec_arm(&mut mem, decoded),
Ok(CpuPipelineAction::IncPC)
);
assert_eq!(mem.read_32(0), 0xabababab); assert_eq!(mem.read_32(0), 0xabababab);
} }
@ -543,10 +531,7 @@ mod tests {
let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); let mut mem = BoxedMemory::new(bytes.into_boxed_slice());
assert_ne!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678); assert_ne!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678);
assert_eq!( core.exec_arm(&mut mem, decoded).unwrap();
core.exec_arm(&mut mem, decoded),
Ok(CpuPipelineAction::IncPC)
);
assert_eq!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678); assert_eq!(mem.read_32(core.get_reg(REG_SP) + 0x10), 0x12345678);
} }
} }

View file

@ -13,49 +13,16 @@ use super::{
Addr, CpuMode, CpuResult, CpuState, DecodedInstruction, InstructionDecoder, Addr, CpuMode, CpuResult, CpuState, DecodedInstruction, InstructionDecoder,
}; };
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub struct PipelineContext<D, N> enum PipelineState {
where Refill1,
D: InstructionDecoder, Refill2,
N: Num, Execute,
{
fetched: Option<(Addr, N)>,
decoded: Option<D>,
} }
impl<D, N> Default for PipelineContext<D, N> impl Default for PipelineState {
where fn default() -> PipelineState {
D: InstructionDecoder, PipelineState::Refill1
N: Num,
{
fn default() -> PipelineContext<D, N> {
PipelineContext {
fetched: None,
decoded: None,
}
}
}
impl<D, N> PipelineContext<D, N>
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()
} }
} }
@ -73,8 +40,13 @@ pub struct Core {
pub cpsr: RegPSR, pub cpsr: RegPSR,
pub spsr: [RegPSR; 5], pub spsr: [RegPSR; 5],
pub pipeline_arm: PipelineContext<ArmInstruction, u32>, pipeline_state: PipelineState,
pub pipeline_thumb: PipelineContext<ThumbInstruction, u16>, fetched_arm: u32,
decoded_arm: u32,
fetched_thumb: u16,
decoded_thumb: u16,
last_executed: Option<DecodedInstruction>,
pub cycles: usize, pub cycles: usize,
// store the gpr before executing an instruction to show diff in the Display impl // store the gpr before executing an instruction to show diff in the Display impl
@ -85,13 +57,7 @@ pub struct Core {
pub verbose: bool, pub verbose: bool,
} }
#[derive(Debug, PartialEq)] pub type CpuExecResult = CpuResult<()>;
pub enum CpuPipelineAction {
IncPC,
Flush,
}
pub type CpuExecResult = CpuResult<CpuPipelineAction>;
impl Core { impl Core {
pub fn new() -> Core { pub fn new() -> Core {
@ -274,119 +240,110 @@ impl Core {
} }
} }
fn step_thumb( fn step_arm_exec(&mut self, insn: u32, sb: &mut Bus) -> CpuResult<()> {
&mut self, let pc = self.pc;
bus: &mut Bus, match self.pipeline_state {
) -> CpuResult<(Option<DecodedInstruction>, CpuPipelineAction)> { PipelineState::Refill1 => {
// fetch self.pc = pc.wrapping_add(4);
// let new_fetched = bus.read_16(self.pc); self.pipeline_state = PipelineState::Refill2;
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)
} }
None => None, PipelineState::Refill2 => {
}; self.pc = pc.wrapping_add(4);
self.pipeline_state = PipelineState::Execute;
// exec }
let result = match self.pipeline_thumb.decoded { PipelineState::Execute => {
Some(d) => { let insn = ArmInstruction::decode(insn, self.pc.wrapping_sub(8))?;
self.gpr_previous = self.get_registers(); self.gpr_previous = self.get_registers();
let action = self.exec_thumb(bus, d)?; self.exec_arm(sb, insn)?;
Ok((Some(DecodedInstruction::Thumb(d)), action)) 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);
} }
Ok(())
result
} }
fn step_arm( fn arm(&mut self, sb: &mut Bus) -> CpuResult<()> {
&mut self, let pc = self.pc;
bus: &mut Bus,
) -> CpuResult<(Option<DecodedInstruction>, CpuPipelineAction)> { // fetch
// let new_fetched = bus.read_32(self.pc); let fetched_now = self.load_32(pc, sb);
let new_fetched = self.load_32(self.pc, bus); let executed_now = self.decoded_arm;
// decode // decode
let new_decoded = match self.pipeline_arm.fetched { self.decoded_arm = self.fetched_arm;
Some((addr, i)) => { self.fetched_arm = fetched_now;
let insn = ArmInstruction::decode(i, addr)?;
Some(insn)
}
None => None,
};
// exec // execute
let result = match self.pipeline_arm.decoded { self.step_arm_exec(executed_now, sb)?;
Some(d) => { 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(); self.gpr_previous = self.get_registers();
let action = self.exec_arm(bus, d)?; self.exec_thumb(sb, insn)?;
Ok((Some(DecodedInstruction::Arm(d)), action)) 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 /// Perform a pipeline step
/// If an instruction was executed in this step, return it. /// If an instruction was executed in this step, return it.
pub fn step(&mut self, bus: &mut Bus) -> CpuResult<Option<DecodedInstruction>> { pub fn step(&mut self, bus: &mut Bus) -> CpuResult<()> {
let (executed_instruction, pipeline_action) = match self.cpsr.state() { match self.cpsr.state() {
CpuState::ARM => self.step_arm(bus), CpuState::ARM => self.arm(bus),
CpuState::THUMB => self.step_thumb(bus), CpuState::THUMB => self.thumb(bus),
}?;
match pipeline_action {
CpuPipelineAction::IncPC => self.advance_pc(),
CpuPipelineAction::Flush => {
self.pipeline_arm.flush();
self.pipeline_thumb.flush();
}
} }
Ok(executed_instruction)
} }
/// Get's the address of the next instruction that is going to be executed /// Get's the address of the next instruction that is going to be executed
pub fn get_next_pc(&self) -> Addr { pub fn get_next_pc(&self) -> Addr {
match self.cpsr.state() { let insn_size = self.word_size() as u32;
CpuState::ARM => { match self.pipeline_state {
if self.pipeline_arm.is_flushed() { PipelineState::Refill1 => self.pc,
self.pc as Addr PipelineState::Refill2 => self.pc - insn_size,
} else if self.pipeline_arm.is_only_fetched() { PipelineState::Execute => self.pc - 2 * insn_size,
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!()
}
}
} }
} }
@ -395,8 +352,14 @@ impl Core {
/// and the address of the next instruction to be executed; /// and the address of the next instruction to be executed;
pub fn step_one(&mut self, bus: &mut Bus) -> CpuResult<DecodedInstruction> { pub fn step_one(&mut self, bus: &mut Bus) -> CpuResult<DecodedInstruction> {
loop { loop {
if let Some(i) = self.step(bus)? { match self.pipeline_state {
return Ok(i); PipelineState::Execute => {
self.step(bus)?;
return Ok(self.last_executed.unwrap());
}
_ => {
self.step(bus)?;
}
} }
} }
} }

View file

@ -49,7 +49,6 @@ impl Core {
// Set PC to vector address // Set PC to vector address
self.pc = vector; self.pc = vector;
self.pipeline_arm.flush(); self.flush_pipeline();
self.pipeline_thumb.flush();
} }
} }

View file

@ -1,5 +1,5 @@
use crate::arm7tdmi::bus::Bus; use crate::arm7tdmi::bus::Bus;
use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction}; use crate::arm7tdmi::cpu::{Core, CpuExecResult};
use crate::arm7tdmi::*; use crate::arm7tdmi::*;
use super::*; use super::*;
@ -35,7 +35,7 @@ impl Core {
self.set_reg(rd, result as u32); self.set_reg(rd, result as u32);
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_thumb_add_sub(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { 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); self.set_reg(insn.rd(), result as u32);
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_thumb_data_process_imm( fn exec_thumb_data_process_imm(
@ -72,7 +72,7 @@ impl Core {
self.set_reg(insn.rd(), result as u32); self.set_reg(insn.rd(), result as u32);
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_thumb_mul(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_mul(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult {
@ -83,7 +83,7 @@ impl Core {
self.add_cycle(); self.add_cycle();
} }
self.gpr[insn.rd()] = op1.wrapping_mul(op2) as u32; 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 { 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); self.set_reg(rd, result as u32);
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
/// Cycles 2S+1N /// Cycles 2S+1N
@ -141,10 +141,10 @@ impl Core {
if let Some(result) = result { if let Some(result) = result {
self.set_reg(dst_reg, result as u32); self.set_reg(dst_reg, result as u32);
if dst_reg == REG_PC { if dst_reg == REG_PC {
return Ok(CpuPipelineAction::Flush); self.flush_pipeline();
} }
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
} }
@ -156,7 +156,7 @@ impl Core {
// +1I // +1I
self.add_cycle(); self.add_cycle();
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn do_exec_thumb_ldr_str( fn do_exec_thumb_ldr_str(
@ -185,7 +185,7 @@ impl Core {
}; };
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_thumb_ldr_str_reg_offset( fn exec_thumb_ldr_str_reg_offset(
@ -232,7 +232,7 @@ impl Core {
} }
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_thumb_ldr_str_imm_offset( fn exec_thumb_ldr_str_imm_offset(
@ -263,7 +263,7 @@ impl Core {
} else { } else {
self.store_16(addr, self.gpr[insn.rd()] as u16, bus); 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 { 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; self.gpr[insn.rd()] = result;
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn do_exec_thumb_ldr_str_with_addr( fn do_exec_thumb_ldr_str_with_addr(
@ -295,7 +295,7 @@ impl Core {
} else { } else {
self.store_32(addr, self.gpr[insn.rd()], bus); 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 { 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; self.gpr[REG_SP] = result as u32;
} }
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_thumb_push_pop(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { 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). // (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 is_pop = insn.is_load();
let mut pipeline_action = CpuPipelineAction::IncPC;
let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R); let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R);
let rlist = insn.register_list(); let rlist = insn.register_list();
@ -326,7 +325,7 @@ impl Core {
if pc_lr_flag { if pc_lr_flag {
pop(self, bus, REG_PC); pop(self, bus, REG_PC);
self.pc = self.pc & !1; self.pc = self.pc & !1;
pipeline_action = CpuPipelineAction::Flush; self.flush_pipeline();
} }
self.add_cycle(); self.add_cycle();
} else { } else {
@ -338,7 +337,7 @@ impl Core {
} }
} }
Ok(pipeline_action) Ok(())
} }
fn exec_thumb_ldm_stm(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { 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; self.gpr[rb] = addr as u32;
Ok(CpuPipelineAction::IncPC) Ok(())
} }
fn exec_thumb_branch_with_cond( fn exec_thumb_branch_with_cond(
@ -374,18 +373,20 @@ impl Core {
insn: ThumbInstruction, insn: ThumbInstruction,
) -> CpuExecResult { ) -> CpuExecResult {
if !self.check_arm_cond(insn.cond()) { if !self.check_arm_cond(insn.cond()) {
Ok(CpuPipelineAction::IncPC) Ok(())
} else { } else {
let offset = ((insn.offset8() as i8) << 1) as i32; let offset = ((insn.offset8() as i8) << 1) as i32;
self.pc = (self.pc as i32).wrapping_add(offset) as u32; 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 { fn exec_thumb_branch(&mut self, _bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult {
let offset = ((insn.offset11() << 21) >> 20) as i32; let offset = ((insn.offset11() << 21) >> 20) as i32;
self.pc = (self.pc as i32).wrapping_add(offset) as u32; 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( 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.pc = (self.gpr[REG_LR] as i32).wrapping_add(off) as u32;
self.gpr[REG_LR] = next_pc; self.gpr[REG_LR] = next_pc;
Ok(CpuPipelineAction::Flush) self.flush_pipeline();
Ok(())
} else { } else {
off = (off << 21) >> 9; off = (off << 21) >> 9;
self.gpr[REG_LR] = (self.pc as i32).wrapping_add(off) as u32; self.gpr[REG_LR] = (self.pc as i32).wrapping_add(off) as u32;
Ok(CpuPipelineAction::IncPC) Ok(())
} }
} }

View file

@ -355,17 +355,11 @@ impl ThumbInstruction {
/// All instructions constants were generated using an ARM assembler. /// All instructions constants were generated using an ARM assembler.
mod tests { mod tests {
use super::*; use super::*;
use crate::arm7tdmi::{ use crate::arm7tdmi::{Core, Bus};
cpu::{Core, CpuPipelineAction},
Bus,
};
use crate::sysbus::BoxedMemory; use crate::sysbus::BoxedMemory;
#[test] #[test]
fn mov_low_reg() { fn mov_low_reg() {
use crate::arm7tdmi::cpu::{Core, CpuPipelineAction};
use crate::sysbus::BoxedMemory;
let bytes = vec![]; let bytes = vec![];
let mut mem = BoxedMemory::new(bytes.into_boxed_slice()); let mut mem = BoxedMemory::new(bytes.into_boxed_slice());
let mut core = Core::new(); let mut core = Core::new();
@ -375,10 +369,7 @@ mod tests {
let insn = ThumbInstruction::decode(0x2027, 0).unwrap(); let insn = ThumbInstruction::decode(0x2027, 0).unwrap();
assert_eq!(format!("{}", insn), "mov\tr0, #0x27"); assert_eq!(format!("{}", insn), "mov\tr0, #0x27");
assert_eq!( core.exec_thumb(&mut mem, insn).unwrap();
core.exec_thumb(&mut mem, insn),
Ok(CpuPipelineAction::IncPC)
);
assert_eq!(core.get_reg(0), 0x27); assert_eq!(core.get_reg(0), 0x27);
} }
@ -395,7 +386,7 @@ mod tests {
#[rustfmt::skip] #[rustfmt::skip]
let bytes = vec![ let bytes = vec![
/* 0: */ 0x00, 0x00, /* 0: */ 0x00, 0x00,
/* 2: */ 0x00, 0x00, /* 2: */ 0x00, 0x00,
/* 4: */ 0x00, 0x00, /* 4: */ 0x00, 0x00,
/* 6: <pc> */ 0x00, 0x00, /* 6: <pc> */ 0x00, 0x00,
@ -407,10 +398,7 @@ mod tests {
core.set_reg(0, 0); core.set_reg(0, 0);
assert_eq!(format!("{}", insn), "ldr\tr0, [pc, #0x4] ; = #0xc"); assert_eq!(format!("{}", insn), "ldr\tr0, [pc, #0x4] ; = #0xc");
assert_eq!( core.exec_thumb(&mut mem, insn).unwrap();
core.exec_thumb(&mut mem, insn),
Ok(CpuPipelineAction::IncPC)
);
assert_eq!(core.get_reg(0), 0x12345678); 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!("{}", str_insn), "str\tr0, [r4, r1]");
assert_eq!(format!("{}", ldr_insn), "ldrb\tr2, [r4, r1]"); assert_eq!(format!("{}", ldr_insn), "ldrb\tr2, [r4, r1]");
assert_eq!( core.exec_thumb(&mut mem, str_insn).unwrap();
core.exec_thumb(&mut mem, str_insn),
Ok(CpuPipelineAction::IncPC)
);
assert_eq!(mem.read_32(0x10), 0x12345678); assert_eq!(mem.read_32(0x10), 0x12345678);
assert_eq!( core.exec_thumb(&mut mem, ldr_insn).unwrap();
core.exec_thumb(&mut mem, ldr_insn),
Ok(CpuPipelineAction::IncPC)
);
assert_eq!(core.get_reg(2), 0x78); assert_eq!(core.get_reg(2), 0x78);
} }

View file

@ -3,9 +3,9 @@
use super::arm7tdmi::{exception::*, Core, DecodedInstruction}; use super::arm7tdmi::{exception::*, Core, DecodedInstruction};
use super::cartridge::Cartridge; use super::cartridge::Cartridge;
use super::dma::DmaChannel; use super::dma::DmaChannel;
use super::gpu::*;
use super::interrupt::*; use super::interrupt::*;
use super::ioregs::consts::*; use super::ioregs::consts::*;
use super::gpu::*;
use super::sysbus::SysBus; use super::sysbus::SysBus;
use super::{EmuIoDev, GBAError, GBAResult}; use super::{EmuIoDev, GBAError, GBAResult};

View file

@ -15,10 +15,10 @@ extern crate ansi_term;
extern crate colored; // not needed in Rust 2018 extern crate colored; // not needed in Rust 2018
pub mod arm7tdmi; pub mod arm7tdmi;
pub mod gpu;
pub mod cartridge; pub mod cartridge;
pub mod debugger; pub mod debugger;
pub mod disass; pub mod disass;
pub mod gpu;
pub mod sysbus; pub mod sysbus;
pub use sysbus::SysBus; pub use sysbus::SysBus;
pub mod interrupt; pub mod interrupt;