1//! Code for handling Genesis controller input I/O registers 2 3mod gamepad; 4mod mouse; 5mod xe1ap; 6 7use crate::input::gamepad::{SixButtonState, ThreeButtonState}; 8use crate::input::mouse::MegaMouseState; 9use crate::input::xe1ap::Xe1apState; 10use bincode::{Decode, Encode}; 11use genesis_config::{GenesisController, GenesisEmulatorConfig, GenesisInputs}; 12use jgenesis_common::num::GetBit; 13 14#[derive(Debug, Clone, Copy, Encode, Decode)] 15struct Pins { 16 // 0 = input (from controller), 1 = output (to controller) 17 directions: u8, 18 // Current pin states 19 pins: u8, 20 // If non-zero, 68K cycles remaining until TH is pulled high due to being set as input 21 cycles_until_th_high: u32, 22 // Used for external interrupts; not yet implemented except as an R/W bit 23 ctrl_bit_7: bool, 24} 25 26macro_rules! impl_set_input_pin { 27 ($name:ident, $bit:ident) => { 28 fn $name(&mut self, pin: bool) { 29 if !self.directions.bit(Self::$bit) { 30 self.pins = (self.pins & !(1 << Self::$bit)) | (u8::from(pin) << Self::$bit); 31 } 32 } 33 }; 34} 35 36impl Pins { 37 const TH: u8 = 6; 38 const TR: u8 = 5; 39 const TL: u8 = 4; 40 const D3: u8 = 3; 41 const D2: u8 = 2; 42 const D1: u8 = 1; 43 const D0: u8 = 0; 44 45 fn new() -> Self { 46 // TH must be initialized to 1 or some games will freeze at boot 47 Self { directions: 0, pins: 0xFF, cycles_until_th_high: 0, ctrl_bit_7: false } 48 } 49 50 fn read_ctrl(self) -> u8 { 51 (self.directions & !(1 << 7)) | (u8::from(self.ctrl_bit_7) << 7) 52 } 53 54 fn write_ctrl(&mut self, value: u8, last_data_write: u8, state: &mut ControllerState) { 55 // DATA bit 7 always reads the last DATA write, so pretend it's always an output pin 56 self.directions = value | (1 << 7); 57 self.ctrl_bit_7 = value.bit(7); 58 self.output(last_data_write, state); 59 60 if !self.directions.bit(Self::TH) { 61 // Gamepads don't drive the TH pin, so when TH is set to input, it should get pulled 62 // high after a short delay. 63 // Micro Machines depends on it getting pulled high within ~70 68K CPU cycles, while 64 // Trouble Shooter depends on it _not_ getting pulled high until after ~15 68K CPU cycles. 65 // TODO some devices do drive TH, e.g. lightguns 66 if self.cycles_until_th_high == 0 { 67 self.cycles_until_th_high = 30; 68 } 69 } else { 70 // TH is set to output 71 self.cycles_until_th_high = 0; 72 } 73 } 74 75 fn th(self) -> bool { 76 self.pins.bit(Self::TH) 77 } 78 79 fn tr(self) -> bool { 80 self.pins.bit(Self::TR) 81 } 82 83 fn tl(self) -> bool { 84 self.pins.bit(Self::TL) 85 } 86 87 impl_set_input_pin!(input_th, TH); 88 impl_set_input_pin!(input_tr, TR); 89 impl_set_input_pin!(input_tl, TL); 90 impl_set_input_pin!(input_d3, D3); 91 impl_set_input_pin!(input_d2, D2); 92 impl_set_input_pin!(input_d1, D1); 93 impl_set_input_pin!(input_d0, D0); 94 95 fn input_data_nibble(&mut self, pins: u8) { 96 let low_nibble = (self.pins & self.directions) | (pins & !self.directions); 97 self.pins = (self.pins & !0x0F) | (low_nibble & 0x0F); 98 } 99 100 fn output(&mut self, pins: u8, state: &mut ControllerState) { 101 self.pins = (self.pins & !self.directions) | (pins & self.directions); 102 state.update_pins(self); 103 } 104 105 fn tick(&mut self, m68k_cycles: u32, state: &mut ControllerState) { 106 if self.cycles_until_th_high == 0 { 107 return; 108 } 109 110 self.cycles_until_th_high = self.cycles_until_th_high.saturating_sub(m68k_cycles); 111 if self.cycles_until_th_high == 0 { 112 self.pins |= 1 << Self::TH; 113 state.update_pins(self); 114 } 115 } 116} 117 118fn update_pins_no_controller(pins: &mut Pins) { 119 // All 1s signals to games that nothing is connected to the controller port 120 pins.input_th(true); 121 pins.input_tr(true); 122 pins.input_tl(true); 123 pins.input_data_nibble(0b1111); 124} 125 126#[derive(Debug, Clone, Encode, Decode)] 127enum ControllerState { 128 ThreeButton(ThreeButtonState), 129 SixButton(SixButtonState), 130 MegaMouse(MegaMouseState), 131 Xe1ap(Xe1apState), 132 None, 133} 134 135impl ControllerState { 136 fn new(controller: GenesisController, mega_mouse_sensitivity: f64) -> Self { 137 log::debug!("Creating new controller state for type {:?}", controller.controller_type()); 138 139 match controller { 140 GenesisController::ThreeButton(joypad) => { 141 Self::ThreeButton(ThreeButtonState::new(joypad)) 142 } 143 GenesisController::SixButton(joypad) => Self::SixButton(SixButtonState::new(joypad)), 144 GenesisController::MegaMouse(joypad) => { 145 Self::MegaMouse(MegaMouseState::new(joypad, mega_mouse_sensitivity)) 146 } 147 GenesisController::Xe1ap(joypad) => Self::Xe1ap(Xe1apState::new(joypad)), 148 GenesisController::None => Self::None, 149 } 150 } 151 152 fn update_inputs(&mut self, controller: GenesisController, mega_mouse_sensitivity: f64) { 153 match (self, controller) { 154 (Self::ThreeButton(state), GenesisController::ThreeButton(joypad)) => { 155 state.joypad = joypad; 156 } 157 (Self::SixButton(state), GenesisController::SixButton(joypad)) => { 158 state.joypad = joypad; 159 } 160 (Self::MegaMouse(state), GenesisController::MegaMouse(joypad)) => { 161 state.joypad = joypad; 162 } 163 (Self::Xe1ap(state), GenesisController::Xe1ap(joypad)) => { 164 state.joypad = joypad; 165 } 166 (Self::None, GenesisController::None) => {} 167 // Controller type changed; reset state 168 (state, controller) => { 169 *state = Self::new(controller, mega_mouse_sensitivity); 170 } 171 } 172 } 173 174 fn update_pins(&mut self, pins: &mut Pins) { 175 match self { 176 Self::ThreeButton(state) => state.update_pins(pins), 177 Self::SixButton(state) => state.update_pins(pins), 178 Self::MegaMouse(state) => state.update_pins(pins), 179 Self::Xe1ap(state) => state.update_pins(pins), 180 Self::None => update_pins_no_controller(pins), 181 } 182 } 183 184 fn tick(&mut self, m68k_cycles: u32, pins: &mut Pins) { 185 match self { 186 Self::SixButton(state) => state.tick(m68k_cycles, pins), 187 Self::MegaMouse(state) => state.tick(m68k_cycles, pins), 188 Self::Xe1ap(state) => state.tick(m68k_cycles, pins), 189 Self::ThreeButton(_) | Self::None => {} 190 } 191 } 192} 193 194trait GenesisControllerExt { 195 fn with_auto_3_button(self, auto_3_button: bool) -> Self; 196 197 fn with_allow_opposing_directions(self, allow_opposing_directions: bool) -> Self; 198} 199 200impl GenesisControllerExt for GenesisController { 201 fn with_auto_3_button(self, auto_3_button: bool) -> Self { 202 match self { 203 Self::SixButton(joypad) if auto_3_button => Self::ThreeButton(joypad), 204 _ => self, 205 } 206 } 207 208 fn with_allow_opposing_directions(mut self, allow_opposing_directions: bool) -> Self { 209 if allow_opposing_directions { 210 return self; 211 } 212 213 match &mut self { 214 Self::ThreeButton(joypad) | Self::SixButton(joypad) => { 215 *joypad = joypad.with_allow_opposing_directions(allow_opposing_directions); 216 } 217 Self::MegaMouse(_) | Self::Xe1ap(_) | Self::None => {} 218 } 219 220 self 221 } 222} 223 224#[derive(Debug, Clone, Encode, Decode)] 225pub struct InputState { 226 inputs: GenesisInputs, 227 allow_opposing_joypad_directions: bool, 228 mega_mouse_sensitivity: f64, 229 auto_3_button_mode: bool, 230 six_button_incompatible_game: bool, 231 p1_state: ControllerState, 232 p2_state: ControllerState, 233 p1_pins: Pins, 234 p2_pins: Pins, 235 ext_pins: Pins, 236 p1_last_data_write: u8, 237 p2_last_data_write: u8, 238 ext_last_data_write: u8, 239 // Serial transfer is not emulated, but these registers are R/W when nothing is connected 240 p1_tx_data: u8, 241 p2_tx_data: u8, 242 ext_tx_data: u8, 243} 244 245impl InputState { 246 #[must_use] 247 pub fn new(config: &GenesisEmulatorConfig, six_button_incompatible_game: bool) -> Self { 248 if six_button_incompatible_game && config.auto_3_button_mode { 249 log::info!( 250 "Game is known to be incompatible with 6-button controller; forcing 3-button mode" 251 ); 252 } 253 254 let mut input_state = Self { 255 inputs: GenesisInputs::default(), 256 allow_opposing_joypad_directions: config.allow_opposing_joypad_directions, 257 mega_mouse_sensitivity: config.mega_mouse_sensitivity, 258 auto_3_button_mode: config.auto_3_button_mode, 259 six_button_incompatible_game, 260 p1_state: ControllerState::new(GenesisController::None, config.mega_mouse_sensitivity), 261 p2_state: ControllerState::new(GenesisController::None, config.mega_mouse_sensitivity), 262 p1_pins: Pins::new(), 263 p2_pins: Pins::new(), 264 ext_pins: Pins::new(), 265 p1_last_data_write: 0xFF, 266 p2_last_data_write: 0xFF, 267 ext_last_data_write: 0xFF, 268 p1_tx_data: 0xFF, 269 p2_tx_data: 0xFF, 270 ext_tx_data: 0xFF, 271 }; 272 273 input_state.update_state_and_pins(); 274 input_state 275 } 276 277 pub fn set_inputs(&mut self, inputs: GenesisInputs) { 278 if inputs == self.inputs { 279 return; 280 } 281 282 self.inputs = inputs; 283 self.update_state_and_pins(); 284 } 285 286 fn update_state_and_pins(&mut self) { 287 let auto_3_button = self.six_button_incompatible_game && self.auto_3_button_mode; 288 289 let p1_inputs = self 290 .inputs 291 .p1 292 .with_auto_3_button(auto_3_button) 293 .with_allow_opposing_directions(self.allow_opposing_joypad_directions); 294 self.p1_state.update_inputs(p1_inputs, self.mega_mouse_sensitivity); 295 self.p1_state.update_pins(&mut self.p1_pins); 296 297 let p2_inputs = self 298 .inputs 299 .p2 300 .with_auto_3_button(auto_3_button) 301 .with_allow_opposing_directions(self.allow_opposing_joypad_directions); 302 self.p2_state.update_inputs(p2_inputs, self.mega_mouse_sensitivity); 303 self.p2_state.update_pins(&mut self.p2_pins); 304 } 305 306 #[allow(clippy::float_cmp)] // Compared float values come from config, not a calculation 307 pub fn reload_config(&mut self, config: &GenesisEmulatorConfig) { 308 macro_rules! update_fields_if_changed { 309 ($first:ident $(, $rest:ident)* $(,)?) => { 310 { 311 if config.$first == self.$first $(&& config.$rest == self.$rest)* { 312 return; 313 } 314 315 self.$first = config.$first; 316 $(self.$rest = config.$rest;)* 317 318 self.update_state_and_pins(); 319 } 320 } 321 } 322 323 for state in [&mut self.p1_state, &mut self.p2_state] { 324 if let ControllerState::MegaMouse(mouse) = state { 325 mouse.set_sensitivity(config.mega_mouse_sensitivity); 326 } 327 } 328 329 update_fields_if_changed!( 330 allow_opposing_joypad_directions, 331 mega_mouse_sensitivity, 332 auto_3_button_mode 333 ); 334 } 335 336 #[must_use] 337 pub fn read_p1_data(&self) -> u8 { 338 log::debug!("P1 DATA read: {:02X}", self.p1_pins.pins); 339 self.p1_pins.pins 340 } 341 342 #[must_use] 343 pub fn read_p2_data(&self) -> u8 { 344 log::debug!("P2 DATA read: {:02X}", self.p2_pins.pins); 345 self.p2_pins.pins 346 } 347 348 #[must_use] 349 pub fn read_ext_data(&self) -> u8 { 350 self.ext_pins.pins 351 } 352 353 pub fn write_p1_data(&mut self, value: u8) { 354 log::debug!("P1 DATA write: {value:02X}"); 355 self.p1_last_data_write = value; 356 self.p1_pins.output(value, &mut self.p1_state); 357 } 358 359 pub fn write_p2_data(&mut self, value: u8) { 360 log::debug!("P2 DATA write: {value:02X}"); 361 self.p2_last_data_write = value; 362 self.p2_pins.output(value, &mut self.p2_state); 363 } 364 365 pub fn write_ext_data(&mut self, value: u8) { 366 self.ext_last_data_write = value; 367 self.ext_pins.output(value, &mut ControllerState::None); 368 } 369 370 #[must_use] 371 pub fn read_p1_ctrl(&self) -> u8 { 372 self.p1_pins.read_ctrl() 373 } 374 375 #[must_use] 376 pub fn read_p2_ctrl(&self) -> u8 { 377 self.p2_pins.read_ctrl() 378 } 379 380 #[must_use] 381 pub fn read_ext_ctrl(&self) -> u8 { 382 self.ext_pins.read_ctrl() 383 } 384 385 pub fn write_p1_ctrl(&mut self, value: u8) { 386 log::debug!("P1 CTRL write: {value:02X}"); 387 self.p1_pins.write_ctrl(value, self.p1_last_data_write, &mut self.p1_state); 388 } 389 390 pub fn write_p2_ctrl(&mut self, value: u8) { 391 log::debug!("P2 CTRL write: {value:02X}"); 392 self.p2_pins.write_ctrl(value, self.p2_last_data_write, &mut self.p2_state); 393 } 394 395 pub fn write_ext_ctrl(&mut self, value: u8) { 396 self.ext_pins.write_ctrl(value, self.ext_last_data_write, &mut ControllerState::None); 397 } 398 399 #[must_use] 400 pub fn read_p1_tx_data(&self) -> u8 { 401 self.p1_tx_data 402 } 403 404 #[must_use] 405 pub fn read_p2_tx_data(&self) -> u8 { 406 self.p2_tx_data 407 } 408 409 #[must_use] 410 pub fn read_ext_tx_data(&self) -> u8 { 411 self.ext_tx_data 412 } 413 414 pub fn write_p1_tx_data(&mut self, value: u8) { 415 self.p1_tx_data = value; 416 } 417 418 pub fn write_p2_tx_data(&mut self, value: u8) { 419 self.p2_tx_data = value; 420 } 421 422 pub fn write_ext_tx_data(&mut self, value: u8) { 423 self.ext_tx_data = value; 424 } 425 426 pub fn tick(&mut self, m68k_cycles: u32) { 427 self.p1_state.tick(m68k_cycles, &mut self.p1_pins); 428 self.p1_pins.tick(m68k_cycles, &mut self.p1_state); 429 430 self.p2_state.tick(m68k_cycles, &mut self.p2_pins); 431 self.p2_pins.tick(m68k_cycles, &mut self.p2_state); 432 } 433}