From d21ddd428fd3a8717e69265175de401fe1487a3a Mon Sep 17 00:00:00 2001 From: David Li Date: Wed, 13 Jan 2016 13:56:48 -0700 Subject: Integrate trapped cache into shareable cache --- src/main.rs | 1 - src/shareable_cache.rs | 100 ++++++++++++++++++++++++++++++++++-------- src/trapped_cache.rs | 116 ------------------------------------------------- 3 files changed, 82 insertions(+), 135 deletions(-) delete mode 100644 src/trapped_cache.rs (limited to 'src') diff --git a/src/main.rs b/src/main.rs index a4cf598..615a965 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,6 @@ mod globals; mod memory_tracker; mod shareable_cache; mod system; -mod trapped_cache; use std::fs::File; use std::io::Read; diff --git a/src/shareable_cache.rs b/src/shareable_cache.rs index 6ee17c3..4da9777 100644 --- a/src/shareable_cache.rs +++ b/src/shareable_cache.rs @@ -1,5 +1,10 @@ use rustv::isa; -use rustv::memory::{MemoryInterface, Result, SharedMemory}; +use rustv::memory::{MemoryError, MemoryInterface, Result, SharedMemory}; + +pub const WRITE_TRAP_VALUE: u8 = 0x42; +pub const AREA_TRAP_VALUE: u8 = 0x43; + +pub const WRITE_TRAP_STALL: u32 = 1_000_000; /// A cache that can be used as two separate caches or one /// set-associative cache. @@ -45,18 +50,77 @@ impl<'a> ShareableCache<'a> { (primary_accessible, secondary_accessible) } +} + +fn snoop(cache: &mut SharedMemory<'a>, + address: isa::Address, value: isa::Word) { + // Cache snooping: update all cache lines when a write is made + if cache.borrow().is_address_accessible(address) { + // Depends on invariant: write_word completes instantly + // when the address is accessible (in-cache) + let _ = cache.borrow_mut().write_word(address, value); + } +} + +fn as_bytes(word: isa::Word) -> [isa::Byte; 4] { + [(word & 0xFF) as isa::Byte, + ((word >> 8) & 0xFF) as isa::Byte, + ((word >> 16) & 0xFF) as isa::Byte, + ((word >> 24) & 0xFF) as isa::Byte] +} + +fn check_traps(cache: &mut MemoryInterface, + address: isa::Address, value: isa::Word) -> Result<()> { + if cache.is_address_accessible(address) { + // No stall - check for trap + let old_value = cache.read_word(address); + + match old_value { + Ok(old_value) => { + // TODO: helper method on isa::Word (would require + // newtype) for accessing individual bytes? + + let old_bytes = as_bytes(old_value); + let new_bytes = as_bytes(value); - fn snoop(cache: &mut SharedMemory<'a>, - address: isa::Address, value: isa::Word) { - // Cache snooping: update all cache lines when a write is made - if cache.borrow().is_address_accessible(address) { - // Depends on invariant: write_word completes instantly - // when the address is accessible (in-cache) - let _ = cache.borrow_mut().write_word(address, value); + let mut traps_set = 0; + let mut traps_hit = 0; + + for (old, new) in old_bytes.iter().zip(new_bytes.iter()) { + if *old == WRITE_TRAP_VALUE && + *new != WRITE_TRAP_VALUE { + traps_hit += 1; + } + else if *old != WRITE_TRAP_VALUE && + *new == WRITE_TRAP_VALUE { + traps_set += 1; + } + } + + if traps_hit > 0 { + info!("[memory] {} write trap(s) hit at address {:x},\ + stalling for 1_000_000 cycles each", + traps_hit, address); + Err(MemoryError::CacheMiss { + stall_cycles: traps_hit * WRITE_TRAP_STALL, + }) + } + else { + cache.cache.write_word(address, value) + } + } + Err(e) => { + panic!("Could not read accessible value: {:?}", e) + } } } + else { + // Not in cache - defer to fetch + cache.cache.write_word(address, value) + } } + impl<'a> MemoryInterface for ShareableCache<'a> { fn latency(&self) -> u32 { self.primary.borrow().latency() @@ -112,28 +176,28 @@ impl<'a> MemoryInterface for ShareableCache<'a> { self.address_accessible(address); if primary_accessible { - ShareableCache::snoop(&mut self.secondary, address, value); - self.primary.borrow_mut().write_word(address, value) + snoop(&mut self.secondary, address, value); + check_traps(&self.primary.borrow_mut(), address, value) } else if secondary_accessible { - ShareableCache::snoop(&mut self.primary, address, value); - self.secondary.borrow_mut().write_word(address, value) + snoop(&mut self.primary, address, value); + check_traps(&self.secondary.borrow_mut(), address, value) } else { self.use_secondary = !self.use_secondary; if self.use_secondary { - ShareableCache::snoop(&mut self.primary, address, value); - self.secondary.borrow_mut().write_word(address, value) + snoop(&mut self.primary, address, value); + check_traps(&self.secondary.borrow_mut(), address, value) } else { - ShareableCache::snoop(&mut self.secondary, address, value); - self.primary.borrow_mut().write_word(address, value) + snoop(&mut self.secondary, address, value); + check_traps(&self.primary.borrow_mut(), address, value) } } } else { - ShareableCache::snoop(&mut self.secondary, address, value); - self.primary.borrow_mut().write_word(address, value) + snoop(&mut self.secondary, address, value); + check_traps(&self.primary.borrow_mut(), address, value) } } } diff --git a/src/trapped_cache.rs b/src/trapped_cache.rs deleted file mode 100644 index 690a734..0000000 --- a/src/trapped_cache.rs +++ /dev/null @@ -1,116 +0,0 @@ -use rustv::isa; -use rustv::memory::{MemoryError, MemoryInterface, Result}; - -pub const WRITE_TRAP_VALUE: u8 = 0x42; -pub const AREA_TRAP_VALUE: u8 = 0x43; - -pub const WRITE_TRAP_STALL: MemoryError = MemoryError::CacheMiss { - stall_cycles: 10000 -}; - -/// A cache that stalls when a trap is triggered. -pub struct TrappedCache { - cache: T, - half: isa::Address, -} - -// TODO: move this t -enum WordOffset { - Byte0, - Byte1, - Byte2, - Byte3, -} - -impl TrappedCache { - pub fn new(cache: T, half: isa::Address) -> TrappedCache { - TrappedCache { - cache: cache, - half: half, - } - } - - fn clear_trap(&mut self, address: isa::Address, offset: WordOffset) { - // Precondition: address is in the cache and can be - // read/written without stalling - match self.read_word(address) { - Ok(value) => { - let new_value = match offset { - WordOffset::Byte0 => value & 0xFFFFFF00, - WordOffset::Byte1 => value & 0xFFFF00FF, - WordOffset::Byte2 => value & 0xFF00FFFF, - WordOffset::Byte3 => value & 0x00FFFFFF, - }; - - match self.write_word(address, new_value) { - Ok(()) => {}, - Err(e) => panic!("{:?}", e), - } - }, - Err(e) => panic!("{:?}", e), - } - } -} - -impl MemoryInterface for TrappedCache { - fn latency(&self) -> u32 { - self.cache.latency() - } - - fn step(&mut self) { - self.cache.step(); - } - - fn is_address_accessible(&self, address: isa::Address) -> bool { - self.cache.is_address_accessible(address) - } - - fn read_word(&mut self, address: isa::Address) -> Result { - self.cache.read_word(address) - } - - fn write_word(&mut self, address: isa::Address, - value: isa::Word) -> Result<()> { - if self.is_address_accessible(address) { - // No stall - check for trap - let old_value = self.read_word(address); - - match old_value { - Ok(old_value) => { - // TODO: helper method on isa::Word (would require - // newtype) for accessing individual bytes? - if ((old_value & 0xFF) as u8) == WRITE_TRAP_VALUE && - ((value & 0xFF) as u8) != WRITE_TRAP_VALUE { - self.clear_trap(old_value, WordOffset::Byte0); - Err(WRITE_TRAP_STALL) - } - else if (((old_value >> 8) & 0xFF) as u8) == WRITE_TRAP_VALUE && - (((value >> 8) & 0xFF) as u8) == WRITE_TRAP_VALUE { - self.clear_trap(old_value, WordOffset::Byte1); - Err(WRITE_TRAP_STALL) - } - else if (((old_value >> 16) & 0xFF) as u8) == WRITE_TRAP_VALUE && - (((value >> 16) & 0xFF) as u8) == WRITE_TRAP_VALUE { - self.clear_trap(old_value, WordOffset::Byte2); - Err(WRITE_TRAP_STALL) - } - else if (((old_value >> 24) & 0xFF) as u8) == WRITE_TRAP_VALUE && - (((value >> 24) & 0xFF) as u8) == WRITE_TRAP_VALUE { - self.clear_trap(old_value, WordOffset::Byte3); - Err(WRITE_TRAP_STALL) - } - else { - self.cache.write_word(address, value) - } - } - Err(e) => { - panic!("Could not read accessible value: {:?}", e) - } - } - } - else { - // Not in cache - defer to fetch - self.cache.write_word(address, value) - } - } -} -- cgit v1.2.3