core: arm7tdmi: thumb: Reduce branches in exec functions
Former-commit-id: 69493480eddee066bc4812c4c1abd6c520a00231
This commit is contained in:
parent
40de6bf893
commit
ec0e796536
|
@ -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;
|
||||||
|
|
Reference in a new issue