2020-02-08 12:19:57 +00:00
|
|
|
#[cfg(feature = "debugger")]
|
2020-02-10 23:52:18 +00:00
|
|
|
use super::reg_string;
|
2020-02-08 12:19:57 +00:00
|
|
|
#[cfg(feature = "debugger")]
|
2019-06-28 23:52:10 +01:00
|
|
|
use ansi_term::{Colour, Style};
|
2020-01-16 18:06:22 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-02-10 23:52:18 +00:00
|
|
|
#[cfg(feature = "debugger")]
|
|
|
|
use std::fmt;
|
2019-06-28 23:52:10 +01:00
|
|
|
|
2019-06-28 09:46:36 +01:00
|
|
|
pub use super::exception::Exception;
|
2020-02-10 23:52:18 +00:00
|
|
|
use super::CpuAction;
|
2020-02-21 12:04:39 +00:00
|
|
|
#[cfg(feature = "debugger")]
|
|
|
|
use super::DecodedInstruction;
|
2019-06-30 14:59:19 +01:00
|
|
|
use super::{
|
2020-02-21 12:04:39 +00:00
|
|
|
arm::*, psr::RegPSR, thumb::ThumbInstruction, Addr, CpuMode, CpuState, InstructionDecoder,
|
2019-08-08 17:46:56 +01:00
|
|
|
};
|
|
|
|
|
2019-12-29 21:03:57 +00:00
|
|
|
use crate::core::bus::Bus;
|
2020-02-10 23:52:18 +00:00
|
|
|
use crate::core::sysbus::{MemoryAccessType::*, MemoryAccessWidth::*, SysBus};
|
2019-06-25 03:35:52 +01:00
|
|
|
|
2020-01-16 18:06:22 +00:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
2019-06-25 00:10:09 +01:00
|
|
|
pub struct Core {
|
2019-06-25 03:35:52 +01:00
|
|
|
pub pc: u32,
|
2019-06-27 13:13:38 +01:00
|
|
|
pub gpr: [u32; 15],
|
|
|
|
// r13 and r14 are banked for all modes. System&User mode share them
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) gpr_banked_r13: [u32; 6],
|
|
|
|
pub(super) gpr_banked_r14: [u32; 6],
|
2019-06-27 13:13:38 +01:00
|
|
|
// r8-r12 are banked for fiq mode
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) gpr_banked_old_r8_12: [u32; 5],
|
|
|
|
pub(super) gpr_banked_fiq_r8_12: [u32; 5],
|
2019-06-27 13:13:38 +01:00
|
|
|
|
2019-06-26 22:45:53 +01:00
|
|
|
pub cpsr: RegPSR,
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) spsr: RegPSR,
|
|
|
|
pub(super) spsr_bank: [RegPSR; 6],
|
2019-06-27 13:13:38 +01:00
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) bs_carry_out: bool,
|
2019-07-22 22:03:15 +01:00
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
pipeline: [u32; 2],
|
2020-02-21 12:04:39 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "debugger")]
|
2019-11-10 18:00:07 +00:00
|
|
|
pub last_executed: Option<DecodedInstruction>,
|
2019-07-20 12:44:49 +01:00
|
|
|
|
2019-07-06 13:53:36 +01:00
|
|
|
pub cycles: usize,
|
2019-06-28 23:52:10 +01:00
|
|
|
|
|
|
|
// store the gpr before executing an instruction to show diff in the Display impl
|
|
|
|
gpr_previous: [u32; 15],
|
|
|
|
|
2019-07-05 11:07:07 +01:00
|
|
|
memreq: Addr,
|
2019-11-08 22:55:09 +00:00
|
|
|
pub breakpoints: Vec<u32>,
|
2019-07-05 11:07:07 +01:00
|
|
|
|
2019-06-26 22:45:53 +01:00
|
|
|
pub verbose: bool,
|
2019-11-16 16:48:24 +00:00
|
|
|
|
|
|
|
pub trace_opcodes: bool,
|
2019-12-21 18:19:43 +00:00
|
|
|
|
|
|
|
pub trace_exceptions: bool,
|
2019-06-25 03:35:52 +01:00
|
|
|
}
|
|
|
|
|
2019-06-25 00:10:09 +01:00
|
|
|
impl Core {
|
|
|
|
pub fn new() -> Core {
|
2020-02-08 12:19:57 +00:00
|
|
|
let cpsr = RegPSR::new(0x0000_00D3);
|
2019-06-25 00:10:09 +01:00
|
|
|
Core {
|
2019-07-05 11:07:07 +01:00
|
|
|
memreq: 0xffff_0000, // set memreq to an invalid addr so the first load cycle will be non-sequential
|
2019-11-11 01:35:16 +00:00
|
|
|
cpsr: cpsr,
|
2019-06-27 13:13:38 +01:00
|
|
|
..Default::default()
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-25 03:35:52 +01:00
|
|
|
pub fn set_verbose(&mut self, v: bool) {
|
|
|
|
self.verbose = v;
|
|
|
|
}
|
|
|
|
|
2019-07-22 07:20:29 +01:00
|
|
|
pub fn get_reg(&self, r: usize) -> u32 {
|
|
|
|
match r {
|
2019-11-08 22:55:09 +00:00
|
|
|
0..=14 => self.gpr[r],
|
2019-06-25 00:10:09 +01:00
|
|
|
15 => self.pc,
|
2019-07-22 18:21:28 +01:00
|
|
|
_ => panic!("invalid register {}", r),
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-22 07:20:29 +01:00
|
|
|
pub fn get_reg_user(&mut self, r: usize) -> u32 {
|
|
|
|
match r {
|
|
|
|
0..=7 => self.gpr[r],
|
|
|
|
8..=12 => {
|
|
|
|
if self.cpsr.mode() == CpuMode::Fiq {
|
|
|
|
self.gpr[r]
|
|
|
|
} else {
|
|
|
|
self.gpr_banked_old_r8_12[r - 8]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
13 => self.gpr_banked_r13[0],
|
|
|
|
14 => self.gpr_banked_r14[0],
|
|
|
|
_ => panic!("invalid register"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_reg(&mut self, r: usize, val: u32) {
|
|
|
|
match r {
|
2020-02-08 12:19:57 +00:00
|
|
|
0..=14 => self.gpr[r] = val,
|
2020-02-07 15:16:52 +00:00
|
|
|
15 => {
|
|
|
|
self.pc = {
|
|
|
|
match self.cpsr.state() {
|
|
|
|
CpuState::THUMB => val & !1,
|
|
|
|
CpuState::ARM => val & !3,
|
|
|
|
}
|
2020-01-17 14:09:45 +00:00
|
|
|
}
|
2020-02-07 15:16:52 +00:00
|
|
|
}
|
2019-06-27 13:13:38 +01:00
|
|
|
_ => panic!("invalid register"),
|
2019-07-22 07:20:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_reg_user(&mut self, r: usize, val: u32) {
|
|
|
|
match r {
|
|
|
|
0..=7 => self.gpr[r] = val,
|
|
|
|
8..=12 => {
|
|
|
|
if self.cpsr.mode() == CpuMode::Fiq {
|
|
|
|
self.gpr[r] = val;
|
|
|
|
} else {
|
|
|
|
self.gpr_banked_old_r8_12[r - 8] = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
13 => {
|
|
|
|
self.gpr_banked_r13[0] = val;
|
|
|
|
}
|
|
|
|
14 => {
|
|
|
|
self.gpr_banked_r14[0] = val;
|
|
|
|
}
|
|
|
|
_ => panic!("invalid register"),
|
2019-06-27 13:13:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn write_32(&mut self, addr: Addr, value: u32, bus: &mut SysBus) {
|
2019-11-08 22:55:09 +00:00
|
|
|
bus.write_32(addr & !0x3, value);
|
|
|
|
}
|
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn write_16(&mut self, addr: Addr, value: u16, bus: &mut SysBus) {
|
2019-11-08 22:55:09 +00:00
|
|
|
bus.write_16(addr & !0x1, value);
|
|
|
|
}
|
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn write_8(&mut self, addr: Addr, value: u8, bus: &mut SysBus) {
|
2019-11-08 22:55:09 +00:00
|
|
|
bus.write_8(addr, value);
|
|
|
|
}
|
|
|
|
|
2019-07-22 18:21:28 +01:00
|
|
|
/// Helper function for "ldr" instruction that handles misaligned addresses
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn ldr_word(&mut self, addr: Addr, bus: &SysBus) -> u32 {
|
2019-07-22 18:21:28 +01:00
|
|
|
if addr & 0x3 != 0 {
|
|
|
|
let rotation = (addr & 0x3) << 3;
|
2019-08-08 17:46:56 +01:00
|
|
|
let value = bus.read_32(addr & !0x3);
|
2019-07-22 22:03:15 +01:00
|
|
|
self.ror(value, rotation, self.cpsr.C(), false, false)
|
2019-07-22 18:21:28 +01:00
|
|
|
} else {
|
2019-08-08 17:46:56 +01:00
|
|
|
bus.read_32(addr)
|
2019-07-22 18:21:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper function for "ldrh" instruction that handles misaligned addresses
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn ldr_half(&mut self, addr: Addr, bus: &SysBus) -> u32 {
|
2019-07-22 18:21:28 +01:00
|
|
|
if addr & 0x1 != 0 {
|
|
|
|
let rotation = (addr & 0x1) << 3;
|
2019-08-08 17:46:56 +01:00
|
|
|
let value = bus.read_16(addr & !0x1);
|
2019-07-22 22:03:15 +01:00
|
|
|
self.ror(value as u32, rotation, self.cpsr.C(), false, false)
|
2019-07-22 18:21:28 +01:00
|
|
|
} else {
|
2019-08-08 17:46:56 +01:00
|
|
|
bus.read_16(addr) as u32
|
2019-07-22 18:21:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper function for "ldrsh" instruction that handles misaligned addresses
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn ldr_sign_half(&mut self, addr: Addr, bus: &SysBus) -> u32 {
|
2019-07-22 18:21:28 +01:00
|
|
|
if addr & 0x1 != 0 {
|
2019-08-08 17:46:56 +01:00
|
|
|
bus.read_8(addr) as i8 as i32 as u32
|
2019-07-22 18:21:28 +01:00
|
|
|
} else {
|
2019-08-08 17:46:56 +01:00
|
|
|
bus.read_16(addr) as i16 as i32 as u32
|
2019-07-22 18:21:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
pub fn get_registers(&self) -> [u32; 15] {
|
|
|
|
self.gpr.clone()
|
|
|
|
}
|
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn change_mode(&mut self, old_mode: CpuMode, new_mode: CpuMode) {
|
|
|
|
let new_index = new_mode.bank_index();
|
|
|
|
let old_index = old_mode.bank_index();
|
|
|
|
|
|
|
|
if new_index == old_index {
|
|
|
|
return;
|
|
|
|
}
|
2019-06-27 13:13:38 +01:00
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
self.spsr_bank[old_index] = self.spsr;
|
|
|
|
self.gpr_banked_r13[old_index] = self.gpr[13];
|
|
|
|
self.gpr_banked_r14[old_index] = self.gpr[14];
|
2019-07-05 01:27:23 +01:00
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
self.spsr = self.spsr_bank[new_index];
|
|
|
|
self.gpr[13] = self.gpr_banked_r13[new_index];
|
|
|
|
self.gpr[14] = self.gpr_banked_r14[new_index];
|
2019-06-27 13:13:38 +01:00
|
|
|
|
|
|
|
if new_mode == CpuMode::Fiq {
|
|
|
|
for r in 0..5 {
|
|
|
|
self.gpr_banked_old_r8_12[r] = self.gpr[r + 8];
|
|
|
|
self.gpr[r + 8] = self.gpr_banked_fiq_r8_12[r];
|
|
|
|
}
|
2019-11-11 01:35:16 +00:00
|
|
|
} else if old_mode == CpuMode::Fiq {
|
2019-06-27 13:13:38 +01:00
|
|
|
for r in 0..5 {
|
|
|
|
self.gpr_banked_fiq_r8_12[r] = self.gpr[r + 8];
|
|
|
|
self.gpr[r + 8] = self.gpr_banked_old_r8_12[r];
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 01:35:16 +00:00
|
|
|
self.cpsr.set_mode(new_mode);
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Resets the cpu
|
2019-08-08 17:46:56 +01:00
|
|
|
pub fn reset(&mut self, sb: &mut SysBus) {
|
2019-11-11 01:35:16 +00:00
|
|
|
self.exception(sb, Exception::Reset, 0);
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
pub fn word_size(&self) -> usize {
|
2019-06-26 22:45:53 +01:00
|
|
|
match self.cpsr.state() {
|
2019-06-25 00:10:09 +01:00
|
|
|
CpuState::ARM => 4,
|
|
|
|
CpuState::THUMB => 2,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-30 14:59:19 +01:00
|
|
|
pub fn cycles(&self) -> usize {
|
|
|
|
self.cycles
|
|
|
|
}
|
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn add_cycle(&mut self) {
|
2019-07-06 13:53:36 +01:00
|
|
|
// println!("<cycle I-Cyclel> total: {}", self.cycles);
|
2019-06-30 14:59:19 +01:00
|
|
|
self.cycles += 1;
|
|
|
|
}
|
|
|
|
|
2019-11-12 22:56:40 +00:00
|
|
|
pub(super) fn get_required_multipiler_array_cycles(&self, rs: u32) -> usize {
|
2019-07-05 11:58:26 +01:00
|
|
|
if rs & 0xff == rs {
|
|
|
|
1
|
|
|
|
} else if rs & 0xffff == rs {
|
|
|
|
2
|
|
|
|
} else if rs & 0xffffff == rs {
|
|
|
|
3
|
|
|
|
} else {
|
|
|
|
4
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-08 17:46:56 +01:00
|
|
|
#[allow(non_snake_case)]
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline(always)]
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn S_cycle32(&mut self, sb: &SysBus, addr: u32) {
|
2019-08-08 17:46:56 +01:00
|
|
|
self.cycles += 1;
|
|
|
|
self.cycles += sb.get_cycles(addr, Seq + MemoryAccess32);
|
2019-07-05 11:07:07 +01:00
|
|
|
}
|
|
|
|
|
2019-08-08 17:46:56 +01:00
|
|
|
#[allow(non_snake_case)]
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline(always)]
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn S_cycle16(&mut self, sb: &SysBus, addr: u32) {
|
2019-08-08 17:46:56 +01:00
|
|
|
self.cycles += 1;
|
|
|
|
self.cycles += sb.get_cycles(addr, Seq + MemoryAccess16);
|
2019-07-05 11:07:07 +01:00
|
|
|
}
|
|
|
|
|
2019-08-08 17:46:56 +01:00
|
|
|
#[allow(non_snake_case)]
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline(always)]
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn S_cycle8(&mut self, sb: &SysBus, addr: u32) {
|
2019-08-08 17:46:56 +01:00
|
|
|
self.cycles += 1;
|
|
|
|
self.cycles += sb.get_cycles(addr, Seq + MemoryAccess8);
|
2019-07-05 11:07:07 +01:00
|
|
|
}
|
|
|
|
|
2019-08-08 17:46:56 +01:00
|
|
|
#[allow(non_snake_case)]
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline(always)]
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn N_cycle32(&mut self, sb: &SysBus, addr: u32) {
|
2019-08-08 17:46:56 +01:00
|
|
|
self.cycles += 1;
|
|
|
|
self.cycles += sb.get_cycles(addr, NonSeq + MemoryAccess32);
|
2019-07-05 11:07:07 +01:00
|
|
|
}
|
|
|
|
|
2019-08-08 17:46:56 +01:00
|
|
|
#[allow(non_snake_case)]
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline(always)]
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn N_cycle16(&mut self, sb: &SysBus, addr: u32) {
|
2019-08-08 17:46:56 +01:00
|
|
|
self.cycles += 1;
|
|
|
|
self.cycles += sb.get_cycles(addr, NonSeq + MemoryAccess16);
|
2019-07-05 11:07:07 +01:00
|
|
|
}
|
|
|
|
|
2019-08-08 17:46:56 +01:00
|
|
|
#[allow(non_snake_case)]
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline(always)]
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn N_cycle8(&mut self, sb: &SysBus, addr: u32) {
|
2019-08-08 17:46:56 +01:00
|
|
|
self.cycles += 1;
|
|
|
|
self.cycles += sb.get_cycles(addr, NonSeq + MemoryAccess8);
|
2019-06-30 14:59:19 +01:00
|
|
|
}
|
|
|
|
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline]
|
2019-11-11 01:35:16 +00:00
|
|
|
pub(super) fn check_arm_cond(&self, cond: ArmCond) -> bool {
|
2019-06-28 23:52:10 +01:00
|
|
|
use ArmCond::*;
|
|
|
|
match cond {
|
2019-07-13 21:32:43 +01:00
|
|
|
EQ => self.cpsr.Z(),
|
|
|
|
NE => !self.cpsr.Z(),
|
|
|
|
HS => self.cpsr.C(),
|
|
|
|
LO => !self.cpsr.C(),
|
|
|
|
MI => self.cpsr.N(),
|
|
|
|
PL => !self.cpsr.N(),
|
|
|
|
VS => self.cpsr.V(),
|
|
|
|
VC => !self.cpsr.V(),
|
|
|
|
HI => self.cpsr.C() && !self.cpsr.Z(),
|
|
|
|
LS => !self.cpsr.C() || self.cpsr.Z(),
|
|
|
|
GE => self.cpsr.N() == self.cpsr.V(),
|
|
|
|
LT => self.cpsr.N() != self.cpsr.V(),
|
|
|
|
GT => !self.cpsr.Z() && (self.cpsr.N() == self.cpsr.V()),
|
|
|
|
LE => self.cpsr.Z() || (self.cpsr.N() != self.cpsr.V()),
|
|
|
|
AL => true,
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:19:57 +00:00
|
|
|
fn step_arm_exec(&mut self, insn: u32, sb: &mut SysBus) {
|
2020-02-14 11:05:14 +00:00
|
|
|
let decoded_arm = ArmInstruction::decode(insn, self.pc.wrapping_sub(8));
|
2020-02-10 23:52:18 +00:00
|
|
|
#[cfg(feature = "debugger")]
|
|
|
|
{
|
|
|
|
self.gpr_previous = self.get_registers();
|
2020-03-28 12:47:10 +00:00
|
|
|
self.last_executed = Some(DecodedInstruction::Arm(decoded_arm.clone()));
|
2020-02-10 23:52:18 +00:00
|
|
|
}
|
2020-03-28 12:47:10 +00:00
|
|
|
let result = self.exec_arm(sb, &decoded_arm);
|
2020-02-10 23:52:18 +00:00
|
|
|
match result {
|
|
|
|
CpuAction::AdvancePC => self.advance_arm(),
|
2020-02-14 11:05:14 +00:00
|
|
|
CpuAction::FlushPipeline => {}
|
2019-07-02 14:57:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:19:57 +00:00
|
|
|
fn step_thumb_exec(&mut self, insn: u16, sb: &mut SysBus) {
|
2020-02-14 11:05:14 +00:00
|
|
|
let decoded_thumb = ThumbInstruction::decode(insn, self.pc.wrapping_sub(4));
|
2020-02-10 23:52:18 +00:00
|
|
|
#[cfg(feature = "debugger")]
|
|
|
|
{
|
|
|
|
self.gpr_previous = self.get_registers();
|
2020-03-28 12:47:10 +00:00
|
|
|
self.last_executed = Some(DecodedInstruction::Thumb(decoded_thumb.clone()));
|
2020-02-10 23:52:18 +00:00
|
|
|
}
|
2020-03-28 12:47:10 +00:00
|
|
|
let result = self.exec_thumb(sb, &decoded_thumb);
|
2020-02-10 23:52:18 +00:00
|
|
|
match result {
|
|
|
|
CpuAction::AdvancePC => self.advance_thumb(),
|
2020-02-14 11:05:14 +00:00
|
|
|
CpuAction::FlushPipeline => {}
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
2019-07-20 12:44:49 +01:00
|
|
|
}
|
|
|
|
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline(always)]
|
2020-02-21 12:04:39 +00:00
|
|
|
pub fn reload_pipeline16(&mut self, sb: &mut SysBus) {
|
2020-02-10 23:52:18 +00:00
|
|
|
self.pipeline[0] = sb.read_16(self.pc) as u32;
|
2019-12-31 23:21:33 +00:00
|
|
|
self.N_cycle16(sb, self.pc);
|
2020-02-10 23:52:18 +00:00
|
|
|
self.advance_thumb();
|
|
|
|
self.pipeline[1] = sb.read_16(self.pc) as u32;
|
|
|
|
self.S_cycle16(sb, self.pc);
|
|
|
|
self.advance_thumb();
|
2019-12-31 23:21:33 +00:00
|
|
|
}
|
|
|
|
|
2020-03-28 12:45:16 +00:00
|
|
|
#[inline(always)]
|
2020-02-21 12:04:39 +00:00
|
|
|
pub fn reload_pipeline32(&mut self, sb: &mut SysBus) {
|
2020-02-10 23:52:18 +00:00
|
|
|
self.pipeline[0] = sb.read_32(self.pc);
|
|
|
|
self.N_cycle16(sb, self.pc);
|
|
|
|
self.advance_arm();
|
|
|
|
self.pipeline[1] = sb.read_32(self.pc);
|
|
|
|
self.S_cycle16(sb, self.pc);
|
|
|
|
self.advance_arm();
|
|
|
|
}
|
|
|
|
|
2020-02-10 23:28:20 +00:00
|
|
|
#[inline]
|
|
|
|
pub(super) fn advance_thumb(&mut self) {
|
|
|
|
self.pc = self.pc.wrapping_add(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub(super) fn advance_arm(&mut self) {
|
|
|
|
self.pc = self.pc.wrapping_add(4)
|
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
/// Perform a pipeline step
|
|
|
|
/// If an instruction was executed in this step, return it.
|
2020-02-08 12:19:57 +00:00
|
|
|
pub fn step(&mut self, bus: &mut SysBus) {
|
2019-11-11 01:35:16 +00:00
|
|
|
let pc = self.pc;
|
|
|
|
|
2019-07-20 12:44:49 +01:00
|
|
|
match self.cpsr.state() {
|
2020-02-08 12:19:57 +00:00
|
|
|
CpuState::ARM => {
|
|
|
|
let fetched_now = bus.read_32(pc);
|
|
|
|
let insn = self.pipeline[0];
|
|
|
|
self.pipeline[0] = self.pipeline[1];
|
|
|
|
self.pipeline[1] = fetched_now;
|
|
|
|
self.step_arm_exec(insn, bus)
|
|
|
|
}
|
|
|
|
CpuState::THUMB => {
|
|
|
|
let fetched_now = bus.read_16(pc);
|
|
|
|
let insn = self.pipeline[0];
|
|
|
|
self.pipeline[0] = self.pipeline[1];
|
|
|
|
self.pipeline[1] = fetched_now as u32;
|
|
|
|
self.step_thumb_exec(insn as u16, bus)
|
|
|
|
}
|
2019-06-25 03:35:52 +01:00
|
|
|
}
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get's the address of the next instruction that is going to be executed
|
|
|
|
pub fn get_next_pc(&self) -> Addr {
|
2019-07-20 12:44:49 +01:00
|
|
|
let insn_size = self.word_size() as u32;
|
2020-02-10 23:52:18 +00:00
|
|
|
self.pc - 2 * insn_size
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
2019-06-25 00:10:09 +01:00
|
|
|
|
2019-11-11 01:35:16 +00:00
|
|
|
pub fn get_cpu_state(&self) -> CpuState {
|
|
|
|
self.cpsr.state()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn skip_bios(&mut self) {
|
|
|
|
self.gpr_banked_r13[0] = 0x0300_7f00; // USR/SYS
|
|
|
|
self.gpr_banked_r13[1] = 0x0300_7f00; // FIQ
|
|
|
|
self.gpr_banked_r13[2] = 0x0300_7fa0; // IRQ
|
|
|
|
self.gpr_banked_r13[3] = 0x0300_7fe0; // SVC
|
|
|
|
self.gpr_banked_r13[4] = 0x0300_7f00; // ABT
|
|
|
|
self.gpr_banked_r13[5] = 0x0300_7f00; // UND
|
|
|
|
|
|
|
|
self.gpr[13] = 0x0300_7f00;
|
|
|
|
self.pc = 0x0800_0000;
|
|
|
|
|
|
|
|
self.cpsr.set(0x5f);
|
|
|
|
}
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
2019-06-26 22:45:53 +01:00
|
|
|
|
2020-02-08 12:19:57 +00:00
|
|
|
#[cfg(feature = "debugger")]
|
2019-06-26 22:45:53 +01:00
|
|
|
impl fmt::Display for Core {
|
2020-02-14 12:01:48 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-06-28 23:52:10 +01:00
|
|
|
writeln!(f, "ARM7TDMI Core Status:")?;
|
2019-06-30 14:59:19 +01:00
|
|
|
writeln!(f, "\tCycles: {}", self.cycles)?;
|
2019-06-28 23:52:10 +01:00
|
|
|
writeln!(f, "\tCPSR: {}", self.cpsr)?;
|
|
|
|
writeln!(f, "\tGeneral Purpose Registers:")?;
|
|
|
|
let reg_normal_style = Style::new().bold();
|
2019-07-03 23:37:47 +01:00
|
|
|
let reg_dirty_style = Colour::Black.bold().on(Colour::Yellow);
|
2019-06-28 23:52:10 +01:00
|
|
|
let gpr = self.get_registers();
|
|
|
|
for i in 0..15 {
|
|
|
|
let mut reg_name = reg_string(i).to_string();
|
|
|
|
reg_name.make_ascii_uppercase();
|
|
|
|
|
|
|
|
let style = if gpr[i] != self.gpr_previous[i] {
|
|
|
|
®_dirty_style
|
|
|
|
} else {
|
|
|
|
®_normal_style
|
|
|
|
};
|
|
|
|
|
2019-07-03 23:37:47 +01:00
|
|
|
let entry = format!("\t{:-3} = 0x{:08x}", reg_name, gpr[i]);
|
2019-06-28 23:52:10 +01:00
|
|
|
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{}{}",
|
|
|
|
style.paint(entry),
|
|
|
|
if (i + 1) % 4 == 0 { "\n" } else { "" }
|
|
|
|
)?;
|
2019-06-26 22:45:53 +01:00
|
|
|
}
|
2019-07-03 23:37:47 +01:00
|
|
|
let pc = format!("\tPC = 0x{:08x}", self.get_next_pc());
|
2019-06-28 23:52:10 +01:00
|
|
|
writeln!(f, "{}", reg_normal_style.paint(pc))
|
2019-06-26 22:45:53 +01:00
|
|
|
}
|
|
|
|
}
|