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}