armv4t_emu/
reg.rs

1//! Register identifiers.
2
3use std::ops::{Index, IndexMut};
4
5use log::*;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use crate::mode::Mode;
10use crate::util::bit::BitUtilExt;
11
12pub type Reg = u8;
13
14const NUM_RGSR: usize = 37;
15
16/// Stack Pointer (R13)
17pub const SP: Reg = 13;
18/// Link Register (R14)
19pub const LR: Reg = 14;
20/// Program Counter (R15)
21pub const PC: Reg = 15;
22/// Current Program Status Register
23pub const CPSR: Reg = 16;
24/// Saved Program Status Register
25pub const SPSR: Reg = 17;
26
27pub(crate) mod cpsr {
28    use super::Reg;
29
30    pub const N: Reg = 31;
31    pub const Z: Reg = 30;
32    pub const C: Reg = 29;
33    pub const V: Reg = 28;
34
35    pub const T: Reg = 5;
36}
37
38#[rustfmt::skip]
39const REG_MAP: [[usize; 18]; 6] = [
40    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16],   // user
41    [0, 1, 2, 3, 4, 5, 6, 7, 17, 18, 19, 20, 21, 22, 23, 15, 16, 24], // fiq
42    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 15, 16, 27],   // irq
43    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 28, 29, 15, 16, 30],   // supervisor
44    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, 32, 15, 16, 33],   // abort
45    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 34, 35, 15, 16, 36],   // undefined
46];
47
48#[cfg(feature = "serde")]
49mod big_array {
50    use serde_big_array::big_array;
51    big_array! { BigArray; +super::NUM_RGSR }
52}
53
54#[derive(Copy, Clone)]
55#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56pub(crate) struct RegFile {
57    #[cfg_attr(feature = "serde", serde(with = "big_array::BigArray"))]
58    reg: [u32; NUM_RGSR],
59    bank: usize,
60}
61
62impl PartialEq for RegFile {
63    fn eq(&self, other: &Self) -> bool {
64        self.reg[..] == other.reg[..] && self.bank == other.bank
65    }
66}
67
68impl Eq for RegFile {}
69
70// This is pretty jank, due to the way registers are stored
71// It could use some improvement.
72impl std::fmt::Debug for RegFile {
73    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
74        let mut builder = fmt.debug_struct("RegFile");
75        builder.field("cur_bank", &self.bank);
76        for (bank, map) in REG_MAP.iter().enumerate() {
77            let mut regs = Vec::new();
78            for (i, reg) in map.iter().copied().enumerate() {
79                match i as u8 {
80                    SP => regs.push(("SP".to_string(), self.reg[reg])),
81                    LR => regs.push(("LR".to_string(), self.reg[reg])),
82                    PC => regs.push(("PC".to_string(), self.reg[reg])),
83                    CPSR => regs.push(("CPSR".to_string(), self.reg[reg])),
84                    SPSR => regs.push(("SPSR".to_string(), self.reg[reg])),
85                    _ => regs.push((format!("r{}", i), self.reg[reg])),
86                };
87            }
88            builder.field(
89                match bank {
90                    0 => "user       ",
91                    1 => "fiq        ",
92                    2 => "irq        ",
93                    3 => "supervisor ",
94                    4 => "abort      ",
95                    5 => "undefined  ",
96                    _ => unreachable!(),
97                },
98                &format!("{:08x?}", regs).replace("\"", ""),
99            );
100        }
101        builder.finish()
102    }
103}
104
105impl RegFile {
106    pub fn new_empty() -> RegFile {
107        RegFile {
108            reg: [0; NUM_RGSR],
109            bank: 0,
110        }
111    }
112
113    #[inline]
114    pub fn mode(&self) -> Mode {
115        // `expect` should never be fired, as mode bits are checked to be valid when
116        // setting the CPSR value.
117        Mode::from_bits(self.reg[CPSR as usize].extract(0, 5) as u8)
118            .expect("CPSR contained invalid mode bits")
119    }
120
121    #[inline]
122    pub fn update_bank(&mut self) {
123        self.bank = self.mode().reg_bank();
124    }
125
126    #[inline]
127    pub fn set(&mut self, bank: usize, reg: Reg, mut val: u32) {
128        if reg == CPSR {
129            let bits = val.extract(0, 5) as u8;
130            let mode = Mode::from_bits(bits);
131            if mode.is_none() {
132                // Switching to an invalid mode leads to unpredictable behavior.
133                //
134                // Panicking here would be unnecessarily harsh, as the error is
135                // originating from emulated code, which the end-user might not
136                // have written themselves.
137                //
138                // Instead, we take a page out of QEMU's book and simply leave
139                // the mode bits unchanged, while logging an error.
140                error!(
141                    "Attempted to write to CPSR with invalid mode bits: {:#x}",
142                    bits
143                );
144
145                let oldval = self.reg[CPSR as usize];
146                val = (val & !0x1f) | (oldval & 0x1f);
147            }
148        }
149
150        self.reg[REG_MAP[bank][reg as usize]] = val;
151        if reg == CPSR {
152            self.update_bank()
153        }
154    }
155
156    #[inline]
157    pub fn get(&self, bank: usize, reg: Reg) -> u32 {
158        self.reg[REG_MAP[bank][reg as usize]]
159    }
160}
161
162impl Index<Reg> for RegFile {
163    type Output = u32;
164    #[inline]
165    fn index(&self, idx: Reg) -> &u32 {
166        &self.reg[REG_MAP[self.bank][idx as usize]]
167    }
168}
169
170impl IndexMut<Reg> for RegFile {
171    #[inline]
172    fn index_mut(&mut self, idx: Reg) -> &mut u32 {
173        &mut self.reg[REG_MAP[self.bank][idx as usize]]
174    }
175}