cpu: Model Program Status Register.
This commit is contained in:
parent
8a057ba159
commit
5808c03fcd
|
@ -1,10 +1,11 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
|
||||
use crate::num_traits::FromPrimitive;
|
||||
use colored::*;
|
||||
|
||||
use super::arm::exec;
|
||||
use super::reg_string;
|
||||
use super::arm::*;
|
||||
use super::psr::{CpuMode, CpuState, RegPSR};
|
||||
use super::sysbus::SysBus;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -44,31 +45,13 @@ impl fmt::Display for CpuError {
|
|||
"illegal instruction at address @0x{:08x} (0x{:08x})",
|
||||
insn.pc, insn.raw
|
||||
),
|
||||
e => write!(f, "error: {:#x?}", e)
|
||||
e => write!(f, "error: {:#x?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type CpuResult<T> = Result<T, CpuError>;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum CpuState {
|
||||
ARM,
|
||||
THUMB,
|
||||
}
|
||||
|
||||
#[derive(Debug, Primitive)]
|
||||
#[repr(u8)]
|
||||
enum CpuMode {
|
||||
User = 0b10000,
|
||||
Fiq = 0b10001,
|
||||
Irq = 0b10010,
|
||||
Supervisor = 0b10011,
|
||||
Abort = 0b10111,
|
||||
Undefined = 0b11011,
|
||||
System = 0b11111,
|
||||
}
|
||||
|
||||
pub struct CpuModeContext {
|
||||
// r8-r14
|
||||
banked_gpr: [u32; 7],
|
||||
|
@ -79,12 +62,9 @@ pub struct CpuModeContext {
|
|||
pub struct Core {
|
||||
pub pc: u32,
|
||||
// r0-r7
|
||||
gpr: [u32; 8],
|
||||
cpsr: u32,
|
||||
|
||||
mode: CpuMode,
|
||||
state: CpuState,
|
||||
verbose: bool
|
||||
gpr: [u32; 15],
|
||||
pub cpsr: RegPSR,
|
||||
pub verbose: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -99,10 +79,8 @@ impl Core {
|
|||
pub fn new() -> Core {
|
||||
Core {
|
||||
pc: 0,
|
||||
gpr: [0; 8],
|
||||
cpsr: 0,
|
||||
mode: CpuMode::System,
|
||||
state: CpuState::ARM,
|
||||
gpr: [0; 15],
|
||||
cpsr: RegPSR::new(),
|
||||
verbose: false,
|
||||
}
|
||||
}
|
||||
|
@ -113,34 +91,30 @@ impl Core {
|
|||
|
||||
pub fn get_reg(&self, reg_num: usize) -> u32 {
|
||||
match reg_num {
|
||||
0...7 => self.gpr[reg_num],
|
||||
0...14 => self.gpr[reg_num],
|
||||
15 => self.pc,
|
||||
_ => unimplemented!("TODO banked registers"),
|
||||
_ => panic!("invalid register")
|
||||
// _ => 0x12345678 // unimplemented!("TODO banked registers"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_reg(&mut self, reg_num: usize, val: u32) {
|
||||
match reg_num {
|
||||
0...7 => self.gpr[reg_num] = val,
|
||||
0...14 => self.gpr[reg_num] = val,
|
||||
15 => self.pc = val,
|
||||
_ => unimplemented!("TODO banked registers"),
|
||||
_ => panic!("invalid register")
|
||||
// _ => unimplemented!("TODO banked registers"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_state(&mut self, s: CpuState) {
|
||||
self.state = s;
|
||||
}
|
||||
|
||||
/// Resets the cpu
|
||||
pub fn reset(&mut self) {
|
||||
self.pc = 0;
|
||||
self.cpsr = 0;
|
||||
self.mode = CpuMode::System;
|
||||
self.state = CpuState::ARM;
|
||||
self.cpsr.set(0);
|
||||
}
|
||||
|
||||
fn word_size(&self) -> usize {
|
||||
match self.state {
|
||||
match self.cpsr.state() {
|
||||
CpuState::ARM => 4,
|
||||
CpuState::THUMB => 2,
|
||||
}
|
||||
|
@ -160,7 +134,7 @@ impl Core {
|
|||
}
|
||||
|
||||
pub fn step(&mut self, sysbus: &mut SysBus) -> CpuResult<()> {
|
||||
let (executed_insn, pipeline_action) = match self.state {
|
||||
let (executed_insn, pipeline_action) = match self.cpsr.state() {
|
||||
CpuState::ARM => self.step_arm(sysbus),
|
||||
CpuState::THUMB => unimplemented!("thumb not implemented :("),
|
||||
}?;
|
||||
|
@ -178,3 +152,16 @@ impl Core {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Core {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f, "ARM7TDMI Core")?;
|
||||
writeln!(f, "REGISTERS:")?;
|
||||
for i in 0..16 {
|
||||
let mut reg = reg_string(i).to_string();
|
||||
reg.make_ascii_uppercase();
|
||||
writeln!(f, "\t{}\t= 0x{:08x}", reg.bright_yellow(), self.get_reg(i))?;
|
||||
}
|
||||
write!(f, "CPSR: {}", self.cpsr)
|
||||
}
|
||||
}
|
||||
|
|
200
src/arm7tdmi/psr.rs
Normal file
200
src/arm7tdmi/psr.rs
Normal file
|
@ -0,0 +1,200 @@
|
|||
/// The program status register
|
||||
use std::fmt;
|
||||
|
||||
use crate::bit::BitIndex;
|
||||
use crate::num_traits::FromPrimitive;
|
||||
|
||||
use colored::*;
|
||||
|
||||
use super::arm::ArmCond;
|
||||
|
||||
#[derive(Debug, PartialEq, Primitive)]
|
||||
#[repr(u8)]
|
||||
pub enum CpuState {
|
||||
ARM = 0,
|
||||
THUMB = 1,
|
||||
}
|
||||
|
||||
impl fmt::Display for CpuState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use CpuState::*;
|
||||
match self {
|
||||
ARM => write!(f, "ARM"),
|
||||
THUMB => write!(f, "THUMB"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CpuState> for bool {
|
||||
fn from(state: CpuState) -> bool {
|
||||
match state {
|
||||
CpuState::ARM => false,
|
||||
CpuState::THUMB => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for CpuState {
|
||||
fn from(flag: bool) -> CpuState {
|
||||
if flag {
|
||||
CpuState::THUMB
|
||||
} else {
|
||||
CpuState::ARM
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Primitive)]
|
||||
#[repr(u8)]
|
||||
pub enum CpuMode {
|
||||
User = 0b10000,
|
||||
Fiq = 0b10001,
|
||||
Irq = 0b10010,
|
||||
Supervisor = 0b10011,
|
||||
Abort = 0b10111,
|
||||
Undefined = 0b11011,
|
||||
System = 0b11111,
|
||||
}
|
||||
|
||||
impl fmt::Display for CpuMode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use CpuMode::*;
|
||||
match self {
|
||||
User => write!(f, "USR"),
|
||||
Fiq => write!(f, "FIQ"),
|
||||
Irq => write!(f, "IRQ"),
|
||||
Supervisor => write!(f, "SVC"),
|
||||
Abort => write!(f, "ABT"),
|
||||
Undefined => write!(f, "UND"),
|
||||
System => write!(f, "SYS"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RegPSR {
|
||||
raw: u32,
|
||||
}
|
||||
|
||||
const RESERVED_BIT_MASK: u32 = 0x0fffff00;
|
||||
fn clear_reserved(n: u32) -> u32 {
|
||||
n & !RESERVED_BIT_MASK
|
||||
}
|
||||
|
||||
impl RegPSR {
|
||||
pub fn new() -> RegPSR {
|
||||
let mut psr = RegPSR { raw: 0 };
|
||||
|
||||
psr.set_irq_disabled(true);
|
||||
psr.set_fiq_disabled(true);
|
||||
psr.set_mode(CpuMode::Supervisor);
|
||||
psr.set_state(CpuState::ARM);
|
||||
println!("RAW: 0x{:08x}", psr.raw);
|
||||
|
||||
psr
|
||||
}
|
||||
|
||||
pub fn get(&self) -> u32 {
|
||||
self.raw
|
||||
}
|
||||
|
||||
pub fn set(&mut self, psr: u32) {
|
||||
self.raw = clear_reserved(psr);
|
||||
}
|
||||
|
||||
pub fn state(&self) -> CpuState {
|
||||
self.raw.bit(5).into()
|
||||
}
|
||||
|
||||
pub fn set_state(&mut self, state: CpuState) {
|
||||
self.raw.set_bit(5, state.into());
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> CpuMode {
|
||||
CpuMode::from_u32(self.raw & 0xb11111).unwrap()
|
||||
}
|
||||
|
||||
pub fn set_mode(&mut self, mode: CpuMode) {
|
||||
self.raw |= mode as u32;
|
||||
}
|
||||
|
||||
pub fn irq_disabled(&self) -> bool {
|
||||
self.raw.bit(7)
|
||||
}
|
||||
|
||||
pub fn set_irq_disabled(&mut self, disabled: bool) {
|
||||
self.raw.set_bit(7, disabled);
|
||||
}
|
||||
|
||||
pub fn fiq_disabled(&self) -> bool {
|
||||
self.raw.bit(6)
|
||||
}
|
||||
|
||||
pub fn set_fiq_disabled(&mut self, disabled: bool) {
|
||||
self.raw.set_bit(6, disabled);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn N(&self) -> bool {
|
||||
self.raw.bit(31)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn set_N(&mut self, flag: bool) {
|
||||
self.raw.set_bit(31, flag);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Z(&self) -> bool {
|
||||
self.raw.bit(30)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn set_Z(&mut self, flag: bool) {
|
||||
self.raw.set_bit(30, flag);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn C(&self) -> bool {
|
||||
self.raw.bit(29)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn set_C(&mut self, flag: bool) {
|
||||
self.raw.set_bit(29, flag);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn V(&self) -> bool {
|
||||
self.raw.bit(28)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn set_V(&mut self, flag: bool) {
|
||||
self.raw.set_bit(28, flag);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RegPSR {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let disabled_string = |disabled: bool| -> ColoredString {
|
||||
if disabled {
|
||||
"disabled".bright_red()
|
||||
} else {
|
||||
"enabled".bright_green()
|
||||
}
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{{ mode: {mode}, state: {state}, irq: {irq}, fiq: {fiq}, condition_flags: (N={N} Z={Z} C={C} V={V}) }}",
|
||||
mode = self.mode(),
|
||||
state = self.state(),
|
||||
irq = disabled_string(self.irq_disabled()),
|
||||
fiq = disabled_string(self.irq_disabled()),
|
||||
N = self.N() as u8,
|
||||
Z = self.Z() as u8,
|
||||
C = self.C() as u8,
|
||||
V = self.V() as u8,
|
||||
)
|
||||
}
|
||||
}
|
Reference in a new issue