2019-06-25 03:35:52 +01:00
|
|
|
use std::fmt;
|
2019-06-25 03:16:14 +01:00
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
use ansi_term::{Colour, Style};
|
2019-07-02 14:57:35 +01:00
|
|
|
use num_traits::Num;
|
2019-06-28 23:52:10 +01:00
|
|
|
|
2019-06-28 09:46:36 +01:00
|
|
|
pub use super::exception::Exception;
|
2019-06-30 14:59:19 +01:00
|
|
|
use super::{
|
2019-07-01 15:45:29 +01:00
|
|
|
arm::*,
|
2019-07-05 11:07:07 +01:00
|
|
|
bus::{Bus, MemoryAccess, MemoryAccessType, MemoryAccessType::*, MemoryAccessWidth::*},
|
2019-07-01 15:45:29 +01:00
|
|
|
psr::RegPSR,
|
2019-07-02 14:57:35 +01:00
|
|
|
reg_string,
|
|
|
|
thumb::ThumbInstruction,
|
|
|
|
Addr, CpuMode, CpuResult, CpuState, DecodedInstruction, InstructionDecoder,
|
2019-06-30 14:59:19 +01:00
|
|
|
};
|
2019-06-27 13:13:38 +01:00
|
|
|
|
2019-07-02 14:57:35 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PipelineContext<D, N>
|
|
|
|
where
|
|
|
|
D: InstructionDecoder,
|
|
|
|
N: Num,
|
|
|
|
{
|
|
|
|
fetched: Option<(Addr, N)>,
|
|
|
|
decoded: Option<D>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<D, N> Default for PipelineContext<D, N>
|
|
|
|
where
|
|
|
|
D: InstructionDecoder,
|
|
|
|
N: Num,
|
|
|
|
{
|
|
|
|
fn default() -> PipelineContext<D, N> {
|
|
|
|
PipelineContext {
|
|
|
|
fetched: None,
|
|
|
|
decoded: None,
|
|
|
|
}
|
|
|
|
}
|
2019-06-27 13:13:38 +01:00
|
|
|
}
|
|
|
|
|
2019-07-02 14:57:35 +01:00
|
|
|
impl<D, N> PipelineContext<D, N>
|
|
|
|
where
|
|
|
|
D: InstructionDecoder,
|
|
|
|
N: Num,
|
|
|
|
{
|
2019-07-06 16:48:22 +01:00
|
|
|
pub fn flush(&mut self) {
|
2019-07-02 14:57:35 +01:00
|
|
|
self.fetched = None;
|
|
|
|
self.decoded = None;
|
|
|
|
}
|
|
|
|
|
2019-07-06 16:48:22 +01:00
|
|
|
pub fn is_flushed(&self) -> bool {
|
2019-06-28 23:52:10 +01:00
|
|
|
self.fetched.is_none() && self.decoded.is_none()
|
2019-06-27 13:13:38 +01:00
|
|
|
}
|
2019-06-25 00:10:09 +01:00
|
|
|
|
2019-07-06 16:48:22 +01:00
|
|
|
pub fn is_only_fetched(&self) -> bool {
|
2019-06-28 23:52:10 +01:00
|
|
|
self.fetched.is_some() && self.decoded.is_none()
|
2019-06-25 03:16:14 +01:00
|
|
|
}
|
|
|
|
|
2019-07-06 16:48:22 +01:00
|
|
|
pub fn is_ready_to_execute(&self) -> bool {
|
2019-06-28 23:52:10 +01:00
|
|
|
self.fetched.is_some() && self.decoded.is_some()
|
2019-06-25 03:35:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-27 13:13:38 +01:00
|
|
|
#[derive(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
|
|
|
|
pub gpr_banked_r13: [u32; 6],
|
|
|
|
pub gpr_banked_r14: [u32; 6],
|
|
|
|
// r8-r12 are banked for fiq mode
|
|
|
|
pub gpr_banked_old_r8_12: [u32; 5],
|
|
|
|
pub gpr_banked_fiq_r8_12: [u32; 5],
|
|
|
|
|
2019-06-26 22:45:53 +01:00
|
|
|
pub cpsr: RegPSR,
|
2019-06-27 13:13:38 +01:00
|
|
|
pub spsr: [RegPSR; 5],
|
|
|
|
|
2019-07-02 14:57:35 +01:00
|
|
|
pub pipeline_arm: PipelineContext<ArmInstruction, u32>,
|
|
|
|
pub pipeline_thumb: PipelineContext<ThumbInstruction, u16>,
|
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-06-26 22:45:53 +01:00
|
|
|
pub verbose: bool,
|
2019-06-25 03:35:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum CpuPipelineAction {
|
2019-06-28 23:52:10 +01:00
|
|
|
IncPC,
|
|
|
|
Flush,
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
pub type CpuExecResult = CpuResult<CpuPipelineAction>;
|
2019-06-25 03:35:52 +01:00
|
|
|
|
2019-06-25 00:10:09 +01:00
|
|
|
impl Core {
|
|
|
|
pub fn new() -> Core {
|
|
|
|
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-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-06-25 00:10:09 +01:00
|
|
|
pub fn get_reg(&self, reg_num: usize) -> u32 {
|
|
|
|
match reg_num {
|
2019-06-26 22:45:53 +01:00
|
|
|
0...14 => self.gpr[reg_num],
|
2019-06-25 00:10:09 +01:00
|
|
|
15 => self.pc,
|
2019-06-27 13:13:38 +01:00
|
|
|
_ => panic!("invalid register"),
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_reg(&mut self, reg_num: usize, val: u32) {
|
|
|
|
match reg_num {
|
2019-06-26 22:45:53 +01:00
|
|
|
0...14 => self.gpr[reg_num] = val,
|
2019-07-07 22:57:18 +01:00
|
|
|
15 => self.pc = val & !1,
|
2019-06-27 13:13:38 +01:00
|
|
|
_ => panic!("invalid register"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
pub fn get_registers(&self) -> [u32; 15] {
|
|
|
|
self.gpr.clone()
|
|
|
|
}
|
|
|
|
|
2019-06-27 13:13:38 +01:00
|
|
|
fn map_banked_registers(&mut self, curr_mode: CpuMode, new_mode: CpuMode) {
|
|
|
|
let next_index = new_mode.bank_index();
|
|
|
|
let curr_index = curr_mode.bank_index();
|
|
|
|
|
|
|
|
self.gpr_banked_r13[curr_index] = self.gpr[13];
|
|
|
|
self.gpr_banked_r14[curr_index] = self.gpr[14];
|
2019-07-05 01:27:23 +01:00
|
|
|
|
|
|
|
self.gpr[13] = self.gpr_banked_r13[next_index];
|
2019-06-27 13:13:38 +01:00
|
|
|
self.gpr[14] = self.gpr_banked_r14[next_index];
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
} else if curr_mode == CpuMode::Fiq {
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn change_mode(&mut self, new_mode: CpuMode) {
|
|
|
|
let curr_mode = self.cpsr.mode();
|
|
|
|
// Copy CPSR to SPSR_mode
|
|
|
|
if let Some(index) = new_mode.spsr_index() {
|
|
|
|
self.spsr[index] = self.cpsr;
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
2019-06-27 13:13:38 +01:00
|
|
|
self.map_banked_registers(curr_mode, new_mode);
|
2019-07-05 01:27:23 +01:00
|
|
|
let next_index = new_mode.bank_index();
|
2019-07-05 11:07:07 +01:00
|
|
|
self.gpr_banked_r14[next_index] = self
|
|
|
|
.pc
|
|
|
|
.wrapping_sub(self.word_size() as u32)
|
|
|
|
.wrapping_add(4);
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Resets the cpu
|
|
|
|
pub fn reset(&mut self) {
|
2019-06-27 13:13:38 +01:00
|
|
|
self.exception(Exception::Reset);
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn advance_pc(&mut self) {
|
|
|
|
self.pc = self.pc.wrapping_add(self.word_size() as u32)
|
|
|
|
}
|
|
|
|
|
2019-06-30 14:59:19 +01:00
|
|
|
pub fn cycles(&self) -> usize {
|
|
|
|
self.cycles
|
|
|
|
}
|
|
|
|
|
|
|
|
pub 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-07-05 11:07:07 +01:00
|
|
|
pub fn add_cycles(&mut self, addr: Addr, bus: &Bus, access: MemoryAccess) {
|
2019-07-06 13:53:36 +01:00
|
|
|
// println!("<cycle {:#x} {}> total: {}", addr, access, self.cycles);
|
2019-07-05 11:07:07 +01:00
|
|
|
self.cycles += bus.get_cycles(addr, access);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cycle_type(&self, addr: Addr) -> MemoryAccessType {
|
2019-07-06 21:38:08 +01:00
|
|
|
if addr == self.memreq || addr == self.memreq.wrapping_add(self.word_size() as Addr) {
|
2019-07-05 11:07:07 +01:00
|
|
|
Seq
|
|
|
|
} else {
|
|
|
|
NonSeq
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-05 11:58:26 +01:00
|
|
|
pub fn get_required_multipiler_array_cycles(&self, rs: i32) -> usize {
|
|
|
|
if rs & 0xff == rs {
|
|
|
|
1
|
|
|
|
} else if rs & 0xffff == rs {
|
|
|
|
2
|
|
|
|
} else if rs & 0xffffff == rs {
|
|
|
|
3
|
|
|
|
} else {
|
|
|
|
4
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-05 11:07:07 +01:00
|
|
|
pub fn load_32(&mut self, addr: Addr, bus: &mut Bus) -> u32 {
|
|
|
|
self.add_cycles(addr, bus, self.cycle_type(addr) + MemoryAccess32);
|
|
|
|
self.memreq = addr;
|
|
|
|
bus.read_32(addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_16(&mut self, addr: Addr, bus: &mut Bus) -> u16 {
|
|
|
|
let cycle_type = self.cycle_type(addr);
|
|
|
|
self.add_cycles(addr, bus, cycle_type + MemoryAccess16);
|
|
|
|
self.memreq = addr;
|
|
|
|
bus.read_16(addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_8(&mut self, addr: Addr, bus: &mut Bus) -> u8 {
|
|
|
|
let cycle_type = self.cycle_type(addr);
|
|
|
|
self.add_cycles(addr, bus, cycle_type + MemoryAccess8);
|
|
|
|
self.memreq = addr;
|
|
|
|
bus.read_8(addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store_32(&mut self, addr: Addr, value: u32, bus: &mut Bus) {
|
|
|
|
let cycle_type = self.cycle_type(addr);
|
|
|
|
self.add_cycles(addr, bus, cycle_type + MemoryAccess32);
|
|
|
|
self.memreq = addr;
|
2019-07-15 05:30:52 +01:00
|
|
|
bus.write_32(addr, value);
|
2019-07-05 11:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store_16(&mut self, addr: Addr, value: u16, bus: &mut Bus) {
|
|
|
|
let cycle_type = self.cycle_type(addr);
|
|
|
|
self.add_cycles(addr, bus, cycle_type + MemoryAccess16);
|
|
|
|
self.memreq = addr;
|
2019-07-15 05:30:52 +01:00
|
|
|
bus.write_16(addr, value);
|
2019-07-05 11:07:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store_8(&mut self, addr: Addr, value: u8, bus: &mut Bus) {
|
|
|
|
let cycle_type = self.cycle_type(addr);
|
|
|
|
self.add_cycles(addr, bus, cycle_type + MemoryAccess8);
|
|
|
|
self.memreq = addr;
|
2019-07-15 05:30:52 +01:00
|
|
|
bus.write_8(addr, value);
|
2019-06-30 14:59:19 +01:00
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
pub fn check_arm_cond(&self, cond: ArmCond) -> bool {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-02 14:57:35 +01:00
|
|
|
fn step_thumb(
|
|
|
|
&mut self,
|
2019-07-05 11:07:07 +01:00
|
|
|
bus: &mut Bus,
|
2019-07-02 14:57:35 +01:00
|
|
|
) -> CpuResult<(Option<DecodedInstruction>, CpuPipelineAction)> {
|
|
|
|
// fetch
|
2019-07-05 11:07:07 +01:00
|
|
|
// let new_fetched = bus.read_16(self.pc);
|
|
|
|
let new_fetched = self.load_16(self.pc, bus);
|
2019-07-02 14:57:35 +01:00
|
|
|
|
|
|
|
// decode
|
|
|
|
let new_decoded = match self.pipeline_thumb.fetched {
|
|
|
|
Some((addr, i)) => {
|
|
|
|
let insn = ThumbInstruction::decode(i, addr)?;
|
|
|
|
Some(insn)
|
|
|
|
}
|
|
|
|
None => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
// exec
|
|
|
|
let result = match self.pipeline_thumb.decoded {
|
|
|
|
Some(d) => {
|
|
|
|
self.gpr_previous = self.get_registers();
|
2019-07-05 11:07:07 +01:00
|
|
|
let action = self.exec_thumb(bus, d)?;
|
2019-07-02 14:57:35 +01:00
|
|
|
Ok((Some(DecodedInstruction::Thumb(d)), action))
|
|
|
|
}
|
|
|
|
None => Ok((None, CpuPipelineAction::IncPC)),
|
|
|
|
};
|
|
|
|
|
|
|
|
self.pipeline_thumb.fetched = Some((self.pc, new_fetched));
|
|
|
|
if let Some(d) = new_decoded {
|
|
|
|
self.pipeline_thumb.decoded = Some(d);
|
|
|
|
}
|
|
|
|
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
fn step_arm(
|
|
|
|
&mut self,
|
2019-07-05 11:07:07 +01:00
|
|
|
bus: &mut Bus,
|
2019-07-02 14:57:35 +01:00
|
|
|
) -> CpuResult<(Option<DecodedInstruction>, CpuPipelineAction)> {
|
2019-07-05 11:07:07 +01:00
|
|
|
// let new_fetched = bus.read_32(self.pc);
|
|
|
|
let new_fetched = self.load_32(self.pc, bus);
|
2019-06-28 23:52:10 +01:00
|
|
|
|
2019-06-25 03:16:14 +01:00
|
|
|
// decode
|
2019-07-02 14:57:35 +01:00
|
|
|
let new_decoded = match self.pipeline_arm.fetched {
|
|
|
|
Some((addr, i)) => {
|
|
|
|
let insn = ArmInstruction::decode(i, addr)?;
|
|
|
|
Some(insn)
|
|
|
|
}
|
2019-06-28 23:52:10 +01:00
|
|
|
None => None,
|
|
|
|
};
|
2019-06-30 14:59:19 +01:00
|
|
|
|
2019-06-25 03:35:52 +01:00
|
|
|
// exec
|
2019-07-02 14:57:35 +01:00
|
|
|
let result = match self.pipeline_arm.decoded {
|
2019-06-28 23:52:10 +01:00
|
|
|
Some(d) => {
|
|
|
|
self.gpr_previous = self.get_registers();
|
2019-07-05 11:07:07 +01:00
|
|
|
let action = self.exec_arm(bus, d)?;
|
2019-07-02 14:57:35 +01:00
|
|
|
Ok((Some(DecodedInstruction::Arm(d)), action))
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
2019-07-01 15:45:29 +01:00
|
|
|
None => Ok((None, CpuPipelineAction::IncPC)),
|
2019-06-28 23:52:10 +01:00
|
|
|
};
|
|
|
|
|
2019-07-02 14:57:35 +01:00
|
|
|
self.pipeline_arm.fetched = Some((self.pc, new_fetched));
|
2019-06-28 23:52:10 +01:00
|
|
|
if let Some(d) = new_decoded {
|
2019-07-02 14:57:35 +01:00
|
|
|
self.pipeline_arm.decoded = Some(d);
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
result
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
/// Perform a pipeline step
|
|
|
|
/// If an instruction was executed in this step, return it.
|
2019-07-05 11:07:07 +01:00
|
|
|
pub fn step(&mut self, bus: &mut Bus) -> CpuResult<Option<DecodedInstruction>> {
|
2019-06-28 23:52:10 +01:00
|
|
|
let (executed_instruction, pipeline_action) = match self.cpsr.state() {
|
2019-07-05 11:07:07 +01:00
|
|
|
CpuState::ARM => self.step_arm(bus),
|
|
|
|
CpuState::THUMB => self.step_thumb(bus),
|
2019-06-25 03:35:52 +01:00
|
|
|
}?;
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
match pipeline_action {
|
|
|
|
CpuPipelineAction::IncPC => self.advance_pc(),
|
|
|
|
CpuPipelineAction::Flush => {
|
2019-07-02 14:57:35 +01:00
|
|
|
self.pipeline_arm.flush();
|
|
|
|
self.pipeline_thumb.flush();
|
2019-06-25 03:35:52 +01:00
|
|
|
}
|
|
|
|
}
|
2019-06-25 00:10:09 +01:00
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
Ok(executed_instruction)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get's the address of the next instruction that is going to be executed
|
|
|
|
pub fn get_next_pc(&self) -> Addr {
|
2019-07-02 14:57:35 +01:00
|
|
|
match self.cpsr.state() {
|
|
|
|
CpuState::ARM => {
|
|
|
|
if self.pipeline_arm.is_flushed() {
|
|
|
|
self.pc as Addr
|
|
|
|
} else if self.pipeline_arm.is_only_fetched() {
|
|
|
|
self.pipeline_arm.fetched.unwrap().0
|
|
|
|
} else if self.pipeline_arm.is_ready_to_execute() {
|
|
|
|
self.pipeline_arm.decoded.unwrap().pc
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CpuState::THUMB => {
|
|
|
|
if self.pipeline_thumb.is_flushed() {
|
|
|
|
self.pc as Addr
|
|
|
|
} else if self.pipeline_thumb.is_only_fetched() {
|
|
|
|
self.pipeline_thumb.fetched.unwrap().0
|
|
|
|
} else if self.pipeline_thumb.is_ready_to_execute() {
|
|
|
|
self.pipeline_thumb.decoded.unwrap().pc
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
2019-06-25 03:35:52 +01:00
|
|
|
}
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
2019-06-25 00:10:09 +01:00
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
/// 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;
|
2019-07-06 13:53:36 +01:00
|
|
|
pub fn step_one(&mut self, bus: &mut Bus) -> CpuResult<DecodedInstruction> {
|
2019-06-28 23:52:10 +01:00
|
|
|
loop {
|
2019-07-05 11:07:07 +01:00
|
|
|
if let Some(i) = self.step(bus)? {
|
2019-06-28 23:52:10 +01:00
|
|
|
return Ok(i);
|
|
|
|
}
|
|
|
|
}
|
2019-06-25 00:10:09 +01:00
|
|
|
}
|
|
|
|
}
|
2019-06-26 22:45:53 +01:00
|
|
|
|
|
|
|
impl fmt::Display for Core {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|