thumb: Finish converting all instructions to use const-generics
Former-commit-id: 671c75a985123a52b312a8ae5495ff545d7678dc Former-commit-id: c0794ce36f410cd8c058cbe087c388a84aae8b85
This commit is contained in:
parent
4a7eb53707
commit
03d28c77b6
|
@ -8,6 +8,8 @@ use bit::BitIndex;
|
||||||
|
|
||||||
// copied and slightly adjusted from src/core/arm7tdmi/thumb/mod.rs
|
// copied and slightly adjusted from src/core/arm7tdmi/thumb/mod.rs
|
||||||
fn thumb_decode(i: u16) -> (&'static str, String) {
|
fn thumb_decode(i: u16) -> (&'static str, String) {
|
||||||
|
let offset5 = i.bit_range(6..11) as u8;
|
||||||
|
let load = i.bit(11);
|
||||||
if i & 0xf800 == 0x1800 {
|
if i & 0xf800 == 0x1800 {
|
||||||
(
|
(
|
||||||
"AddSub",
|
"AddSub",
|
||||||
|
@ -22,9 +24,9 @@ fn thumb_decode(i: u16) -> (&'static str, String) {
|
||||||
(
|
(
|
||||||
"MoveShiftedReg",
|
"MoveShiftedReg",
|
||||||
format!(
|
format!(
|
||||||
"exec_thumb_move_shifted_reg::<{BS_OP}, {OFFSET5}>",
|
"exec_thumb_move_shifted_reg::<{BS_OP}, {IMM}>",
|
||||||
BS_OP = i.bit_range(11..13) as u8,
|
BS_OP = i.bit_range(11..13) as u8,
|
||||||
OFFSET5 = i.bit_range(6..11) as u8
|
IMM = i.bit_range(6..11) as u8
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else if i & 0xe000 == 0x2000 {
|
} else if i & 0xe000 == 0x2000 {
|
||||||
|
@ -64,16 +66,23 @@ fn thumb_decode(i: u16) -> (&'static str, String) {
|
||||||
"LdrStrRegOffset",
|
"LdrStrRegOffset",
|
||||||
format!(
|
format!(
|
||||||
"exec_thumb_ldr_str_reg_offset::<{LOAD}, {RO}, {BYTE}>",
|
"exec_thumb_ldr_str_reg_offset::<{LOAD}, {RO}, {BYTE}>",
|
||||||
LOAD = i.bit(11),
|
LOAD = load,
|
||||||
RO = i.bit_range(6..9) as usize,
|
RO = i.bit_range(6..9) as usize,
|
||||||
BYTE = i.bit(10),
|
BYTE = i.bit(10),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else if i & 0xf200 == 0x5200 {
|
} else if i & 0xf200 == 0x5200 {
|
||||||
("LdrStrSHB", String::from("exec_thumb_ldr_str_shb"))
|
(
|
||||||
|
"LdrStrSHB",
|
||||||
|
format!(
|
||||||
|
"exec_thumb_ldr_str_shb::<{RO}, {SIGN_EXTEND}, {HALFWORD}>",
|
||||||
|
RO = i.bit_range(6..9) as usize,
|
||||||
|
SIGN_EXTEND = i.bit(10),
|
||||||
|
HALFWORD = i.bit(11),
|
||||||
|
),
|
||||||
|
)
|
||||||
} else if i & 0xe000 == 0x6000 {
|
} else if i & 0xe000 == 0x6000 {
|
||||||
let is_transferring_bytes = i.bit(12);
|
let is_transferring_bytes = i.bit(12);
|
||||||
let offset5 = i.bit_range(6..11) as u8;
|
|
||||||
let offset = if is_transferring_bytes {
|
let offset = if is_transferring_bytes {
|
||||||
offset5
|
offset5
|
||||||
} else {
|
} else {
|
||||||
|
@ -83,7 +92,7 @@ fn thumb_decode(i: u16) -> (&'static str, String) {
|
||||||
"LdrStrImmOffset",
|
"LdrStrImmOffset",
|
||||||
format!(
|
format!(
|
||||||
"exec_thumb_ldr_str_imm_offset::<{LOAD}, {BYTE}, {OFFSET}>",
|
"exec_thumb_ldr_str_imm_offset::<{LOAD}, {BYTE}, {OFFSET}>",
|
||||||
LOAD = i.bit(11),
|
LOAD = load,
|
||||||
BYTE = is_transferring_bytes,
|
BYTE = is_transferring_bytes,
|
||||||
OFFSET = offset
|
OFFSET = offset
|
||||||
),
|
),
|
||||||
|
@ -91,31 +100,72 @@ fn thumb_decode(i: u16) -> (&'static str, String) {
|
||||||
} else if i & 0xf000 == 0x8000 {
|
} else if i & 0xf000 == 0x8000 {
|
||||||
(
|
(
|
||||||
"LdrStrHalfWord",
|
"LdrStrHalfWord",
|
||||||
String::from("exec_thumb_ldr_str_halfword"),
|
format!(
|
||||||
|
"exec_thumb_ldr_str_halfword::<{LOAD}, {OFFSET}>",
|
||||||
|
LOAD = load,
|
||||||
|
OFFSET = (offset5 << 1) as i32
|
||||||
|
),
|
||||||
)
|
)
|
||||||
} else if i & 0xf000 == 0x9000 {
|
} else if i & 0xf000 == 0x9000 {
|
||||||
("LdrStrSp", String::from("exec_thumb_ldr_str_sp"))
|
(
|
||||||
|
"LdrStrSp",
|
||||||
|
format!(
|
||||||
|
"exec_thumb_ldr_str_sp::<{LOAD}, {RD}>",
|
||||||
|
LOAD = load,
|
||||||
|
RD = i.bit_range(8..11)
|
||||||
|
),
|
||||||
|
)
|
||||||
} else if i & 0xf000 == 0xa000 {
|
} else if i & 0xf000 == 0xa000 {
|
||||||
("LoadAddress", String::from("exec_thumb_load_address"))
|
(
|
||||||
|
"LoadAddress",
|
||||||
|
format!(
|
||||||
|
"exec_thumb_load_address::<{SP}, {RD}>",
|
||||||
|
SP = i.bit(11),
|
||||||
|
RD = i.bit_range(8..11)
|
||||||
|
),
|
||||||
|
)
|
||||||
} else if i & 0xff00 == 0xb000 {
|
} else if i & 0xff00 == 0xb000 {
|
||||||
("AddSp", String::from("exec_thumb_add_sp"))
|
(
|
||||||
|
"AddSp",
|
||||||
|
format!("exec_thumb_add_sp::<{FLAG_S}>", FLAG_S = i.bit(7)),
|
||||||
|
)
|
||||||
} else if i & 0xf600 == 0xb400 {
|
} else if i & 0xf600 == 0xb400 {
|
||||||
("PushPop", String::from("exec_thumb_push_pop"))
|
(
|
||||||
|
"PushPop",
|
||||||
|
format!(
|
||||||
|
"exec_thumb_push_pop::<{POP}, {FLAG_R}>",
|
||||||
|
POP = load,
|
||||||
|
FLAG_R = i.bit(8)
|
||||||
|
),
|
||||||
|
)
|
||||||
} else if i & 0xf000 == 0xc000 {
|
} else if i & 0xf000 == 0xc000 {
|
||||||
("LdmStm", String::from("exec_thumb_ldm_stm"))
|
(
|
||||||
|
"LdmStm",
|
||||||
|
format!(
|
||||||
|
"exec_thumb_ldm_stm::<{LOAD}, {RB}>",
|
||||||
|
LOAD = load,
|
||||||
|
RB = i.bit_range(8..11) as usize
|
||||||
|
),
|
||||||
|
)
|
||||||
} else if i & 0xff00 == 0xdf00 {
|
} else if i & 0xff00 == 0xdf00 {
|
||||||
("Swi", String::from("exec_thumb_swi"))
|
("Swi", String::from("exec_thumb_swi"))
|
||||||
} else if i & 0xf000 == 0xd000 {
|
} else if i & 0xf000 == 0xd000 {
|
||||||
(
|
(
|
||||||
"BranchConditional",
|
"BranchConditional",
|
||||||
String::from("exec_thumb_branch_with_cond"),
|
format!(
|
||||||
|
"exec_thumb_branch_with_cond::<{COND}>",
|
||||||
|
COND = i.bit_range(8..12) as u8
|
||||||
|
),
|
||||||
)
|
)
|
||||||
} else if i & 0xf800 == 0xe000 {
|
} else if i & 0xf800 == 0xe000 {
|
||||||
("Branch", String::from("exec_thumb_branch"))
|
("Branch", String::from("exec_thumb_branch"))
|
||||||
} else if i & 0xf000 == 0xf000 {
|
} else if i & 0xf000 == 0xf000 {
|
||||||
(
|
(
|
||||||
"BranchLongWithLink",
|
"BranchLongWithLink",
|
||||||
String::from("exec_thumb_branch_long_with_link"),
|
format!(
|
||||||
|
"exec_thumb_branch_long_with_link::<{FLAG_LOW_OFFSET}>",
|
||||||
|
FLAG_LOW_OFFSET = i.bit(11),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
("Undefined", String::from("thumb_undefined"))
|
("Undefined", String::from("thumb_undefined"))
|
||||||
|
|
|
@ -7,6 +7,18 @@ use crate::arm7tdmi::*;
|
||||||
|
|
||||||
use super::ThumbDecodeHelper;
|
use super::ThumbDecodeHelper;
|
||||||
|
|
||||||
|
pub(super) mod consts {
|
||||||
|
pub(super) mod flags {
|
||||||
|
pub const FLAG_H1: usize = 7;
|
||||||
|
pub const FLAG_H2: usize = 6;
|
||||||
|
pub const FLAG_R: usize = 8;
|
||||||
|
pub const FLAG_LOW_OFFSET: usize = 11;
|
||||||
|
pub const FLAG_SP: usize = 11;
|
||||||
|
pub const FLAG_SIGN_EXTEND: usize = 10;
|
||||||
|
pub const FLAG_HALFWORD: usize = 11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ThumbInstruction {
|
impl ThumbInstruction {
|
||||||
fn fmt_thumb_move_shifted_reg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt_thumb_move_shifted_reg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
|
|
@ -10,14 +10,14 @@ use MemoryAccess::*;
|
||||||
impl<I: MemoryInterface> Core<I> {
|
impl<I: MemoryInterface> Core<I> {
|
||||||
/// Format 1
|
/// Format 1
|
||||||
/// Execution Time: 1S
|
/// Execution Time: 1S
|
||||||
pub(in super::super) fn exec_thumb_move_shifted_reg<const BS_OP: u8, const OFFSET5: u8>(
|
pub(in super::super) fn exec_thumb_move_shifted_reg<const BS_OP: u8, const IMM: u8>(
|
||||||
&mut self,
|
&mut self,
|
||||||
insn: u16,
|
insn: u16,
|
||||||
) -> CpuAction {
|
) -> CpuAction {
|
||||||
let rd = (insn & 0b111) as usize;
|
let rd = (insn & 0b111) as usize;
|
||||||
let rs = insn.bit_range(3..6) as usize;
|
let rs = insn.bit_range(3..6) as usize;
|
||||||
|
|
||||||
let shift_amount = OFFSET5 as u32;
|
let shift_amount = IMM as u32;
|
||||||
let mut carry = self.cpsr.C();
|
let mut carry = self.cpsr.C();
|
||||||
let bsop = match BS_OP {
|
let bsop = match BS_OP {
|
||||||
0 => BarrelShiftOpCode::LSL,
|
0 => BarrelShiftOpCode::LSL,
|
||||||
|
@ -258,15 +258,19 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
|
|
||||||
/// Format 8 load/store sign-extended byte/halfword
|
/// Format 8 load/store sign-extended byte/halfword
|
||||||
/// Execution Time: 1S+1N+1I for LDR, or 2N for STR
|
/// Execution Time: 1S+1N+1I for LDR, or 2N for STR
|
||||||
pub(in super::super) fn exec_thumb_ldr_str_shb(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_ldr_str_shb<
|
||||||
|
const RO: usize,
|
||||||
|
const SIGN_EXTEND: bool,
|
||||||
|
const HALFWORD: bool,
|
||||||
|
>(
|
||||||
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
|
) -> CpuAction {
|
||||||
let rb = insn.bit_range(3..6) as usize;
|
let rb = insn.bit_range(3..6) as usize;
|
||||||
let rd = (insn & 0b111) as usize;
|
let rd = (insn & 0b111) as usize;
|
||||||
|
|
||||||
let addr = self.gpr[rb].wrapping_add(self.gpr[insn.ro()]);
|
let addr = self.gpr[rb].wrapping_add(self.gpr[RO]);
|
||||||
match (
|
match (SIGN_EXTEND, HALFWORD) {
|
||||||
insn.bit(consts::flags::FLAG_SIGN_EXTEND),
|
|
||||||
insn.bit(consts::flags::FLAG_HALFWORD),
|
|
||||||
) {
|
|
||||||
(false, false) =>
|
(false, false) =>
|
||||||
/* strh */
|
/* strh */
|
||||||
{
|
{
|
||||||
|
@ -314,12 +318,15 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
|
|
||||||
/// Format 10
|
/// Format 10
|
||||||
/// Execution Time: 1S+1N+1I for LDR, or 2N for STR
|
/// Execution Time: 1S+1N+1I for LDR, or 2N for STR
|
||||||
pub(in super::super) fn exec_thumb_ldr_str_halfword(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_ldr_str_halfword<const LOAD: bool, const OFFSET: i32>(
|
||||||
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
|
) -> CpuAction {
|
||||||
let rb = insn.bit_range(3..6) as usize;
|
let rb = insn.bit_range(3..6) as usize;
|
||||||
let rd = (insn & 0b111) as usize;
|
let rd = (insn & 0b111) as usize;
|
||||||
let base = self.gpr[rb] as i32;
|
let base = self.gpr[rb] as i32;
|
||||||
let addr = base.wrapping_add((insn.offset5() << 1) as i32) as Addr;
|
let addr = base.wrapping_add(OFFSET) as Addr;
|
||||||
if insn.is_load() {
|
if LOAD {
|
||||||
let data = self.ldr_half(addr, NonSeq);
|
let data = self.ldr_half(addr, NonSeq);
|
||||||
self.idle_cycle();
|
self.idle_cycle();
|
||||||
self.gpr[rd] = data as u32;
|
self.gpr[rd] = data as u32;
|
||||||
|
@ -332,26 +339,29 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
|
|
||||||
/// Format 11 load/store SP-relative
|
/// Format 11 load/store SP-relative
|
||||||
/// Execution Time: 1S+1N+1I for LDR, or 2N for STR
|
/// Execution Time: 1S+1N+1I for LDR, or 2N for STR
|
||||||
pub(in super::super) fn exec_thumb_ldr_str_sp(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_ldr_str_sp<const LOAD: bool, const RD: usize>(
|
||||||
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
|
) -> CpuAction {
|
||||||
let addr = self.gpr[REG_SP] + (insn.word8() as Addr);
|
let addr = self.gpr[REG_SP] + (insn.word8() as Addr);
|
||||||
let rd = insn.bit_range(8..11) as usize;
|
if LOAD {
|
||||||
if insn.is_load() {
|
|
||||||
let data = self.ldr_word(addr, NonSeq);
|
let data = self.ldr_word(addr, NonSeq);
|
||||||
self.idle_cycle();
|
self.idle_cycle();
|
||||||
self.gpr[rd] = data;
|
self.gpr[RD] = data;
|
||||||
CpuAction::AdvancePC(Seq)
|
CpuAction::AdvancePC(Seq)
|
||||||
} else {
|
} else {
|
||||||
self.store_aligned_32(addr, self.gpr[rd], NonSeq);
|
self.store_aligned_32(addr, self.gpr[RD], NonSeq);
|
||||||
CpuAction::AdvancePC(NonSeq)
|
CpuAction::AdvancePC(NonSeq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format 12
|
/// Format 12
|
||||||
/// Execution Time: 1S
|
/// Execution Time: 1S
|
||||||
pub(in super::super) fn exec_thumb_load_address(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_load_address<const SP: bool, const RD: usize>(
|
||||||
let rd = insn.bit_range(8..11) as usize;
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
self.gpr[rd] = if insn.bit(consts::flags::FLAG_SP) {
|
) -> CpuAction {
|
||||||
|
self.gpr[RD] = if SP {
|
||||||
self.gpr[REG_SP] + (insn.word8() as Addr)
|
self.gpr[REG_SP] + (insn.word8() as Addr)
|
||||||
} else {
|
} else {
|
||||||
(self.pc_thumb() & !0b10) + 4 + (insn.word8() as Addr)
|
(self.pc_thumb() & !0b10) + 4 + (insn.word8() as Addr)
|
||||||
|
@ -362,17 +372,26 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
|
|
||||||
/// Format 13
|
/// Format 13
|
||||||
/// Execution Time: 1S
|
/// Execution Time: 1S
|
||||||
pub(in super::super) fn exec_thumb_add_sp(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_add_sp<const FLAG_S: bool>(
|
||||||
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
|
) -> CpuAction {
|
||||||
let op1 = self.gpr[REG_SP] as i32;
|
let op1 = self.gpr[REG_SP] as i32;
|
||||||
let op2 = insn.sword7();
|
let offset = ((insn & 0x7f) << 2) as i32;
|
||||||
|
self.gpr[REG_SP] = if FLAG_S {
|
||||||
self.gpr[REG_SP] = op1.wrapping_add(op2) as u32;
|
op1.wrapping_sub(offset) as u32
|
||||||
|
} else {
|
||||||
|
op1.wrapping_add(offset) as u32
|
||||||
|
};
|
||||||
|
|
||||||
CpuAction::AdvancePC(Seq)
|
CpuAction::AdvancePC(Seq)
|
||||||
}
|
}
|
||||||
/// Format 14
|
/// Format 14
|
||||||
/// Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH).
|
/// Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH).
|
||||||
pub(in super::super) fn exec_thumb_push_pop(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_push_pop<const POP: bool, const FLAG_R: bool>(
|
||||||
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
|
) -> CpuAction {
|
||||||
macro_rules! push {
|
macro_rules! push {
|
||||||
($r:expr, $access:ident) => {
|
($r:expr, $access:ident) => {
|
||||||
self.gpr[REG_SP] -= 4;
|
self.gpr[REG_SP] -= 4;
|
||||||
|
@ -395,17 +414,15 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let mut result = CpuAction::AdvancePC(NonSeq);
|
let mut result = CpuAction::AdvancePC(NonSeq);
|
||||||
let is_pop = insn.is_load();
|
|
||||||
let pc_lr_flag = insn.bit(consts::flags::FLAG_R);
|
|
||||||
let rlist = insn.register_list();
|
let rlist = insn.register_list();
|
||||||
let mut access = MemoryAccess::NonSeq;
|
let mut access = MemoryAccess::NonSeq;
|
||||||
if is_pop {
|
if POP {
|
||||||
for r in 0..8 {
|
for r in 0..8 {
|
||||||
if rlist.bit(r) {
|
if rlist.bit(r) {
|
||||||
pop!(r, access);
|
pop!(r, access);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pc_lr_flag {
|
if FLAG_R {
|
||||||
pop!(REG_PC);
|
pop!(REG_PC);
|
||||||
self.pc = self.pc & !1;
|
self.pc = self.pc & !1;
|
||||||
result = CpuAction::PipelineFlushed;
|
result = CpuAction::PipelineFlushed;
|
||||||
|
@ -414,7 +431,7 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
// Idle 1 cycle
|
// Idle 1 cycle
|
||||||
self.idle_cycle();
|
self.idle_cycle();
|
||||||
} else {
|
} else {
|
||||||
if pc_lr_flag {
|
if FLAG_R {
|
||||||
push!(REG_LR, access);
|
push!(REG_LR, access);
|
||||||
}
|
}
|
||||||
for r in (0..8).rev() {
|
for r in (0..8).rev() {
|
||||||
|
@ -429,19 +446,18 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
|
|
||||||
/// Format 15
|
/// Format 15
|
||||||
/// Execution Time: nS+1N+1I for LDM, or (n-1)S+2N for STM.
|
/// Execution Time: nS+1N+1I for LDM, or (n-1)S+2N for STM.
|
||||||
pub(in super::super) fn exec_thumb_ldm_stm(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_ldm_stm<const LOAD: bool, const RB: usize>(
|
||||||
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
|
) -> CpuAction {
|
||||||
let mut result = CpuAction::AdvancePC(NonSeq);
|
let mut result = CpuAction::AdvancePC(NonSeq);
|
||||||
|
|
||||||
let rb = insn.bit_range(8..11) as usize;
|
let align_preserve = self.gpr[RB] & 3;
|
||||||
let base_reg = rb;
|
let mut addr = self.gpr[RB] & !3;
|
||||||
let is_load = insn.is_load();
|
|
||||||
|
|
||||||
let align_preserve = self.gpr[base_reg] & 3;
|
|
||||||
let mut addr = self.gpr[base_reg] & !3;
|
|
||||||
let rlist = insn.register_list();
|
let rlist = insn.register_list();
|
||||||
// let mut first = true;
|
// let mut first = true;
|
||||||
if rlist != 0 {
|
if rlist != 0 {
|
||||||
if is_load {
|
if LOAD {
|
||||||
let mut access = NonSeq;
|
let mut access = NonSeq;
|
||||||
for r in 0..8 {
|
for r in 0..8 {
|
||||||
if rlist.bit(r) {
|
if rlist.bit(r) {
|
||||||
|
@ -452,15 +468,15 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.idle_cycle();
|
self.idle_cycle();
|
||||||
if !rlist.bit(base_reg) {
|
if !rlist.bit(RB) {
|
||||||
self.gpr[base_reg] = addr + align_preserve;
|
self.gpr[RB] = addr + align_preserve;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
let mut access = NonSeq;
|
let mut access = NonSeq;
|
||||||
for r in 0..8 {
|
for r in 0..8 {
|
||||||
if rlist.bit(r) {
|
if rlist.bit(r) {
|
||||||
let v = if r != base_reg {
|
let v = if r != RB {
|
||||||
self.gpr[r]
|
self.gpr[r]
|
||||||
} else {
|
} else {
|
||||||
if first {
|
if first {
|
||||||
|
@ -476,12 +492,12 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
access = Seq;
|
access = Seq;
|
||||||
addr += 4;
|
addr += 4;
|
||||||
}
|
}
|
||||||
self.gpr[base_reg] = addr + align_preserve;
|
self.gpr[RB] = addr + align_preserve;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// From gbatek.htm: Empty Rlist: R15 loaded/stored (ARMv4 only), and Rb=Rb+40h (ARMv4-v5).
|
// From gbatek.htm: Empty Rlist: R15 loaded/stored (ARMv4 only), and Rb=Rb+40h (ARMv4-v5).
|
||||||
if is_load {
|
if LOAD {
|
||||||
let val = self.load_32(addr, NonSeq);
|
let val = self.load_32(addr, NonSeq);
|
||||||
self.pc = val & !1;
|
self.pc = val & !1;
|
||||||
result = CpuAction::PipelineFlushed;
|
result = CpuAction::PipelineFlushed;
|
||||||
|
@ -490,7 +506,7 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
self.store_32(addr, self.pc + 2, NonSeq);
|
self.store_32(addr, self.pc + 2, NonSeq);
|
||||||
}
|
}
|
||||||
addr += 0x40;
|
addr += 0x40;
|
||||||
self.gpr[base_reg] = addr + align_preserve;
|
self.gpr[RB] = addr + align_preserve;
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
|
@ -500,8 +516,12 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
/// Execution Time:
|
/// Execution Time:
|
||||||
/// 2S+1N if condition true (jump executed)
|
/// 2S+1N if condition true (jump executed)
|
||||||
/// 1S if condition false
|
/// 1S if condition false
|
||||||
pub(in super::super) fn exec_thumb_branch_with_cond(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_branch_with_cond<const COND: u8>(
|
||||||
if !self.check_arm_cond(insn.cond()) {
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
|
) -> CpuAction {
|
||||||
|
let cond = ArmCond::from_u8(COND).expect("bad cond");
|
||||||
|
if !self.check_arm_cond(cond) {
|
||||||
CpuAction::AdvancePC(Seq)
|
CpuAction::AdvancePC(Seq)
|
||||||
} else {
|
} else {
|
||||||
let offset = insn.bcond_offset();
|
let offset = insn.bcond_offset();
|
||||||
|
@ -529,9 +549,12 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
|
|
||||||
/// Format 19
|
/// Format 19
|
||||||
/// Execution Time: 3S+1N (first opcode 1S, second opcode 2S+1N).
|
/// Execution Time: 3S+1N (first opcode 1S, second opcode 2S+1N).
|
||||||
pub(in super::super) fn exec_thumb_branch_long_with_link(&mut self, insn: u16) -> CpuAction {
|
pub(in super::super) fn exec_thumb_branch_long_with_link<const FLAG_LOW_OFFSET: bool>(
|
||||||
|
&mut self,
|
||||||
|
insn: u16,
|
||||||
|
) -> CpuAction {
|
||||||
let mut off = insn.offset11();
|
let mut off = insn.offset11();
|
||||||
if insn.bit(consts::flags::FLAG_LOW_OFFSET) {
|
if FLAG_LOW_OFFSET {
|
||||||
off = off << 1;
|
off = off << 1;
|
||||||
let next_pc = (self.pc - 2) | 1;
|
let next_pc = (self.pc - 2) | 1;
|
||||||
self.pc = ((self.gpr[REG_LR] & !1) as i32).wrapping_add(off) as u32;
|
self.pc = ((self.gpr[REG_LR] & !1) as i32).wrapping_add(off) as u32;
|
||||||
|
|
|
@ -208,21 +208,6 @@ impl From<OpFormat5> for AluOpCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) mod consts {
|
|
||||||
pub(super) mod flags {
|
|
||||||
#[cfg(feature = "debugger")]
|
|
||||||
pub const FLAG_H1: usize = 7;
|
|
||||||
#[cfg(feature = "debugger")]
|
|
||||||
pub const FLAG_H2: usize = 6;
|
|
||||||
pub const FLAG_R: usize = 8;
|
|
||||||
pub const FLAG_S: usize = 7;
|
|
||||||
pub const FLAG_LOW_OFFSET: usize = 11;
|
|
||||||
pub const FLAG_SP: usize = 11;
|
|
||||||
pub const FLAG_SIGN_EXTEND: usize = 10;
|
|
||||||
pub const FLAG_HALFWORD: usize = 11;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait which provides methods to extract thumb instruction fields
|
/// A trait which provides methods to extract thumb instruction fields
|
||||||
pub trait ThumbDecodeHelper {
|
pub trait ThumbDecodeHelper {
|
||||||
// Consts
|
// Consts
|
||||||
|
@ -367,7 +352,7 @@ macro_rules! thumb_decode_helper_impl {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sword7(&self) -> i32 {
|
fn sword7(&self) -> i32 {
|
||||||
let imm7 = *self & 0x7f;
|
let imm7 = *self & 0x7f;
|
||||||
if self.bit(consts::flags::FLAG_S) {
|
if self.bit(7) {
|
||||||
-((imm7 << 2) as i32)
|
-((imm7 << 2) as i32)
|
||||||
} else {
|
} else {
|
||||||
(imm7 << 2) as i32
|
(imm7 << 2) as i32
|
||||||
|
|
Reference in a new issue