aboutsummaryrefslogtreecommitdiff
path: root/src/shareable_cache.rs
diff options
context:
space:
mode:
authorDavid Li <li.davidm96@gmail.com>2016-01-14 15:57:12 -0700
committerDavid Li <li.davidm96@gmail.com>2016-01-14 15:57:12 -0700
commit5600ebffdf12117d398476f93897a8cc289eb468 (patch)
tree3a8fd401efb4de13704970f715e61adeec7a61a3 /src/shareable_cache.rs
parent367a945a6a921e4580bb7c1d8bd1db51de0dec2f (diff)
Match rustv refactor, check traps properly
Diffstat (limited to 'src/shareable_cache.rs')
-rw-r--r--src/shareable_cache.rs233
1 files changed, 134 insertions, 99 deletions
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<isa::Address>,
+}
+
+// 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)
}
}