arm7tdmi/optimize: Optimize and cleanup CPU, roughly about 10% fps improvement.
This commit removes the error handling (CpuResult<>) in order to reduce overhead in the cpu implementation. Also, some cleanup of warning messages. Notice: this commit breaks '--feature debugger' for now Former-commit-id: d4484047c3f5d509eff89cef7090aa88b07a8d17
This commit is contained in:
parent
48eb2a4104
commit
ae7bf63d3f
|
@ -1,6 +1,6 @@
|
||||||
use bit::BitIndex;
|
use bit::BitIndex;
|
||||||
|
|
||||||
use super::{Core, CpuError, CpuResult, REG_PC};
|
use super::{Core, REG_PC};
|
||||||
|
|
||||||
#[derive(Debug, Primitive, PartialEq)]
|
#[derive(Debug, Primitive, PartialEq)]
|
||||||
pub enum AluOpCode {
|
pub enum AluOpCode {
|
||||||
|
@ -246,26 +246,25 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_shift(&mut self, shift: ShiftedRegister) -> CpuResult<u32> {
|
pub fn shift_by_register(&mut self, bs_op: BarrelShiftOpCode, reg: usize, rs: usize, carry: bool) -> u32 {
|
||||||
let mut val = self.get_reg(shift.reg);
|
let mut val = self.get_reg(reg);
|
||||||
|
self.add_cycle(); // +1I
|
||||||
|
if reg == REG_PC {
|
||||||
|
val += 4; // PC prefetching
|
||||||
|
}
|
||||||
|
let amount = self.get_reg(rs) & 0xff;
|
||||||
|
self.barrel_shift_op(bs_op, val, amount, carry, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_shift(&mut self, shift: ShiftedRegister) -> u32 {
|
||||||
let carry = self.cpsr.C();
|
let carry = self.cpsr.C();
|
||||||
match shift.shift_by {
|
match shift.shift_by {
|
||||||
ShiftRegisterBy::ByAmount(amount) => {
|
ShiftRegisterBy::ByAmount(amount) => {
|
||||||
let result = self.barrel_shift_op(shift.bs_op, val, amount, carry, true);
|
let result = self.barrel_shift_op(shift.bs_op, self.get_reg(shift.reg), amount, carry, true);
|
||||||
Ok(result)
|
result
|
||||||
}
|
}
|
||||||
ShiftRegisterBy::ByRegister(rs) => {
|
ShiftRegisterBy::ByRegister(rs) => {
|
||||||
self.add_cycle(); // +1I
|
self.shift_by_register(shift.bs_op, shift.reg, rs, carry)
|
||||||
if shift.reg == REG_PC {
|
|
||||||
val = val + 4; // PC prefetching
|
|
||||||
}
|
|
||||||
if rs != REG_PC {
|
|
||||||
let amount = self.get_reg(rs) & 0xff;
|
|
||||||
let result = self.barrel_shift_op(shift.bs_op, val, amount, carry, false);
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(CpuError::IllegalInstruction)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,7 +275,7 @@ impl Core {
|
||||||
BarrelShifterValue::ImmediateValue(offset) => offset as u32,
|
BarrelShifterValue::ImmediateValue(offset) => offset as u32,
|
||||||
BarrelShifterValue::ShiftedRegister(shifted_reg) => {
|
BarrelShifterValue::ShiftedRegister(shifted_reg) => {
|
||||||
let added = shifted_reg.added.unwrap_or(true);
|
let added = shifted_reg.added.unwrap_or(true);
|
||||||
let abs = self.register_shift(shifted_reg).unwrap() as u32;
|
let abs = self.register_shift(shifted_reg) as u32;
|
||||||
if added {
|
if added {
|
||||||
abs as u32
|
abs as u32
|
||||||
} else {
|
} else {
|
||||||
|
@ -337,7 +336,7 @@ impl Core {
|
||||||
self.alu_adc_flags(a, !b, carry, overflow)
|
self.alu_adc_flags(a, !b, carry, overflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alu_update_flags(&mut self, result: u32, is_arithmetic: bool, c: bool, v: bool) {
|
pub fn alu_update_flags(&mut self, result: u32, _is_arithmetic: bool, c: bool, v: bool) {
|
||||||
self.cpsr.set_N((result as i32) < 0);
|
self.cpsr.set_N((result as i32) < 0);
|
||||||
self.cpsr.set_Z(result == 0);
|
self.cpsr.set_Z(result == 0);
|
||||||
self.cpsr.set_C(c);
|
self.cpsr.set_C(c);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
use crate::bit::BitIndex;
|
use crate::bit::BitIndex;
|
||||||
|
|
||||||
use super::{AluOpCode, ArmCond, ArmFormat, ArmHalfwordTransferType, ArmInstruction};
|
#[cfg(feature = "debugger")]
|
||||||
use crate::core::arm7tdmi::alu::*;
|
use super::{ArmFormat, ArmInstruction};
|
||||||
use crate::core::arm7tdmi::psr::RegPSR;
|
|
||||||
|
use super::{AluOpCode, ArmCond, ArmHalfwordTransferType};
|
||||||
use crate::core::arm7tdmi::*;
|
use crate::core::arm7tdmi::*;
|
||||||
|
|
||||||
impl fmt::Display for ArmCond {
|
impl fmt::Display for ArmCond {
|
||||||
|
@ -100,6 +102,7 @@ impl fmt::Display for ShiftedRegister {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
impl ArmInstruction {
|
impl ArmInstruction {
|
||||||
fn fmt_bx(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt_bx(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "bx\t{Rn}", Rn = reg_string(self.rn()))
|
write!(f, "bx\t{Rn}", Rn = reg_string(self.rn()))
|
||||||
|
@ -408,6 +411,7 @@ impl ArmInstruction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
impl fmt::Display for ArmInstruction {
|
impl fmt::Display for ArmInstruction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use ArmFormat::*;
|
use ArmFormat::*;
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
use crate::bit::BitIndex;
|
use crate::bit::BitIndex;
|
||||||
|
|
||||||
use super::super::alu::*;
|
use super::super::alu::*;
|
||||||
use crate::core::arm7tdmi::cpu::{Core, CpuExecResult};
|
|
||||||
use crate::core::arm7tdmi::psr::RegPSR;
|
use crate::core::arm7tdmi::psr::RegPSR;
|
||||||
use crate::core::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, REG_LR, REG_PC};
|
use crate::core::arm7tdmi::{Core, Addr, CpuMode, CpuState, REG_LR, REG_PC};
|
||||||
use crate::core::sysbus::SysBus;
|
use crate::core::sysbus::SysBus;
|
||||||
use crate::core::Bus;
|
use crate::core::Bus;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl Core {
|
impl Core {
|
||||||
pub fn exec_arm(&mut self, bus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
pub fn exec_arm(&mut self, bus: &mut SysBus, insn: ArmInstruction) {
|
||||||
if !self.check_arm_cond(insn.cond) {
|
if !self.check_arm_cond(insn.cond) {
|
||||||
self.S_cycle32(bus, self.pc);
|
self.S_cycle32(bus, self.pc);
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
match insn.fmt {
|
match insn.fmt {
|
||||||
ArmFormat::BX => self.exec_bx(bus, insn),
|
ArmFormat::BX => self.exec_bx(bus, insn),
|
||||||
|
@ -21,7 +20,6 @@ impl Core {
|
||||||
ArmFormat::DP => self.exec_data_processing(bus, insn),
|
ArmFormat::DP => self.exec_data_processing(bus, insn),
|
||||||
ArmFormat::SWI => {
|
ArmFormat::SWI => {
|
||||||
self.software_interrupt(bus, self.pc - 4, insn.swi_comment());
|
self.software_interrupt(bus, self.pc - 4, insn.swi_comment());
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
ArmFormat::LDR_STR => self.exec_ldr_str(bus, insn),
|
ArmFormat::LDR_STR => self.exec_ldr_str(bus, insn),
|
||||||
ArmFormat::LDR_STR_HS_IMM => self.exec_ldr_str_hs(bus, insn),
|
ArmFormat::LDR_STR_HS_IMM => self.exec_ldr_str_hs(bus, insn),
|
||||||
|
@ -37,7 +35,7 @@ impl Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cycles 2S+1N
|
/// Cycles 2S+1N
|
||||||
fn exec_b_bl(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_b_bl(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
self.S_cycle32(sb, self.pc);
|
self.S_cycle32(sb, self.pc);
|
||||||
if insn.link_flag() {
|
if insn.link_flag() {
|
||||||
self.set_reg(REG_LR, (insn.pc + (self.word_size() as u32)) & !0b1);
|
self.set_reg(REG_LR, (insn.pc + (self.word_size() as u32)) & !0b1);
|
||||||
|
@ -46,10 +44,9 @@ impl Core {
|
||||||
self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32 & !1;
|
self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32 & !1;
|
||||||
self.flush_pipeline32(sb);
|
self.flush_pipeline32(sb);
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn branch_exchange(&mut self, sb: &mut SysBus, mut addr: Addr) -> CpuExecResult {
|
pub fn branch_exchange(&mut self, sb: &mut SysBus, mut addr: Addr) {
|
||||||
match self.cpsr.state() {
|
match self.cpsr.state() {
|
||||||
CpuState::ARM => self.S_cycle32(sb, self.pc),
|
CpuState::ARM => self.S_cycle32(sb, self.pc),
|
||||||
CpuState::THUMB => self.S_cycle16(sb, self.pc),
|
CpuState::THUMB => self.S_cycle16(sb, self.pc),
|
||||||
|
@ -65,11 +62,10 @@ impl Core {
|
||||||
self.pc = addr;
|
self.pc = addr;
|
||||||
self.flush_pipeline32(sb); // +1S+1N
|
self.flush_pipeline32(sb); // +1S+1N
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cycles 2S+1N
|
/// Cycles 2S+1N
|
||||||
fn exec_bx(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_bx(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
self.branch_exchange(sb, self.get_reg(insn.rn()))
|
self.branch_exchange(sb, self.get_reg(insn.rn()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +74,7 @@ impl Core {
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
rd: usize,
|
rd: usize,
|
||||||
is_spsr: bool,
|
is_spsr: bool,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let result = if is_spsr {
|
let result = if is_spsr {
|
||||||
self.spsr.get()
|
self.spsr.get()
|
||||||
} else {
|
} else {
|
||||||
|
@ -86,10 +82,9 @@ impl Core {
|
||||||
};
|
};
|
||||||
self.set_reg(rd, result);
|
self.set_reg(rd, result);
|
||||||
self.S_cycle32(sb, self.pc);
|
self.S_cycle32(sb, self.pc);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_msr_reg(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_msr_reg(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
self.write_status_register(sb, insn.spsr_flag(), self.get_reg(insn.rm()))
|
self.write_status_register(sb, insn.spsr_flag(), self.get_reg(insn.rm()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +93,7 @@ impl Core {
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
is_spsr: bool,
|
is_spsr: bool,
|
||||||
value: u32,
|
value: u32,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let new_status_reg = RegPSR::new(value);
|
let new_status_reg = RegPSR::new(value);
|
||||||
match self.cpsr.mode() {
|
match self.cpsr.mode() {
|
||||||
CpuMode::User => {
|
CpuMode::User => {
|
||||||
|
@ -125,32 +120,27 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.S_cycle32(sb, self.pc);
|
self.S_cycle32(sb, self.pc);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_msr_flags(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_msr_flags(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
self.S_cycle32(sb, self.pc);
|
self.S_cycle32(sb, self.pc);
|
||||||
let op = insn.operand2()?;
|
let op = insn.operand2();
|
||||||
let op = self.decode_operand2(op)?;
|
let op = self.decode_operand2(op);
|
||||||
|
|
||||||
let old_mode = self.cpsr.mode();
|
|
||||||
if insn.spsr_flag() {
|
if insn.spsr_flag() {
|
||||||
self.spsr.set_flag_bits(op);
|
self.spsr.set_flag_bits(op);
|
||||||
} else {
|
} else {
|
||||||
self.cpsr.set_flag_bits(op);
|
self.cpsr.set_flag_bits(op);
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_operand2(&mut self, op2: BarrelShifterValue) -> CpuResult<u32> {
|
fn decode_operand2(&mut self, op2: BarrelShifterValue) -> u32 {
|
||||||
match op2 {
|
match op2 {
|
||||||
BarrelShifterValue::RotatedImmediate(val, amount) => {
|
BarrelShifterValue::RotatedImmediate(val, amount) => {
|
||||||
let result = self.ror(val, amount, self.cpsr.C(), false, true);
|
self.ror(val, amount, self.cpsr.C(), false, true)
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
BarrelShifterValue::ShiftedRegister(x) => {
|
BarrelShifterValue::ShiftedRegister(x) => {
|
||||||
let result = self.register_shift(x)?;
|
self.register_shift(x)
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -168,7 +158,7 @@ impl Core {
|
||||||
///
|
///
|
||||||
/// Cycles: 1S+x+y (from GBATEK)
|
/// Cycles: 1S+x+y (from GBATEK)
|
||||||
/// Add x=1I cycles if Op2 shifted-by-register. Add y=1S+1N cycles if Rd=R15.
|
/// Add x=1I cycles if Op2 shifted-by-register. Add y=1S+1N cycles if Rd=R15.
|
||||||
fn exec_data_processing(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_data_processing(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
use AluOpCode::*;
|
use AluOpCode::*;
|
||||||
|
|
||||||
self.S_cycle32(sb, self.pc);
|
self.S_cycle32(sb, self.pc);
|
||||||
|
@ -181,7 +171,7 @@ impl Core {
|
||||||
let mut s_flag = insn.set_cond_flag();
|
let mut s_flag = insn.set_cond_flag();
|
||||||
let opcode = insn.opcode().unwrap();
|
let opcode = insn.opcode().unwrap();
|
||||||
|
|
||||||
let op2 = insn.operand2()?;
|
let op2 = insn.operand2();
|
||||||
match op2 {
|
match op2 {
|
||||||
BarrelShifterValue::ShiftedRegister(shifted_reg) => {
|
BarrelShifterValue::ShiftedRegister(shifted_reg) => {
|
||||||
if insn.rn() == REG_PC && shifted_reg.is_shifted_by_reg() {
|
if insn.rn() == REG_PC && shifted_reg.is_shifted_by_reg() {
|
||||||
|
@ -190,7 +180,7 @@ impl Core {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let op2 = self.decode_operand2(op2)?;
|
let op2 = self.decode_operand2(op2);
|
||||||
|
|
||||||
let reg_rd = insn.rd();
|
let reg_rd = insn.rd();
|
||||||
if !s_flag {
|
if !s_flag {
|
||||||
|
@ -212,7 +202,7 @@ impl Core {
|
||||||
s_flag = false;
|
s_flag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let C = self.cpsr.C() as u32;
|
let carry = self.cpsr.C() as u32;
|
||||||
let alu_res = if s_flag {
|
let alu_res = if s_flag {
|
||||||
let mut carry = self.bs_carry_out;
|
let mut carry = self.bs_carry_out;
|
||||||
let mut overflow = self.cpsr.V();
|
let mut overflow = self.cpsr.V();
|
||||||
|
@ -245,9 +235,9 @@ impl Core {
|
||||||
SUB => op1.wrapping_sub(op2),
|
SUB => op1.wrapping_sub(op2),
|
||||||
RSB => op2.wrapping_sub(op1),
|
RSB => op2.wrapping_sub(op1),
|
||||||
ADD => op1.wrapping_add(op2),
|
ADD => op1.wrapping_add(op2),
|
||||||
ADC => op1.wrapping_add(op2).wrapping_add(C),
|
ADC => op1.wrapping_add(op2).wrapping_add(carry),
|
||||||
SBC => op1.wrapping_sub(op2.wrapping_add(1 - C)),
|
SBC => op1.wrapping_sub(op2.wrapping_add(1 - carry)),
|
||||||
RSC => op2.wrapping_sub(op1.wrapping_add(1 - C)),
|
RSC => op2.wrapping_sub(op1.wrapping_add(1 - carry)),
|
||||||
ORR => op1 | op2,
|
ORR => op1 | op2,
|
||||||
MOV => op2,
|
MOV => op2,
|
||||||
BIC => op1 & (!op2),
|
BIC => op1 & (!op2),
|
||||||
|
@ -263,7 +253,6 @@ impl Core {
|
||||||
self.set_reg(reg_rd, result as u32);
|
self.set_reg(reg_rd, result as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory Load/Store
|
/// Memory Load/Store
|
||||||
|
@ -273,7 +262,7 @@ impl Core {
|
||||||
/// STR{cond}{B}{T} Rd,<Address> | 2N | ---- | [Rn+/-<offset>]=Rd
|
/// STR{cond}{B}{T} Rd,<Address> | 2N | ---- | [Rn+/-<offset>]=Rd
|
||||||
/// ------------------------------------------------------------------------------
|
/// ------------------------------------------------------------------------------
|
||||||
/// 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) {
|
||||||
let load = insn.load_flag();
|
let load = insn.load_flag();
|
||||||
let pre_index = insn.pre_index_flag();
|
let pre_index = insn.pre_index_flag();
|
||||||
let writeback = insn.write_back_flag();
|
let writeback = insn.write_back_flag();
|
||||||
|
@ -344,10 +333,9 @@ impl Core {
|
||||||
self.change_mode(self.cpsr.mode(), old_mode);
|
self.change_mode(self.cpsr.mode(), old_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
let load = insn.load_flag();
|
let load = insn.load_flag();
|
||||||
let pre_index = insn.pre_index_flag();
|
let pre_index = insn.pre_index_flag();
|
||||||
let writeback = insn.write_back_flag();
|
let writeback = insn.write_back_flag();
|
||||||
|
@ -423,10 +411,9 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_ldm_stm(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_ldm_stm(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
let mut 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 s_flag = insn.raw.bit(22);
|
let s_flag = insn.raw.bit(22);
|
||||||
|
@ -569,19 +556,14 @@ impl Core {
|
||||||
self.set_reg(base_reg, addr as u32);
|
self.set_reg(base_reg, addr as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_mul_mla(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_mul_mla(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
let (rd, rn, rs, rm) = (insn.rd(), insn.rn(), insn.rs(), insn.rm());
|
let (rd, rn, rs, rm) = (insn.rd(), insn.rn(), insn.rs(), insn.rm());
|
||||||
|
|
||||||
// check validity
|
// check validity
|
||||||
if REG_PC == rd || REG_PC == rn || REG_PC == rs || REG_PC == rm {
|
assert!(!(REG_PC == rd || REG_PC == rn || REG_PC == rs || REG_PC == rm));
|
||||||
return Err(CpuError::IllegalInstruction);
|
assert!(rd != rm);
|
||||||
}
|
|
||||||
if rd == rm {
|
|
||||||
return Err(CpuError::IllegalInstruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
let op1 = self.get_reg(rm);
|
let op1 = self.get_reg(rm);
|
||||||
let op2 = self.get_reg(rs);
|
let op2 = self.get_reg(rs);
|
||||||
|
@ -607,20 +589,15 @@ impl Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.S_cycle32(sb, self.pc);
|
self.S_cycle32(sb, self.pc);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_mull_mlal(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_mull_mlal(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
let (rd_hi, rd_lo, rn, rs, rm) =
|
let (rd_hi, rd_lo, rn, rs, rm) =
|
||||||
(insn.rd_hi(), insn.rd_lo(), insn.rn(), insn.rs(), insn.rm());
|
(insn.rd_hi(), insn.rd_lo(), insn.rn(), insn.rs(), insn.rm());
|
||||||
|
|
||||||
// check validity
|
// check validity
|
||||||
if REG_PC == rd_hi || REG_PC == rd_lo || REG_PC == rn || REG_PC == rs || REG_PC == rm {
|
assert!(!(REG_PC == rd_hi || REG_PC == rd_lo || REG_PC == rn || REG_PC == rs || REG_PC == rm));
|
||||||
return Err(CpuError::IllegalInstruction);
|
assert!(!(rd_hi != rd_hi && rd_hi != rm && rd_lo != rm));
|
||||||
}
|
|
||||||
if rd_hi != rd_hi && rd_hi != rm && rd_lo != rm {
|
|
||||||
return Err(CpuError::IllegalInstruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
let op1 = self.get_reg(rm);
|
let op1 = self.get_reg(rm);
|
||||||
let op2 = self.get_reg(rs);
|
let op2 = self.get_reg(rs);
|
||||||
|
@ -655,10 +632,9 @@ impl Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.S_cycle32(sb, self.pc);
|
self.S_cycle32(sb, self.pc);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_arm_swp(&mut self, sb: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
fn exec_arm_swp(&mut self, sb: &mut SysBus, insn: ArmInstruction) {
|
||||||
let base_addr = self.get_reg(insn.rn());
|
let base_addr = self.get_reg(insn.rn());
|
||||||
self.add_cycle();
|
self.add_cycle();
|
||||||
if insn.transfer_size() == 1 {
|
if insn.transfer_size() == 1 {
|
||||||
|
@ -675,6 +651,5 @@ impl Core {
|
||||||
self.set_reg(insn.rd(), t as u32);
|
self.set_reg(insn.rd(), t as u32);
|
||||||
}
|
}
|
||||||
self.N_cycle32(sb, self.pc);
|
self.N_cycle32(sb, self.pc);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,12 +338,12 @@ impl ArmInstruction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operand2(&self) -> Result<BarrelShifterValue, ArmDecodeError> {
|
pub fn operand2(&self) -> BarrelShifterValue {
|
||||||
let op2 = self.raw.bit_range(0..12);
|
let op2 = self.raw.bit_range(0..12);
|
||||||
if self.raw.bit(25) {
|
if self.raw.bit(25) {
|
||||||
let immediate = op2 & 0xff;
|
let immediate = op2 & 0xff;
|
||||||
let rotate = 2 * op2.bit_range(8..12);
|
let rotate = 2 * op2.bit_range(8..12);
|
||||||
Ok(BarrelShifterValue::RotatedImmediate(immediate, rotate))
|
BarrelShifterValue::RotatedImmediate(immediate, rotate)
|
||||||
} else {
|
} else {
|
||||||
let reg = op2 & 0xf;
|
let reg = op2 & 0xf;
|
||||||
let shifted_reg = ShiftedRegister {
|
let shifted_reg = ShiftedRegister {
|
||||||
|
@ -352,7 +352,7 @@ impl ArmInstruction {
|
||||||
shift_by: self.get_shift_reg_by(op2),
|
shift_by: self.get_shift_reg_by(op2),
|
||||||
added: None,
|
added: None,
|
||||||
}; // TODO error handling
|
}; // TODO error handling
|
||||||
Ok(BarrelShifterValue::ShiftedRegister(shifted_reg))
|
BarrelShifterValue::ShiftedRegister(shifted_reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
use ansi_term::{Colour, Style};
|
use ansi_term::{Colour, Style};
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
|
use super::reg_string;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub use super::exception::Exception;
|
pub use super::exception::Exception;
|
||||||
use super::{
|
use super::{
|
||||||
arm::*, psr::RegPSR, reg_string, thumb::ThumbInstruction, Addr, CpuMode, CpuResult, CpuState,
|
arm::*, psr::RegPSR, thumb::ThumbInstruction, Addr, CpuMode, CpuResult, CpuState,
|
||||||
DecodedInstruction, InstructionDecoder,
|
DecodedInstruction, InstructionDecoder,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::core::bus::Bus;
|
use crate::core::bus::Bus;
|
||||||
use crate::core::sysbus::{
|
use crate::core::sysbus::{
|
||||||
MemoryAccess, MemoryAccessType, MemoryAccessType::*, MemoryAccessWidth::*, SysBus,
|
MemoryAccessType::*, MemoryAccessWidth::*, SysBus,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
|
||||||
|
@ -67,7 +70,7 @@ pub type CpuExecResult = CpuResult<()>;
|
||||||
|
|
||||||
impl Core {
|
impl Core {
|
||||||
pub fn new() -> Core {
|
pub fn new() -> Core {
|
||||||
let mut cpsr = RegPSR::new(0x0000_00D3);
|
let cpsr = RegPSR::new(0x0000_00D3);
|
||||||
Core {
|
Core {
|
||||||
memreq: 0xffff_0000, // set memreq to an invalid addr so the first load cycle will be non-sequential
|
memreq: 0xffff_0000, // set memreq to an invalid addr so the first load cycle will be non-sequential
|
||||||
cpsr: cpsr,
|
cpsr: cpsr,
|
||||||
|
@ -105,7 +108,7 @@ impl Core {
|
||||||
|
|
||||||
pub fn set_reg(&mut self, r: usize, val: u32) {
|
pub fn set_reg(&mut self, r: usize, val: u32) {
|
||||||
match r {
|
match r {
|
||||||
0...14 => self.gpr[r] = val,
|
0..=14 => self.gpr[r] = val,
|
||||||
15 => {
|
15 => {
|
||||||
self.pc = {
|
self.pc = {
|
||||||
match self.cpsr.state() {
|
match self.cpsr.state() {
|
||||||
|
@ -236,20 +239,6 @@ impl Core {
|
||||||
self.cycles += 1;
|
self.cycles += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn add_cycles(&mut self, addr: Addr, bus: &SysBus, access: MemoryAccess) {
|
|
||||||
let cycles_to_add = 1 + bus.get_cycles(addr, access);
|
|
||||||
// println!("<cycle {:#x} {}> took: {}", addr, access, cycles_to_add);
|
|
||||||
self.cycles += cycles_to_add;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn cycle_type(&self, addr: Addr) -> MemoryAccessType {
|
|
||||||
if addr == self.memreq || addr == self.memreq.wrapping_add(self.word_size() as Addr) {
|
|
||||||
Seq
|
|
||||||
} else {
|
|
||||||
NonSeq
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn get_required_multipiler_array_cycles(&self, rs: u32) -> usize {
|
pub(super) fn get_required_multipiler_array_cycles(&self, rs: u32) -> usize {
|
||||||
if rs & 0xff == rs {
|
if rs & 0xff == rs {
|
||||||
1
|
1
|
||||||
|
@ -323,7 +312,7 @@ impl Core {
|
||||||
self.pipeline_state != PipelineState::Execute
|
self.pipeline_state != PipelineState::Execute
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step_arm_exec(&mut self, insn: u32, sb: &mut SysBus) -> CpuResult<()> {
|
fn step_arm_exec(&mut self, insn: u32, sb: &mut SysBus) {
|
||||||
let pc = self.pc;
|
let pc = self.pc;
|
||||||
match self.pipeline_state {
|
match self.pipeline_state {
|
||||||
PipelineState::Refill1 => {
|
PipelineState::Refill1 => {
|
||||||
|
@ -337,19 +326,21 @@ impl Core {
|
||||||
self.last_executed = None;
|
self.last_executed = None;
|
||||||
}
|
}
|
||||||
PipelineState::Execute => {
|
PipelineState::Execute => {
|
||||||
let decoded_arm = ArmInstruction::decode(insn, self.pc.wrapping_sub(8))?;
|
let decoded_arm = ArmInstruction::decode(insn, self.pc.wrapping_sub(8)).unwrap();
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
|
{
|
||||||
self.gpr_previous = self.get_registers();
|
self.gpr_previous = self.get_registers();
|
||||||
self.exec_arm(sb, decoded_arm)?;
|
}
|
||||||
|
self.exec_arm(sb, decoded_arm);
|
||||||
if !self.did_pipeline_flush() {
|
if !self.did_pipeline_flush() {
|
||||||
self.pc = pc.wrapping_add(4);
|
self.pc = pc.wrapping_add(4);
|
||||||
}
|
}
|
||||||
self.last_executed = Some(DecodedInstruction::Arm(decoded_arm));
|
self.last_executed = Some(DecodedInstruction::Arm(decoded_arm));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step_thumb_exec(&mut self, insn: u16, sb: &mut SysBus) -> CpuResult<()> {
|
fn step_thumb_exec(&mut self, insn: u16, sb: &mut SysBus) {
|
||||||
let pc = self.pc;
|
let pc = self.pc;
|
||||||
match self.pipeline_state {
|
match self.pipeline_state {
|
||||||
PipelineState::Refill1 => {
|
PipelineState::Refill1 => {
|
||||||
|
@ -363,16 +354,18 @@ impl Core {
|
||||||
self.last_executed = None;
|
self.last_executed = None;
|
||||||
}
|
}
|
||||||
PipelineState::Execute => {
|
PipelineState::Execute => {
|
||||||
let decoded_thumb = ThumbInstruction::decode(insn, self.pc.wrapping_sub(4))?;
|
let decoded_thumb = ThumbInstruction::decode(insn, self.pc.wrapping_sub(4)).unwrap();
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
|
{
|
||||||
self.gpr_previous = self.get_registers();
|
self.gpr_previous = self.get_registers();
|
||||||
self.exec_thumb(sb, decoded_thumb)?;
|
}
|
||||||
|
self.exec_thumb(sb, decoded_thumb);
|
||||||
if !self.did_pipeline_flush() {
|
if !self.did_pipeline_flush() {
|
||||||
self.pc = pc.wrapping_add(2);
|
self.pc = pc.wrapping_add(2);
|
||||||
}
|
}
|
||||||
self.last_executed = Some(DecodedInstruction::Thumb(decoded_thumb));
|
self.last_executed = Some(DecodedInstruction::Thumb(decoded_thumb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn flush_pipeline16(&mut self, sb: &mut SysBus) {
|
pub(super) fn flush_pipeline16(&mut self, sb: &mut SysBus) {
|
||||||
|
@ -387,41 +380,43 @@ impl Core {
|
||||||
self.S_cycle32(sb, self.pc + 4);
|
self.S_cycle32(sb, self.pc + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_opcode(&self, insn: u32) {
|
// fn trace_opcode(&self, insn: u32) {
|
||||||
if self.trace_opcodes && self.pipeline_state == PipelineState::Execute {
|
// if self.trace_opcodes && self.pipeline_state == PipelineState::Execute {
|
||||||
print!("[{:08X}] PC=0x{:08x} | ", insn, self.pc);
|
// println!("[{:08X}] PC=0x{:08x} | ", insn, self.pc);
|
||||||
for r in 0..15 {
|
// for r in 0..15 {
|
||||||
print!("R{}=0x{:08x} ", r, self.gpr[r]);
|
// println!("R{}=0x{:08x} ", r, self.gpr[r]);
|
||||||
}
|
// }
|
||||||
print!(
|
// println!(
|
||||||
" N={} Z={} C={} V={} T={}\n",
|
// " N={} Z={} C={} V={} T={}\n",
|
||||||
self.cpsr.N() as u8,
|
// self.cpsr.N() as u8,
|
||||||
self.cpsr.Z() as u8,
|
// self.cpsr.Z() as u8,
|
||||||
self.cpsr.C() as u8,
|
// self.cpsr.C() as u8,
|
||||||
self.cpsr.V() as u8,
|
// self.cpsr.V() as u8,
|
||||||
self.cpsr.state() as u8,
|
// self.cpsr.state() as u8,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Perform a pipeline step
|
/// Perform a pipeline step
|
||||||
/// If an instruction was executed in this step, return it.
|
/// If an instruction was executed in this step, return it.
|
||||||
pub fn step(&mut self, bus: &mut SysBus) -> CpuResult<()> {
|
pub fn step(&mut self, bus: &mut SysBus) {
|
||||||
let pc = self.pc;
|
let pc = self.pc;
|
||||||
|
|
||||||
let fetched_now = match self.cpsr.state() {
|
match self.cpsr.state() {
|
||||||
CpuState::ARM => bus.read_32(pc),
|
CpuState::ARM => {
|
||||||
CpuState::THUMB => bus.read_16(pc) as u32,
|
let fetched_now = bus.read_32(pc);
|
||||||
};
|
|
||||||
|
|
||||||
let insn = self.pipeline[0];
|
let insn = self.pipeline[0];
|
||||||
self.pipeline[0] = self.pipeline[1];
|
self.pipeline[0] = self.pipeline[1];
|
||||||
self.pipeline[1] = fetched_now;
|
self.pipeline[1] = fetched_now;
|
||||||
|
self.step_arm_exec(insn, bus)
|
||||||
self.trace_opcode(insn.into());
|
}
|
||||||
|
CpuState::THUMB => {
|
||||||
match self.cpsr.state() {
|
let fetched_now = bus.read_16(pc);
|
||||||
CpuState::ARM => self.step_arm_exec(insn, bus),
|
let insn = self.pipeline[0];
|
||||||
CpuState::THUMB => self.step_thumb_exec(insn as u16, bus),
|
self.pipeline[0] = self.pipeline[1];
|
||||||
|
self.pipeline[1] = fetched_now as u32;
|
||||||
|
self.step_thumb_exec(insn as u16, bus)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,23 +430,6 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A step that returns only once an instruction was executed.
|
|
||||||
/// Returns the address of PC before executing an instruction,
|
|
||||||
/// and the address of the next instruction to be executed;
|
|
||||||
pub fn step_one(&mut self, bus: &mut SysBus) -> CpuResult<DecodedInstruction> {
|
|
||||||
loop {
|
|
||||||
match self.pipeline_state {
|
|
||||||
PipelineState::Execute => {
|
|
||||||
self.step(bus)?;
|
|
||||||
return Ok(self.last_executed.unwrap());
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.step(bus)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_cpu_state(&self) -> CpuState {
|
pub fn get_cpu_state(&self) -> CpuState {
|
||||||
self.cpsr.state()
|
self.cpsr.state()
|
||||||
}
|
}
|
||||||
|
@ -471,6 +449,7 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
impl fmt::Display for Core {
|
impl fmt::Display for Core {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
writeln!(f, "ARM7TDMI Core Status:")?;
|
writeln!(f, "ARM7TDMI Core Status:")?;
|
||||||
|
|
|
@ -69,19 +69,11 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn software_interrupt(&mut self, sb: &mut SysBus, lr: u32, cmt: u32) {
|
pub fn software_interrupt(&mut self, sb: &mut SysBus, lr: u32, _cmt: u32) {
|
||||||
match self.cpsr.state() {
|
match self.cpsr.state() {
|
||||||
CpuState::ARM => self.N_cycle32(sb, self.pc),
|
CpuState::ARM => self.N_cycle32(sb, self.pc),
|
||||||
CpuState::THUMB => self.N_cycle16(sb, self.pc),
|
CpuState::THUMB => self.N_cycle16(sb, self.pc),
|
||||||
};
|
};
|
||||||
if cmt == 0x55 {
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
println!("Special breakpoint detected!");
|
|
||||||
host_breakpoint!();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.exception(sb, Exception::SoftwareInterrupt, lr);
|
self.exception(sb, Exception::SoftwareInterrupt, lr);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,13 @@ pub mod alu;
|
||||||
pub use alu::*;
|
pub use alu::*;
|
||||||
pub mod exception;
|
pub mod exception;
|
||||||
pub mod psr;
|
pub mod psr;
|
||||||
|
pub use psr::*;
|
||||||
|
|
||||||
pub const REG_PC: usize = 15;
|
pub const REG_PC: usize = 15;
|
||||||
pub const REG_LR: usize = 14;
|
pub const REG_LR: usize = 14;
|
||||||
pub const REG_SP: usize = 13;
|
pub const REG_SP: usize = 13;
|
||||||
|
|
||||||
pub(self) use crate::core::{Addr, Bus};
|
pub(self) use crate::core::Addr;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)]
|
||||||
pub enum DecodedInstruction {
|
pub enum DecodedInstruction {
|
||||||
|
@ -36,6 +37,8 @@ impl DecodedInstruction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
impl fmt::Display for DecodedInstruction {
|
impl fmt::Display for DecodedInstruction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -64,7 +67,7 @@ impl From<ThumbDecodeError> for InstructionDecoderError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait InstructionDecoder: Sized + fmt::Display {
|
pub trait InstructionDecoder: Sized {
|
||||||
type IntType: Num;
|
type IntType: Num;
|
||||||
|
|
||||||
fn decode(n: Self::IntType, addr: Addr) -> Result<Self, InstructionDecoderError>;
|
fn decode(n: Self::IntType, addr: Addr) -> Result<Self, InstructionDecoderError>;
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
use crate::bit::BitIndex;
|
use crate::bit::BitIndex;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
use crate::core::arm7tdmi::*;
|
use crate::core::arm7tdmi::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
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!(
|
||||||
|
@ -268,6 +271,7 @@ impl ThumbInstruction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debugger")]
|
||||||
impl fmt::Display for ThumbInstruction {
|
impl fmt::Display for ThumbInstruction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.fmt {
|
match self.fmt {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::core::arm7tdmi::cpu::{Core, CpuExecResult};
|
|
||||||
use crate::core::arm7tdmi::*;
|
use crate::core::arm7tdmi::*;
|
||||||
use crate::core::sysbus::SysBus;
|
use crate::core::sysbus::SysBus;
|
||||||
use crate::core::Bus;
|
use crate::core::Bus;
|
||||||
|
@ -18,31 +17,26 @@ fn pop(cpu: &mut Core, bus: &mut SysBus, r: usize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Core {
|
impl Core {
|
||||||
|
/// Format 1
|
||||||
fn exec_thumb_move_shifted_reg(
|
fn exec_thumb_move_shifted_reg(
|
||||||
&mut self,
|
&mut self,
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let rd = (insn.raw & 0b111) as usize;
|
let rd = (insn.raw & 0b111) as usize;
|
||||||
let rs = insn.raw.bit_range(3..6) as usize;
|
let rs = insn.raw.bit_range(3..6) as usize;
|
||||||
|
|
||||||
let op2 = self
|
|
||||||
.register_shift(ShiftedRegister {
|
|
||||||
reg: rs,
|
|
||||||
shift_by: ShiftRegisterBy::ByAmount(insn.offset5() as u8 as u32),
|
|
||||||
bs_op: insn.format1_op(),
|
|
||||||
added: None,
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
self.set_reg(rd, op2);
|
let shift_amount = insn.offset5() as u8 as u32;
|
||||||
|
let op2 = self.barrel_shift_op(insn.format1_op(), self.gpr[rs], shift_amount, self.cpsr.C(), true);
|
||||||
|
self.gpr[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);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_add_sub(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 2
|
||||||
|
fn exec_thumb_add_sub(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
let rd = (insn.raw & 0b111) as usize;
|
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() {
|
||||||
|
@ -62,14 +56,14 @@ impl Core {
|
||||||
self.set_reg(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(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format 3
|
||||||
fn exec_thumb_data_process_imm(
|
fn exec_thumb_data_process_imm(
|
||||||
&mut self,
|
&mut self,
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
use OpFormat3::*;
|
use OpFormat3::*;
|
||||||
let op = insn.format3_op();
|
let op = insn.format3_op();
|
||||||
let rd = insn.raw.bit_range(8..11) as usize;
|
let rd = insn.raw.bit_range(8..11) as usize;
|
||||||
|
@ -88,17 +82,16 @@ impl Core {
|
||||||
self.gpr[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(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_alu_ops(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 4
|
||||||
|
fn exec_thumb_alu_ops(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
let rd = (insn.raw & 0b111) as usize;
|
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);
|
||||||
|
|
||||||
let mut carry = self.cpsr.C();
|
let mut carry = self.cpsr.C();
|
||||||
let c = self.cpsr.C() as u32;
|
|
||||||
let mut overflow = self.cpsr.V();
|
let mut overflow = self.cpsr.V();
|
||||||
|
|
||||||
use ThumbAluOps::*;
|
use ThumbAluOps::*;
|
||||||
|
@ -115,13 +108,7 @@ impl Core {
|
||||||
ROR => BarrelShiftOpCode::ROR,
|
ROR => BarrelShiftOpCode::ROR,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let shft = BarrelShifterValue::shifted_register(
|
let result = self.shift_by_register(bs_op, rd, rs, carry);
|
||||||
rd,
|
|
||||||
ShiftRegisterBy::ByRegister(rs),
|
|
||||||
bs_op,
|
|
||||||
Some(true),
|
|
||||||
);
|
|
||||||
let result = self.get_barrel_shifted_value(shft);
|
|
||||||
carry = self.bs_carry_out;
|
carry = self.bs_carry_out;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -150,24 +137,14 @@ impl Core {
|
||||||
self.set_reg(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(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cycles 2S+1N
|
|
||||||
fn exec_thumb_bx(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
|
||||||
let src_reg = if insn.flag(ThumbInstruction::FLAG_H2) {
|
|
||||||
insn.rs() + 8
|
|
||||||
} else {
|
|
||||||
insn.rs()
|
|
||||||
};
|
|
||||||
self.branch_exchange(sb, self.get_reg(src_reg))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format 5
|
||||||
fn exec_thumb_hi_reg_op_or_bx(
|
fn exec_thumb_hi_reg_op_or_bx(
|
||||||
&mut self,
|
&mut self,
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let op = insn.format5_op();
|
let op = insn.format5_op();
|
||||||
let rd = (insn.raw & 0b111) as usize;
|
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) {
|
||||||
|
@ -184,7 +161,10 @@ impl Core {
|
||||||
let op2 = self.get_reg(src_reg);
|
let op2 = self.get_reg(src_reg);
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
OpFormat5::BX => return self.exec_thumb_bx(sb, insn),
|
OpFormat5::BX => {
|
||||||
|
self.branch_exchange(sb, self.get_reg(src_reg));
|
||||||
|
return;
|
||||||
|
},
|
||||||
OpFormat5::ADD => {
|
OpFormat5::ADD => {
|
||||||
self.set_reg(dst_reg, op1.wrapping_add(op2));
|
self.set_reg(dst_reg, op1.wrapping_add(op2));
|
||||||
if dst_reg == REG_PC {
|
if dst_reg == REG_PC {
|
||||||
|
@ -205,10 +185,10 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.S_cycle16(sb, self.pc + 2);
|
self.S_cycle16(sb, self.pc + 2);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_ldr_pc(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 6
|
||||||
|
fn exec_thumb_ldr_pc(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
let rd = insn.raw.bit_range(8..11) as usize;
|
let rd = insn.raw.bit_range(8..11) as usize;
|
||||||
|
|
||||||
let ofs = insn.word8() as Addr;
|
let ofs = insn.word8() as Addr;
|
||||||
|
@ -223,7 +203,6 @@ impl Core {
|
||||||
// +1I
|
// +1I
|
||||||
self.add_cycle();
|
self.add_cycle();
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_exec_thumb_ldr_str(
|
fn do_exec_thumb_ldr_str(
|
||||||
|
@ -232,7 +211,7 @@ impl Core {
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
addr: Addr,
|
addr: Addr,
|
||||||
is_transferring_bytes: bool,
|
is_transferring_bytes: bool,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let rd = (insn.raw & 0b111) as usize;
|
let rd = (insn.raw & 0b111) as usize;
|
||||||
if insn.is_load() {
|
if insn.is_load() {
|
||||||
let data = if is_transferring_bytes {
|
let data = if is_transferring_bytes {
|
||||||
|
@ -259,20 +238,21 @@ impl Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.N_cycle16(sb, self.pc + 2);
|
self.N_cycle16(sb, self.pc + 2);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format 7
|
||||||
fn exec_thumb_ldr_str_reg_offset(
|
fn exec_thumb_ldr_str_reg_offset(
|
||||||
&mut self,
|
&mut self,
|
||||||
bus: &mut SysBus,
|
bus: &mut SysBus,
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let rb = insn.raw.bit_range(3..6) as usize;
|
let rb = insn.raw.bit_range(3..6) as usize;
|
||||||
let addr = self.gpr[rb].wrapping_add(self.gpr[insn.ro()]);
|
let addr = self.gpr[rb].wrapping_add(self.gpr[insn.ro()]);
|
||||||
self.do_exec_thumb_ldr_str(bus, insn, addr, insn.raw.bit(10))
|
self.do_exec_thumb_ldr_str(bus, insn, addr, insn.raw.bit(10))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_ldr_str_shb(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 8
|
||||||
|
fn exec_thumb_ldr_str_shb(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
let rb = insn.raw.bit_range(3..6) as usize;
|
let rb = insn.raw.bit_range(3..6) as usize;
|
||||||
let rd = (insn.raw & 0b111) as usize;
|
let rd = (insn.raw & 0b111) as usize;
|
||||||
|
|
||||||
|
@ -313,14 +293,14 @@ impl Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.N_cycle16(sb, self.pc + 2);
|
self.N_cycle16(sb, self.pc + 2);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format 9
|
||||||
fn exec_thumb_ldr_str_imm_offset(
|
fn exec_thumb_ldr_str_imm_offset(
|
||||||
&mut self,
|
&mut self,
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let rb = insn.raw.bit_range(3..6) as usize;
|
let rb = insn.raw.bit_range(3..6) as usize;
|
||||||
|
|
||||||
let offset = if insn.raw.bit(12) {
|
let offset = if insn.raw.bit(12) {
|
||||||
|
@ -332,11 +312,12 @@ impl Core {
|
||||||
self.do_exec_thumb_ldr_str(sb, insn, addr, insn.raw.bit(12))
|
self.do_exec_thumb_ldr_str(sb, insn, addr, insn.raw.bit(12))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format 10
|
||||||
fn exec_thumb_ldr_str_halfword(
|
fn exec_thumb_ldr_str_halfword(
|
||||||
&mut self,
|
&mut self,
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let rb = insn.raw.bit_range(3..6) as usize;
|
let rb = insn.raw.bit_range(3..6) as usize;
|
||||||
let rd = (insn.raw & 0b111) as usize;
|
let rd = (insn.raw & 0b111) as usize;
|
||||||
let base = self.gpr[rb] as i32;
|
let base = self.gpr[rb] as i32;
|
||||||
|
@ -351,37 +332,12 @@ impl Core {
|
||||||
self.N_cycle16(sb, addr);
|
self.N_cycle16(sb, addr);
|
||||||
}
|
}
|
||||||
self.N_cycle16(sb, self.pc + 2);
|
self.N_cycle16(sb, self.pc + 2);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_ldr_str_sp(&mut self, bus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 11
|
||||||
|
fn exec_thumb_ldr_str_sp(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
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, insn.raw.bit_range(8..11) as usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exec_thumb_load_address(
|
|
||||||
&mut self,
|
|
||||||
sb: &mut SysBus,
|
|
||||||
insn: ThumbInstruction,
|
|
||||||
) -> CpuExecResult {
|
|
||||||
let rd = insn.raw.bit_range(8..11) as usize;
|
let rd = insn.raw.bit_range(8..11) as usize;
|
||||||
let result = if insn.flag(ThumbInstruction::FLAG_SP) {
|
|
||||||
self.gpr[REG_SP] + (insn.word8() as Addr)
|
|
||||||
} else {
|
|
||||||
(insn.pc & !0b10) + 4 + (insn.word8() as Addr)
|
|
||||||
};
|
|
||||||
self.gpr[rd] = result;
|
|
||||||
self.S_cycle16(sb, self.pc + 2);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_exec_thumb_ldr_str_with_addr(
|
|
||||||
&mut self,
|
|
||||||
sb: &mut SysBus,
|
|
||||||
insn: ThumbInstruction,
|
|
||||||
addr: Addr,
|
|
||||||
rd: usize,
|
|
||||||
) -> 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);
|
||||||
|
@ -392,19 +348,35 @@ impl Core {
|
||||||
self.N_cycle16(sb, addr);
|
self.N_cycle16(sb, addr);
|
||||||
}
|
}
|
||||||
self.N_cycle16(sb, self.pc + 2);
|
self.N_cycle16(sb, self.pc + 2);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_add_sp(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 12
|
||||||
|
fn exec_thumb_load_address(
|
||||||
|
&mut self,
|
||||||
|
sb: &mut SysBus,
|
||||||
|
insn: ThumbInstruction,
|
||||||
|
) {
|
||||||
|
let rd = insn.raw.bit_range(8..11) as usize;
|
||||||
|
let result = if insn.flag(ThumbInstruction::FLAG_SP) {
|
||||||
|
self.gpr[REG_SP] + (insn.word8() as Addr)
|
||||||
|
} else {
|
||||||
|
(insn.pc & !0b10) + 4 + (insn.word8() as Addr)
|
||||||
|
};
|
||||||
|
self.gpr[rd] = result;
|
||||||
|
self.S_cycle16(sb, self.pc + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format 13
|
||||||
|
fn exec_thumb_add_sp(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
let op1 = self.gpr[REG_SP] as i32;
|
let op1 = self.gpr[REG_SP] as i32;
|
||||||
let op2 = insn.sword7();
|
let op2 = insn.sword7();
|
||||||
|
|
||||||
self.gpr[REG_SP] = op1.wrapping_add(op2) as u32;
|
self.gpr[REG_SP] = op1.wrapping_add(op2) as u32;
|
||||||
self.S_cycle16(sb, self.pc + 2);
|
self.S_cycle16(sb, self.pc + 2);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_push_pop(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 14
|
||||||
|
fn exec_thumb_push_pop(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
// (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 is_pop = insn.is_load();
|
let is_pop = insn.is_load();
|
||||||
let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R);
|
let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R);
|
||||||
|
@ -445,10 +417,10 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_ldm_stm(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 15
|
||||||
|
fn exec_thumb_ldm_stm(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
// (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 rb = insn.raw.bit_range(8..11) as usize;
|
||||||
|
@ -518,39 +490,48 @@ impl Core {
|
||||||
self.gpr[base_reg] = addr + align_preserve;
|
self.gpr[base_reg] = addr + align_preserve;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format 16
|
||||||
fn exec_thumb_branch_with_cond(
|
fn exec_thumb_branch_with_cond(
|
||||||
&mut self,
|
&mut self,
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
if !self.check_arm_cond(insn.cond()) {
|
if !self.check_arm_cond(insn.cond()) {
|
||||||
self.S_cycle16(sb, self.pc + 2);
|
self.S_cycle16(sb, self.pc + 2);
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
let offset = insn.bcond_offset();
|
let offset = insn.bcond_offset();
|
||||||
self.S_cycle16(sb, self.pc);
|
self.S_cycle16(sb, self.pc);
|
||||||
self.pc = (self.pc as i32).wrapping_add(offset) as u32;
|
self.pc = (self.pc as i32).wrapping_add(offset) as u32;
|
||||||
self.flush_pipeline16(sb);
|
self.flush_pipeline16(sb);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_thumb_branch(&mut self, sb: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
/// Format 17
|
||||||
|
fn exec_thumb_swi(
|
||||||
|
&mut self,
|
||||||
|
sb: &mut SysBus,
|
||||||
|
_insn: ThumbInstruction,
|
||||||
|
) {
|
||||||
|
self.N_cycle16(sb, self.pc);
|
||||||
|
self.exception(sb, Exception::SoftwareInterrupt, self.pc - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format 18
|
||||||
|
fn exec_thumb_branch(&mut self, sb: &mut SysBus, insn: ThumbInstruction) {
|
||||||
let offset = ((insn.offset11() << 21) >> 20) as i32;
|
let offset = ((insn.offset11() << 21) >> 20) as i32;
|
||||||
self.pc = (self.pc as i32).wrapping_add(offset) as u32;
|
self.pc = (self.pc as i32).wrapping_add(offset) as u32;
|
||||||
self.S_cycle16(sb, self.pc);
|
self.S_cycle16(sb, self.pc);
|
||||||
self.flush_pipeline16(sb);
|
self.flush_pipeline16(sb);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format 19
|
||||||
fn exec_thumb_branch_long_with_link(
|
fn exec_thumb_branch_long_with_link(
|
||||||
&mut self,
|
&mut self,
|
||||||
sb: &mut SysBus,
|
sb: &mut SysBus,
|
||||||
insn: ThumbInstruction,
|
insn: ThumbInstruction,
|
||||||
) -> CpuExecResult {
|
) {
|
||||||
let mut off = insn.offset11();
|
let mut off = insn.offset11();
|
||||||
if insn.flag(ThumbInstruction::FLAG_LOW_OFFSET) {
|
if insn.flag(ThumbInstruction::FLAG_LOW_OFFSET) {
|
||||||
self.S_cycle16(sb, self.pc);
|
self.S_cycle16(sb, self.pc);
|
||||||
|
@ -560,16 +541,14 @@ impl Core {
|
||||||
self.gpr[REG_LR] = next_pc;
|
self.gpr[REG_LR] = next_pc;
|
||||||
|
|
||||||
self.flush_pipeline16(sb);
|
self.flush_pipeline16(sb);
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
off = (off << 21) >> 9;
|
off = (off << 21) >> 9;
|
||||||
self.gpr[REG_LR] = (self.pc as i32).wrapping_add(off) as u32;
|
self.gpr[REG_LR] = (self.pc as i32).wrapping_add(off) as u32;
|
||||||
self.S_cycle16(sb, self.pc);
|
self.S_cycle16(sb, self.pc);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec_thumb(&mut self, bus: &mut SysBus, insn: ThumbInstruction) -> CpuExecResult {
|
pub fn exec_thumb(&mut self, bus: &mut SysBus, insn: ThumbInstruction) {
|
||||||
match insn.fmt {
|
match insn.fmt {
|
||||||
ThumbFormat::MoveShiftedReg => self.exec_thumb_move_shifted_reg(bus, insn),
|
ThumbFormat::MoveShiftedReg => self.exec_thumb_move_shifted_reg(bus, insn),
|
||||||
ThumbFormat::AddSub => self.exec_thumb_add_sub(bus, insn),
|
ThumbFormat::AddSub => self.exec_thumb_add_sub(bus, insn),
|
||||||
|
@ -587,10 +566,7 @@ impl Core {
|
||||||
ThumbFormat::PushPop => self.exec_thumb_push_pop(bus, insn),
|
ThumbFormat::PushPop => self.exec_thumb_push_pop(bus, insn),
|
||||||
ThumbFormat::LdmStm => self.exec_thumb_ldm_stm(bus, insn),
|
ThumbFormat::LdmStm => self.exec_thumb_ldm_stm(bus, insn),
|
||||||
ThumbFormat::BranchConditional => self.exec_thumb_branch_with_cond(bus, insn),
|
ThumbFormat::BranchConditional => self.exec_thumb_branch_with_cond(bus, insn),
|
||||||
ThumbFormat::Swi => {
|
ThumbFormat::Swi => self.exec_thumb_swi(bus, insn),
|
||||||
self.software_interrupt(bus, self.pc - 2, (insn.raw & 0xff) as u32);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
ThumbFormat::Branch => self.exec_thumb_branch(bus, insn),
|
ThumbFormat::Branch => self.exec_thumb_branch(bus, insn),
|
||||||
ThumbFormat::BranchLongWithLink => self.exec_thumb_branch_long_with_link(bus, insn),
|
ThumbFormat::BranchLongWithLink => self.exec_thumb_branch_long_with_link(bus, insn),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use super::core::arm7tdmi::{InstructionDecoder, InstructionDecoderError};
|
use super::core::arm7tdmi::{InstructionDecoder, InstructionDecoderError};
|
||||||
|
@ -32,7 +33,7 @@ where
|
||||||
|
|
||||||
impl<'a, D> Iterator for Disassembler<'a, D>
|
impl<'a, D> Iterator for Disassembler<'a, D>
|
||||||
where
|
where
|
||||||
D: InstructionDecoder,
|
D: InstructionDecoder + fmt::Display,
|
||||||
<D as InstructionDecoder>::IntType: std::fmt::LowerHex,
|
<D as InstructionDecoder>::IntType: std::fmt::LowerHex,
|
||||||
{
|
{
|
||||||
type Item = (Addr, String);
|
type Item = (Addr, String);
|
||||||
|
|
Reference in a new issue