use std::error::Error;
use log::{info, warn};
use crate::component::reset::Reset;
use crate::component::snapshot::Snapshot;
use crate::util::bit_manipulation::{is_bit_set_32, set_bit_32};
pub const SP_REG: usize = 13;
pub const LP_REG: usize = 14;
pub const PC_REG: usize = 15;
const NUM_OF_REGISTERS: usize = 16;
pub struct Registers {
skip_bios: bool,
registers: Box<[u32]>,
r8: u32,
r8_fiq: u32,
r9: u32,
r9_fiq: u32,
r10: u32,
r10_fiq: u32,
r11: u32,
r11_fiq: u32,
r12: u32,
r12_fiq: u32,
r13: u32,
r13_fiq: u32,
r13_svc: u32,
r13_abt: u32,
r13_irq: u32,
r13_und: u32,
r14: u32,
r14_fiq: u32,
r14_svc: u32,
r14_abt: u32,
r14_irq: u32,
r14_und: u32,
r15: u32,
cpsr: Cpsr,
spsr: u32,
spsr_fiq: u32,
spsr_svc: u32,
spsr_abt: u32,
spsr_irq: u32,
spsr_und: u32,
null_spsr: u32,
}
struct Cpsr {
sign_flag: bool,
zero_flag: bool,
carry_flag: bool,
overflow_flag: bool,
sticky_overflow_flag: bool,
jazelle_state: bool,
greater_than_or_equal_to: [bool; 4],
data_endianness_bit: bool,
imprecise_data_abort: bool,
irq_disabled: bool,
fiq_disabled: bool,
thumb_state: bool,
mode: OperatingMode,
}
#[derive(Clone, Copy, PartialEq)]
pub enum OperatingMode {
Unknown,
User = 0x10,
Fiq = 0x11,
Irq = 0x12,
Supervisor = 0x13,
Abort = 0x17,
Undefined = 0x1B,
System = 0x1F,
}
impl OperatingMode {
pub fn to_string(self) -> &'static str {
match self {
OperatingMode::User => "User",
OperatingMode::Fiq => "FIQ",
OperatingMode::Irq => "IRQ",
OperatingMode::Supervisor => "Supervisor",
OperatingMode::Abort => "Abort",
OperatingMode::Undefined => "Undefined",
OperatingMode::System => "System",
OperatingMode::Unknown => "Unknown",
}
}
pub fn from_u32(val: u32) -> OperatingMode {
match val {
0x10 => OperatingMode::User,
0x11 => OperatingMode::Fiq,
0x12 => OperatingMode::Irq,
0x13 => OperatingMode::Supervisor,
0x17 => OperatingMode::Abort,
0x1B => OperatingMode::Undefined,
0x1F => OperatingMode::System,
_ => OperatingMode::Unknown,
}
}
}
impl Cpsr {
const SIGN_FLAG_IDX: i32 = 31;
const ZERO_FLAG_IDX: i32 = 30;
const CARRY_FLAG_IDX: i32 = 29;
const OVERFLOW_FLAG_IDX: i32 = 28;
const STICKY_OVERFLOW_IDX: i32 = 27;
const JAZELLE_STATE_IDX: i32 = 24;
const GREATER_THAN_OR_EQUAL_TO_BIT_3_IDX: i32 = 22;
const GREATER_THAN_OR_EQUAL_TO_BIT_2_IDX: i32 = 21;
const GREATER_THAN_OR_EQUAL_TO_BIT_1_IDX: i32 = 20;
const GREATER_THAN_OR_EQUAL_TO_BIT_0_IDX: i32 = 19;
const E_BIT_IDX: i32 = 9;
const A_BIT_IDX: i32 = 8;
const IRQ_DISABLED_IDX: i32 = 7;
const FIQ_DISABLED_IDX: i32 = 6;
const THUMB_STATE_IDX: i32 = 5;
const MODE_EXTRACT_BITS: u32 = 0x1F;
fn new() -> Self {
Self {
sign_flag: false,
zero_flag: false,
carry_flag: false,
overflow_flag: false,
sticky_overflow_flag: false,
jazelle_state: false,
greater_than_or_equal_to: [false, false, false, false],
data_endianness_bit: false,
imprecise_data_abort: false,
irq_disabled: false,
fiq_disabled: false,
thumb_state: false,
mode: OperatingMode::User,
}
}
fn get_mode(&self) -> OperatingMode {
self.mode
}
fn set(&mut self, val: u32) {
self.sign_flag = is_bit_set_32(val, Cpsr::SIGN_FLAG_IDX);
self.zero_flag = is_bit_set_32(val, Cpsr::ZERO_FLAG_IDX);
self.carry_flag = is_bit_set_32(val, Cpsr::CARRY_FLAG_IDX);
self.overflow_flag = is_bit_set_32(val, Cpsr::OVERFLOW_FLAG_IDX);
self.sticky_overflow_flag = is_bit_set_32(val, Cpsr::STICKY_OVERFLOW_IDX);
self.jazelle_state = is_bit_set_32(val, Cpsr::JAZELLE_STATE_IDX);
self.greater_than_or_equal_to[3] =
is_bit_set_32(val, Cpsr::GREATER_THAN_OR_EQUAL_TO_BIT_3_IDX);
self.greater_than_or_equal_to[2] =
is_bit_set_32(val, Cpsr::GREATER_THAN_OR_EQUAL_TO_BIT_2_IDX);
self.greater_than_or_equal_to[1] =
is_bit_set_32(val, Cpsr::GREATER_THAN_OR_EQUAL_TO_BIT_1_IDX);
self.greater_than_or_equal_to[0] =
is_bit_set_32(val, Cpsr::GREATER_THAN_OR_EQUAL_TO_BIT_0_IDX);
self.data_endianness_bit = is_bit_set_32(val, Cpsr::E_BIT_IDX);
self.imprecise_data_abort = is_bit_set_32(val, Cpsr::A_BIT_IDX);
self.irq_disabled = is_bit_set_32(val, Cpsr::IRQ_DISABLED_IDX);
self.fiq_disabled = is_bit_set_32(val, Cpsr::FIQ_DISABLED_IDX);
self.thumb_state = is_bit_set_32(val, Cpsr::THUMB_STATE_IDX);
let new_mode = OperatingMode::from_u32(val & Cpsr::MODE_EXTRACT_BITS);
if new_mode != OperatingMode::Unknown {
self.mode = new_mode;
}
}
fn val(&self) -> u32 {
let mut cpsr_val: u32 = 0;
cpsr_val = set_bit_32(cpsr_val, Cpsr::SIGN_FLAG_IDX, self.sign_flag);
cpsr_val = set_bit_32(cpsr_val, Cpsr::ZERO_FLAG_IDX, self.zero_flag);
cpsr_val = set_bit_32(cpsr_val, Cpsr::CARRY_FLAG_IDX, self.carry_flag);
cpsr_val = set_bit_32(cpsr_val, Cpsr::OVERFLOW_FLAG_IDX, self.overflow_flag);
cpsr_val = set_bit_32(cpsr_val, Cpsr::STICKY_OVERFLOW_IDX, self.sticky_overflow_flag);
cpsr_val = set_bit_32(cpsr_val, Cpsr::JAZELLE_STATE_IDX, self.jazelle_state);
cpsr_val = set_bit_32(
cpsr_val,
Cpsr::GREATER_THAN_OR_EQUAL_TO_BIT_3_IDX,
self.greater_than_or_equal_to[3],
);
cpsr_val = set_bit_32(
cpsr_val,
Cpsr::GREATER_THAN_OR_EQUAL_TO_BIT_2_IDX,
self.greater_than_or_equal_to[2],
);
cpsr_val = set_bit_32(
cpsr_val,
Cpsr::GREATER_THAN_OR_EQUAL_TO_BIT_1_IDX,
self.greater_than_or_equal_to[1],
);
cpsr_val = set_bit_32(
cpsr_val,
Cpsr::GREATER_THAN_OR_EQUAL_TO_BIT_0_IDX,
self.greater_than_or_equal_to[0],
);
cpsr_val = set_bit_32(cpsr_val, Cpsr::E_BIT_IDX, self.data_endianness_bit);
cpsr_val = set_bit_32(cpsr_val, Cpsr::A_BIT_IDX, self.imprecise_data_abort);
cpsr_val = set_bit_32(cpsr_val, Cpsr::IRQ_DISABLED_IDX, self.irq_disabled);
cpsr_val = set_bit_32(cpsr_val, Cpsr::FIQ_DISABLED_IDX, self.fiq_disabled);
cpsr_val = set_bit_32(cpsr_val, Cpsr::THUMB_STATE_IDX, self.thumb_state);
cpsr_val |= self.mode as u32;
cpsr_val
}
}
impl Reset for Cpsr {
fn reset(&mut self) {
self.sign_flag = false;
self.zero_flag = false;
self.carry_flag = false;
self.overflow_flag = false;
self.sticky_overflow_flag = false;
self.jazelle_state = false;
self.greater_than_or_equal_to.fill(false);
self.data_endianness_bit = false;
self.imprecise_data_abort = false;
self.irq_disabled = false;
self.fiq_disabled = false;
self.thumb_state = false;
self.mode = OperatingMode::Supervisor;
}
}
impl Registers {
pub fn new(skip_bios: bool) -> Self {
Self {
skip_bios,
registers: vec![0u32; NUM_OF_REGISTERS].into_boxed_slice(),
r8: 0,
r8_fiq: 0,
r9: 0,
r9_fiq: 0,
r10: 0,
r10_fiq: 0,
r11: 0,
r11_fiq: 0,
r12: 0,
r12_fiq: 0,
r13: 0,
r13_fiq: 0,
r13_svc: 0,
r13_abt: 0,
r13_irq: 0,
r13_und: 0,
r14: 0,
r14_fiq: 0,
r14_svc: 0,
r14_abt: 0,
r14_irq: 0,
r14_und: 0,
r15: 0,
cpsr: Cpsr::new(),
spsr: 0,
spsr_fiq: 0,
spsr_svc: 0,
spsr_abt: 0,
spsr_irq: 0,
spsr_und: 0,
null_spsr: 0,
}
}
pub fn read_register(&self, reg_idx: usize) -> u32 {
self.registers[reg_idx]
}
pub fn write_register(&mut self, reg_idx: usize, val: u32) {
self.registers[reg_idx] = val
}
pub fn spsr(&self) -> u32 {
if !self.does_spsr_exist() {
info!("[Register] Reading spsr in mode where it shouldn't exist");
}
self.spsr
}
pub fn set_spsr(&mut self, spsr: u32) {
if !self.does_spsr_exist() {
info!(
"[Register] Writing to spsr in mode where it shouldn't exist with data: {:#X}",
spsr
);
}
self.spsr = spsr;
}
fn does_spsr_exist(&self) -> bool {
self.cpsr.get_mode() == OperatingMode::User || self.cpsr.get_mode() == OperatingMode::System
}
pub fn switch_operating_mode(&mut self, new_mode: OperatingMode) {
let old_mode = self.cpsr.get_mode();
if new_mode == OperatingMode::Unknown {
warn!("Tried to set to unknown mode");
return;
}
if new_mode == old_mode {
return;
}
match old_mode {
OperatingMode::User | OperatingMode::System => {
self.r8 = self.registers[8];
self.r9 = self.registers[9];
self.r10 = self.registers[10];
self.r11 = self.registers[11];
self.r12 = self.registers[12];
self.r13 = self.registers[13];
self.r14 = self.registers[14];
self.null_spsr = self.spsr;
}
OperatingMode::Fiq => {
self.r8_fiq = self.registers[8];
self.r9_fiq = self.registers[9];
self.r10_fiq = self.registers[10];
self.r11_fiq = self.registers[11];
self.r12_fiq = self.registers[12];
self.r13_fiq = self.registers[13];
self.r14_fiq = self.registers[14];
self.spsr_fiq = self.spsr
}
OperatingMode::Irq => {
self.r8 = self.registers[8];
self.r9 = self.registers[9];
self.r10 = self.registers[10];
self.r11 = self.registers[11];
self.r12 = self.registers[12];
self.r13_irq = self.registers[13];
self.r14_irq = self.registers[14];
self.spsr_irq = self.spsr
}
OperatingMode::Supervisor => {
self.r8 = self.registers[8];
self.r9 = self.registers[9];
self.r10 = self.registers[10];
self.r11 = self.registers[11];
self.r12 = self.registers[12];
self.r13_svc = self.registers[13];
self.r14_svc = self.registers[14];
self.spsr_svc = self.spsr
}
OperatingMode::Abort => {
self.r8 = self.registers[8];
self.r9 = self.registers[9];
self.r10 = self.registers[10];
self.r11 = self.registers[11];
self.r12 = self.registers[12];
self.r13_abt = self.registers[13];
self.r14_abt = self.registers[14];
self.spsr_abt = self.spsr
}
OperatingMode::Undefined => {
self.r8 = self.registers[8];
self.r9 = self.registers[9];
self.r10 = self.registers[10];
self.r11 = self.registers[11];
self.r12 = self.registers[12];
self.r13_und = self.registers[13];
self.r14_und = self.registers[14];
self.spsr_und = self.spsr
}
_ => {
warn!(
"[Registers] Unable to switch operating mode because current mode is an invalid mode"
)
}
}
self.registers[8] = self.r8;
self.registers[9] = self.r9;
self.registers[10] = self.r10;
self.registers[11] = self.r11;
self.registers[12] = self.r12;
self.registers[13] = self.r13;
self.registers[14] = self.r14;
self.spsr = self.null_spsr;
match new_mode {
OperatingMode::User | OperatingMode::System => {}
OperatingMode::Fiq => {
self.registers[8] = self.r8_fiq;
self.registers[9] = self.r9_fiq;
self.registers[10] = self.r10_fiq;
self.registers[11] = self.r11_fiq;
self.registers[12] = self.r12_fiq;
self.registers[13] = self.r13_fiq;
self.registers[14] = self.r14_fiq;
self.spsr = self.spsr_fiq;
}
OperatingMode::Irq => {
self.registers[13] = self.r13_irq;
self.registers[14] = self.r14_irq;
self.spsr = self.spsr_irq;
}
OperatingMode::Supervisor => {
self.registers[13] = self.r13_svc;
self.registers[14] = self.r14_svc;
self.spsr = self.spsr_svc;
}
OperatingMode::Abort => {
self.registers[13] = self.r13_abt;
self.registers[14] = self.r14_abt;
self.spsr = self.spsr_abt;
}
OperatingMode::Undefined => {
self.registers[13] = self.r13_und;
self.registers[14] = self.r14_und;
self.spsr = self.spsr_und;
}
_ => {
warn!("Can't update to invalid opearting mode: {:#X}", new_mode as i32);
}
}
self.cpsr.mode = new_mode;
}
pub fn get_sign_flag(&self) -> bool {
self.cpsr.sign_flag
}
pub fn set_sign_flag(&mut self, sign_flag_val: bool) {
self.cpsr.sign_flag = sign_flag_val
}
pub fn get_zero_flag(&self) -> bool {
self.cpsr.zero_flag
}
pub fn set_zero_flag(&mut self, zero_flag_val: bool) {
self.cpsr.zero_flag = zero_flag_val
}
pub fn get_carry_flag(&self) -> bool {
self.cpsr.carry_flag
}
pub fn set_carry_flag(&mut self, carry_flag_val: bool) {
self.cpsr.carry_flag = carry_flag_val
}
pub fn get_overflow_flag(&self) -> bool {
self.cpsr.overflow_flag
}
pub fn set_overflow_flag(&mut self, overflow_flag_val: bool) {
self.cpsr.overflow_flag = overflow_flag_val
}
pub fn get_irq_disabled_flag(&self) -> bool {
self.cpsr.irq_disabled
}
pub fn set_irq_disabled(&mut self, irq_disabled_val: bool) {
self.cpsr.irq_disabled = irq_disabled_val
}
pub fn get_fiq_disabled(&self) -> bool {
self.cpsr.fiq_disabled
}
pub fn set_fiq_disabled(&mut self, fiq_disabled_val: bool) {
self.cpsr.fiq_disabled = fiq_disabled_val
}
pub fn get_thumb_state(&self) -> bool {
self.cpsr.thumb_state
}
pub fn set_thumb_state(&mut self, thumb_state_val: bool) {
self.cpsr.thumb_state = thumb_state_val
}
pub fn get_opearting_mode(&self) -> OperatingMode {
self.cpsr.mode
}
pub fn cpsr(&self) -> u32 {
self.cpsr.val()
}
pub fn set_cpsr(&mut self, cpsr: u32) {
self.switch_operating_mode(OperatingMode::from_u32(cpsr & Cpsr::MODE_EXTRACT_BITS));
self.cpsr.set(cpsr);
}
}
impl Reset for Registers {
fn reset(&mut self) {
self.cpsr.reset();
self.registers.fill(0);
self.r8 = 0;
self.r8_fiq = 0;
self.r9 = 0;
self.r9_fiq = 0;
self.r10 = 0;
self.r10_fiq = 0;
self.r11 = 0;
self.r11_fiq = 0;
self.r12 = 0;
self.r12_fiq = 0;
self.r13 = 0;
self.r13_fiq = 0;
self.r13_svc = 0;
self.r13_abt = 0;
self.r13_irq = 0;
self.r13_und = 0;
self.r14 = 0;
self.r14_fiq = 0;
self.r14_svc = 0;
self.r14_abt = 0;
self.r14_irq = 0;
self.r14_und = 0;
self.r15 = 0;
self.spsr = 0;
self.spsr_fiq = 0;
self.spsr_svc = 0;
self.spsr_abt = 0;
self.spsr_irq = 0;
self.spsr_und = 0;
self.null_spsr = 0;
}
}
struct CpsrSnapshot {
sign_flag: bool,
zero_flag: bool,
carry_flag: bool,
overflow_flag: bool,
sticky_overflow_flag: bool,
jazelle_state: bool,
greater_than_or_equal_to: [bool; 4],
data_endianness_bit: bool,
imprecise_data_abort: bool,
irq_disabled: bool,
fiq_disabled: bool,
thumb_state: bool,
mode: OperatingMode,
}
pub struct RegistersSnapshot {
skip_bios: bool,
registers: Box<[u32]>,
r8: u32,
r8_fiq: u32,
r9: u32,
r9_fiq: u32,
r10: u32,
r10_fiq: u32,
r11: u32,
r11_fiq: u32,
r12: u32,
r12_fiq: u32,
r13: u32,
r13_fiq: u32,
r13_svc: u32,
r13_abt: u32,
r13_irq: u32,
r13_und: u32,
r14: u32,
r14_fiq: u32,
r14_svc: u32,
r14_abt: u32,
r14_irq: u32,
r14_und: u32,
r15: u32,
cpsr: CpsrSnapshot,
spsr: u32,
spsr_fiq: u32,
spsr_svc: u32,
spsr_abt: u32,
spsr_irq: u32,
spsr_und: u32,
null_spsr: u32,
}
impl Snapshot<RegistersSnapshot> for Registers {
fn capture(self) -> Result<RegistersSnapshot, ()> {
Ok(RegistersSnapshot {
skip_bios: self.skip_bios.to_owned(),
registers: self.registers.to_owned(),
r8: self.r8.to_owned(),
r8_fiq: self.r8_fiq.to_owned(),
r9: self.r9.to_owned(),
r9_fiq: self.r9_fiq.to_owned(),
r10: self.r10.to_owned(),
r10_fiq: self.r10_fiq.to_owned(),
r11: self.r11.to_owned(),
r11_fiq: self.r11_fiq.to_owned(),
r12: self.r12.to_owned(),
r12_fiq: self.r12_fiq.to_owned(),
r13: self.r13.to_owned(),
r13_fiq: self.r13_fiq.to_owned(),
r13_svc: self.r13_svc.to_owned(),
r13_abt: self.r13_abt.to_owned(),
r13_irq: self.r13_irq.to_owned(),
r13_und: self.r13_und.to_owned(),
r14: self.r14.to_owned(),
r14_fiq: self.r14_fiq.to_owned(),
r14_svc: self.r14_svc.to_owned(),
r14_abt: self.r14_abt.to_owned(),
r14_irq: self.r14_irq.to_owned(),
r14_und: self.r14_und.to_owned(),
r15: self.r15.to_owned(),
cpsr: CpsrSnapshot {
sign_flag: self.cpsr.sign_flag.to_owned(),
zero_flag: self.cpsr.zero_flag.to_owned(),
carry_flag: self.cpsr.carry_flag.to_owned(),
overflow_flag: self.cpsr.overflow_flag.to_owned(),
sticky_overflow_flag: self.cpsr.sticky_overflow_flag.to_owned(),
jazelle_state: self.cpsr.jazelle_state.to_owned(),
greater_than_or_equal_to: self.cpsr.greater_than_or_equal_to.to_owned(),
data_endianness_bit: self.cpsr.data_endianness_bit.to_owned(),
imprecise_data_abort: self.cpsr.imprecise_data_abort.to_owned(),
irq_disabled: self.cpsr.irq_disabled.to_owned(),
fiq_disabled: self.cpsr.fiq_disabled.to_owned(),
thumb_state: self.cpsr.thumb_state.to_owned(),
mode: self.cpsr.mode.to_owned(),
},
spsr: self.spsr.to_owned(),
spsr_fiq: self.spsr_fiq.to_owned(),
spsr_svc: self.spsr_svc.to_owned(),
spsr_abt: self.spsr_abt.to_owned(),
spsr_irq: self.spsr_irq.to_owned(),
spsr_und: self.spsr_und.to_owned(),
null_spsr: self.null_spsr.to_owned(),
})
}
fn restore(&mut self, snapshot: RegistersSnapshot) -> Result<(), Box<dyn Error>> {
self.skip_bios = snapshot.skip_bios.to_owned();
self.registers = snapshot.registers.to_owned();
self.r8 = snapshot.r8.to_owned();
self.r8_fiq = snapshot.r8_fiq.to_owned();
self.r9 = snapshot.r9.to_owned();
self.r9_fiq = snapshot.r9_fiq.to_owned();
self.r10 = snapshot.r10.to_owned();
self.r10_fiq = snapshot.r10_fiq.to_owned();
self.r11 = snapshot.r11.to_owned();
self.r11_fiq = snapshot.r11_fiq.to_owned();
self.r12 = snapshot.r12.to_owned();
self.r12_fiq = snapshot.r12_fiq.to_owned();
self.r13 = snapshot.r13.to_owned();
self.r13_fiq = snapshot.r13_fiq.to_owned();
self.r13_svc = snapshot.r13_svc.to_owned();
self.r13_abt = snapshot.r13_abt.to_owned();
self.r13_irq = snapshot.r13_irq.to_owned();
self.r13_und = snapshot.r13_und.to_owned();
self.r14 = snapshot.r14.to_owned();
self.r14_fiq = snapshot.r14_fiq.to_owned();
self.r14_svc = snapshot.r14_svc.to_owned();
self.r14_abt = snapshot.r14_abt.to_owned();
self.r14_irq = snapshot.r14_irq.to_owned();
self.r14_und = snapshot.r14_und.to_owned();
self.r15 = snapshot.r15.to_owned();
self.cpsr.sign_flag = snapshot.cpsr.sign_flag.to_owned();
self.cpsr.zero_flag = snapshot.cpsr.zero_flag.to_owned();
self.cpsr.carry_flag = snapshot.cpsr.carry_flag.to_owned();
self.cpsr.overflow_flag = snapshot.cpsr.overflow_flag.to_owned();
self.cpsr.irq_disabled = snapshot.cpsr.irq_disabled.to_owned();
self.cpsr.fiq_disabled = snapshot.cpsr.fiq_disabled.to_owned();
self.cpsr.thumb_state = snapshot.cpsr.thumb_state.to_owned();
self.cpsr.mode = snapshot.cpsr.mode.to_owned();
self.spsr = snapshot.spsr.to_owned();
self.spsr_fiq = snapshot.spsr_fiq.to_owned();
self.spsr_svc = snapshot.spsr_svc.to_owned();
self.spsr_abt = snapshot.spsr_abt.to_owned();
self.spsr_irq = snapshot.spsr_irq.to_owned();
self.spsr_und = snapshot.spsr_und.to_owned();
self.null_spsr = snapshot.null_spsr.to_owned();
Ok(())
}
}