From b0f627e9df022cedefee871bdaa64c8e06198a1c Mon Sep 17 00:00:00 2001
From: David Li
Date: Wed, 30 Dec 2015 10:24:36 -0700
Subject: Convert simulator to using cache
---
src/lib.rs | 7 ++-
src/memory.rs | 39 +++++++------
src/simulator.rs | 167 +++++++++++++++++++++++++++++--------------------------
3 files changed, 118 insertions(+), 95 deletions(-)
diff --git a/src/lib.rs b/src/lib.rs
index ac87f77..4c3db9e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -22,11 +22,16 @@ pub mod simulator;
#[test]
fn it_works() {
+ use std::rc::Rc;
+ use std::cell::RefCell;
+
use std::path::Path;
match binary::Binary::new_from_hex_file(Path::new("../riscv/kernel.hex")) {
Ok(b) => {
let memory = memory::Memory::new_from_binary(0x2000, b);
- let mut simulator = simulator::Simulator::new(1, memory);
+ let memory_ref = Rc::new(RefCell::new(Box::new(memory) as Box));
+ let core = simulator::Core::new(memory_ref.clone());
+ let mut simulator = simulator::Simulator::new(vec![core], memory_ref.clone());
simulator.run();
},
Err(err) => println!("Error: {:?}", err),
diff --git a/src/memory.rs b/src/memory.rs
index 9f606e4..2170556 100644
--- a/src/memory.rs
+++ b/src/memory.rs
@@ -31,11 +31,18 @@ pub enum MemoryError {
pub type Result = ::std::result::Result;
pub trait MemoryInterface {
- fn latency() -> u32;
+ fn latency(&self) -> u32;
fn read_word(&mut self, address: isa::Address) -> Result;
fn write_word(&mut self, address: isa::Address, value: isa::Word) -> Result<()>;
+ fn read_instruction(&mut self, address: isa::Address) -> Option {
+ match self.read_word(address / 4) {
+ Ok(word) => Some(Instruction::new(word)),
+ Err(_) => None,
+ }
+ }
+
// fn read_halfword(&self, address: isa::Address) -> Result;
// fn write_halfword(&self, address: isa::Address) -> Result<()>;
@@ -70,11 +77,11 @@ struct CacheBlock {
// investigate how LRU is implemented
// TODO: use hashtable for a way?
// TODO: hashtable-based FA cache?
-pub struct DirectMappedCache {
+pub struct DirectMappedCache {
num_sets: u32,
block_words: u32,
cache: Vec,
- next_level: Rc>,
+ next_level: Rc>,
}
impl Memory {
@@ -95,16 +102,10 @@ impl Memory {
memory: memory,
}
}
-
- pub fn read_instruction(&self, pc: isa::Address) -> Option {
- self.memory.get((pc / 4) as usize)
- .map(Clone::clone)
- .map(Instruction::new)
- }
}
impl MemoryInterface for Memory {
- fn latency() -> u32 {
+ fn latency(&self) -> u32 {
100
}
@@ -126,11 +127,17 @@ impl MemoryInterface for Memory {
Ok(())
}
}
+
+ fn read_instruction(&mut self, pc: isa::Address) -> Option {
+ self.memory.get((pc / 4) as usize)
+ .map(Clone::clone)
+ .map(Instruction::new)
+ }
}
-impl DirectMappedCache {
- pub fn new(sets: u32, block_words: u32, next_level: Rc>)
- -> DirectMappedCache {
+impl DirectMappedCache {
+ pub fn new(sets: u32, block_words: u32, next_level: Rc>)
+ -> DirectMappedCache {
let set = CacheBlock {
valid: false,
tag: 0,
@@ -172,16 +179,16 @@ impl DirectMappedCache {
}
}
-impl MemoryInterface for DirectMappedCache {
- fn latency() -> u32 {
+impl MemoryInterface for DirectMappedCache {
+ fn latency(&self) -> u32 {
100
}
fn read_word(&mut self, address: isa::Address) -> Result {
let normalized = self.normalize_address(address);
+ let stall = self.latency() + self.next_level.borrow().latency();
let (tag, index, offset) = self.parse_address(address);
let ref mut set = self.cache[index as usize];
- let stall = DirectMappedCache::::latency() + T::latency();
if set.tag == tag {
return Ok(set.contents[(offset / 4) as usize]);
}
diff --git a/src/simulator.rs b/src/simulator.rs
index 971427e..be47764 100644
--- a/src/simulator.rs
+++ b/src/simulator.rs
@@ -14,25 +14,27 @@
// You should have received a copy of the GNU General Public License
// along with rustv. If not, see .
+use std::cell::RefCell;
+use std::rc::Rc;
+
use isa;
use binary::{Binary};
use memory::{MemoryInterface, Memory, MemoryError};
-pub struct Simulator {
- num_cores: usize,
- memory: Memory,
-}
-
-#[derive(Clone)]
struct RegisterFile {
registers: [isa::Word; 32],
}
-#[derive(Clone)]
-struct Core {
+pub struct Core<'a> {
pc: isa::Address,
registers: RegisterFile,
running: bool,
+ cache: Rc>>,
+}
+
+pub struct Simulator<'a> {
+ cores: Vec>,
+ memory: Rc>>,
}
#[derive(Debug)]
@@ -73,75 +75,47 @@ impl RegisterFile {
}
}
-impl Simulator {
- pub fn new(num_cores: usize, memory: Memory) -> Simulator {
- // TODO: pass in GP, SP, _start
- // TODO: allow API user to specify core-cache layout
- // TODO: initialize GP, registers (GP is in headers)
- Simulator {
- num_cores: num_cores,
- memory: memory,
- }
- }
-
- pub fn run(&mut self) {
- let base_core = Core {
- pc: 0x1002C,
+impl<'a> Core<'a> {
+ pub fn new(cache: Rc>>) -> Core<'a> {
+ Core {
+ pc: 0, // TODO: hardcoded: fix later
registers: RegisterFile::new(),
running: true,
- };
- let mut cores = vec![base_core; self.num_cores];
- // hardcode GP
- cores[0].registers.write_word(isa::Register::X3, 0x108D0);
- // hardcode SP
- cores[0].registers.write_word(isa::Register::X2, 0x7FFC);
- loop {
- let mut ran = false;
- for core in cores.iter_mut() {
- if !core.running {
- continue;
- }
- self.step_core(core);
- ran = true;
- }
- if !ran {
- println!("All cores are not running, stopping...");
- break;
- }
+ cache: cache,
}
}
- fn step_core(&mut self, core: &mut Core) {
- let pc = core.pc;
- if let Some(inst) = self.memory.read_instruction(pc) {
+ fn step(&mut self, inst: Option) {
+ let pc = self.pc;
+ if let Some(inst) = inst {
match inst.opcode() {
isa::opcodes::JALR => {
// TODO: assert funct3 is 0
- let base = core.registers.read_word(inst.rs1())
+ let base = self.registers.read_word(inst.rs1())
as isa::SignedWord;
let target = (base + inst.i_imm()) as isa::Address;
let retval = (pc + 4) as isa::Word;
if target == 0x0 {
// ret
- core.running = false;
+ self.running = false;
}
else {
- core.registers.write_word(inst.rd(), retval);
- core.pc = target;
+ self.registers.write_word(inst.rd(), retval);
+ self.pc = target;
return;
}
},
isa::opcodes::JAL => {
let target = ((pc as isa::SignedWord) + inst.uj_imm()) as isa::Address;
- core.registers.write_word(inst.rd(), (pc + 4) as isa::Word);
- core.pc = target;
+ self.registers.write_word(inst.rd(), (pc + 4) as isa::Word);
+ self.pc = target;
// panic!("JAL to {:X} 0x{:X}", pc, target);
return;
}
isa::opcodes::BRANCH => {
let target = ((pc as isa::SignedWord) + inst.sb_imm()) as isa::Address;
- let rs1 = core.registers.read_word(inst.rs1());
- let rs2 = core.registers.read_word(inst.rs2());
+ let rs1 = self.registers.read_word(inst.rs1());
+ let rs2 = self.registers.read_word(inst.rs2());
if match inst.funct3() {
isa::funct3::BEQ => rs1 == rs2,
isa::funct3::BNE => rs1 != rs2,
@@ -150,20 +124,20 @@ impl Simulator {
isa::funct3::BLTU => rs1 < rs2,
isa::funct3::BGEU => rs1 > rs2,
_ => {
- self.trap(core, Trap::IllegalInstruction {
+ self.trap(Trap::IllegalInstruction {
address: pc,
instruction: inst,
});
false
}
} {
- core.pc = target;
+ self.pc = target;
return;
}
},
isa::opcodes::INTEGER_IMMEDIATE => {
let imm = inst.i_imm();
- let src = core.registers.read_word(inst.rs1()) as isa::SignedWord;
+ let src = self.registers.read_word(inst.rs1()) as isa::SignedWord;
if let Some(value) = match inst.funct3() {
isa::funct3::ADDI => {
Some(src.wrapping_add(imm) as isa::Word)
@@ -195,7 +169,7 @@ impl Simulator {
isa::funct7::SRLI => Some(((src as isa::Word) >> inst.shamt()) as isa::Word),
isa::funct7::SRAI => Some((src >> inst.shamt()) as isa::Word),
_ => {
- self.trap(core, Trap::IllegalInstruction {
+ self.trap(Trap::IllegalInstruction {
address: pc,
instruction: inst,
});
@@ -210,19 +184,19 @@ impl Simulator {
Some((src & imm) as isa::Word)
},
_ => {
- self.trap(core, Trap::IllegalInstruction {
+ self.trap(Trap::IllegalInstruction {
address: pc,
instruction: inst,
});
None
}
} {
- core.registers.write_word(inst.rd(), value);
+ self.registers.write_word(inst.rd(), value);
}
},
isa::opcodes::INTEGER_REGISTER => {
- let src1 = core.registers.read_word(inst.rs1());
- let src2 = core.registers.read_word(inst.rs2());
+ let src1 = self.registers.read_word(inst.rs1());
+ let src2 = self.registers.read_word(inst.rs2());
let src2_shift = src2 & 0x1F;
if let Some(value) = match inst.funct3() {
isa::funct3::ADD_SUB => {
@@ -230,7 +204,7 @@ impl Simulator {
isa::funct7::ADD_SRL => Some(((src1 as isa::SignedWord).wrapping_add(src2 as isa::SignedWord)) as isa::Word),
isa::funct7::SUB_SRA => Some(((src1 as isa::SignedWord).wrapping_sub(src2 as isa::SignedWord)) as isa::Word),
_ => {
- self.trap(core, Trap::IllegalInstruction {
+ self.trap(Trap::IllegalInstruction {
address: pc,
instruction: inst,
});
@@ -265,7 +239,7 @@ impl Simulator {
isa::funct7::ADD_SRL => Some(src1 >> src2_shift),
isa::funct7::SUB_SRA => Some(((src1 as isa::SignedWord) >> src2_shift) as isa::Word),
_ => {
- self.trap(core, Trap::IllegalInstruction {
+ self.trap(Trap::IllegalInstruction {
address: pc,
instruction: inst,
});
@@ -280,27 +254,28 @@ impl Simulator {
Some(src1 & src2)
},
_ => {
- self.trap(core, Trap::IllegalInstruction {
+ self.trap(Trap::IllegalInstruction {
address: pc,
instruction: inst,
});
None
}
} {
- core.registers.write_word(inst.rd(), value);
+ self.registers.write_word(inst.rd(), value);
}
},
isa::opcodes::LOAD => match inst.funct3() {
isa::funct3::LW => {
let imm = inst.i_imm();
- let base = core.registers.read_word(inst.rs1());
+ let base = self.registers.read_word(inst.rs1());
let address = ((base as isa::SignedWord) + imm) as isa::Address;
- match self.memory.read_word(address) {
+ let result = self.cache.borrow_mut().read_word(address);
+ match result {
Ok(value) =>
- core.registers.write_word(inst.rd(), value),
+ self.registers.write_word(inst.rd(), value),
Err(MemoryError::CacheMiss {..}) => return,
Err(MemoryError::InvalidAddress) => {
- self.trap(core, Trap::IllegalRead {
+ self.trap(Trap::IllegalRead {
address: pc,
instruction: inst,
memory_address: address,
@@ -315,14 +290,15 @@ impl Simulator {
isa::opcodes::STORE => match inst.funct3() {
isa::funct3::SW => {
let imm = inst.s_imm();
- let base = core.registers.read_word(inst.rs1());
- let val = core.registers.read_word(inst.rs2());
+ let base = self.registers.read_word(inst.rs1());
+ let val = self.registers.read_word(inst.rs2());
let address = ((base as isa::SignedWord) + imm) as isa::Address;
- match self.memory.write_word(address, val) {
+ let result = self.cache.borrow_mut().write_word(address, val);
+ match result {
Ok(()) => (),
Err(MemoryError::CacheMiss {..}) => return,
Err(MemoryError::InvalidAddress) => {
- self.trap(core, Trap::IllegalWrite {
+ self.trap(Trap::IllegalWrite {
address: pc,
instruction: inst,
memory_address: address,
@@ -338,9 +314,9 @@ impl Simulator {
isa::opcodes::SYSTEM => match inst.i_imm() {
0x0 => {
// System call
- println!("System call {}:", core.registers.read_word(isa::Register::X10));
- let address = core.registers.read_word(isa::Register::X11);
- println!("Argument {:X}: {:?}", address, self.memory.read_word(address));
+ println!("System call {}:", self.registers.read_word(isa::Register::X10));
+ let address = self.registers.read_word(isa::Register::X11);
+ println!("Argument {:X}: {:?}", address, self.cache.borrow_mut().read_word(address));
}
_ => {
@@ -354,11 +330,46 @@ impl Simulator {
else {
// trap
}
- core.pc += 4;
+ self.pc += 4;
}
- fn trap(&mut self, core: &mut Core, trap: Trap) {
+ fn trap(&mut self, trap: Trap) {
println!("Trap: {:?}", trap);
- core.running = false;
+ self.running = false;
+ }
+}
+
+impl<'a> Simulator<'a> {
+ pub fn new(cores: Vec>, memory: Rc>>) -> Simulator<'a> {
+ // TODO: pass in GP, SP, _start
+ // TODO: initialize GP, registers (GP is in headers)
+ Simulator {
+ cores: cores,
+ memory: memory,
+ }
+ }
+
+ pub fn run(&mut self) {
+ // hardcode _start
+ self.cores[0].pc = 0x1002C;
+ // hardcode GP
+ self.cores[0].registers.write_word(isa::Register::X3, 0x108D0);
+ // hardcode SP
+ self.cores[0].registers.write_word(isa::Register::X2, 0x7FFC);
+ loop {
+ let mut ran = false;
+ for core in self.cores.iter_mut() {
+ if !core.running {
+ continue;
+ }
+ let inst = self.memory.borrow_mut().read_instruction(core.pc);
+ core.step(inst);
+ ran = true;
+ }
+ if !ran {
+ println!("All cores are not running, stopping...");
+ break;
+ }
+ }
}
}
--
cgit v1.2.3