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:
parent
4763f79abf
commit
95f45e55a9
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue