input.rsannotatedinput.rssource433 lines · 13.7 KB · raw
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}