From 5600ebffdf12117d398476f93897a8cc289eb468 Mon Sep 17 00:00:00 2001 From: David Li Date: Thu, 14 Jan 2016 15:57:12 -0700 Subject: Match rustv refactor, check traps properly --- src/shareable_cache.rs | 233 ++++++++++++++++++++++++++++--------------------- 1 file changed, 134 insertions(+), 99 deletions(-) (limited to 'src/shareable_cache.rs') diff --git a/src/shareable_cache.rs b/src/shareable_cache.rs index 4da9777..a4c993b 100644 --- a/src/shareable_cache.rs +++ b/src/shareable_cache.rs @@ -1,8 +1,10 @@ -use rustv::isa; +use std::collections::HashSet; + +use rustv::isa::{self, IsaType}; 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_VALUE: isa::Byte = isa::Byte(0xE0); +pub const AREA_TRAP_VALUE: isa::Byte = isa::Byte(0xE4); pub const WRITE_TRAP_STALL: u32 = 1_000_000; @@ -14,6 +16,126 @@ pub struct ShareableCache<'a> { secondary: SharedMemory<'a>, secondary_enabled: bool, use_secondary: bool, + traps_hit: HashSet, +} + +// Cache snooping: update all cache lines when a write is made +macro_rules! snoop { + ($cache: expr, $write_value: ident, $address: ident, $value: ident) => { + 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_value($address, $value); + } + } +} + +macro_rules! check_traps { + ($core_id: expr, $cache: expr, $traps_hit: expr, $write_value: ident, + $address: ident, $value: ident) => {{ + // Requires invariant: if x is the address of a word, x + 0 is + // the address of the LSB and x + 3 is the address of the MSB. + + let accessible = { + $cache.borrow().is_address_accessible($address) + }; + + if accessible { + // No stall - check for trap + let old_value = { + $cache.borrow_mut().read_word($address) + }; + + match old_value { + Ok(old_value) => { + let old_bytes = old_value.as_bytes(); + let new_bytes = $value.as_bytes(); + + let mut num_traps_hit = 0; + + let iter = old_bytes.iter() + .take(new_bytes.len()) + .enumerate(); + for (offset, old) in iter { + // Make sure offset bits are cleared before + // adding offset + let trap_address = ($address & 0xFFFFFFFC) + + isa::Word(offset as u32); + if *old == WRITE_TRAP_VALUE && + !$traps_hit.contains(&trap_address) { + num_traps_hit += 1; + $traps_hit.insert(trap_address); + } + else if *old != WRITE_TRAP_VALUE { + $traps_hit.remove(&trap_address); + } + } + + if num_traps_hit > 0 { + info!("[memory] core {}: {} write trap(s) hit at address {:x},\ + stalling for 1_000_000 cycles each", + $core_id, num_traps_hit, $address); + Err(MemoryError::CacheMiss { + stall_cycles: num_traps_hit * WRITE_TRAP_STALL, + }) + } + else { + $cache.borrow_mut().$write_value($address, $value) + } + } + Err(e) => { + panic!("Could not read accessible value: {:?}", e) + } + } + } + else { + // Not in cache - defer to fetch + $cache.borrow_mut().$write_value($address, $value) + } + }} +} + +macro_rules! write_value { + ($self_: ident, $write_value: ident, $address: ident, $value: ident) => { + if $self_.secondary_enabled { + let (primary_accessible, secondary_accessible) = + $self_.address_accessible($address); + + if primary_accessible { + snoop!($self_.secondary, $write_value, $address, $value); + check_traps!($self_.core_id, $self_.primary, + &mut $self_.traps_hit, + $write_value, $address, $value) + } + else if secondary_accessible { + snoop!($self_.primary, $write_value, $address, $value); + check_traps!($self_.core_id, $self_.secondary, + &mut $self_.traps_hit, + $write_value, $address, $value) + } + else { + $self_.use_secondary = !$self_.use_secondary; + if $self_.use_secondary { + snoop!($self_.primary, $write_value, $address, $value); + check_traps!($self_.core_id, $self_.secondary, + &mut $self_.traps_hit, + $write_value, $address, $value) + } + else { + snoop!($self_.secondary, $write_value, $address, $value); + check_traps!($self_.core_id, $self_.primary, + &mut $self_.traps_hit, + $write_value, $address, $value) + } + } + } + else { + snoop!($self_.secondary, $write_value, $address, $value); + check_traps!($self_.core_id, $self_.primary, + &mut $self_.traps_hit, + $write_value, $address, $value) + } + } } impl<'a> ShareableCache<'a> { @@ -26,6 +148,7 @@ impl<'a> ShareableCache<'a> { secondary: cache2.clone(), secondary_enabled: false, use_secondary: false, + traps_hit: HashSet::new(), } } @@ -52,75 +175,6 @@ impl<'a> ShareableCache<'a> { } } -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); - - 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() @@ -171,33 +225,14 @@ impl<'a> MemoryInterface for ShareableCache<'a> { } fn write_word(&mut self, address: isa::Address, value: isa::Word) -> Result<()> { - if self.secondary_enabled { - let (primary_accessible, secondary_accessible) = - self.address_accessible(address); + write_value!(self, write_word, address, value) + } - if primary_accessible { - snoop(&mut self.secondary, address, value); - check_traps(&self.primary.borrow_mut(), address, value) - } - else if secondary_accessible { - 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 { - snoop(&mut self.primary, address, value); - check_traps(&self.secondary.borrow_mut(), address, value) - } - else { - snoop(&mut self.secondary, address, value); - check_traps(&self.primary.borrow_mut(), address, value) - } - } - } - else { - snoop(&mut self.secondary, address, value); - check_traps(&self.primary.borrow_mut(), address, value) - } + fn write_halfword(&mut self, address: isa::Address, value: isa::HalfWord) -> Result<()> { + write_value!(self, write_halfword, address, value) + } + + fn write_byte(&mut self, address: isa::Address, value: isa::Byte) -> Result<()> { + write_value!(self, write_byte, address, value) } } -- cgit v1.2.3