From ad805c698cd1c4d68d090f842fb14621c32ee8d6 Mon Sep 17 00:00:00 2001 From: David Li Date: Fri, 8 Jan 2016 10:04:27 -0700 Subject: Refactor into multiple files --- Cargo.lock | 30 +++++++++++ Cargo.toml | 1 + src/main.rs | 141 ++++++++++--------------------------------------- src/memory_tracker.rs | 85 +++++++++++++++++++++++++++++ src/shareable_cache.rs | 104 ++++++++++++++++++++++++++++++++++++ src/system.rs | 67 +++++++++++++++++++++++ 6 files changed, 314 insertions(+), 114 deletions(-) create mode 100644 src/memory_tracker.rs create mode 100644 src/shareable_cache.rs create mode 100644 src/system.rs diff --git a/Cargo.lock b/Cargo.lock index 12379b0..b3f0c3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ dependencies = [ "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustv 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -30,6 +31,15 @@ name = "elfloader32" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "kernel32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libc" version = "0.2.4" @@ -76,3 +86,23 @@ name = "strsim" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "time" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + diff --git a/Cargo.toml b/Cargo.toml index 7efe290..6515d90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ authors = ["David Li "] rustv = "0.3.0" docopt = "0.6" rustc-serialize = "0.3" +time = "0.1" diff --git a/src/main.rs b/src/main.rs index 722efdb..50cc8ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,11 @@ extern crate docopt; extern crate rustc_serialize; extern crate rustv; +extern crate time; + +mod memory_tracker; +mod shareable_cache; +mod system; use std::fs::File; use std::io::Read; @@ -12,12 +17,11 @@ use docopt::Docopt; use rustv::elfloader; use rustv::isa; use rustv::memory; -use rustv::memory::MemoryInterface; use rustv::memory::Mmu; -use rustv::register_file; use rustv::simulator; -use rustv::syscall; -use rustv::trap; + +use memory_tracker::MemoryTracker; +use system::SyscallHandler; const USAGE: &'static str = " cacheracer - A F/OSS implementation of the CS 3410 CacheRacer @@ -36,102 +40,7 @@ struct Args { arg_program2: String, } -struct MemoryTracker { - memory: memory::Memory, - program1_byte: u8, - program2_byte: u8, - program1: usize, - program2: usize, -} - -impl memory::MemoryInterface for MemoryTracker { - fn latency(&self) -> u32 { - self.memory.latency() - } - - fn step(&mut self) { - self.memory.step(); - } - - fn read_word(&mut self, address: isa::Address) -> memory::Result { - self.memory.read_word(address) - } - - fn write_word(&mut self, address: isa::Address, value: isa::Word) -> memory::Result<()> { - let original = self.memory.read_word(address); - let result = self.memory.write_word(address, value); - - if let Ok(original) = original { - if let Ok(()) = result { - let p1b = self.program1_byte as u32; - let mut p1orig = 0; - let mut p1new = 0; - if original & 0xFF == p1b { p1orig += 1; } - if (original >> 8) & 0xFF == p1b { p1orig += 1; } - if (original >> 8) & 0xFF == p1b { p1orig += 1; } - if (original >> 8) & 0xFF == p1b { p1orig += 1; } - - if value & 0xFF == p1b { p1new += 1; } - if (value >> 8) & 0xFF == p1b { p1new += 1; } - if (value >> 8) & 0xFF == p1b { p1new += 1; } - if (value >> 8) & 0xFF == p1b { p1new += 1; } - - self.program1 += p1new - p1orig; - - let p2b = self.program2_byte as u32; - let mut p2orig = 0; - let mut p2new = 0; - if original & 0xFF == p2b { p2orig += 1; } - if (original >> 8) & 0xFF == p2b { p2orig += 1; } - if (original >> 8) & 0xFF == p2b { p2orig += 1; } - if (original >> 8) & 0xFF == p2b { p2orig += 1; } - - if value & 0xFF == p2b { p2new += 1; } - if (value >> 8) & 0xFF == p2b { p2new += 1; } - if (value >> 8) & 0xFF == p2b { p2new += 1; } - if (value >> 8) & 0xFF == p2b { p2new += 1; } - - self.program2 += p2new - p2orig; - } - } - - result - } -} - -struct SyscallHandler<'a> { - memory: memory::SharedMemory<'a>, -} - -impl<'a> syscall::SyscallHandler for SyscallHandler<'a> { - fn syscall(&mut self, registers: &mut register_file::RegisterFile) -> Option { - println!("Syscall number {}", registers.read_word(isa::Register::X10)); - let mut base = registers.read_word(isa::Register::X11); - let mut string = vec![]; - loop { - let c = self.memory.borrow_mut().read_byte(base); - - if let Ok(0x00) = c { - break; - } - else if let Ok(c) = c { - string.push(c); - } - - base += 1; - } - - let result = std::str::from_utf8(&string); - if let Ok(string) = result { - println!("{}", string); - } - else { - println!("Error printing string: {:?}", result); - } - None - } -} fn load_program(memory: &mut memory::Memory, mmu: &T, path: &str) -> isa::Address { @@ -159,36 +68,40 @@ fn main() { .unwrap_or_else(|e| e.exit()); let mmu = memory::IdentityMmu::new(); - let mmu2 = memory::ReverseMmu::new(0x8000); - let mut memory = memory::Memory::new(0x10000); + // TODO: account for word-vs-byte addressed. Use newtype pattern? + let mmu2 = memory::ReverseMmu::new(0x4000000); + let mut memory = memory::Memory::new(0x400000); let start1 = load_program(&mut memory, &mmu, &args.arg_program1); let start2 = load_program(&mut memory, &mmu2, &args.arg_program2); - let mut memory = MemoryTracker { - memory: memory, - program1_byte: 0x43, - program2_byte: 0x42, - program1: 0, - program2: 0, - }; + let memory = MemoryTracker::new(memory, 0x43, 0x42); let memory_ref = Rc::new(RefCell::new(memory)); - let cache = memory::DirectMappedCache::new(4, 4, memory_ref.clone()); + let cache = memory::DirectMappedCache::new(4, 64, memory_ref.clone()); let cache_ref = Rc::new(RefCell::new(cache)); + let cache2 = memory::DirectMappedCache::new(4, 64, memory_ref.clone()); + let cache2_ref = Rc::new(RefCell::new(cache2)); + let core = simulator::Core::new( start1, 0x1000, cache_ref.clone(), Box::new(mmu)); let core2 = simulator::Core::new( start2, 0x1000, - cache_ref.clone(), Box::new(mmu2)); + cache2_ref.clone(), Box::new(mmu2)); let cores = vec![core, core2]; - let system = SyscallHandler { memory: memory_ref.clone(), }; + let system = SyscallHandler::new(memory_ref.clone()); let mut simulator = simulator::Simulator::new( cores, memory_ref.clone(), system); - simulator.run(); + // let cycles = 0x1000000; + let cycles = 0x1000000; + let start = time::precise_time_s(); + simulator.run_max(cycles); + let end = time::precise_time_s(); - println!("Program 1 bytes written: {}", memory_ref.borrow().program1); - println!("Program 2 bytes written: {}", memory_ref.borrow().program2); + println!("{} cycles in {:04} seconds ({} cycles/sec)", cycles, end - start, (cycles as f64) / (end - start)); + let (p1, p2) = memory_ref.borrow().score(); + println!("Program 1 bytes written: {}", p1); + println!("Program 2 bytes written: {}", p2); } diff --git a/src/memory_tracker.rs b/src/memory_tracker.rs new file mode 100644 index 0000000..e35bf2d --- /dev/null +++ b/src/memory_tracker.rs @@ -0,0 +1,85 @@ +use rustv::isa; +use rustv::memory::{Memory, MemoryInterface, Result}; + +pub struct MemoryTracker { + memory: Memory, + program1_byte: u8, + program2_byte: u8, + program1: i64, + program2: i64, +} + +impl MemoryTracker { + pub fn new(memory: Memory, program1: u8, program2: u8) -> MemoryTracker { + MemoryTracker { + memory: memory, + program1_byte: program1, + program2_byte: program2, + program1: 0, + program2: 0, + } + } + + pub fn score(&self) -> (i64, i64) { + (self.program1, self.program2) + } +} + +impl MemoryInterface for MemoryTracker { + fn latency(&self) -> u32 { + self.memory.latency() + } + + fn step(&mut self) { + self.memory.step(); + } + + fn is_address_accessible(&self, address: isa::Address) -> bool { + self.memory.is_address_accessible(address) + } + + fn read_word(&mut self, address: isa::Address) -> Result { + self.memory.read_word(address) + } + + fn write_word(&mut self, address: isa::Address, value: isa::Word) -> Result<()> { + let original = self.memory.read_word(address); + let result = self.memory.write_word(address, value); + + if let Ok(original) = original { + if let Ok(()) = result { + let p1b = self.program1_byte as u32; + let mut p1orig = 0; + let mut p1new = 0; + if original & 0xFF == p1b { p1orig += 1; } + if (original >> 8) & 0xFF == p1b { p1orig += 1; } + if (original >> 16) & 0xFF == p1b { p1orig += 1; } + if (original >> 24) & 0xFF == p1b { p1orig += 1; } + + if value & 0xFF == p1b { p1new += 1; } + if (value >> 8) & 0xFF == p1b { p1new += 1; } + if (value >> 16) & 0xFF == p1b { p1new += 1; } + if (value >> 24) & 0xFF == p1b { p1new += 1; } + + self.program1 += p1new - p1orig; + + let p2b = self.program2_byte as u32; + let mut p2orig = 0; + let mut p2new = 0; + if original & 0xFF == p2b { p2orig += 1; } + if (original >> 8) & 0xFF == p2b { p2orig += 1; } + if (original >> 16) & 0xFF == p2b { p2orig += 1; } + if (original >> 24) & 0xFF == p2b { p2orig += 1; } + + if value & 0xFF == p2b { p2new += 1; } + if (value >> 8) & 0xFF == p2b { p2new += 1; } + if (value >> 16) & 0xFF == p2b { p2new += 1; } + if (value >> 24) & 0xFF == p2b { p2new += 1; } + + self.program2 += p2new - p2orig; + } + } + + result + } +} diff --git a/src/shareable_cache.rs b/src/shareable_cache.rs new file mode 100644 index 0000000..b6c6654 --- /dev/null +++ b/src/shareable_cache.rs @@ -0,0 +1,104 @@ +use rustv::isa; +use rustv::memory::{MemoryInterface, Result, SharedMemory}; + +/// A cache that can be used as two separate caches or one +/// set-associative cache. +struct ShareableCache<'a> { + // The idea is to create two separate ShareableCaches, one for + // each player. + primary: SharedMemory<'a>, + secondary: SharedMemory<'a>, + secondary_enabled: bool, + use_secondary: bool, +} + +impl<'a> ShareableCache<'a> { + pub fn new(cache1: SharedMemory<'a>, cache2: SharedMemory<'a>) + -> (ShareableCache<'a>, ShareableCache<'a>) { + (ShareableCache { + primary: cache1.clone(), + secondary: cache2.clone(), + secondary_enabled: false, + use_secondary: false, + }, ShareableCache { + primary: cache2.clone(), + secondary: cache1.clone(), + secondary_enabled: false, + use_secondary: false, + }) + } + + pub fn enable_secondary(&mut self) { + self.secondary_enabled = true; + self.use_secondary = true; + } + + pub fn disable_secondary(&mut self) { + self.secondary_enabled = false; + } +} + +impl<'a> MemoryInterface for ShareableCache<'a> { + fn latency(&self) -> u32 { + self.primary.borrow().latency() + } + + fn step(&mut self) { + // We only step the primary cache. The idea is that the + // secondary cache should be the primary cache of another + // ShareableCache. + self.primary.borrow_mut().step(); + } + + fn is_address_accessible(&self, address: isa::Address) -> bool { + self.primary.borrow().is_address_accessible(address) || + (self.secondary_enabled && + self.secondary.borrow().is_address_accessible(address)) + } + + fn read_word(&mut self, address: isa::Address) -> Result { + if self.secondary_enabled { + if self.primary.borrow().is_address_accessible(address) { + self.primary.borrow_mut().read_word(address) + } + else if self.secondary.borrow().is_address_accessible(address) { + self.secondary.borrow_mut().read_word(address) + } + else { + self.use_secondary = !self.use_secondary; + if self.use_secondary { + self.secondary.borrow_mut().read_word(address) + } + else { + self.primary.borrow_mut().read_word(address) + } + } + } + else { + self.primary.borrow_mut().read_word(address) + } + } + + fn write_word(&mut self, address: isa::Address, value: isa::Word) -> Result<()> { + if self.secondary_enabled { + if self.primary.borrow().is_address_accessible(address) { + self.primary.borrow_mut().write_word(address, value) + } + else if self.secondary.borrow().is_address_accessible(address) { + self.secondary.borrow_mut().write_word(address, value) + } + else { + self.use_secondary = !self.use_secondary; + if self.use_secondary { + self.secondary.borrow_mut().write_word(address, value) + } + else { + self.primary.borrow_mut().write_word(address, value) + } + } + } + else { + self.primary.borrow_mut().write_word(address, value) + } + } +} diff --git a/src/system.rs b/src/system.rs new file mode 100644 index 0000000..faadb13 --- /dev/null +++ b/src/system.rs @@ -0,0 +1,67 @@ +use std; + +use rustv::isa; +use rustv::memory::SharedMemory; +use rustv::register_file::RegisterFile; +use rustv::syscall; +use rustv::trap::Trap; + +pub struct SyscallHandler<'a> { + memory: SharedMemory<'a>, +} + +impl<'a> SyscallHandler<'a> { + pub fn new(memory: SharedMemory<'a>) -> SyscallHandler<'a> { + SyscallHandler { + memory: memory + } + } +} + +impl<'a> SyscallHandler<'a> { + fn print(&mut self, registers: &mut RegisterFile) -> Option { + let mut base = registers.read_word(isa::Register::X11); + let mut string = vec![]; + + loop { + let c = self.memory.borrow_mut().read_byte(base); + + if let Ok(0x00) = c { + break; + } + else if let Ok(c) = c { + string.push(c); + } + + base += 1; + } + + let result = std::str::from_utf8(&string); + if let Ok(string) = result { + println!("{}", string); + } + else { + println!("Error printing string: not valid UTF-8: {:?}", result); + } + None + + } +} + +impl<'a> syscall::SyscallHandler for SyscallHandler<'a> { + // TODO: is trap really appropriate here? + fn syscall(&mut self, registers: &mut RegisterFile) -> Option { + let syscall_number = registers.read_word(isa::Register::X10); + + match syscall_number { + 22 => { + self.print(registers) + } + + _ => { + // TODO: some sort of error reporting + None + } + } + } +} -- cgit v1.2.3