core.rsannotatedcore.rssource256 lines · 6.1 KB · raw
1mod instructions;
2
3use crate::traits::BusInterface;
4use bincode::{Decode, Encode};
5use jgenesis_common::num::GetBit;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
8enum SizeBits {
9    Eight,
10    Sixteen,
11}
12
13impl SizeBits {
14    fn from_bit(bit: bool) -> Self {
15        if bit { Self::Eight } else { Self::Sixteen }
16    }
17
18    fn to_bit(self) -> bool {
19        self == Self::Eight
20    }
21}
22
23#[derive(Debug, Clone, Copy, Encode, Decode)]
24pub struct StatusRegister {
25    carry: bool,
26    zero: bool,
27    irq_disabled: bool,
28    decimal_mode: bool,
29    index_size: SizeBits,
30    accumulator_size: SizeBits,
31    overflow: bool,
32    negative: bool,
33}
34
35impl Default for StatusRegister {
36    fn default() -> Self {
37        Self {
38            carry: false,
39            zero: false,
40            irq_disabled: true,
41            decimal_mode: false,
42            index_size: SizeBits::Eight,
43            accumulator_size: SizeBits::Eight,
44            overflow: false,
45            negative: false,
46        }
47    }
48}
49
50impl From<StatusRegister> for u8 {
51    fn from(value: StatusRegister) -> Self {
52        (u8::from(value.negative) << 7)
53            | (u8::from(value.overflow) << 6)
54            | (u8::from(value.accumulator_size.to_bit()) << 5)
55            | (u8::from(value.index_size.to_bit()) << 4)
56            | (u8::from(value.decimal_mode) << 3)
57            | (u8::from(value.irq_disabled) << 2)
58            | (u8::from(value.zero) << 1)
59            | u8::from(value.carry)
60    }
61}
62
63impl From<u8> for StatusRegister {
64    fn from(value: u8) -> Self {
65        Self {
66            carry: value.bit(0),
67            zero: value.bit(1),
68            irq_disabled: value.bit(2),
69            decimal_mode: value.bit(3),
70            index_size: SizeBits::from_bit(value.bit(4)),
71            accumulator_size: SizeBits::from_bit(value.bit(5)),
72            overflow: value.bit(6),
73            negative: value.bit(7),
74        }
75    }
76}
77
78#[derive(Debug, Clone, Encode, Decode)]
79pub struct Registers {
80    // Accumulator
81    pub a: u16,
82    // Index registers
83    pub x: u16,
84    pub y: u16,
85    // Stack pointer
86    pub s: u16,
87    // Direct page pointer
88    pub d: u16,
89    // Program bank register
90    pub pbr: u8,
91    // Program counter
92    pub pc: u16,
93    // Data bank register
94    pub dbr: u8,
95    // Status register
96    pub p: StatusRegister,
97    // Emulation mode flag
98    pub emulation_mode: bool,
99}
100
101impl Registers {
102    fn new() -> Self {
103        Self {
104            a: 0,
105            x: 0,
106            y: 0,
107            s: 0x01FF,
108            d: 0,
109            pbr: 0,
110            pc: 0,
111            dbr: 0,
112            p: StatusRegister::default(),
113            // 65816 always powers on in emulation mode
114            emulation_mode: true,
115        }
116    }
117}
118
119#[derive(Debug, Clone, Default, Encode, Decode)]
120struct State {
121    cycle: u8,
122    opcode: u8,
123    handling_interrupt: Option<InterruptType>,
124    waiting: bool,
125    stopped: bool,
126    last_nmi: bool,
127    nmi_triggered: bool,
128    last_irq: bool,
129    irq_triggered: bool,
130    reset_pending: bool,
131    // Temp values to store internal instruction state between cycles
132    t0: u8,
133    t1: u8,
134    t2: u8,
135    t3: u8,
136    t4: u8,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
140pub(crate) enum InterruptType {
141    Breakpoint,
142    Coprocessor,
143    Nmi,
144    Irq,
145    Reset,
146}
147
148impl InterruptType {
149    const fn is_software(self) -> bool {
150        matches!(self, Self::Breakpoint | Self::Coprocessor)
151    }
152
153    const fn emulation_vector(self) -> u16 {
154        match self {
155            Self::Coprocessor => 0xFFF4,
156            Self::Nmi => 0xFFFA,
157            Self::Reset => 0xFFFC,
158            Self::Breakpoint | Self::Irq => 0xFFFE,
159        }
160    }
161
162    const fn native_vector(self) -> u16 {
163        match self {
164            Self::Coprocessor => 0xFFE4,
165            Self::Breakpoint => 0xFFE6,
166            Self::Nmi => 0xFFEA,
167            Self::Irq => 0xFFEE,
168            Self::Reset => 0xFFFC,
169        }
170    }
171}
172
173#[derive(Debug, Clone, Encode, Decode)]
174pub struct Wdc65816 {
175    registers: Registers,
176    state: State,
177}
178
179impl Wdc65816 {
180    #[must_use]
181    pub fn new() -> Self {
182        Self { registers: Registers::new(), state: State::default() }
183    }
184
185    pub fn reset<B: BusInterface>(&mut self, bus: &mut B) {
186        let reset_vector: u32 = InterruptType::Reset.emulation_vector().into();
187        let address_lsb = bus.read(reset_vector);
188        let address_msb = bus.read(reset_vector + 1);
189        self.registers.pc = u16::from_le_bytes([address_lsb, address_msb]);
190        self.registers.pbr = 0;
191
192        self.registers.p.irq_disabled = true;
193        self.registers.p.decimal_mode = false;
194        self.registers.emulation_mode = true;
195
196        // Emulation mode forces on m and x flags and forces the stack to page 1
197        self.registers.p.accumulator_size = SizeBits::Eight;
198        self.registers.p.index_size = SizeBits::Eight;
199        self.registers.x &= 0x00FF;
200        self.registers.y &= 0x00FF;
201        self.registers.s = 0x0100 | (self.registers.s & 0x00FF);
202
203        self.state = State::default();
204    }
205
206    #[inline]
207    pub fn tick<B: BusInterface>(&mut self, bus: &mut B) {
208        if bus.reset() {
209            self.state.reset_pending = true;
210            bus.idle();
211            return;
212        }
213
214        if self.state.reset_pending {
215            // TODO timing? this does 2 bus reads and probably takes more internal cycles
216            self.reset(bus);
217            self.state.reset_pending = false;
218            return;
219        }
220
221        if bus.halt() {
222            bus.idle();
223            return;
224        }
225
226        instructions::execute(self, bus);
227    }
228
229    #[inline]
230    #[must_use]
231    pub fn is_mid_instruction(&self) -> bool {
232        self.state.cycle != 0
233    }
234
235    #[inline]
236    #[must_use]
237    pub fn registers(&self) -> &Registers {
238        &self.registers
239    }
240
241    #[inline]
242    pub fn set_registers(&mut self, registers: Registers) {
243        self.registers = registers;
244
245        if self.registers.emulation_mode {
246            // Stack is forced to page 1 in emulation mode
247            self.registers.s = 0x0100 | (self.registers.s & 0x00FF);
248        }
249    }
250}
251
252impl Default for Wdc65816 {
253    fn default() -> Self {
254        Self::new()
255    }
256}