2019-06-25 11:28:02 +01:00
|
|
|
use super::super::cpu::{Core, CpuState, CpuPipelineAction, CpuError, CpuInstruction, CpuResult, CpuExecResult};
|
2019-06-25 03:35:52 +01:00
|
|
|
use super::super::sysbus::SysBus;
|
|
|
|
use super::{ArmInstruction, ArmInstructionFormat};
|
|
|
|
|
2019-06-25 11:28:02 +01:00
|
|
|
use crate::bit::BitIndex;
|
|
|
|
|
2019-06-25 03:35:52 +01:00
|
|
|
impl Core {
|
2019-06-25 11:28:02 +01:00
|
|
|
fn exec_b_bl(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuResult<CpuPipelineAction> {
|
|
|
|
if insn.link_flag() {
|
|
|
|
self.set_reg(14, self.pc & !0b1);
|
|
|
|
}
|
|
|
|
self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32;
|
|
|
|
Ok(CpuPipelineAction::Branch)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn exec_bx(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuResult<CpuPipelineAction> {
|
|
|
|
let rn = self.get_reg(insn.rn());
|
|
|
|
if rn.bit(0) {
|
|
|
|
self.set_state(CpuState::THUMB);
|
|
|
|
} else {
|
|
|
|
self.set_state(CpuState::ARM);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(CpuPipelineAction::Branch)
|
|
|
|
}
|
|
|
|
|
2019-06-25 03:35:52 +01:00
|
|
|
pub fn exec_arm(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
|
2019-06-25 11:28:02 +01:00
|
|
|
let action = match insn.fmt {
|
|
|
|
ArmInstructionFormat::BX => self.exec_bx(sysbus, insn),
|
|
|
|
ArmInstructionFormat::B_BL => self.exec_b_bl(sysbus, insn),
|
2019-06-25 03:35:52 +01:00
|
|
|
fmt => Err(CpuError::UnimplementedCpuInstruction(CpuInstruction::Arm(insn))),
|
2019-06-25 11:28:02 +01:00
|
|
|
}?;
|
|
|
|
Ok((CpuInstruction::Arm(insn), action))
|
2019-06-25 03:35:52 +01:00
|
|
|
}
|
|
|
|
}
|