use serde::{Deserialize, Serialize};
use super::registers::{control, get, is_set, mask, set, xpsr};
#[repr(C)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct State {
pub(crate) r: [u32; 16],
pub(crate) n: u32,
pub(crate) z: u32,
pub(crate) c: u32,
pub(crate) v: u32,
pub(crate) q: u32,
pub(crate) ge: u32,
pub(crate) it: u32,
pub(crate) t: u32,
pub(crate) ipsr: u32,
pub(crate) primask: u32,
pub(crate) faultmask: u32,
pub(crate) control: u32,
pub(crate) other_sp: u32,
pub(crate) s: [u32; 32],
pub(crate) fpscr: u32,
pub(crate) locked_up: u32,
pub(crate) sleeping: u32,
pub(crate) exclusive_valid: u32,
pub(crate) event: u32,
}
impl Default for State {
fn default() -> Self {
Self {
r: [0; 16],
n: 0,
z: 0,
c: 0,
v: 0,
q: 0,
ge: 0,
it: 0,
t: 1,
ipsr: 0,
primask: 0,
faultmask: 0,
control: 0,
other_sp: 0,
s: [0; 32],
fpscr: 0,
locked_up: 0,
sleeping: 0,
exclusive_valid: 0,
event: 0,
}
}
}
impl State {
pub(crate) fn xpsr(&self) -> u32 {
let it = self.it;
set(xpsr::N, 0, self.n)
| set(xpsr::Z, 0, self.z)
| set(xpsr::C, 0, self.c)
| set(xpsr::V, 0, self.v)
| set(xpsr::Q, 0, self.q)
| set(xpsr::IT_1_0, 0, it)
| set(xpsr::T, 0, self.t)
| set(xpsr::GE, 0, self.ge)
| set(xpsr::IT_7_2, 0, it >> xpsr::IT_1_0.width)
| set(xpsr::EXCEPTION_NUMBER, 0, self.ipsr)
}
pub(crate) fn consistent(&self) -> bool {
let flags = [
self.n,
self.z,
self.c,
self.v,
self.q,
self.t,
self.primask,
self.faultmask,
self.locked_up,
self.exclusive_valid,
self.event,
];
flags.iter().all(|&flag| flag <= 1)
&& self.ge <= 0xF
&& self.it <= 0xFF
&& self.control <= mask(control::NPRIV) | mask(control::SPSEL) | mask(control::FPCA)
&& self.sleeping <= super::exception::ON_EXIT
&& self.r[13].trailing_zeros() >= 2
&& self.other_sp.trailing_zeros() >= 2
}
pub(crate) fn set_xpsr(&mut self, value: u32) {
self.n = get(xpsr::N, value);
self.z = get(xpsr::Z, value);
self.c = get(xpsr::C, value);
self.v = get(xpsr::V, value);
self.q = get(xpsr::Q, value);
self.it = get(xpsr::IT_1_0, value) | get(xpsr::IT_7_2, value) << xpsr::IT_1_0.width;
self.t = get(xpsr::T, value);
self.ge = get(xpsr::GE, value);
self.ipsr = get(xpsr::EXCEPTION_NUMBER, value);
}
pub(crate) fn handler(&self) -> bool {
self.ipsr != 0
}
pub(crate) fn privileged(&self) -> bool {
self.handler() || !is_set(control::NPRIV, self.control)
}
pub(crate) fn on_process_stack(&self) -> bool {
!self.handler() && is_set(control::SPSEL, self.control)
}
pub(crate) fn msp(&self) -> u32 {
if self.on_process_stack() {
self.other_sp
} else {
self.r[13]
}
}
pub(crate) fn psp(&self) -> u32 {
if self.on_process_stack() {
self.r[13]
} else {
self.other_sp
}
}
pub(crate) fn set_msp(&mut self, value: u32) {
let value = value & !3;
if self.on_process_stack() {
self.other_sp = value;
} else {
self.r[13] = value;
}
}
pub(crate) fn set_psp(&mut self, value: u32) {
let value = value & !3;
if self.on_process_stack() {
self.r[13] = value;
} else {
self.other_sp = value;
}
}
pub(crate) fn set_mode(&mut self, ipsr: u32, control: u32) {
let (msp, psp) = (self.msp(), self.psp());
self.ipsr = ipsr;
self.control = control;
self.set_msp(msp);
self.set_psp(psp);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn xpsr_holds_every_field_where_the_manual_puts_it() {
let mut state = State::default();
state.set_xpsr(0xF900_FC23);
assert_eq!(
(state.n, state.z, state.c, state.v, state.q),
(1, 1, 1, 1, 1)
);
assert_eq!(state.t, 1);
assert_eq!(state.ipsr, 0x23);
assert_eq!(state.it, 0b1111_1100);
assert_eq!(state.xpsr(), 0xF900_FC23);
}
#[test]
fn a_change_of_mode_keeps_both_stack_pointers() {
let mut state = State::default();
state.r[13] = 0x100;
state.other_sp = 0x200;
state.set_mode(0, mask(control::SPSEL));
assert_eq!(
(state.msp(), state.psp(), state.r[13]),
(0x100, 0x200, 0x200)
);
state.set_mode(15, mask(control::SPSEL));
assert_eq!(
(state.msp(), state.psp(), state.r[13]),
(0x100, 0x200, 0x100)
);
}
}