use super::MMix;
pub const RA_X: u64 = 0x01; pub const RA_Z: u64 = 0x02; pub const RA_U: u64 = 0x04; pub const RA_O: u64 = 0x08; pub const RA_I: u64 = 0x10; pub const RA_W: u64 = 0x20; pub const RA_V: u64 = 0x40; pub const RA_D: u64 = 0x80;
pub const RA_ROUND_SHIFT: u32 = 16;
pub const RA_MAX: u64 = 0x3FFFF;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SpecialReg {
RB = 0, RD = 1, RE = 2, RH = 3, RJ = 4, RM = 5, RR = 6, RBB = 7, RC = 8, RN = 9, RO = 10, RS = 11, RI = 12, RT = 13, RTT = 14, RK = 15, RQ = 16, RU = 17, RV = 18, RG = 19, RL = 20, RA = 21, RF = 22, RP = 23, RW = 24, RX = 25, RY = 26, RZ = 27, RWW = 28, RXX = 29, RYY = 30, RZZ = 31, }
impl SpecialReg {
pub fn name(self) -> &'static str {
match self {
SpecialReg::RB => "rB",
SpecialReg::RD => "rD",
SpecialReg::RE => "rE",
SpecialReg::RH => "rH",
SpecialReg::RJ => "rJ",
SpecialReg::RM => "rM",
SpecialReg::RR => "rR",
SpecialReg::RBB => "rBB",
SpecialReg::RC => "rC",
SpecialReg::RN => "rN",
SpecialReg::RO => "rO",
SpecialReg::RS => "rS",
SpecialReg::RI => "rI",
SpecialReg::RT => "rT",
SpecialReg::RTT => "rTT",
SpecialReg::RK => "rK",
SpecialReg::RQ => "rQ",
SpecialReg::RU => "rU",
SpecialReg::RV => "rV",
SpecialReg::RG => "rG",
SpecialReg::RL => "rL",
SpecialReg::RA => "rA",
SpecialReg::RF => "rF",
SpecialReg::RP => "rP",
SpecialReg::RW => "rW",
SpecialReg::RX => "rX",
SpecialReg::RY => "rY",
SpecialReg::RZ => "rZ",
SpecialReg::RWW => "rWW",
SpecialReg::RXX => "rXX",
SpecialReg::RYY => "rYY",
SpecialReg::RZZ => "rZZ",
}
}
pub fn from_u8(n: u8) -> Option<Self> {
match n {
0 => Some(SpecialReg::RB),
1 => Some(SpecialReg::RD),
2 => Some(SpecialReg::RE),
3 => Some(SpecialReg::RH),
4 => Some(SpecialReg::RJ),
5 => Some(SpecialReg::RM),
6 => Some(SpecialReg::RR),
7 => Some(SpecialReg::RBB),
8 => Some(SpecialReg::RC),
9 => Some(SpecialReg::RN),
10 => Some(SpecialReg::RO),
11 => Some(SpecialReg::RS),
12 => Some(SpecialReg::RI),
13 => Some(SpecialReg::RT),
14 => Some(SpecialReg::RTT),
15 => Some(SpecialReg::RK),
16 => Some(SpecialReg::RQ),
17 => Some(SpecialReg::RU),
18 => Some(SpecialReg::RV),
19 => Some(SpecialReg::RG),
20 => Some(SpecialReg::RL),
21 => Some(SpecialReg::RA),
22 => Some(SpecialReg::RF),
23 => Some(SpecialReg::RP),
24 => Some(SpecialReg::RW),
25 => Some(SpecialReg::RX),
26 => Some(SpecialReg::RY),
27 => Some(SpecialReg::RZ),
28 => Some(SpecialReg::RWW),
29 => Some(SpecialReg::RXX),
30 => Some(SpecialReg::RYY),
31 => Some(SpecialReg::RZZ),
_ => None,
}
}
}
pub(super) const SAVE_SPECIALS: [SpecialReg; 12] = [
SpecialReg::RB,
SpecialReg::RD,
SpecialReg::RE,
SpecialReg::RH,
SpecialReg::RJ,
SpecialReg::RM,
SpecialReg::RR,
SpecialReg::RP,
SpecialReg::RW,
SpecialReg::RX,
SpecialReg::RY,
SpecialReg::RZ,
];
impl MMix {
pub(super) fn put_special(&mut self, mnemonic: &str, x: u8, value: u64) -> bool {
let Some(reg) = SpecialReg::from_u8(x) else {
return self.reject(&format!(
"{mnemonic} X={x},{value}: no special register above 31 at PC={:#018x}",
self.pc
));
};
match reg {
SpecialReg::RC
| SpecialReg::RI
| SpecialReg::RK
| SpecialReg::RQ
| SpecialReg::RT
| SpecialReg::RU
| SpecialReg::RV
| SpecialReg::RTT => self.reject(&format!(
"{mnemonic} {},{value}: privileged-operation interrupt at PC={:#018x}",
reg.name(),
self.pc
)),
SpecialReg::RN | SpecialReg::RO | SpecialReg::RS => self.reject(&format!(
"{mnemonic} {},{value}: illegal-instruction interrupt at PC={:#018x}",
reg.name(),
self.pc
)),
SpecialReg::RG => {
let rl = self.get_special(SpecialReg::RL);
if value < 32 || value < rl || value > 255 {
return self.reject(&format!(
"{mnemonic} rG,{value}: illegal-instruction interrupt \
(rG must be 32-255 and >= rL={rl}) at PC={:#018x}",
self.pc
));
}
self.put_rg(value);
true
}
SpecialReg::RL => {
self.put_rl(value);
true
}
SpecialReg::RA if value > RA_MAX => self.reject(&format!(
"{mnemonic} rA,{value:#x}: illegal-instruction interrupt \
(rA holds at most 18 bits, max {RA_MAX:#x}) at PC={:#018x}",
self.pc
)),
_ => {
self.set_special(reg, value);
true
}
}
}
fn put_rl(&mut self, z: u64) {
let rl_old = self.get_special(SpecialReg::RL);
let rl_new = z.min(rl_old);
let rg = self.get_special(SpecialReg::RG);
let drop_end = rl_old.min(rg).min(self.general_regs.len() as u64);
for marginal in rl_new..drop_end {
self.general_regs[marginal as usize] = 0;
}
self.set_special(SpecialReg::RL, rl_new);
}
fn put_rg(&mut self, z: u64) {
let rg_old = self.get_special(SpecialReg::RG);
let (lo, hi) = if z > rg_old { (rg_old, z) } else { (z, rg_old) };
let hi = hi.min(self.general_regs.len() as u64);
for reg in lo..hi {
self.general_regs[reg as usize] = 0;
}
self.set_special(SpecialReg::RG, z);
}
}