extern crate docopt; extern crate rustc_serialize; extern crate rustv; use std::fs::File; use std::io::Read; use std::rc::Rc; use std::cell::RefCell; 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; const USAGE: &'static str = " cacheracer - A F/OSS implementation of the CS 3410 CacheRacer Usage: cacheracer Options: -h --help Show this screen. --version Show version. "; #[derive(Debug, RustcDecodable)] struct Args { arg_program1: String, 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 { let mut f = File::open(path).unwrap(); let mut buffer = Vec::new(); f.read_to_end(&mut buffer).unwrap(); let elf = elfloader::ElfBinary::new("test", &buffer).unwrap(); let start = elf.file_header().entry as isa::Address; for p in elf.section_headers() { let name = elf.section_name(p); if name == ".text" || name == ".sdata" || name == ".rodata" { memory.write_segment(mmu, elf.section_data(p), p.addr as usize); } } start } fn main() { let args: Args = Docopt::new(USAGE) .and_then(|d| d.decode()) .unwrap_or_else(|e| e.exit()); let mmu = memory::IdentityMmu::new(); let mmu2 = memory::ReverseMmu::new(0x8000); let mut memory = memory::Memory::new(0x10000); 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_ref = Rc::new(RefCell::new(memory)); let cache = memory::DirectMappedCache::new(4, 4, memory_ref.clone()); let cache_ref = Rc::new(RefCell::new(cache)); 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)); let cores = vec![core, core2]; let system = SyscallHandler { memory: memory_ref.clone(), }; let mut simulator = simulator::Simulator::new( cores, memory_ref.clone(), system); simulator.run(); println!("Program 1 bytes written: {}", memory_ref.borrow().program1); println!("Program 2 bytes written: {}", memory_ref.borrow().program2); }