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