Game Pak prefetcher-related code
Prefetch holds up to 8 halfwords
8const PREFETCH_LEN: u8 = 8;
10#[derive(Debug, Clone, Encode, Decode)] 11pub struct GamePakPrefetcher { 12 buffer: [u16; PREFETCH_LEN as usize], 13 read_address: u32, 14 write_address: u32, 15 read_idx: u8, 16 write_idx: u8, 17 len: u8, 18 active: bool, 19 fetch_cycles_remaining: u64, 20} 21 22impl GamePakPrefetcher { 23 pub fn new() -> Self { 24 Self { 25 buffer: array::from_fn(|_| 0), 26 read_address: 0, 27 write_address: 0, 28 read_idx: 0, 29 write_idx: 0, 30 len: 0, 31 active: false, 32 fetch_cycles_remaining: 0, 33 } 34 } 35 36 pub fn empty(&self) -> bool { 37 self.len == 0 38 } 39 40 pub fn full(&self) -> bool { 41 self.len == PREFETCH_LEN 42 } 43 44 pub fn can_use_for(&self, address: u32) -> bool { 45 self.read_address == address && (self.active || !self.empty()) 46 } 47 48 fn push(&mut self, opcode: u16) { 49 self.buffer[self.write_idx as usize] = opcode; 50 self.write_address += 2; 51 self.write_idx = (self.write_idx + 1) % PREFETCH_LEN; 52 self.len += 1; 53 } 54 55 fn pop(&mut self) -> u16 { 56 let opcode = self.buffer[self.read_idx as usize]; 57 self.read_address += 2; 58 self.read_idx = (self.read_idx + 1) % PREFETCH_LEN; 59 self.len -= 1; 60 61 opcode 62 } 63} 64 65impl Bus { 66 pub fn prepare_prefetch_read(&mut self, address: u32) { 67 if self.prefetch.can_use_for(address) { 68 // Prefetch is already in the right spot 69 return; 70 } 71 72 self.finish_in_progress_fetch(); 73 74 self.prefetch.read_address = address; 75 self.prefetch.write_address = address; 76 self.prefetch.read_idx = 0; 77 self.prefetch.write_idx = 0; 78 self.prefetch.len = 0; 79 self.prefetch.active = true; 80 self.prefetch.fetch_cycles_remaining = self.memory.control().rom_n_cycles(address); 81 } 82 83 fn finish_in_progress_fetch(&mut self) { 84 if self.prefetch.fetch_cycles_remaining == 1 { 85 // 1-cycle delay when stopping prefetch during last cycle of a fetch 86 self.state.cycles += 1; 87 } 88 self.cartridge.end_rom_burst(); 89 } 90 91 pub fn prefetch_read(&mut self) -> u16 { 92 if self.prefetch.empty() { 93 if !self.prefetch.active { 94 self.prepare_prefetch_read(self.prefetch.write_address); 95 } 96 97 // Block until the first fetch completes 98 self.state.cycles += self.prefetch.fetch_cycles_remaining; 99 self.advance_prefetch(self.prefetch.fetch_cycles_remaining); 100 } 101 102 self.prefetch.pop() 103 } 104 105 pub fn advance_prefetch(&mut self, mut cycles: u64) { 106 if !self.prefetch.active { 107 return; 108 } 109 110 while cycles != 0 { 111 if self.prefetch.full() { 112 // When prefetch fills up, it stops until a read occurs while the buffer is empty 113 self.pause_prefetch(); 114 break; 115 } 116 117 if cycles >= self.prefetch.fetch_cycles_remaining { 118 cycles -= self.prefetch.fetch_cycles_remaining; 119 120 let opcode = self.cartridge.read_rom(self.prefetch.write_address); 121 self.prefetch.push(opcode); 122 123 if !self.memory.control().prefetch_enabled { 124 self.pause_prefetch(); 125 break; 126 } 127 128 self.prefetch.fetch_cycles_remaining = 129 self.rom_access_cycles(self.prefetch.write_address); 130 } else { 131 self.prefetch.fetch_cycles_remaining -= cycles; 132 break; 133 } 134 } 135 } 136 137 fn pause_prefetch(&mut self) { 138 self.prefetch.active = false; 139 self.prefetch.fetch_cycles_remaining = 0; 140 self.cartridge.end_rom_burst(); 141 } 142 143 pub fn stop_prefetch(&mut self) { 144 if self.prefetch.active { 145 self.finish_in_progress_fetch(); 146 } 147 148 self.prefetch.active = false; 149 self.prefetch.fetch_cycles_remaining = 0; 150 self.prefetch.read_address = 0; 151 } 152}