1use crate::input::InputState; 2use crate::memory::{HuCard, Memory}; 3use crate::psg::Huc6280Psg; 4use crate::video::VideoSubsystem; 5use huc6280_emu::bus::{BusInterface, ClockSpeed, InterruptLines}; 6 7pub struct Bus<'a> { 8 pub memory: &'a mut Memory, 9 pub video: &'a mut VideoSubsystem, 10 pub psg: &'a mut Huc6280Psg, 11 pub cartridge: &'a mut HuCard, 12 pub input: &'a mut InputState, 13 pub cycle_counter: &'a mut u64, 14} 15 16impl Bus<'_> { 17 fn cpu_cycle(&mut self) { 18 *self.cycle_counter += self.memory.cpu_clock_divider(); 19 20 // TODO it's really not necessary to sync everything at every CPU cycle 21 self.video.step_to(*self.cycle_counter, self.memory.cpu_registers().irq1_pending_mut()); 22 self.memory.cpu_registers().step_timer_to(*self.cycle_counter); 23 } 24 25 #[allow(clippy::match_same_arms)] 26 fn read_io(&mut self, address: u32) -> u8 { 27 if address < 0x1FE800 { 28 // Wait cycle on VDC/VCE access 29 self.cpu_cycle(); 30 } 31 32 match address & 0x1FFF { 33 0x0000..=0x03FF => self.video.read_vdc( 34 address, 35 self.cycle_counter, 36 self.memory.cpu_registers().irq1_pending_mut(), 37 ), 38 0x0400..=0x07FF => self.video.read_vce(address), 39 0x0800..=0x0BFF => self.memory.cpu_registers().io_buffer(), // PSG, write-only 40 0x0C00..=0x0FFF => self.memory.cpu_registers().read_timer_register(*self.cycle_counter), 41 0x1000..=0x13FF => { 42 let value = self.input.read_port(); 43 self.memory.cpu_registers().update_io_buffer(value, !0) 44 } 45 0x1400..=0x17FF => self.memory.cpu_registers().read_interrupt_register(address), 46 0x1800..=0x1BFF => 0xFF, // CD-ROM 47 0x1C00..=0x1FFF => 0xFF, // Unused 48 _ => unreachable!("value & 0x1FFF is always <= 0x1FFF"), 49 } 50 } 51 52 #[allow(clippy::match_same_arms)] 53 fn write_io(&mut self, address: u32, value: u8) { 54 if address < 0x1FE800 { 55 // Wait cycle on VDC/VCE access 56 self.cpu_cycle(); 57 } 58 59 match address & 0x1FFF { 60 0x0000..=0x03FF => self.video.write_vdc( 61 address, 62 value, 63 self.cycle_counter, 64 self.memory.cpu_registers().irq1_pending_mut(), 65 ), 66 0x0400..=0x07FF => self.video.write_vce(address, value), 67 0x0800..=0x0BFF => { 68 self.psg.step_to(*self.cycle_counter); 69 self.psg.write(address, value); 70 self.memory.cpu_registers().update_io_buffer(value, !0); 71 } 72 0x0C00..=0x0FFF => { 73 self.memory.cpu_registers().write_timer_register( 74 address, 75 value, 76 *self.cycle_counter, 77 ); 78 } 79 0x1000..=0x13FF => { 80 self.input.write_port(value); 81 self.memory.cpu_registers().update_io_buffer(value, !0); 82 } 83 0x1400..=0x17FF => { 84 self.memory.cpu_registers().write_interrupt_register(address, value); 85 } 86 0x1800..=0x1BFF => {} // CD-ROM 87 0x1C00..=0x1FFF => {} // Unused 88 _ => unreachable!("value & 0x1FFF is always <= 0x1FFF"), 89 } 90 } 91} 92 93impl BusInterface for Bus<'_> { 94 #[inline] 95 #[allow(clippy::match_same_arms)] 96 fn read(&mut self, address: u32) -> u8 { 97 debug_assert!(address < 0x200000); 98 99 self.cpu_cycle(); 100 101 match address { 102 0x000000..=0x0FFFFF => self.cartridge.read(address), 103 0x100000..=0x1EFFFF => 0xFF, // CD-ROM 104 0x1F0000..=0x1F7FFF => self.memory.read_working_ram(address), 105 0x1F8000..=0x1FDFFF => 0xFF, // Unused memory 106 0x1FE000..=0x1FFFFF => self.read_io(address), 107 0x200000..=0xFFFFFFFF => panic!("invalid HuC6280 address {address:06X}"), 108 } 109 } 110 111 #[inline] 112 #[allow(clippy::match_same_arms)] 113 fn write(&mut self, address: u32, value: u8) { 114 debug_assert!(address < 0x200000); 115 116 self.cpu_cycle(); 117 118 match address { 119 0x000000..=0x0FFFFF => self.cartridge.write(address, value), 120 0x100000..=0x1EFFFF => {} // CD-ROM 121 0x1F0000..=0x1F7FFF => self.memory.write_working_ram(address, value), 122 0x1F8000..=0x1FDFFF => {} // Unused memory 123 0x1FE000..=0x1FFFFF => self.write_io(address, value), 124 0x200000..=0xFFFFFFFF => panic!("invalid HuC6280 address {address:06X}"), 125 } 126 } 127 128 #[inline] 129 fn idle(&mut self) { 130 self.cpu_cycle(); 131 } 132 133 #[inline] 134 fn interrupt_lines(&self) -> InterruptLines { 135 self.memory.interrupt_lines() 136 } 137 138 #[inline] 139 fn set_clock_speed(&mut self, speed: ClockSpeed) { 140 self.memory.set_clock_speed(speed); 141 } 142}