arm: Impl MULL_MLAL and fix writeback for post-index memory transfers

Also some minor fixes and formatting


Former-commit-id: 4929b28cbb4eeeed5acfbdcdd19392ffa3bb0f37
This commit is contained in:
Michel Heily 2019-07-11 18:09:47 +03:00
parent 4763f79abf
commit 95f45e55a9
2 changed files with 56 additions and 11 deletions

View file

@ -27,6 +27,7 @@ impl Core {
ArmFormat::MSR_REG => self.exec_msr_reg(bus, insn), ArmFormat::MSR_REG => self.exec_msr_reg(bus, insn),
ArmFormat::MSR_FLAGS => self.exec_msr_flags(bus, insn), ArmFormat::MSR_FLAGS => self.exec_msr_flags(bus, insn),
ArmFormat::MUL_MLA => self.exec_mul_mla(bus, insn), ArmFormat::MUL_MLA => self.exec_mul_mla(bus, insn),
ArmFormat::MULL_MLAL => self.exec_mull_mlal(bus, insn),
_ => Err(CpuError::UnimplementedCpuInstruction( _ => Err(CpuError::UnimplementedCpuInstruction(
insn.pc, insn.pc,
insn.raw, insn.raw,
@ -200,10 +201,11 @@ impl Core {
/// ------------------------------------------------------------------------------ /// ------------------------------------------------------------------------------
/// For LDR, add y=1S+1N if Rd=R15. /// For LDR, add y=1S+1N if Rd=R15.
fn exec_ldr_str(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_ldr_str(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
if insn.write_back_flag() && insn.rd() == insn.rn() { let mut writeback = insn.write_back_flag();
if writeback && insn.rd() == insn.rn() {
return Err(CpuError::IllegalInstruction); return Err(CpuError::IllegalInstruction);
} }
let mut pipeline_action = CpuPipelineAction::IncPC; let mut pipeline_action = CpuPipelineAction::IncPC;
let mut addr = self.get_reg(insn.rn()); let mut addr = self.get_reg(insn.rn());
@ -217,6 +219,7 @@ impl Core {
addr = if insn.pre_index_flag() { addr = if insn.pre_index_flag() {
effective_addr effective_addr
} else { } else {
writeback = true;
addr addr
}; };
@ -248,7 +251,7 @@ impl Core {
}; };
} }
if insn.write_back_flag() { if writeback {
self.set_reg(insn.rn(), effective_addr as u32) self.set_reg(insn.rn(), effective_addr as u32)
} }
@ -256,7 +259,8 @@ impl Core {
} }
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 {
if insn.write_back_flag() && insn.rd() == insn.rn() { let mut writeback = insn.write_back_flag();
if writeback && insn.rd() == insn.rn() {
return Err(CpuError::IllegalInstruction); return Err(CpuError::IllegalInstruction);
} }
@ -273,6 +277,7 @@ impl Core {
addr = if insn.pre_index_flag() { addr = if insn.pre_index_flag() {
effective_addr effective_addr
} else { } else {
writeback = true;
addr addr
}; };
@ -308,7 +313,7 @@ impl Core {
}; };
} }
if insn.write_back_flag() { if writeback {
self.set_reg(insn.rn(), effective_addr as u32) self.set_reg(insn.rn(), effective_addr as u32)
} }
@ -386,10 +391,7 @@ impl Core {
} }
fn exec_mul_mla(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_mul_mla(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
let rd = insn.rd(); let (rd, rn, rs, rm) = (insn.rd(), insn.rn(), insn.rs(), insn.rm());
let rn = insn.rn();
let rs = insn.rs();
let rm = insn.rm();
// check validity // check validity
if REG_PC == rd || REG_PC == rn || REG_PC == rs || REG_PC == rm { if REG_PC == rd || REG_PC == rn || REG_PC == rs || REG_PC == rm {
@ -416,7 +418,50 @@ impl Core {
} }
if insn.set_cond_flag() { if insn.set_cond_flag() {
self.cpsr.set_N(result.bit(31)); self.cpsr.set_N((result as i32) < 0);
self.cpsr.set_Z(result == 0);
}
Ok(CpuPipelineAction::IncPC)
}
fn exec_mull_mlal(&mut self, bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
let (rd_hi, rd_lo, rn, rs, rm) =
(insn.rd_hi(), insn.rd_lo(), insn.rn(), insn.rs(), insn.rm());
// check validity
if REG_PC == rd_hi || REG_PC == rd_lo || REG_PC == rn || REG_PC == rs || REG_PC == rm {
return Err(CpuError::IllegalInstruction);
}
if rd_hi != rd_hi && rd_hi != rm && rd_lo != rm {
return Err(CpuError::IllegalInstruction);
}
let op1 = self.get_reg(rm) as u64;
let op2 = self.get_reg(rs) as u64;
let mut result: u64 = if insn.u_flag() {
// signed
(op1 as i64).wrapping_mul(op2 as i64) as u64
} else {
op1.wrapping_mul(op2)
};
self.add_cycle();
if insn.accumulate_flag() {
result = result.wrapping_add(self.get_reg(rn) as u64);
self.add_cycle();
}
self.set_reg(rd_hi, (result >> 32) as u32);
self.set_reg(rd_lo, (result & 0xffffffff) as u32);
let m = self.get_required_multipiler_array_cycles(self.get_reg(rs) as i32);
for _ in 0..m {
self.add_cycle();
}
if insn.set_cond_flag() {
self.cpsr.set_N((result as i64) < 0);
self.cpsr.set_Z(result == 0); self.cpsr.set_Z(result == 0);
} }

View file

@ -333,7 +333,7 @@ impl ThumbInstruction {
pub fn register_list(&self) -> Vec<usize> { pub fn register_list(&self) -> Vec<usize> {
let list_bits = self.raw & 0xff; let list_bits = self.raw & 0xff;
let mut list = Vec::with_capacity(8); let mut list = Vec::with_capacity(8);
for i in 0..=7 { for i in 0..8 {
if (list_bits & (1 << i)) != 0 { if (list_bits & (1 << i)) != 0 {
list.push(i) list.push(i)
} }