1//! Implementation of the Z80's bus interface, which connects it to all other components 2 3use crate::input::InputState; 4use crate::memory::Memory; 5use crate::vdp::Vdp; 6use crate::{SmsGgHardware, VdpVersion}; 7use jgenesis_common::num::GetBit; 8use smsgg_config::SmsGgRegion; 9use ti_sn76489::Sn76489; 10use ym_opll::Ym2413; 11use z80_emu::debug::DummyZ80Debugger; 12use z80_emu::traits::{BusInterface, InterruptLine}; 13 14pub struct Bus<'a> { 15 version: VdpVersion, 16 memory: &'a mut Memory, 17 vdp: &'a mut Vdp, 18 psg: &'a mut Sn76489, 19 ym2413: Option<&'a mut Ym2413>, 20 input: &'a mut InputState, 21} 22 23impl<'a> Bus<'a> { 24 pub fn new( 25 version: VdpVersion, 26 memory: &'a mut Memory, 27 vdp: &'a mut Vdp, 28 psg: &'a mut Sn76489, 29 ym2413: Option<&'a mut Ym2413>, 30 input: &'a mut InputState, 31 ) -> Self { 32 Self { version, memory, vdp, psg, ym2413, input } 33 } 34} 35 36impl BusInterface for Bus<'_> { 37 type DebugView<'a> 38 = DummyZ80Debugger 39 where 40 Self: 'a; 41 42 fn read_memory(&mut self, address: u16) -> u8 { 43 self.memory.read(address) 44 } 45 46 fn write_memory(&mut self, address: u16, value: u8) { 47 self.memory.write(address, value); 48 } 49 50 fn read_io(&mut self, address: u16) -> u8 { 51 let address = address & 0xFF; 52 if self.version == VdpVersion::GameGear && address <= 0x06 { 53 // TODO Game Gear serial port / EXT registers 54 return match address { 55 0x00 => { 56 // Start/Pause button and region 57 (u8::from(!self.input.pause_pressed()) << 7) 58 | (u8::from(self.input.region() == SmsGgRegion::International) << 6) 59 } 60 0x01 => self.memory.gg_registers().ext_port, 61 0x02 => self.memory.gg_registers().parallel_port, 62 0x04 | 0x06 => 0xFF, 63 0x03 | 0x05 => 0x00, 64 _ => unreachable!("value is <= 0x06"), 65 }; 66 } 67 68 if self.ym2413.is_some() && address == 0xF2 { 69 return self.memory.read_audio_control(); 70 } 71 72 match (address.bit(7), address.bit(6), address.bit(0)) { 73 (false, false, _) => { 74 // Invalid read addresses 75 0xFF 76 } 77 (false, true, false) => { 78 if self.version.hardware() != SmsGgHardware::Sg1000 { 79 log::trace!("V counter read"); 80 self.vdp.v_counter() 81 } else { 82 // Invalid read 83 0xFF 84 } 85 } 86 (false, true, true) => { 87 if self.version.hardware() != SmsGgHardware::Sg1000 { 88 log::trace!("H counter read"); 89 self.vdp.h_counter() 90 } else { 91 // Invalid read 92 0xFF 93 } 94 } 95 (true, false, false) => { 96 log::trace!("VDP data read"); 97 self.vdp.read_data() 98 } 99 (true, false, true) => { 100 log::trace!("VDP control read"); 101 self.vdp.read_control() 102 } 103 (true, true, false) => { 104 log::trace!("I/O A/B read"); 105 self.input.port_dc() 106 } 107 (true, true, true) => { 108 log::trace!("I/O B/misc. read"); 109 self.input.port_dd() 110 } 111 } 112 } 113 114 fn write_io(&mut self, address: u16, value: u8) { 115 let address = address & 0xFF; 116 if self.version == VdpVersion::GameGear && address <= 0x06 { 117 match address { 118 0x01 => self.memory.gg_registers().ext_port = value & 0x7F, 119 0x02 => self.memory.gg_registers().parallel_port = value, 120 0x06 => self.psg.write_stereo_control(value), 121 _ => {} 122 } 123 return; 124 } 125 126 if let Some(ym2413) = &mut self.ym2413 { 127 match address { 128 0xF0 => { 129 ym2413.select_register(value); 130 return; 131 } 132 0xF1 => { 133 ym2413.write_data(value); 134 return; 135 } 136 0xF2 => { 137 self.memory.write_audio_control(value); 138 return; 139 } 140 _ => {} 141 } 142 } 143 144 match (address.bit(7), address.bit(6), address.bit(0)) { 145 (false, false, false) => { 146 let memory_control = self.memory.memory_control(); 147 memory_control.cartridge_enabled = 148 !value.bit(6) || self.version == VdpVersion::GameGear; 149 memory_control.bios_enabled = !value.bit(3); 150 // TODO other memory control bits? expansion, card, WRAM, I/O 151 log::debug!("Memory control write: {value:02X}"); 152 } 153 (false, false, true) => { 154 log::debug!("I/O control write: {value:02X}"); 155 self.input.write_control(value, self.vdp); 156 } 157 (false, true, _) => { 158 log::trace!("PSG write: {value:02X}"); 159 self.psg.write(value); 160 } 161 (true, false, false) => { 162 log::trace!("VDP data write: {value:02X}"); 163 self.vdp.write_data(value); 164 } 165 (true, false, true) => { 166 log::trace!("VDP control write: {value:02X}"); 167 self.vdp.write_control(value); 168 } 169 (true, true, _) => {} 170 } 171 } 172 173 fn nmi(&self) -> InterruptLine { 174 if matches!(self.version.hardware(), SmsGgHardware::MasterSystem | SmsGgHardware::Sg1000) 175 && self.input.pause_pressed() 176 { 177 InterruptLine::Low 178 } else { 179 InterruptLine::High 180 } 181 } 182 183 fn int(&self) -> InterruptLine { 184 self.vdp.interrupt_line() 185 } 186 187 fn busreq(&self) -> bool { 188 false 189 } 190 191 fn reset(&self) -> bool { 192 false 193 } 194}