bus.rsannotatedbus.rssource194 lines · 6.0 KB · raw

Implementation of the Z80's bus interface, which connects it to all other components

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};
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}