Implement thumb format 6 (PC-Relative Load) and test it.
Former-commit-id: ae161edb0c8968913d2ef72a14053c118c6f7692
This commit is contained in:
parent
58e1230e7a
commit
eaf972de93
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue