Implement thumb format 6 (PC-Relative Load) and test it.

Former-commit-id: ae161edb0c8968913d2ef72a14053c118c6f7692
This commit is contained in:
Michel Heily 2019-07-03 02:15:16 +03:00
parent 58e1230e7a
commit eaf972de93
4 changed files with 64 additions and 15 deletions

View file

@ -65,11 +65,7 @@ impl Core {
} }
/// Cycles 2S+1N /// Cycles 2S+1N
fn exec_bx( fn exec_bx(&mut self, sysbus: &mut Bus, insn: ArmInstruction) -> CpuResult<CpuPipelineAction> {
&mut self,
sysbus: &mut Bus,
insn: ArmInstruction,
) -> CpuResult<CpuPipelineAction> {
let rn = self.get_reg(insn.rn()); let rn = self.get_reg(insn.rn());
if rn.bit(0) { if rn.bit(0) {
self.cpsr.set_state(CpuState::THUMB); self.cpsr.set_state(CpuState::THUMB);
@ -162,7 +158,13 @@ impl Core {
res res
} }
pub fn alu(&mut self, opcode: ArmOpCode, op1: i32, op2: i32, set_cond_flags: bool) -> Option<i32> { pub fn alu(
&mut self,
opcode: ArmOpCode,
op1: i32,
op2: i32,
set_cond_flags: bool,
) -> Option<i32> {
let C = self.cpsr.C() as i32; let C = self.cpsr.C() as i32;
let mut carry = self.cpsr.C(); let mut carry = self.cpsr.C();
@ -314,11 +316,11 @@ impl Core {
if insn.load_flag() { if insn.load_flag() {
let data = if insn.transfer_size() == 1 { let data = if insn.transfer_size() == 1 {
// +1N // +1N
self.add_cycles(dest, sysbus, NonSeq + MemoryAccess8); self.add_cycles(addr, sysbus, NonSeq + MemoryAccess8);
sysbus.read_8(addr) as u32 sysbus.read_8(addr) as u32
} else { } else {
// +1N // +1N
self.add_cycles(dest, sysbus, NonSeq + MemoryAccess32); self.add_cycles(addr, sysbus, NonSeq + MemoryAccess32);
sysbus.read_32(addr) sysbus.read_32(addr)
}; };
// +1S // +1S

View file

@ -58,7 +58,7 @@ impl ThumbInstruction {
"ldr\t{Rd}, [pc, #{Imm:#x}] ; = #{effective:#x}", "ldr\t{Rd}, [pc, #{Imm:#x}] ; = #{effective:#x}",
Rd = reg_string(self.rd()), Rd = reg_string(self.rd()),
Imm = self.word8(), Imm = self.word8(),
effective = self.pc + 2 + (self.word8() as Addr) effective = (self.pc + 4 & !0b10) + (self.word8() as Addr)
) )
} }

View file

@ -1,14 +1,14 @@
use crate::arm7tdmi::arm::exec::*; use crate::arm7tdmi::arm::*;
use crate::arm7tdmi::arm::ArmOpCode;
use crate::arm7tdmi::bus::{Bus, MemoryAccessType::*, MemoryAccessWidth::*}; use crate::arm7tdmi::bus::{Bus, MemoryAccessType::*, MemoryAccessWidth::*};
use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction}; use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction};
use crate::arm7tdmi::{Addr, REG_PC};
use super::{ThumbFormat, ThumbInstruction}; use super::{ThumbFormat, ThumbInstruction};
impl Core { impl Core {
fn exec_thumb_data_process_imm( fn exec_thumb_data_process_imm(
&mut self, &mut self,
sysbus: &mut Bus, bus: &mut Bus,
insn: ThumbInstruction, insn: ThumbInstruction,
) -> CpuExecResult { ) -> CpuExecResult {
let arm_alu_op: ArmOpCode = insn.format3_op().into(); let arm_alu_op: ArmOpCode = insn.format3_op().into();
@ -21,15 +21,34 @@ impl Core {
// +1S // +1S
self.add_cycles( self.add_cycles(
self.pc + (self.word_size() as u32), self.pc + (self.word_size() as u32),
sysbus, bus,
Seq + MemoryAccess32, Seq + MemoryAccess32,
); );
Ok(CpuPipelineAction::IncPC) Ok(CpuPipelineAction::IncPC)
} }
pub fn exec_thumb(&mut self, sysbus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_ldr_pc(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult {
let addr = (insn.pc & !0b10) + 4 + (insn.word8() as Addr);
let data = bus.read_32(addr);
// +1N
self.add_cycles(addr, bus, NonSeq + MemoryAccess32);
// +1S
self.add_cycles(
self.pc + (self.word_size() as u32),
bus,
Seq + MemoryAccess32,
);
self.set_reg(insn.rd(), data);
// +1I
self.add_cycle();
Ok(CpuPipelineAction::IncPC)
}
pub fn exec_thumb(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult {
match insn.fmt { match insn.fmt {
ThumbFormat::DataProcessImm => self.exec_thumb_data_process_imm(sysbus, insn), ThumbFormat::DataProcessImm => self.exec_thumb_data_process_imm(bus, insn),
ThumbFormat::LdrPc => self.exec_thumb_ldr_pc(bus, insn),
_ => unimplemented!("thumb not implemented {:#}", insn), _ => unimplemented!("thumb not implemented {:#}", insn),
} }
} }

View file

@ -293,4 +293,32 @@ mod tests {
); );
assert_eq!(core.get_reg(0), 0x27); assert_eq!(core.get_reg(0), 0x27);
} }
#[test]
fn ldr_pc() {
use crate::arm7tdmi::cpu::{Core, CpuPipelineAction};
use crate::sysbus::BoxedMemory;
// ldr r0, [pc, #4]
let insn = ThumbInstruction::decode(0x4801, 0x6).unwrap();
let bytes = vec![
/* 0: */ 0x00, 0x00,
/* 2: */ 0x00, 0x00,
/* 4: */ 0x00, 0x00,
/* 6: <pc> */ 0x00, 0x00,
/* 8: */ 0x00, 0x00, 0x00, 0x00,
/* c: */ 0x78, 0x56, 0x34, 0x12,
];
let mut mem = BoxedMemory::new(bytes.into_boxed_slice());
let mut core = Core::new();
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)
);
assert_eq!(core.get_reg(0), 0x12345678);
}
} }