cgb.rsannotatedcgb.rssource93 lines · 2.3 KB · raw
1use bincode::{Decode, Encode};
2use jgenesis_common::num::GetBit;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
5pub enum CpuSpeed {
6    #[default]
7    Normal = 0,
8    Double = 1,
9}
10
11impl CpuSpeed {
12    fn toggle(self) -> Self {
13        match self {
14            Self::Normal => Self::Double,
15            Self::Double => Self::Normal,
16        }
17    }
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
21pub enum ObjPriority {
22    // CGB behavior
23    #[default]
24    OamIndex = 0,
25    // DMG behavior
26    XCoordinate = 1,
27}
28
29impl ObjPriority {
30    fn from_bit(bit: bool) -> Self {
31        if bit { Self::XCoordinate } else { Self::OamIndex }
32    }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
36pub struct CgbRegisters {
37    pub speed: CpuSpeed,
38    pub speed_switch_armed: bool,
39    pub double_speed_odd_cycle: bool,
40    pub obj_priority: ObjPriority,
41    pub dmg_compatibility: bool,
42}
43
44impl CgbRegisters {
45    pub fn new() -> Self {
46        Self {
47            speed: CpuSpeed::default(),
48            speed_switch_armed: false,
49            double_speed_odd_cycle: false,
50            obj_priority: ObjPriority::default(),
51            dmg_compatibility: false,
52        }
53    }
54
55    pub fn write_key0(&mut self, value: u8) {
56        self.dmg_compatibility = value.bit(2);
57
58        log::trace!(
59            "KEY0 write: {value:02X} (DMG compatibility mode = {})",
60            self.dmg_compatibility
61        );
62    }
63
64    pub fn read_key1(self) -> u8 {
65        0x7E | ((self.speed as u8) << 7) | u8::from(self.speed_switch_armed)
66    }
67
68    pub fn write_key1(&mut self, value: u8) {
69        self.speed_switch_armed = value.bit(0);
70
71        log::trace!("KEY1 write: {value:02X} (speed switch armed = {})", self.speed_switch_armed);
72    }
73
74    pub fn perform_speed_switch(&mut self) {
75        // TODO implement speed switch delay?
76
77        self.speed = self.speed.toggle();
78        self.speed_switch_armed = false;
79        self.double_speed_odd_cycle = false;
80
81        log::trace!("Speed changed to {:?}", self.speed);
82    }
83
84    pub fn read_opri(self) -> u8 {
85        0xFE | (self.obj_priority as u8)
86    }
87
88    pub fn write_opri(&mut self, value: u8) {
89        self.obj_priority = ObjPriority::from_bit(value.bit(0));
90
91        log::trace!("OPRI write: {value:02X} (OBJ priority = {:?})", self.obj_priority);
92    }
93}