From efaf4844e51bd47f9385cedfc3f1392f04af2f42 Mon Sep 17 00:00:00 2001 From: David Li Date: Mon, 25 Jan 2016 14:46:40 -0500 Subject: feat(memory): write cache tag info to global status structs --- .clog.toml | 8 +++++ src/globals.rs | 87 +++++++++++++++++++++++++++++++++++++++++++------- src/main.rs | 22 ++++++++++--- src/shareable_cache.rs | 5 +-- 4 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 .clog.toml diff --git a/.clog.toml b/.clog.toml new file mode 100644 index 0000000..3ec45b8 --- /dev/null +++ b/.clog.toml @@ -0,0 +1,8 @@ +[clog] +repository = "https://git.lidavidm.me/cacheracer" + +link-style = "cgit" + +changelog = "CHANGELOG.md" + +from-latest-tag = true \ No newline at end of file diff --git a/src/globals.rs b/src/globals.rs index dc96403..3a661e4 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,6 +1,8 @@ use std::cell::RefCell; +use std::fmt; use std::rc::Rc; +use rustv::cache; use rustv::isa::{self, IsaType}; use rustv::memory::{MemoryInterface, Mmu}; @@ -10,18 +12,33 @@ 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 GlobalsUpdater -pub struct GlobalsUpdater<'a> { +// Intended to be passed around as &'a Updater +pub struct Updater<'a> { // TODO: weak reference? memory: Rc>, mmu1: Box, mmu2: Box, } -impl<'a> GlobalsUpdater<'a> { +#[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) -> GlobalsUpdater<'a> { - GlobalsUpdater { + mmu1: Box, mmu2: Box) -> Updater<'a> { + Updater { memory: memory, mmu1: mmu1, mmu2: mmu2, @@ -42,18 +59,66 @@ impl<'a> GlobalsUpdater<'a> { } } - // TODO: how to distinguish which player? - // TODO: we want virtual addresses? or physical ones? - pub fn fetch_tag(&self, tag: isa::Address, index: u32) { - // TODO: assert index is 0 or 1 - let address = HOME_STATUS; + /// 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), + } } - pub fn finish_tag(&self, tag: isa::Address, index: u32) { + /// 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); + } +} diff --git a/src/main.rs b/src/main.rs index f4ef2cc..c4cb1e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,10 +20,10 @@ use std::cell::RefCell; use docopt::Docopt; +use rustv::cache; use rustv::elfloader; use rustv::isa::{self, IsaType}; use rustv::memory; -use rustv::memory::Mmu; use rustv::simulator; use memory_tracker::MemoryTracker; @@ -98,9 +98,23 @@ fn main() { // TODO: initialize global data let memory_ref = Rc::new(RefCell::new(memory)); - let cache = memory::DirectMappedCache::new(2, 64, memory_ref.clone()); + + let updater = globals::Updater::new( + memory_ref.clone(), + Box::new(memory::IdentityMmu::new()), + Box::new(memory::IdentityMmu::new())); + updater.init_memory(); + + let player1_event = globals::CacheEventHandler::new( + &updater, globals::Player::One); + let player2_event = globals::CacheEventHandler::new( + &updater, globals::Player::Two); + + let cache = cache::DirectMappedCache::new( + 2, 64, memory_ref.clone(), player1_event); let cache_ref = Rc::new(RefCell::new(cache)); - let cache2 = memory::DirectMappedCache::new(2, 64, memory_ref.clone()); + let cache2 = cache::DirectMappedCache::new( + 2, 64, memory_ref.clone(), player2_event); let cache2_ref = Rc::new(RefCell::new(cache2)); let mut cores = vec![]; @@ -155,7 +169,7 @@ fn main() { let end = time::precise_time_s(); for (core_id, cycles_stalled, total_cycles) in simulator.report().iter().cloned() { - println!("Core {}: stalled {:08} of {:08} cycles ({:.2}%)", + println!("Core {}: stalled {:8} of {:8} cycles ({:.2}%)", core_id, cycles_stalled, total_cycles, diff --git a/src/shareable_cache.rs b/src/shareable_cache.rs index 503c7d5..6cc22df 100644 --- a/src/shareable_cache.rs +++ b/src/shareable_cache.rs @@ -1,8 +1,8 @@ use std::collections::HashSet; +use rustv::cache::{CacheInterface, CacheMetadata, SharedCache}; use rustv::isa::{self, IsaType}; -use rustv::memory::{CacheInterface, CacheMetadata, MemoryError, MemoryInterface, - Result, SharedCache, SharedMemory}; +use rustv::memory::{MemoryError, MemoryInterface, Result}; pub const WRITE_TRAP_VALUE: isa::Byte = isa::Byte(0xE0); pub const AREA_TRAP_VALUE: isa::Byte = isa::Byte(0xE4); @@ -24,6 +24,7 @@ pub struct ShareableCache<'a> { /// Cache snooping: update the secondary cache when the primary cache /// is written to. This is a macro in order to be generic with regard /// to the size of the write. +// TODO: snoop needs to take care of in-flight fetch requests? macro_rules! snoop { ($cache: expr, $write_value: ident, $address: ident, $value: ident) => { if $cache.borrow().is_address_accessible($address) { -- cgit v1.2.3