lib.rsannotatedlib.rssource479 lines · 15.0 KB · raw
1pub mod bus;
2mod instructions;
3
4use crate::bus::{BusInterface, MemoryCycle};
5use crate::instructions::{ArmOpTable, ThumbOpTable};
6use bincode::{Decode, Encode};
7use jgenesis_common::num::GetBit;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
10pub enum CpuState {
11    // 32-bit opcodes, full instruction set
12    #[default]
13    Arm = 0,
14    // 16-bit opcodes, limited instruction set
15    Thumb = 1,
16}
17
18impl CpuState {
19    fn from_bit(bit: bool) -> Self {
20        if bit { Self::Thumb } else { Self::Arm }
21    }
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
25pub enum CpuMode {
26    #[default]
27    User = 0x10,
28    Fiq = 0x11,
29    Irq = 0x12,
30    Supervisor = 0x13,
31    Abort = 0x17,
32    Undefined = 0x1B,
33    // Arbitrary unused mode value
34    Illegal = 0x1E,
35    System = 0x1F,
36}
37
38impl CpuMode {
39    fn from_bits(bits: u32) -> Self {
40        // Only lowest 4 bits are checked on mode writes; highest bit is forced to 1
41        // (alyosha-tas/gba-tests PSR tests)
42        match bits & 0xF {
43            0x0 => Self::User,
44            0x1 => Self::Fiq,
45            0x2 => Self::Irq,
46            0x3 => Self::Supervisor,
47            0x7 => Self::Abort,
48            0xB => Self::Undefined,
49            0xF => Self::System,
50            _ => Self::Illegal,
51        }
52    }
53
54    fn spsr(self, registers: &mut Registers) -> Option<&mut StatusRegister> {
55        match self {
56            Self::Irq => Some(&mut registers.spsr_irq),
57            Self::Fiq => Some(&mut registers.spsr_fiq),
58            Self::Supervisor => Some(&mut registers.spsr_svc),
59            Self::Undefined => Some(&mut registers.spsr_und),
60            Self::Abort => Some(&mut registers.spsr_abt),
61            Self::User | Self::System | Self::Illegal => None,
62        }
63    }
64}
65
66#[derive(Debug, Clone, Copy, Default, Encode, Decode)]
67struct StatusRegister {
68    sign: bool,
69    zero: bool,
70    carry: bool,
71    overflow: bool,
72    irq_disabled: bool,
73    fiq_disabled: bool,
74    state: CpuState,
75    mode: CpuMode,
76}
77
78impl From<StatusRegister> for u32 {
79    fn from(value: StatusRegister) -> Self {
80        (u32::from(value.sign) << 31)
81            | (u32::from(value.zero) << 30)
82            | (u32::from(value.carry) << 29)
83            | (u32::from(value.overflow) << 28)
84            | (u32::from(value.irq_disabled) << 7)
85            | (u32::from(value.fiq_disabled) << 6)
86            | ((value.state as u32) << 5)
87            | (value.mode as u32)
88    }
89}
90
91impl From<u32> for StatusRegister {
92    fn from(value: u32) -> Self {
93        Self {
94            sign: value.bit(31),
95            zero: value.bit(30),
96            carry: value.bit(29),
97            overflow: value.bit(28),
98            irq_disabled: value.bit(7),
99            fiq_disabled: value.bit(6),
100            state: CpuState::from_bit(value.bit(5)),
101            mode: CpuMode::from_bits(value & 0x1F),
102        }
103    }
104}
105
106#[derive(Debug, Clone, Default, Encode, Decode)]
107struct Registers {
108    // "General-purpose" registers; R15 is the program counter
109    r: [u32; 16],
110    // R13 and R14 are banked by mode
111    r13_usr: u32,
112    r14_usr: u32,
113    r13_svc: u32,
114    r14_svc: u32,
115    r13_irq: u32,
116    r14_irq: u32,
117    r13_und: u32,
118    r14_und: u32,
119    r13_abt: u32,
120    r14_abt: u32,
121    r13_fiq: u32,
122    r14_fiq: u32,
123    // R8-R12 are banked only for FIQ vs. non-FIQ
124    fiq_r_8_12: [u32; 5],
125    other_r_8_12: [u32; 5],
126    // Condition codes and control register
127    cpsr: StatusRegister,
128    // Previous condition codes and control registers, banked by CPU mode (excluding usr)
129    spsr_svc: StatusRegister,
130    spsr_irq: StatusRegister,
131    spsr_und: StatusRegister,
132    spsr_abt: StatusRegister,
133    spsr_fiq: StatusRegister,
134}
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137enum Exception {
138    Reset,
139    UndefinedInstruction,
140    SoftwareInterrupt,
141    Irq,
142}
143
144impl Exception {
145    const fn vector_address(self) -> u32 {
146        match self {
147            Self::Reset => 0x00,
148            Self::UndefinedInstruction => 0x04,
149            Self::SoftwareInterrupt => 0x08,
150            Self::Irq => 0x18,
151        }
152    }
153
154    const fn new_mode(self) -> CpuMode {
155        match self {
156            Self::Reset | Self::SoftwareInterrupt => CpuMode::Supervisor,
157            Self::UndefinedInstruction => CpuMode::Undefined,
158            Self::Irq => CpuMode::Irq,
159        }
160    }
161
162    #[allow(clippy::match_same_arms)]
163    fn return_address(self, state: CpuState, r15: u32) -> u32 {
164        // R15 is PC+8 for ARM and PC+4 for Thumb
165        match (state, self) {
166            // ARM R14 is always PC+4 except for Data abort, which is not emulated
167            (CpuState::Arm, _) => r15.wrapping_sub(4),
168            // Thumb R14 is PC+2 for SWI and Undefined
169            (CpuState::Thumb, Self::UndefinedInstruction | Self::SoftwareInterrupt) => {
170                r15.wrapping_sub(2)
171            }
172            // Thumb R14 is PC+4 for IRQ (and FIQ and Data abort, which are not emulated)
173            (CpuState::Thumb, Self::Irq) => r15,
174            // Reset value doesn't matter because return address is not written when handling Reset
175            (CpuState::Thumb, Self::Reset) => r15,
176        }
177    }
178}
179
180#[derive(Debug, Clone, Encode, Decode)]
181pub struct Arm7Tdmi<Bus: BusInterface> {
182    registers: Registers,
183    prefetch: [u32; 2],
184    fetch_cycle: MemoryCycle,
185    prev_r15: u32,
186    irq_disabled_latch: bool,
187    arm_op_table: ArmOpTable<Bus>,
188    thumb_op_table: ThumbOpTable<Bus>,
189}
190
191impl<Bus: BusInterface> Default for Arm7Tdmi<Bus> {
192    fn default() -> Self {
193        Self::new()
194    }
195}
196
197pub struct Arm7TdmiResetArgs {
198    pub pc: u32,
199    pub sp_usr: u32,
200    pub sp_svc: u32,
201    pub sp_irq: u32,
202    pub sp_fiq: u32,
203    pub mode: CpuMode,
204}
205
206impl<Bus: BusInterface> Arm7Tdmi<Bus> {
207    #[must_use]
208    pub fn new() -> Self {
209        Self {
210            registers: Registers::default(),
211            prefetch: [0, 0],
212            fetch_cycle: MemoryCycle::N,
213            prev_r15: 0,
214            irq_disabled_latch: false,
215            arm_op_table: ArmOpTable::default(),
216            thumb_op_table: ThumbOpTable::default(),
217        }
218    }
219
220    pub fn reset(&mut self, bus: &mut Bus) {
221        self.handle_exception(Exception::Reset, bus);
222    }
223
224    pub fn manual_reset(&mut self, args: Arm7TdmiResetArgs, bus: &mut Bus) {
225        self.registers = Registers::default();
226        self.registers.r[..13].fill(0);
227        self.registers.r[14] = args.pc;
228        self.registers.r[15] = args.pc;
229        self.registers.r[13] = args.sp_usr;
230        self.registers.r13_svc = args.sp_svc;
231        self.registers.r13_irq = args.sp_irq;
232        self.registers.r13_fiq = args.sp_fiq;
233        self.registers.cpsr = StatusRegister {
234            sign: false,
235            zero: false,
236            carry: false,
237            overflow: false,
238            irq_disabled: false,
239            fiq_disabled: false,
240            state: CpuState::Arm,
241            mode: args.mode,
242        };
243        self.registers.spsr_svc = 0_u32.into();
244        self.registers.spsr_irq = 0_u32.into();
245
246        self.refill_prefetch(bus);
247    }
248
249    #[inline]
250    pub fn execute_instruction(&mut self, bus: &mut Bus) {
251        let irq = !self.irq_disabled_latch && bus.irq();
252        let opcode = self.prefetch[0];
253        self.fetch_opcode(bus);
254
255        if irq {
256            return self.handle_exception(Exception::Irq, bus);
257        }
258
259        match self.registers.cpsr.state {
260            CpuState::Arm => self.execute_arm_opcode(opcode, bus),
261            CpuState::Thumb => self.execute_thumb_opcode(opcode as u16, bus),
262        }
263    }
264
265    fn refill_prefetch(&mut self, bus: &mut Bus) {
266        self.fetch_cycle = MemoryCycle::N;
267
268        match self.registers.cpsr.state {
269            CpuState::Arm => {
270                self.registers.r[15] &= !3;
271
272                self.fetch_opcode_state::<true>(bus);
273                self.fetch_opcode_state::<true>(bus);
274            }
275            CpuState::Thumb => {
276                self.registers.r[15] &= !1;
277
278                self.fetch_opcode_state::<false>(bus);
279                self.fetch_opcode_state::<false>(bus);
280            }
281        }
282    }
283
284    fn fetch_opcode(&mut self, bus: &mut Bus) {
285        match self.registers.cpsr.state {
286            CpuState::Arm => self.fetch_opcode_state::<true>(bus),
287            CpuState::Thumb => self.fetch_opcode_state::<false>(bus),
288        }
289    }
290
291    fn fetch_opcode_state<const ARM: bool>(&mut self, bus: &mut Bus) {
292        self.irq_disabled_latch = self.registers.cpsr.irq_disabled;
293
294        let fetch_cycle = self.fetch_cycle;
295        self.fetch_cycle = MemoryCycle::S;
296        self.prev_r15 = self.registers.r[15];
297
298        self.prefetch[0] = self.prefetch[1];
299        if ARM {
300            self.prefetch[1] = bus.fetch_opcode_word(self.registers.r[15], fetch_cycle);
301            self.registers.r[15] = self.registers.r[15].wrapping_add(4);
302
303            log::trace!(
304                "Fetched ARM opcode {:08X} from {:08X}",
305                self.prefetch[1],
306                self.registers.r[15].wrapping_sub(4)
307            );
308        } else {
309            // Thumb
310            self.prefetch[1] = bus.fetch_opcode_halfword(self.registers.r[15], fetch_cycle).into();
311            self.registers.r[15] = self.registers.r[15].wrapping_add(2);
312
313            log::trace!(
314                "Fetched Thumb opcode {:04X} from {:08X}",
315                self.prefetch[1],
316                self.registers.r[15].wrapping_sub(2)
317            );
318        }
319    }
320
321    fn write_cpsr(&mut self, value: u32) {
322        log::trace!("CPSR write: {value:08X}");
323
324        if self.registers.cpsr.mode != CpuMode::User {
325            let new_mode = CpuMode::from_bits(value);
326            self.change_mode(new_mode);
327
328            self.registers.cpsr = value.into();
329        } else {
330            // Cannot modify control bits in user mode
331            self.registers.cpsr = StatusRegister {
332                mode: self.registers.cpsr.mode,
333                state: self.registers.cpsr.state,
334                fiq_disabled: self.registers.cpsr.fiq_disabled,
335                irq_disabled: self.registers.cpsr.irq_disabled,
336                ..StatusRegister::from(value)
337            };
338        }
339    }
340
341    fn spsr_to_cpsr(&mut self) {
342        let spsr = match self.registers.cpsr.mode.spsr(&mut self.registers) {
343            Some(spsr) => *spsr,
344            None => {
345                log::warn!("Attempted to read SPSR in mode {:?}", self.registers.cpsr.mode);
346                return;
347            }
348        };
349
350        self.change_mode(spsr.mode);
351        self.registers.cpsr = spsr;
352    }
353
354    fn change_mode(&mut self, new_mode: CpuMode) {
355        if new_mode == self.registers.cpsr.mode {
356            return;
357        }
358
359        log::trace!("Changing CPU mode to {new_mode:?} from {:?}", self.registers.cpsr.mode);
360
361        // Bank R13 and R14, as well as R8-12 if changing out of FIQ mode
362        match self.registers.cpsr.mode {
363            CpuMode::User | CpuMode::System => {
364                self.registers.r13_usr = self.registers.r[13];
365                self.registers.r14_usr = self.registers.r[14];
366            }
367            CpuMode::Supervisor => {
368                self.registers.r13_svc = self.registers.r[13];
369                self.registers.r14_svc = self.registers.r[14];
370            }
371            CpuMode::Irq => {
372                self.registers.r13_irq = self.registers.r[13];
373                self.registers.r14_irq = self.registers.r[14];
374            }
375            CpuMode::Undefined => {
376                self.registers.r13_und = self.registers.r[13];
377                self.registers.r14_und = self.registers.r[14];
378            }
379            CpuMode::Abort => {
380                self.registers.r13_abt = self.registers.r[13];
381                self.registers.r14_abt = self.registers.r[14];
382            }
383            CpuMode::Fiq => {
384                self.registers.r13_fiq = self.registers.r[13];
385                self.registers.r14_fiq = self.registers.r[14];
386
387                // Bank and update R8-12 if switching out of FIQ mode
388                self.registers.fiq_r_8_12.copy_from_slice(&self.registers.r[8..13]);
389                self.registers.r[8..13].copy_from_slice(&self.registers.other_r_8_12);
390            }
391            CpuMode::Illegal => {
392                log::warn!(
393                    "Exiting unusual CPU mode {:?}, changing to mode {new_mode:?}",
394                    self.registers.cpsr.mode
395                );
396            }
397        }
398
399        // Update R13 and R14 to banked values, as well as R8-12 if switching into FIQ mode
400        match new_mode {
401            CpuMode::User | CpuMode::System => {
402                self.registers.r[13] = self.registers.r13_usr;
403                self.registers.r[14] = self.registers.r14_usr;
404            }
405            CpuMode::Supervisor => {
406                self.registers.r[13] = self.registers.r13_svc;
407                self.registers.r[14] = self.registers.r14_svc;
408            }
409            CpuMode::Irq => {
410                self.registers.r[13] = self.registers.r13_irq;
411                self.registers.r[14] = self.registers.r14_irq;
412            }
413            CpuMode::Undefined => {
414                self.registers.r[13] = self.registers.r13_und;
415                self.registers.r[14] = self.registers.r14_und;
416            }
417            CpuMode::Abort => {
418                self.registers.r[13] = self.registers.r13_abt;
419                self.registers.r[14] = self.registers.r14_abt;
420            }
421            CpuMode::Fiq => {
422                // Bank and update R8-12 if switching into FIQ mode
423                self.registers.other_r_8_12.copy_from_slice(&self.registers.r[8..13]);
424                self.registers.r[8..13].copy_from_slice(&self.registers.fiq_r_8_12);
425
426                self.registers.r[13] = self.registers.r13_fiq;
427                self.registers.r[14] = self.registers.r14_fiq;
428            }
429            CpuMode::Illegal => {
430                log::warn!(
431                    "Entering unusual CPU mode {new_mode:?}, changing from mode {:?}",
432                    self.registers.cpsr.mode
433                );
434            }
435        }
436
437        self.registers.cpsr.mode = new_mode;
438    }
439
440    fn handle_exception(&mut self, exception: Exception, bus: &mut Bus) {
441        log::trace!("Handling exception of type {exception:?}");
442
443        let mode = exception.new_mode();
444        match exception {
445            Exception::Reset => {
446                self.registers.cpsr.mode = mode;
447            }
448            _ => {
449                let old_cpsr = self.registers.cpsr;
450
451                self.change_mode(mode);
452                if let Some(spsr) = mode.spsr(&mut self.registers) {
453                    *spsr = old_cpsr;
454                }
455
456                self.registers.r[14] =
457                    exception.return_address(self.registers.cpsr.state, self.prev_r15);
458            }
459        }
460
461        self.registers.cpsr.state = CpuState::Arm;
462        self.registers.cpsr.irq_disabled = true;
463        if exception == Exception::Reset {
464            self.registers.cpsr.fiq_disabled = true;
465        }
466
467        self.registers.r[15] = exception.vector_address();
468        self.refill_prefetch(bus);
469    }
470
471    fn read_register(&self, r: u32) -> u32 {
472        if r == 15 {
473            // Return R15 from before the opcode fetch
474            self.prev_r15
475        } else {
476            self.registers.r[r as usize]
477        }
478    }
479}