diff --git a/src/machines/genesis.rs b/src/machines/genesis.rs index 5973aa3..3eb9e35 100644 --- a/src/machines/genesis.rs +++ b/src/machines/genesis.rs @@ -90,7 +90,7 @@ pub fn build_genesis(host: &mut H, options: SegaGenesisOptions) -> Resu system.add_device("coproc", wrap_transmutable(coproc))?; - let controllers = genesis::controllers::GenesisController::create(host)?; + let controllers = genesis::controllers::GenesisControllers::create(host)?; let interrupt = controllers.get_interrupt_signal(); system.add_addressable_device(0x00a10000, wrap_transmutable(controllers)).unwrap(); diff --git a/src/peripherals/genesis/controllers.rs b/src/peripherals/genesis/controllers.rs index 238889b..76557d9 100644 --- a/src/peripherals/genesis/controllers.rs +++ b/src/peripherals/genesis/controllers.rs @@ -85,9 +85,9 @@ impl GenesisControllerPort { } } -pub struct GenesisControllerUpdater(HostData, HostData); +pub struct GenesisControllersUpdater(HostData, HostData); -impl ControllerUpdater for GenesisControllerUpdater { +impl ControllerUpdater for GenesisControllersUpdater { fn update_controller(&mut self, event: ControllerEvent) { let (mask, state) = match event { ControllerEvent::ButtonA(state) => (0x0040, state), @@ -112,7 +112,7 @@ impl ControllerUpdater for GenesisControllerUpdater { -pub struct GenesisController { +pub struct GenesisControllers { port_1: GenesisControllerPort, port_2: GenesisControllerPort, expansion: GenesisControllerPort, @@ -120,9 +120,9 @@ pub struct GenesisController { reset_timer: Clock, } -impl GenesisController { +impl GenesisControllers { pub fn new() -> Self { - GenesisController { + Self { port_1: GenesisControllerPort::new(), port_2: GenesisControllerPort::new(), expansion: GenesisControllerPort::new(), @@ -132,11 +132,11 @@ impl GenesisController { } pub fn create(host: &mut H) -> Result { - let controller = GenesisController::new(); + let controller = GenesisControllers::new(); - let controller1 = Box::new(GenesisControllerUpdater(controller.port_1.buttons.clone(), controller.interrupt.clone())); + let controller1 = Box::new(GenesisControllersUpdater(controller.port_1.buttons.clone(), controller.interrupt.clone())); host.register_controller(ControllerDevice::A, controller1)?; - let controller2 = Box::new(GenesisControllerUpdater(controller.port_2.buttons.clone(), controller.interrupt.clone())); + let controller2 = Box::new(GenesisControllersUpdater(controller.port_2.buttons.clone(), controller.interrupt.clone())); host.register_controller(ControllerDevice::B, controller2)?; Ok(controller) @@ -147,7 +147,7 @@ impl GenesisController { } } -impl Addressable for GenesisController { +impl Addressable for GenesisControllers { fn len(&self) -> usize { 0x30 } @@ -197,7 +197,7 @@ impl Addressable for GenesisController { } } -impl Steppable for GenesisController { +impl Steppable for GenesisControllers { fn step(&mut self, system: &System) -> Result { let duration = 100_00; // Update every 100us @@ -211,7 +211,7 @@ impl Steppable for GenesisController { } } -impl Transmutable for GenesisController { +impl Transmutable for GenesisControllers { fn as_addressable(&mut self) -> Option<&mut dyn Addressable> { Some(self) } diff --git a/src/peripherals/genesis/ym7101.rs b/src/peripherals/genesis/ym7101.rs index b5a2910..0bc4ebc 100644 --- a/src/peripherals/genesis/ym7101.rs +++ b/src/peripherals/genesis/ym7101.rs @@ -311,9 +311,13 @@ pub struct Ym7101State { pub sprites_by_line: Vec>, pub last_clock: Clock, + pub p_clock: u32, pub h_clock: u32, pub v_clock: u32, pub h_scanlines: u8, + + pub current_x: i32, + pub current_y: i32, } impl Ym7101State { @@ -342,9 +346,13 @@ impl Ym7101State { sprites_by_line: vec![], last_clock: 0, + p_clock: 0, h_clock: 0, v_clock: 0, h_scanlines: 0, + + current_x: 0, + current_y: 0, } } @@ -608,12 +616,22 @@ impl Steppable for Ym7101 { system.get_interrupt_controller().set(true, 2, 26)?; } + let clocks_per_pixel = 63_500 / (self.state.screen_size.0 as u32 * 8 + 88); + self.state.p_clock += diff; + if self.state.p_clock >= clocks_per_pixel { + let pixels = self.state.p_clock / clocks_per_pixel; + self.state.p_clock -= pixels * clocks_per_pixel; + self.state.current_x += pixels as i32; + } + self.state.h_clock += diff; if (self.state.status & STATUS_IN_HBLANK) != 0 && self.state.h_clock >= 2_340 && self.state.h_clock <= 61_160 { self.state.status &= !STATUS_IN_HBLANK; + self.state.current_x = 0; } if (self.state.status & STATUS_IN_HBLANK) == 0 && self.state.h_clock >= 61_160 { self.state.status |= STATUS_IN_HBLANK; + self.state.current_y += 1; self.state.h_scanlines = self.state.h_scanlines.wrapping_sub(1); if self.state.hsync_int_enabled() && self.state.h_scanlines == 0 { @@ -628,6 +646,7 @@ impl Steppable for Ym7101 { self.state.v_clock += diff; if (self.state.status & STATUS_IN_VBLANK) != 0 && self.state.v_clock >= 1_205_992 && self.state.v_clock <= 15_424_008 { self.state.status &= !STATUS_IN_VBLANK; + self.state.current_y = 0; } if (self.state.status & STATUS_IN_VBLANK) == 0 && self.state.v_clock >= 15_424_008 { self.state.status |= STATUS_IN_VBLANK; @@ -692,6 +711,7 @@ impl Ym7101 { REG_MODE_SET_2 => { self.state.mode_2 = data; self.state.update_screen_size(); + self.swapper.set_size(self.state.screen_size.0 as u32 * 8, self.state.screen_size.1 as u32 * 8); }, REG_SCROLL_A_ADDR => { self.state.scroll_a_addr = (data as usize) << 10; }, REG_WINDOW_ADDR => { self.state.window_addr = (data as usize) << 10; }, @@ -703,6 +723,7 @@ impl Ym7101 { REG_MODE_SET_4 => { self.state.mode_4 = data; self.state.update_screen_size(); + self.swapper.set_size(self.state.screen_size.0 as u32 * 8, self.state.screen_size.1 as u32 * 8); }, REG_HSCROLL_ADDR => { self.state.hscroll_addr = (data as usize) << 10; }, REG_AUTO_INCREMENT => { self.state.memory.transfer_auto_inc = data as u32; }, @@ -776,6 +797,14 @@ impl Addressable for Ym7101 { } }, + // Read from H/V Counter + 0x08 | 0x0A => { + data[0] = self.state.current_y as u8; + if data.len() > 1 { + data[1] = (self.state.current_x >> 1) as u8; + } + }, + _ => { println!("{}: !!! unhandled read from {:x}", DEV_NAME, addr); }, } Ok(())