Partially Impl Arm LDM_STM (give me a break)

Manually testing seems to work, too lazy to write any tests now,
Will do it after all instructions are complete, buggy or not.


Former-commit-id: 0f36c81d6451c706408dd3c4815bfb3abea1ff44
This commit is contained in:
Michel Heily 2019-07-05 18:38:20 +03:00
parent 4da863da9b
commit 600bebc9d2
5 changed files with 79 additions and 9 deletions

View file

@ -254,7 +254,15 @@ impl ArmInstruction {
for reg in register_list {
write!(f, ", {}", reg_string(reg))?;
}
write!(f, "}}")
write!(
f,
"}}{}",
if self.psr_and_force_user_flag() {
"^"
} else {
""
}
)
}
/// MRS - transfer PSR contents to a register

View file

@ -21,6 +21,7 @@ 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::LDM_STM => self.exec_ldm_stm(bus, insn),
ArmFormat::MSR_REG => self.exec_msr_reg(bus, insn),
_ => Err(CpuError::UnimplementedCpuInstruction(
insn.pc,
@ -115,7 +116,7 @@ impl Core {
ArmShiftType::ROR => {
let amount = amount % 32;
let result = val.rotate_right(amount);
self.cpsr.set_C((result >> 1) &1 == 1);
self.cpsr.set_C((result >> 1) & 1 == 1);
result
}
}
@ -322,4 +323,69 @@ impl Core {
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();
let psr_user = insn.psr_and_force_user_flag();
let is_load = insn.load_flag();
let mut writeback = insn.write_back_flag();
let mut pipeline_action = CpuPipelineAction::IncPC;
let rn = insn.rn();
let mut addr = self.gpr[rn] as i32;
let step: i32 = if ascending { 4 } else { -4 };
let rlist = if ascending {
insn.register_list()
} else {
let mut rlist = insn.register_list();
rlist.reverse();
rlist
};
if psr_user {
unimplemented!("Too tired to implement the mode enforcement");
}
if is_load {
if rlist.contains(&rn) {
writeback = false;
}
for r in rlist {
if full {
addr = addr.wrapping_add(step);
}
self.add_cycle();
let val = self.load_32(addr as Addr, bus);
self.set_reg(r, val);
if r == REG_PC {
pipeline_action = CpuPipelineAction::Flush;
}
if !full {
addr = addr.wrapping_add(step);
}
}
} else {
for r in rlist {
if full {
addr = addr.wrapping_add(step);
}
self.store_32(addr as Addr, self.get_reg(r), bus);
if !full {
addr = addr.wrapping_add(step);
}
}
}
if writeback {
self.set_reg(rn, addr as u32);
}
Ok(pipeline_action)
}
}

View file

@ -342,7 +342,7 @@ impl ArmInstruction {
}
}
pub fn is_loading_psr_and_forcing_user_mode(&self) -> bool {
pub fn psr_and_force_user_flag(&self) -> bool {
self.raw.bit(22)
}

View file

@ -269,11 +269,7 @@ impl Core {
}
}
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;
self.pc = (self.pc as i32).wrapping_add(offset) as u32;
Ok(CpuPipelineAction::Flush)

View file

@ -188,7 +188,7 @@ impl From<OpFormat5> for ArmOpCode {
OpFormat5::ADD => ArmOpCode::ADD,
OpFormat5::CMP => ArmOpCode::CMP,
OpFormat5::MOV => ArmOpCode::MOV,
OpFormat5::BX => panic!("this should not be called if op = BX")
OpFormat5::BX => panic!("this should not be called if op = BX"),
}
}
}