fix(tests): Fix all arm tests

Former-commit-id: a3138584636cc34115207dc6a7b52cf175da187a
This commit is contained in:
Michel Heily 2020-01-17 13:10:26 +02:00
parent 70c72bec2f
commit 9cc293fb02

View file

@ -274,23 +274,31 @@ 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, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { fn exec_ldr_str(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
let mut writeback = insn.write_back_flag(); let load = insn.load_flag();
let mut addr = self.get_reg(insn.rn()); let pre_index = insn.pre_index_flag();
if insn.rn() == REG_PC { let writeback = insn.write_back_flag();
let base_reg = insn.rn();
let dest_reg = insn.rd();
let mut addr = self.get_reg(base_reg);
if base_reg == REG_PC {
addr = insn.pc + 8; // prefetching addr = insn.pc + 8; // prefetching
} }
let offset = self.get_barrel_shifted_value(insn.ldr_str_offset()); let offset = self.get_barrel_shifted_value(insn.ldr_str_offset());
let effective_addr = (addr as i32).wrapping_add(offset as i32) as Addr; let effective_addr = (addr as i32).wrapping_add(offset as i32) as Addr;
// TODO - confirm this
let old_mode = self.cpsr.mode();
if !pre_index && writeback {
self.change_mode(old_mode, CpuMode::User);
}
addr = if insn.pre_index_flag() { addr = if insn.pre_index_flag() {
effective_addr effective_addr
} else { } else {
writeback = true;
addr addr
}; };
if writeback && insn.rd() == insn.rn() {
writeback = false; if load {
}
if insn.load_flag() {
self.S_cycle32(sb, self.pc); self.S_cycle32(sb, self.pc);
let data = if insn.transfer_size() == 1 { let data = if insn.transfer_size() == 1 {
self.N_cycle8(sb, addr); self.N_cycle8(sb, addr);
@ -300,19 +308,19 @@ impl Core {
self.ldr_word(addr, sb) self.ldr_word(addr, sb)
}; };
self.set_reg(insn.rd(), data); self.set_reg(dest_reg, data);
// +1I // +1I
self.add_cycle(); self.add_cycle();
if insn.rd() == REG_PC { if dest_reg == REG_PC {
self.flush_pipeline32(sb); self.flush_pipeline32(sb);
} }
} else { } else {
let value = if insn.rd() == REG_PC { let value = if dest_reg == REG_PC {
insn.pc + 12 insn.pc + 12
} else { } else {
self.get_reg(insn.rd()) self.get_reg(dest_reg)
}; };
if insn.transfer_size() == 1 { if insn.transfer_size() == 1 {
self.N_cycle8(sb, addr); self.N_cycle8(sb, addr);
@ -324,34 +332,49 @@ impl Core {
self.N_cycle32(sb, self.pc); self.N_cycle32(sb, self.pc);
} }
if writeback { if !load || base_reg != dest_reg {
self.set_reg(insn.rn(), effective_addr as u32) if !pre_index {
self.set_reg(base_reg, effective_addr);
} else if insn.write_back_flag() {
self.set_reg(base_reg, effective_addr);
}
}
if !pre_index && insn.write_back_flag() {
self.change_mode(self.cpsr.mode(), old_mode);
} }
Ok(()) Ok(())
} }
fn exec_ldr_str_hs(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { fn exec_ldr_str_hs(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
let mut writeback = insn.write_back_flag(); let load = insn.load_flag();
let pre_index = insn.pre_index_flag();
let mut addr = self.get_reg(insn.rn()); let writeback = insn.write_back_flag();
if insn.rn() == REG_PC { let base_reg = insn.rn();
let dest_reg = insn.rd();
let mut addr = self.get_reg(base_reg);
if base_reg == REG_PC {
addr = insn.pc + 8; // prefetching addr = insn.pc + 8; // prefetching
} }
let offset = self.get_barrel_shifted_value(insn.ldr_str_hs_offset().unwrap()); let offset = self.get_barrel_shifted_value(insn.ldr_str_hs_offset().unwrap());
// TODO - confirm this
let old_mode = self.cpsr.mode();
if !pre_index && writeback {
println!("SPECIAL CHANGE MODE");
self.change_mode(old_mode, CpuMode::User);
}
let effective_addr = (addr as i32).wrapping_add(offset as i32) as Addr; let effective_addr = (addr as i32).wrapping_add(offset as i32) as Addr;
addr = if insn.pre_index_flag() { addr = if insn.pre_index_flag() {
effective_addr effective_addr
} else { } else {
writeback = true;
addr addr
}; };
if writeback && insn.rd() == insn.rn() {
writeback = false; if load {
}
if insn.load_flag() {
self.S_cycle32(sb, self.pc); self.S_cycle32(sb, self.pc);
let data = match insn.halfword_data_transfer_type().unwrap() { let data = match insn.halfword_data_transfer_type().unwrap() {
ArmHalfwordTransferType::SignedByte => { ArmHalfwordTransferType::SignedByte => {
@ -368,19 +391,19 @@ impl Core {
} }
}; };
self.set_reg(insn.rd(), data); self.set_reg(dest_reg, data);
// +1I // +1I
self.add_cycle(); self.add_cycle();
if insn.rd() == REG_PC { if dest_reg == REG_PC {
self.flush_pipeline32(sb); self.flush_pipeline32(sb);
} }
} else { } else {
let value = if insn.rd() == REG_PC { let value = if dest_reg == REG_PC {
insn.pc + 12 insn.pc + 12
} else { } else {
self.get_reg(insn.rd()) self.get_reg(dest_reg)
}; };
match insn.halfword_data_transfer_type().unwrap() { match insn.halfword_data_transfer_type().unwrap() {
@ -393,26 +416,29 @@ impl Core {
}; };
} }
if writeback { if !load || base_reg != dest_reg {
self.set_reg(insn.rn(), effective_addr as u32) if !pre_index {
self.set_reg(base_reg, effective_addr);
} else if insn.write_back_flag() {
self.set_reg(base_reg, effective_addr);
}
} }
Ok(()) Ok(())
} }
fn exec_ldm_stm(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { fn exec_ldm_stm(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
let full = insn.pre_index_flag(); let mut full = insn.pre_index_flag();
let ascending = insn.add_offset_flag(); let ascending = insn.add_offset_flag();
let psr_user_flag = insn.psr_and_force_user_flag(); let s_flag = insn.raw.bit(22);
let is_load = insn.load_flag(); let is_load = insn.load_flag();
let mut writeback = insn.write_back_flag(); let mut writeback = insn.write_back_flag();
let rn = insn.rn(); let base_reg = insn.rn();
let mut addr = self.gpr[rn] as i32; let mut base_addr = self.get_reg(base_reg);
let step: i32 = if ascending { 4 } else { -4 };
let rlist = insn.register_list(); let rlist = insn.register_list();
if psr_user_flag { if s_flag {
match self.cpsr.mode() { match self.cpsr.mode() {
CpuMode::User | CpuMode::System => { CpuMode::User | CpuMode::System => {
panic!("LDM/STM with S bit in unprivileged mode") panic!("LDM/STM with S bit in unprivileged mode")
@ -421,7 +447,7 @@ impl Core {
}; };
} }
let user_bank_transfer = if psr_user_flag { let user_bank_transfer = if s_flag {
if is_load { if is_load {
!rlist.bit(REG_PC) !rlist.bit(REG_PC)
} else { } else {
@ -431,29 +457,45 @@ impl Core {
false false
}; };
let psr_transfer = psr_user_flag & is_load & rlist.bit(REG_PC); let old_mode = self.cpsr.mode();
if user_bank_transfer {
self.change_mode(old_mode, CpuMode::User);
}
let psr_transfer = s_flag & is_load & rlist.bit(REG_PC);
let rlist_count = rlist.count_ones();
let old_base = base_addr;
if rlist != 0 && !ascending {
base_addr = base_addr.wrapping_sub(rlist_count * 4);
if writeback {
self.set_reg(base_reg, base_addr);
writeback = false;
}
full = !full;
}
let mut addr = base_addr;
if rlist != 0 { if rlist != 0 {
if is_load { if is_load {
self.add_cycle(); self.add_cycle();
self.N_cycle32(sb, self.pc); self.N_cycle32(sb, self.pc);
for r in 0..16 { for r in 0..16 {
let r = if ascending { r } else { 15 - r };
if rlist.bit(r) { if rlist.bit(r) {
if r == rn { if r == base_reg {
writeback = false; writeback = false;
} }
if full { if full {
addr = addr.wrapping_add(step); addr = addr.wrapping_add(4);
} }
let val = sb.read_32(addr as Addr); let val = sb.read_32(addr);
self.S_cycle32(sb, self.pc); self.S_cycle32(sb, self.pc);
if user_bank_transfer {
self.set_reg_user(r, val); self.set_reg(r, val);
} else {
self.set_reg(r, val);
}
if r == REG_PC { if r == REG_PC {
if psr_transfer { if psr_transfer {
@ -463,38 +505,47 @@ impl Core {
} }
if !full { if !full {
addr = addr.wrapping_add(step); addr = addr.wrapping_add(4);
} }
} }
} }
} else { } else {
let mut first = true; let mut first = true;
for r in 0..16 { for r in 0..16 {
let r = if ascending { r } else { 15 - r };
if rlist.bit(r) { if rlist.bit(r) {
if full { let val = if r != base_reg {
addr = addr.wrapping_add(step); if r == REG_PC {
} insn.pc + 12
let val = if r == REG_PC {
insn.pc + 12
} else {
if user_bank_transfer {
self.get_reg_user(r)
} else { } else {
self.get_reg(r) self.get_reg(r)
} }
} else {
if first {
old_base
} else {
let x = rlist_count * 4;
if ascending {
old_base + x
} else {
old_base - x
}
}
}; };
if full {
addr = addr.wrapping_add(4);
}
if first { if first {
self.N_cycle32(sb, addr as u32); self.N_cycle32(sb, addr);
first = false; first = false;
} else { } else {
self.S_cycle32(sb, addr as u32); self.S_cycle32(sb, addr);
} }
self.write_32(addr as Addr, val, sb); self.write_32(addr, val, sb);
if !full { if !full {
addr = addr.wrapping_add(step); addr = addr.wrapping_add(4);
} }
} }
} }
@ -502,17 +553,21 @@ impl Core {
} }
} else { } else {
if is_load { if is_load {
let val = self.ldr_word(addr as u32, sb); let val = self.ldr_word(addr, sb);
self.set_reg(REG_PC, val & !3); self.set_reg(REG_PC, val & !3);
self.flush_pipeline32(sb); self.flush_pipeline32(sb);
} else { } else {
self.write_32(addr as u32, self.pc + 4, sb); self.write_32(addr, self.pc + 4, sb);
} }
addr = addr.wrapping_add(step * 0x10); addr = addr.wrapping_add(0x40);
}
if user_bank_transfer {
self.change_mode(self.cpsr.mode(), old_mode);
} }
if writeback { if writeback {
self.set_reg(rn, addr as u32); self.set_reg(base_reg, addr as u32);
} }
Ok(()) Ok(())
@ -614,9 +669,9 @@ impl Core {
self.S_cycle8(sb, base_addr); self.S_cycle8(sb, base_addr);
self.set_reg(insn.rd(), t as u32); self.set_reg(insn.rd(), t as u32);
} else { } else {
let t = sb.read_32(base_addr); let t = self.ldr_word(base_addr, sb);
self.N_cycle32(sb, base_addr); self.N_cycle32(sb, base_addr);
sb.write_32(base_addr, self.get_reg(insn.rm())); self.write_32(base_addr, self.get_reg(insn.rm()), sb);
self.S_cycle32(sb, base_addr); self.S_cycle32(sb, base_addr);
self.set_reg(insn.rd(), t as u32); self.set_reg(insn.rd(), t as u32);
} }