core: arm7tdmi: thumb: Reduce branches in exec functions

Former-commit-id: 69493480eddee066bc4812c4c1abd6c520a00231
This commit is contained in:
Michel Heily 2020-01-17 16:10:17 +02:00
parent 40de6bf893
commit ec0e796536

View file

@ -23,16 +23,19 @@ impl Core {
sb: &mut SysBus, sb: &mut SysBus,
insn: ThumbInstruction, insn: ThumbInstruction,
) -> CpuExecResult { ) -> CpuExecResult {
let rd = (insn.raw & 0b111) as usize;
let rs = insn.raw.bit_range(3..6) as usize;
let op2 = self let op2 = self
.register_shift(ShiftedRegister { .register_shift(ShiftedRegister {
reg: insn.rs(), reg: rs,
shift_by: ShiftRegisterBy::ByAmount(insn.offset5() as u8 as u32), shift_by: ShiftRegisterBy::ByAmount(insn.offset5() as u8 as u32),
bs_op: insn.format1_op(), bs_op: insn.format1_op(),
added: None, added: None,
}) })
.unwrap(); .unwrap();
self.set_reg(insn.rd(), op2); self.set_reg(rd, op2);
self.alu_update_flags(op2, false, self.bs_carry_out, self.cpsr.V()); self.alu_update_flags(op2, false, self.bs_carry_out, self.cpsr.V());
self.S_cycle16(sb, self.pc + 2); self.S_cycle16(sb, self.pc + 2);
@ -40,6 +43,7 @@ impl Core {
} }
fn exec_thumb_add_sub(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_add_sub(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
let rd = (insn.raw & 0b111) as usize;
let op1 = self.get_reg(insn.rs()); let op1 = self.get_reg(insn.rs());
let op2 = if insn.is_immediate_operand() { let op2 = if insn.is_immediate_operand() {
insn.rn() as u32 insn.rn() as u32
@ -55,7 +59,7 @@ impl Core {
self.alu_add_flags(op1, op2, &mut carry, &mut overflow) self.alu_add_flags(op1, op2, &mut carry, &mut overflow)
}; };
self.alu_update_flags(result, true, carry, overflow); self.alu_update_flags(result, true, carry, overflow);
self.set_reg(insn.rd(), result as u32); self.set_reg(rd, result as u32);
self.S_cycle16(sb, self.pc + 2); self.S_cycle16(sb, self.pc + 2);
Ok(()) Ok(())
@ -68,7 +72,8 @@ impl Core {
) -> CpuExecResult { ) -> CpuExecResult {
use OpFormat3::*; use OpFormat3::*;
let op = insn.format3_op(); let op = insn.format3_op();
let op1 = self.get_reg(insn.rd()); let rd = insn.raw.bit_range(8..11) as usize;
let op1 = self.gpr[rd];
let op2_imm = (insn.raw & 0xff) as u32; let op2_imm = (insn.raw & 0xff) as u32;
let mut carry = self.cpsr.C(); let mut carry = self.cpsr.C();
let mut overflow = self.cpsr.V(); let mut overflow = self.cpsr.V();
@ -80,14 +85,14 @@ impl Core {
let arithmetic = op == ADD || op == SUB; let arithmetic = op == ADD || op == SUB;
self.alu_update_flags(result, arithmetic, carry, overflow); self.alu_update_flags(result, arithmetic, carry, overflow);
if op != CMP { if op != CMP {
self.set_reg(insn.rd(), result as u32); self.gpr[rd] = result as u32;
} }
self.S_cycle16(sb, self.pc + 2); self.S_cycle16(sb, self.pc + 2);
Ok(()) Ok(())
} }
fn exec_thumb_alu_ops(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_alu_ops(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
let rd = insn.rd(); let rd = (insn.raw & 0b111) as usize;
let rs = insn.rs(); let rs = insn.rs();
let dst = self.get_reg(rd); let dst = self.get_reg(rd);
let src = self.get_reg(rs); let src = self.get_reg(rs);
@ -164,10 +169,11 @@ impl Core {
insn: ThumbInstruction, insn: ThumbInstruction,
) -> CpuExecResult { ) -> CpuExecResult {
let op = insn.format5_op(); let op = insn.format5_op();
let rd = (insn.raw & 0b111) as usize;
let dst_reg = if insn.flag(ThumbInstruction::FLAG_H1) { let dst_reg = if insn.flag(ThumbInstruction::FLAG_H1) {
insn.rd() + 8 rd + 8
} else { } else {
insn.rd() rd
}; };
let src_reg = if insn.flag(ThumbInstruction::FLAG_H2) { let src_reg = if insn.flag(ThumbInstruction::FLAG_H2) {
insn.rs() + 8 insn.rs() + 8
@ -203,12 +209,17 @@ impl Core {
} }
fn exec_thumb_ldr_pc(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_ldr_pc(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
let addr = (insn.pc & !0b10) + 4 + (insn.word8() as Addr); let rd = insn.raw.bit_range(8..11) as usize;
let ofs = insn.word8() as Addr;
let addr = (self.pc & !3) + ofs;
self.S_cycle16(sb, self.pc + 2); self.S_cycle16(sb, self.pc + 2);
let data = self.ldr_word(addr, sb); let data = self.ldr_word(addr, sb);
self.N_cycle16(sb, addr); self.N_cycle16(sb, addr);
self.set_reg(insn.rd(), data); self.gpr[rd] = data;
// +1I // +1I
self.add_cycle(); self.add_cycle();
@ -220,9 +231,11 @@ impl Core {
sb: &mut SysBus, sb: &mut SysBus,
insn: ThumbInstruction, insn: ThumbInstruction,
addr: Addr, addr: Addr,
is_transferring_bytes: bool
) -> CpuExecResult { ) -> CpuExecResult {
let rd = (insn.raw & 0b111) as usize;
if insn.is_load() { if insn.is_load() {
let data = if insn.is_transferring_bytes() { let data = if is_transferring_bytes {
self.S_cycle8(sb, addr); self.S_cycle8(sb, addr);
sb.read_8(addr) as u32 sb.read_8(addr) as u32
} else { } else {
@ -230,13 +243,13 @@ impl Core {
self.ldr_word(addr, sb) self.ldr_word(addr, sb)
}; };
self.set_reg(insn.rd(), data); self.gpr[rd] = data;
// +1I // +1I
self.add_cycle(); self.add_cycle();
} else { } else {
let value = self.get_reg(insn.rd()); let value = self.get_reg(rd);
if insn.is_transferring_bytes() { if is_transferring_bytes {
self.N_cycle8(sb, addr); self.N_cycle8(sb, addr);
self.write_8(addr, value as u8, sb); self.write_8(addr, value as u8, sb);
} else { } else {
@ -254,17 +267,16 @@ impl Core {
bus: &mut SysBus, bus: &mut SysBus,
insn: ThumbInstruction, insn: ThumbInstruction,
) -> CpuExecResult { ) -> CpuExecResult {
let addr = self let rb = insn.raw.bit_range(3..6) as usize;
.get_reg(insn.rb()) let addr = self.gpr[rb].wrapping_add(self.gpr[insn.ro()]);
.wrapping_add(self.get_reg(insn.ro())); self.do_exec_thumb_ldr_str(bus, insn, addr, insn.raw.bit(10))
self.do_exec_thumb_ldr_str(bus, insn, addr)
} }
fn exec_thumb_ldr_str_shb(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_ldr_str_shb(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
let addr = self let rb = insn.raw.bit_range(3..6) as usize;
.get_reg(insn.rb()) let rd = (insn.raw & 0b111) as usize;
.wrapping_add(self.get_reg(insn.ro()));
let rd = insn.rd(); let addr = self.gpr[rb].wrapping_add(self.gpr[insn.ro()]);
match ( match (
insn.flag(ThumbInstruction::FLAG_SIGN_EXTEND), insn.flag(ThumbInstruction::FLAG_SIGN_EXTEND),
insn.flag(ThumbInstruction::FLAG_HALFWORD), insn.flag(ThumbInstruction::FLAG_HALFWORD),
@ -309,13 +321,15 @@ impl Core {
sb: &mut SysBus, sb: &mut SysBus,
insn: ThumbInstruction, insn: ThumbInstruction,
) -> CpuExecResult { ) -> CpuExecResult {
let rb = insn.raw.bit_range(3..6) as usize;
let offset = if insn.raw.bit(12) { let offset = if insn.raw.bit(12) {
insn.offset5() insn.offset5()
} else { } else {
(insn.offset5() << 3) >> 1 (insn.offset5() << 3) >> 1
}; };
let addr = self.get_reg(insn.rb()).wrapping_add(offset as u32); let addr = self.gpr[rb].wrapping_add(offset as u32);
self.do_exec_thumb_ldr_str(sb, insn, addr) self.do_exec_thumb_ldr_str(sb, insn, addr, insn.raw.bit(12))
} }
fn exec_thumb_ldr_str_halfword( fn exec_thumb_ldr_str_halfword(
@ -323,15 +337,17 @@ impl Core {
sb: &mut SysBus, sb: &mut SysBus,
insn: ThumbInstruction, insn: ThumbInstruction,
) -> CpuExecResult { ) -> CpuExecResult {
let base = self.gpr[insn.rb()] as i32; let rb = insn.raw.bit_range(3..6) as usize;
let rd = (insn.raw & 0b111) as usize;
let base = self.gpr[rb] as i32;
let addr = base.wrapping_add((insn.offset5() << 1) as i32) as Addr; let addr = base.wrapping_add((insn.offset5() << 1) as i32) as Addr;
if insn.is_load() { if insn.is_load() {
let data = self.ldr_half(addr, sb); let data = self.ldr_half(addr, sb);
self.S_cycle16(sb, addr); self.S_cycle16(sb, addr);
self.add_cycle(); self.add_cycle();
self.gpr[insn.rd()] = data as u32; self.gpr[rd] = data as u32;
} else { } else {
self.write_16(addr, self.gpr[insn.rd()] as u16, sb); self.write_16(addr, self.gpr[rd] as u16, sb);
self.N_cycle16(sb, addr); self.N_cycle16(sb, addr);
} }
self.N_cycle16(sb, self.pc + 2); self.N_cycle16(sb, self.pc + 2);
@ -340,7 +356,7 @@ impl Core {
fn exec_thumb_ldr_str_sp(&mut self, bus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_ldr_str_sp(&mut self, bus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
let addr = self.gpr[REG_SP] + (insn.word8() as Addr); let addr = self.gpr[REG_SP] + (insn.word8() as Addr);
self.do_exec_thumb_ldr_str_with_addr(bus, insn, addr) self.do_exec_thumb_ldr_str_with_addr(bus, insn, addr, insn.raw.bit_range(8..11) as usize)
} }
fn exec_thumb_load_address( fn exec_thumb_load_address(
@ -348,12 +364,13 @@ impl Core {
sb: &mut SysBus, sb: &mut SysBus,
insn: ThumbInstruction, insn: ThumbInstruction,
) -> CpuExecResult { ) -> CpuExecResult {
let rd = insn.raw.bit_range(8..11) as usize;
let result = if insn.flag(ThumbInstruction::FLAG_SP) { let result = if insn.flag(ThumbInstruction::FLAG_SP) {
self.gpr[REG_SP] + (insn.word8() as Addr) self.gpr[REG_SP] + (insn.word8() as Addr)
} else { } else {
(insn.pc & !0b10) + 4 + (insn.word8() as Addr) (insn.pc & !0b10) + 4 + (insn.word8() as Addr)
}; };
self.gpr[insn.rd()] = result; self.gpr[rd] = result;
self.S_cycle16(sb, self.pc + 2); self.S_cycle16(sb, self.pc + 2);
Ok(()) Ok(())
} }
@ -363,14 +380,15 @@ impl Core {
sb: &mut SysBus, sb: &mut SysBus,
insn: ThumbInstruction, insn: ThumbInstruction,
addr: Addr, addr: Addr,
rd: usize,
) -> CpuExecResult { ) -> CpuExecResult {
if insn.is_load() { if insn.is_load() {
let data = self.ldr_word(addr, sb); let data = self.ldr_word(addr, sb);
self.S_cycle16(sb, addr); self.S_cycle16(sb, addr);
self.add_cycle(); self.add_cycle();
self.gpr[insn.rd()] = data; self.gpr[rd] = data;
} else { } else {
self.write_32(addr, self.gpr[insn.rd()], sb); self.write_32(addr, self.gpr[rd], sb);
self.N_cycle16(sb, addr); self.N_cycle16(sb, addr);
} }
self.N_cycle16(sb, self.pc + 2); self.N_cycle16(sb, self.pc + 2);
@ -433,8 +451,9 @@ impl Core {
fn exec_thumb_ldm_stm(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_ldm_stm(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
// (From GBATEK) Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH). // (From GBATEK) Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH).
let rb = insn.raw.bit_range(8..11) as usize;
let base_reg = rb;
let is_load = insn.is_load(); let is_load = insn.is_load();
let base_reg = insn.rb();
let align_preserve = self.gpr[base_reg] & 3; let align_preserve = self.gpr[base_reg] & 3;
let mut addr = self.gpr[base_reg] & !3; let mut addr = self.gpr[base_reg] & !3;