aboutsummaryrefslogtreecommitdiff
path: root/src
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
parent367a945a6a921e4580bb7c1d8bd1db51de0dec2f (diff)
Match rustv refactor, check traps properly
Diffstat (limited to 'src')
-rw-r--r--src/globals.rs8
-rw-r--r--src/main.rs36
-rw-r--r--src/memory_tracker.rs19
-rw-r--r--src/shareable_cache.rs233
-rw-r--r--src/system.rs6
5 files changed, 175 insertions, 127 deletions
diff --git a/src/globals.rs b/src/globals.rs
index 27d3bbd..2d2a067 100644
--- a/src/globals.rs
+++ b/src/globals.rs
@@ -1,12 +1,12 @@
use std::cell::RefCell;
use std::rc::Rc;
-use rustv::isa;
+use rustv::isa::{self, IsaType};
use rustv::memory::{Memory, MemoryInterface, Mmu};
use memory_tracker::MemoryTracker;
-pub const HOME_STATUS: isa::Address = 0xFFF00;
+pub const HOME_STATUS: isa::Address = isa::Word(0xFFF00);
/// Update the various global data structures as requested by other
/// subsystems.
@@ -35,10 +35,10 @@ impl<'a> GlobalsUpdater<'a> {
let address2 = self.mmu2.translate(HOME_STATUS + 28 + offset);
let _ = self.memory.borrow_mut().write_word(
address1,
- (-1 as i32) as isa::Word);
+ isa::SignedWord(-1).as_word());
let _ = self.memory.borrow_mut().write_word(
address2,
- (-1 as i32) as isa::Word);
+ isa::SignedWord(-1).as_word());
}
}
diff --git a/src/main.rs b/src/main.rs
index 615a965..ce1f336 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,5 @@
+#![feature(augmented_assignments)]
+
extern crate docopt;
#[macro_use] extern crate log;
extern crate env_logger;
@@ -19,7 +21,7 @@ use std::cell::RefCell;
use docopt::Docopt;
use rustv::elfloader;
-use rustv::isa;
+use rustv::isa::{self, IsaType};
use rustv::memory;
use rustv::memory::Mmu;
use rustv::simulator;
@@ -53,7 +55,7 @@ fn load_program<T: memory::Mmu>(memory: &mut memory::Memory,
f.read_to_end(&mut buffer).unwrap();
let elf = elfloader::ElfBinary::new("test", &buffer).unwrap();
- let start = elf.file_header().entry as isa::Address;
+ let start = isa::Word(elf.file_header().entry);
for p in elf.section_headers() {
if p.flags.0 & elfloader::elf::SHF_ALLOC.0 != 0 {
@@ -64,6 +66,16 @@ fn load_program<T: memory::Mmu>(memory: &mut memory::Memory,
start
}
+fn generate_payload() -> isa::Byte {
+ let mut payload = rand::random::<u8>();
+ while payload == shareable_cache::WRITE_TRAP_VALUE.0 ||
+ payload == shareable_cache::AREA_TRAP_VALUE.0 {
+ payload = rand::random::<u8>();
+ }
+
+ isa::Byte(payload)
+}
+
fn main() {
env_logger::init().unwrap();
@@ -73,14 +85,14 @@ fn main() {
let mmu = memory::IdentityMmu::new();
// TODO: account for word-vs-byte addressed. Use newtype pattern?
- let mmu2 = memory::ReverseMmu::new(0x4000000);
+ let mmu2 = memory::ReverseMmu::new(isa::Word(0x4000000));
let mut memory = memory::Memory::new(0x1000000);
let start1 = load_program(&mut memory, &mmu, &args.arg_program1);
let start2 = load_program(&mut memory, &mmu2, &args.arg_program2);
- let payload1 = rand::random::<u8>();
- let payload2 = rand::random::<u8>();
+ let payload1 = generate_payload();
+ let payload2 = generate_payload();
let memory = MemoryTracker::new(memory, payload1, payload2);
// TODO: initialize global data
@@ -99,11 +111,11 @@ fn main() {
ShareableCache::new(i, cache_ref.clone(), cache2_ref.clone())));
core_caches.push(core_cache.clone());
let mut core = simulator::Core::new(
- i, start1, (0x100000 * (i + 1)) as u32, core_cache,
+ i, start1, isa::Word(0x100000 * (i + 1) as u32), core_cache,
Box::new(memory::IdentityMmu::new())
);
- core.registers().write_word(isa::Register::X10, i as isa::Word);
- core.registers().write_word(isa::Register::X11, payload1 as isa::Word);
+ core.registers().write_word(isa::Register::X10, isa::Word(i as u32));
+ core.registers().write_word(isa::Register::X11, payload1.as_word());
cores.push(core);
}
@@ -112,11 +124,11 @@ fn main() {
ShareableCache::new(i, cache2_ref.clone(), cache_ref.clone())));
core_caches.push(core_cache.clone());
let mut core = simulator::Core::new(
- i, start2, (0x100000 * (i + 1)) as u32, core_cache,
- Box::new(memory::ReverseMmu::new(0x4000000))
+ i, start2, isa::Word(0x100000 * (i + 1) as u32), core_cache,
+ Box::new(memory::ReverseMmu::new(isa::Word(0x4000000)))
);
- core.registers().write_word(isa::Register::X10, (i - 4) as isa::Word);
- core.registers().write_word(isa::Register::X11, payload2 as isa::Word);
+ core.registers().write_word(isa::Register::X10, isa::Word((i - 4) as u32));
+ core.registers().write_word(isa::Register::X11, payload2.as_word());
cores.push(core);
}
diff --git a/src/memory_tracker.rs b/src/memory_tracker.rs
index e35bf2d..26c986a 100644
--- a/src/memory_tracker.rs
+++ b/src/memory_tracker.rs
@@ -1,16 +1,17 @@
-use rustv::isa;
+use rustv::isa::{self, IsaType};
use rustv::memory::{Memory, MemoryInterface, Result};
pub struct MemoryTracker {
memory: Memory,
- program1_byte: u8,
- program2_byte: u8,
- program1: i64,
- program2: i64,
+ program1_byte: isa::Byte,
+ program2_byte: isa::Byte,
+ program1: i32,
+ program2: i32,
}
impl MemoryTracker {
- pub fn new(memory: Memory, program1: u8, program2: u8) -> MemoryTracker {
+ pub fn new(memory: Memory,
+ program1: isa::Byte, program2: isa::Byte) -> MemoryTracker {
MemoryTracker {
memory: memory,
program1_byte: program1,
@@ -20,7 +21,7 @@ impl MemoryTracker {
}
}
- pub fn score(&self) -> (i64, i64) {
+ pub fn score(&self) -> (i32, i32) {
(self.program1, self.program2)
}
}
@@ -48,7 +49,7 @@ impl MemoryInterface for MemoryTracker {
if let Ok(original) = original {
if let Ok(()) = result {
- let p1b = self.program1_byte as u32;
+ let p1b = self.program1_byte.as_word();
let mut p1orig = 0;
let mut p1new = 0;
if original & 0xFF == p1b { p1orig += 1; }
@@ -63,7 +64,7 @@ impl MemoryInterface for MemoryTracker {
self.program1 += p1new - p1orig;
- let p2b = self.program2_byte as u32;
+ let p2b = self.program2_byte.as_word();
let mut p2orig = 0;
let mut p2new = 0;
if original & 0xFF == p2b { p2orig += 1; }
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)
}
}
diff --git a/src/system.rs b/src/system.rs
index c0343bb..a69beb4 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -34,11 +34,11 @@ impl<'a> SyscallHandler<'a> {
loop {
let c = self.memory.borrow_mut().read_byte(base);
- if let Ok(0x00) = c {
+ if let Ok(isa::Byte(0x00)) = c {
break;
}
else if let Ok(c) = c {
- string.push(c);
+ string.push(c.0);
}
base += 1;
@@ -81,7 +81,7 @@ impl<'a> syscall::SyscallHandler for SyscallHandler<'a> {
registers: &mut RegisterFile, mmu: &Mmu) -> Option<Trap> {
let syscall_number = registers.read_word(isa::Register::X10);
- match syscall_number {
+ match syscall_number.0 {
22 => self.prints(registers),
23 => self.printi(registers),
24 => self.enable_secondary(core_id),