arm: Impl LDR_STR_HS
Former-commit-id: 2baa0f2fb8cf855cb4626fbb1937e17f4e7d3035
This commit is contained in:
parent
45f3bd6264
commit
d36da30618
|
@ -6,9 +6,7 @@ use crate::arm7tdmi::exception::Exception;
|
|||
use crate::arm7tdmi::psr::RegPSR;
|
||||
use crate::arm7tdmi::{Addr, CpuError, CpuResult, CpuState, DecodedInstruction, REG_PC};
|
||||
|
||||
use super::{
|
||||
ArmFormat, ArmInstruction, ArmOpCode, ArmRegisterShift, ArmShiftType, ArmShiftedValue,
|
||||
};
|
||||
use super::*;
|
||||
|
||||
impl Core {
|
||||
pub fn exec_arm(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
|
||||
|
@ -21,6 +19,8 @@ impl Core {
|
|||
ArmFormat::DP => self.exec_data_processing(bus, insn),
|
||||
ArmFormat::SWI => self.exec_swi(bus, insn),
|
||||
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::MSR_REG => self.exec_msr_reg(bus, insn),
|
||||
_ => Err(CpuError::UnimplementedCpuInstruction(
|
||||
|
@ -241,9 +241,9 @@ impl Core {
|
|||
Ok(pipeline_action)
|
||||
}
|
||||
|
||||
fn get_rn_offset(&mut self, insn: &ArmInstruction) -> i32 {
|
||||
fn get_rn_offset(&mut self, sval: ArmShiftedValue) -> i32 {
|
||||
// TODO decide if error handling or panic here
|
||||
match insn.ldr_str_offset().unwrap() {
|
||||
match sval {
|
||||
ArmShiftedValue::ImmediateValue(offset) => offset,
|
||||
ArmShiftedValue::ShiftedRegister {
|
||||
reg,
|
||||
|
@ -284,7 +284,7 @@ impl Core {
|
|||
addr = insn.pc + 8; // prefetching
|
||||
}
|
||||
|
||||
let offset = self.get_rn_offset(&insn);
|
||||
let offset = self.get_rn_offset(insn.ldr_str_offset().unwrap());
|
||||
|
||||
let effective_addr = (addr as i32).wrapping_add(offset) as Addr;
|
||||
addr = if insn.pre_index_flag() {
|
||||
|
@ -328,6 +328,70 @@ impl Core {
|
|||
Ok(pipeline_action)
|
||||
}
|
||||
|
||||
fn exec_ldr_str_hs(
|
||||
&mut self,
|
||||
bus: &mut Bus,
|
||||
insn: ArmInstruction,
|
||||
) -> CpuResult<CpuPipelineAction> {
|
||||
if insn.write_back_flag() && 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 {
|
||||
addr = insn.pc + 8; // prefetching
|
||||
}
|
||||
|
||||
let offset = self.get_rn_offset(insn.ldr_str_hs_offset().unwrap());
|
||||
|
||||
let effective_addr = (addr as i32).wrapping_add(offset) as Addr;
|
||||
addr = if insn.pre_index_flag() {
|
||||
effective_addr
|
||||
} else {
|
||||
addr
|
||||
};
|
||||
|
||||
if insn.load_flag() {
|
||||
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.load_16(addr, bus) as u16 as i16 as u32
|
||||
}
|
||||
ArmHalfwordTransferType::UnsignedHalfwords => self.load_16(addr, bus) as u16 as u32,
|
||||
};
|
||||
|
||||
self.set_reg(insn.rd(), data);
|
||||
|
||||
// +1I
|
||||
self.add_cycle();
|
||||
|
||||
if insn.rd() == REG_PC {
|
||||
pipeline_action = CpuPipelineAction::Flush;
|
||||
}
|
||||
} else {
|
||||
let value = if insn.rd() == REG_PC {
|
||||
insn.pc + 12
|
||||
} else {
|
||||
self.get_reg(insn.rd())
|
||||
};
|
||||
|
||||
match insn.halfword_data_transfer_type().unwrap() {
|
||||
ArmHalfwordTransferType::UnsignedHalfwords => {
|
||||
self.store_16(addr, value as u16, bus)
|
||||
}
|
||||
_ => panic!("invalid HS flags for L=0")
|
||||
};
|
||||
}
|
||||
|
||||
if insn.write_back_flag() {
|
||||
self.set_reg(insn.rn(), effective_addr as u32)
|
||||
}
|
||||
|
||||
Ok(pipeline_action)
|
||||
}
|
||||
|
||||
fn exec_ldm_stm(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
|
||||
let full = insn.pre_index_flag();
|
||||
let ascending = insn.add_offset_flag();
|
||||
|
|
Reference in a new issue