1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
use std::ops::{Index, IndexMut};

use faucon_asm::{Operand, Register, RegisterKind};

/// A special-purpose register that holds the address for Interrupt Vector 0.
pub const IV0: Register = Register(RegisterKind::Spr, 0);

/// A special-purpose register that holds the address for Interrupt Vector 1.
pub const IV1: Register = Register(RegisterKind::Spr, 1);

/// A special-purpose register that holds the address for Interrupt Vector 2.
pub const IV2: Register = Register(RegisterKind::Spr, 2);

/// A special-purpose register that holds the address for the Trap Vector.
pub const TV: Register = Register(RegisterKind::Spr, 3);

/// A special-purpose register that holds the current stack pointer.
pub const SP: Register = Register(RegisterKind::Spr, 4);

/// A special-purpose register that holds the current program counter.
pub const PC: Register = Register(RegisterKind::Spr, 5);

/// A special-purpose register that holds the external base address for IMEM
/// transfers.
pub const XCBASE: Register = Register(RegisterKind::Spr, 6);

/// A special-purpose register that holds the external base address for DMEM
/// transfers.
pub const XDBASE: Register = Register(RegisterKind::Spr, 7);

/// A special-purpose register that holds various CPU flag bits.
pub const FLAGS: Register = Register(RegisterKind::Spr, 8);

/// A special-purpose register that holds the configuration bits for the SCP DMA
/// functionality.
pub const CX: Register = Register(RegisterKind::Spr, 9);

/// A special-purpose register that holds the configuration bits for the SCP
/// authentication process.
pub const CAUTH: Register = Register(RegisterKind::Spr, 10);

/// A special-purpose register that holds the configuration bits for the CTXDMA
/// ports.
pub const XTARGETS: Register = Register(RegisterKind::Spr, 11);

/// A special-purpose register that holds details on triggered traps.
pub const TSTATUS: Register = Register(RegisterKind::Spr, 12);

enum_from_primitive! {
    /// Flag bits for the `flags` special-purpose register.
    #[derive(Debug)]
    #[repr(u32)]
    pub enum CpuFlag {
        /// General-purpose predicate 0.
        P0 = 1 << 0,
        /// General-purpose predicate 1.
        P1 = 1 << 1,
        /// General-purpose predicate 2.
        P2 = 1 << 2,
        /// General-purpose predicate 3.
        P3 = 1 << 3,
        /// General-purpose predicate 4.
        P4 = 1 << 4,
        /// General-purpose predicate 5.
        P5 = 1 << 5,
        /// General-purpose predicate 6.
        P6 = 1 << 6,
        /// General-purpose predicate 7.
        P7 = 1 << 7,
        /// ALU carry flag.
        CARRY = 1 << 8,
        /// ALU signed overflow flag.
        OVERFLOW = 1 << 9,
        /// ALU sign/negative flag.
        NEGATIVE = 1 << 10,
        /// ALU zero flag.
        ZERO = 1 << 11,
        /// Interrupt 0 enable flag.
        IE0 = 1 << 16,
        /// Interrupt 1 enable flag.
        IE1 = 1 << 17,
        /// Interrupt 2 enable flag.
        IE2 = 1 << 18,
        /// Interrupt 0 saved enable flag.
        IS0 = 1 << 20,
        /// Interrupt 1 saved enable flag.
        IS1 = 1 << 21,
        /// Interrupt 2 saved enable flag.
        IS2 = 1 << 22,
        /// Trap handler active flag.
        TA = 1 << 24,
    }
}

/// Representation of all Falcon CPU registers.
pub struct CpuRegisters {
    /// The general-purpose CPU registers of the Falcon.
    gpr: [u32; 0x10],
    /// The special-purpose CPU registers of the Falcon.
    spr: [u32; 0x10],
}

impl CpuRegisters {
    /// Creates a new instance of the registers and initializes all of
    /// them to zero.
    pub fn new() -> Self {
        CpuRegisters {
            gpr: [0; 0x10],
            spr: [0; 0x10],
        }
    }

    /// Sets a given CPU flag bit in the `$flags` register.
    pub fn set_flag(&mut self, flag: CpuFlag, set: bool) {
        if set {
            self[FLAGS] |= flag as u32;
        } else {
            self[FLAGS] &= !(flag as u32);
        }
    }

    /// Checks if a given CPU flag bit in the `$flags` register is set.
    pub fn get_flag(&self, flag: CpuFlag) -> bool {
        (self[FLAGS] & flag as u32) != 0
    }

    /// A debugging method that grants immutable access to the registers of the
    /// supplied [`faucon_asm::operands::RegisterKind`].
    ///
    /// NOTE: The intent behind this method is to query internal state for
    /// inspection during emulation.
    pub fn debug_get(&self, kind: &RegisterKind) -> &[u32] {
        match kind {
            RegisterKind::Gpr => &self.gpr,
            RegisterKind::Spr => &self.spr,
        }
    }
}

impl Index<Register> for CpuRegisters {
    type Output = u32;

    fn index(&self, reg: Register) -> &Self::Output {
        match reg.0 {
            RegisterKind::Gpr => &self.gpr[reg.1],
            RegisterKind::Spr => &self.spr[reg.1],
        }
    }
}

impl IndexMut<Register> for CpuRegisters {
    fn index_mut(&mut self, reg: Register) -> &mut Self::Output {
        match reg.0 {
            RegisterKind::Gpr => &mut self.gpr[reg.1],
            RegisterKind::Spr => &mut self.spr[reg.1],
        }
    }
}

impl Index<Operand> for CpuRegisters {
    type Output = u32;

    fn index(&self, operand: Operand) -> &Self::Output {
        match operand {
            Operand::Register(reg) => &self[reg],
            _ => panic!("Invalid operand supplied"),
        }
    }
}

impl IndexMut<Operand> for CpuRegisters {
    fn index_mut(&mut self, operand: Operand) -> &mut Self::Output {
        match operand {
            Operand::Register(reg) => &mut self[reg],
            _ => panic!("Invalid operand supplied"),
        }
    }
}