use std::cell::RefCell; use std::fmt; use std::rc::Rc; use rustv::cache; use rustv::isa::{self, IsaType}; use rustv::memory::{MemoryInterface, Mmu}; use memory_tracker::MemoryTracker; pub const HOME_STATUS: isa::Address = isa::Word(0xFFF00); /// Update the various global data structures as requested by other /// subsystems. // Intended to be passed around as &'a Updater pub struct Updater<'a> { // TODO: weak reference? memory: Rc>, mmu1: Box, mmu2: Box, } #[derive(Clone,Copy)] pub enum Player { One, Two, } impl fmt::Display for Player { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Player::One => write!(f, "Player 1"), Player::Two => write!(f, "Player 2"), } } } impl<'a> Updater<'a> { pub fn new(memory: Rc>, mmu1: Box, mmu2: Box) -> Updater<'a> { Updater { memory: memory, mmu1: mmu1, mmu2: mmu2, } } pub fn init_memory(&self) { // Initialize taunt array to all -1 for offset in 0..(228 / 4) { let address1 = self.mmu1.translate(HOME_STATUS + 28 + offset); let address2 = self.mmu2.translate(HOME_STATUS + 28 + offset); let _ = self.memory.borrow_mut().write_word( address1, isa::SignedWord(-1).as_word()); let _ = self.memory.borrow_mut().write_word( address2, isa::SignedWord(-1).as_word()); } } /// Update the player's status struct with the physical address of /// a tag that has been fetched. pub fn finish_tag(&self, player: Player, tag: u32, index: u32) { debug_assert!(index == 0 || index == 1); let address = HOME_STATUS + isa::Word(index * 4); let address = match player { Player::One => self.mmu1.translate(address), Player::Two => self.mmu2.translate(address), }; match self.memory.borrow_mut().write_word(address, isa::Word(tag)) { Ok(()) => {}, Err(e) => panic!("Could not update memory with cache tag: {:?}", e), } } /// Update the player's status struct with the physical address of /// a tag that has been requested. pub fn fetch_tag(&self, player: Player, tag: u32, index: u32) { debug_assert!(index == 0 || index == 1); let address = HOME_STATUS + isa::Word(8 + index * 4); let address = match player { Player::One => self.mmu1.translate(address), Player::Two => self.mmu2.translate(address), }; match self.memory.borrow_mut().write_word(address, isa::Word(tag)) { Ok(()) => {}, Err(e) => panic!("Could not update memory with cache tag: {:?}", e), } } pub fn update_score(&self, player1: i64, player2: i64) { } } pub struct CacheEventHandler<'a> { player: Player, updater: &'a Updater<'a>, } impl<'a> CacheEventHandler<'a> { pub fn new(updater: &'a Updater<'a>, player: Player) -> CacheEventHandler<'a> { CacheEventHandler { player: player, updater: updater, } } } impl<'a> cache::EventHandler for CacheEventHandler<'a> { fn block_fetched(&self, location: cache::CacheLocation) { // TODO: need to snoop cache info!("[memory] [cache] {}: tag {:x} fetched", self.player, location.tag); self.updater.finish_tag(self.player, location.tag, location.index); } fn block_requested(&self, location: cache::CacheLocation) { self.updater.fetch_tag(self.player, location.tag, location.index); } }