1use bincode::{Decode, Encode}; 2use jgenesis_common::num::GetBit; 3 4const CODE_CACHE_RAM_LEN: usize = 512; 5 6type CodeCacheRam = [u8; CODE_CACHE_RAM_LEN]; 7 8#[derive(Debug, Clone, Encode, Decode)] 9pub struct CodeCache { 10 ram: Box<CodeCacheRam>, 11 cbr: u16, 12 cached_lines: u32, 13} 14 15impl CodeCache { 16 pub fn new() -> Self { 17 Self { 18 ram: vec![0; CODE_CACHE_RAM_LEN].into_boxed_slice().try_into().unwrap(), 19 cbr: 0, 20 cached_lines: 0, 21 } 22 } 23 24 pub fn pc_is_cacheable(&self, address: u16) -> bool { 25 if self.cbr < 0xFE00 { 26 (self.cbr..self.cbr + 512).contains(&address) 27 } else { 28 address >= self.cbr || address < self.cbr.wrapping_add(512) 29 } 30 } 31 32 pub fn get(&self, address: u16) -> Option<u8> { 33 let cache_addr = address.wrapping_sub(self.cbr); 34 let cache_line_bit = (cache_addr >> 4) as u8; 35 self.cached_lines.bit(cache_line_bit).then_some(self.ram[cache_addr as usize]) 36 } 37 38 pub fn set(&mut self, address: u16, value: u8) { 39 let cache_addr = address.wrapping_sub(self.cbr); 40 self.ram[cache_addr as usize] = value; 41 42 if address & 0xF == 0xF { 43 // Cache line is set when the last address of a 16-byte block is written 44 self.set_cache_line(cache_addr); 45 } 46 } 47 48 fn set_cache_line(&mut self, cache_addr: u16) { 49 let cache_line = 1 << (cache_addr >> 4); 50 self.cached_lines |= cache_line; 51 } 52 53 pub fn read_ram(&self, address: u16) -> u8 { 54 self.ram[(address & 0x1FF) as usize] 55 } 56 57 pub fn write_ram(&mut self, address: u16, value: u8) { 58 let cache_addr = address & 0x1FF; 59 self.ram[cache_addr as usize] = value; 60 61 if address & 0xF == 0xF { 62 // Cache line is set when the last address of a 16-byte block is written 63 self.set_cache_line(cache_addr); 64 } 65 } 66 67 pub fn update_cbr(&mut self, cbr: u16) { 68 // Changing CBR via a CACHE or LJMP instruction clears all cache lines 69 self.cbr = cbr; 70 self.cached_lines = 0; 71 72 log::trace!("Set CBR to {cbr:04X}"); 73 } 74 75 pub fn full_clear(&mut self) { 76 self.cbr = 0; 77 self.cached_lines = 0; 78 } 79 80 pub fn cbr(&self) -> u16 { 81 self.cbr 82 } 83}