aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Li <li.davidm96@gmail.com>2016-01-07 10:34:36 -0700
committerDavid Li <li.davidm96@gmail.com>2016-01-07 10:34:36 -0700
commit6f92b9ccda52387f0ab6dbfcc0d0b1bed742e9d4 (patch)
tree439cd06ad947099fba6b878fd776258ad4a7a446
parent7a3dae00d742394a114a9fafbdf25f08cd458ce4 (diff)
Let API user handle syscalls
-rw-r--r--src/lib.rs70
-rw-r--r--src/register_file.rs40
-rw-r--r--src/simulator.rs64
-rw-r--r--src/syscall.rs23
-rw-r--r--src/trap.rs36
5 files changed, 164 insertions, 69 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 5aa69e3..feba5e2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,7 +20,10 @@ extern crate elfloader32 as elfloader_lib;
pub mod isa;
pub mod binary;
pub mod memory;
+pub mod register_file;
pub mod simulator;
+pub mod syscall;
+pub mod trap;
pub use elfloader_lib as elfloader;
@@ -31,6 +34,42 @@ fn test_elfloader() {
use std::rc::Rc;
use std::cell::RefCell;
+ use memory::MemoryInterface;
+
+ struct SyscallHandler<'a> {
+ memory: memory::SharedMemory<'a>,
+ }
+
+ impl<'a> syscall::SyscallHandler for SyscallHandler<'a> {
+ fn syscall(&mut self, registers: &mut register_file::RegisterFile) -> Option<trap::Trap> {
+ 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
+ }
+ }
+
let mut f = File::open("../riscv/kernel").unwrap();
let mut buffer = Vec::new();
@@ -39,27 +78,18 @@ fn test_elfloader() {
let elf = elfloader::ElfBinary::new("test", &buffer).unwrap();
let start = elf.file_header().entry as isa::Address;
- let mut text = None;
- let mut data = None;
- for p in elf.section_headers() {
- if p.name.0 == 0x1b {
- text = Some((elf.section_data(p), p.addr));
- }
- else if p.name.0 == 0x33 {
- data = Some((elf.section_data(p), p.addr));
- }
- }
-
- let (text, text_offset) = text.unwrap();
- let (data, data_offset) = data.unwrap();
-
let mmu = memory::IdentityMmu::new();
let mmu2 = memory::ReverseMmu::new(0x8000);
let mut memory = memory::Memory::new(0x10000);
- memory.write_segment(&mmu, text, text_offset as usize);
- memory.write_segment(&mmu, data, data_offset as usize);
- memory.write_segment(&mmu2, text, text_offset as usize);
- memory.write_segment(&mmu2, data, data_offset as usize);
+
+ for p in elf.section_headers() {
+ let name = elf.section_name(p);
+ if name == ".text" || name == ".sdata" || name == ".rodata" {
+ println!("Loading {} section", name);
+ memory.write_segment(&mmu, elf.section_data(p), p.addr as usize);
+ memory.write_segment(&mmu2, elf.section_data(p), p.addr as usize);
+ }
+ }
let memory_ref = Rc::new(RefCell::new(memory));
let cache = memory::DirectMappedCache::new(4, 4, memory_ref.clone());
@@ -71,7 +101,9 @@ fn test_elfloader() {
start, 0x3000,
cache_ref.clone(), Box::new(mmu2));
let cores = vec![core, core2];
- let mut simulator = simulator::Simulator::new(cores, memory_ref.clone());
+
+ let system = SyscallHandler { memory: memory_ref.clone(), };
+ let mut simulator = simulator::Simulator::new(cores, memory_ref.clone(), system);
simulator.run();
}
diff --git a/src/register_file.rs b/src/register_file.rs
new file mode 100644
index 0000000..6437eed
--- /dev/null
+++ b/src/register_file.rs
@@ -0,0 +1,40 @@
+// Copyright 2016 David Li
+// This file is part of rustv.
+
+// rustv is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// rustv is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with rustv. If not, see <http://www.gnu.org/licenses/>.
+
+use isa;
+
+pub struct RegisterFile {
+ registers: [isa::Word; 32],
+}
+
+impl RegisterFile {
+ pub fn new() -> RegisterFile {
+ RegisterFile {
+ registers: [0; 32],
+ }
+ }
+
+ pub fn write_word<T: Into<isa::Register>>(&mut self, reg: T, value: isa::Word) {
+ // TODO: should be safe to use unchecked index
+ let reg = reg.into();
+ if reg == isa::Register::X0 { return; }
+ self.registers[reg.as_num()] = value;
+ }
+
+ pub fn read_word<T: Into<isa::Register>>(&mut self, reg: T) -> isa::Word {
+ self.registers[reg.into().as_num()]
+ }
+}
diff --git a/src/simulator.rs b/src/simulator.rs
index 073de67..d1c4aae 100644
--- a/src/simulator.rs
+++ b/src/simulator.rs
@@ -16,10 +16,9 @@
use isa;
use memory::{MemoryInterface, MemoryError, Mmu, SharedMemory};
-
-struct RegisterFile {
- registers: [isa::Word; 32],
-}
+use register_file::RegisterFile;
+use syscall::SyscallHandler;
+use trap::Trap;
pub struct Core<'a>{
pc: isa::Address,
@@ -32,47 +31,10 @@ pub struct Core<'a>{
stall_count: u32,
}
-pub struct Simulator<'a> {
+pub struct Simulator<'a, T: SyscallHandler> {
cores: Vec<Core<'a>>,
memory: SharedMemory<'a>,
-}
-
-#[derive(Debug)]
-enum Trap {
- IllegalInstruction {
- address: isa::Address,
- instruction: isa::Instruction,
- },
- IllegalRead {
- address: isa::Address,
- instruction: isa::Instruction,
- memory_address: isa::Address,
- },
- IllegalWrite {
- address: isa::Address,
- instruction: isa::Instruction,
- memory_address: isa::Address,
- memory_value: isa::Word,
- }
-}
-
-impl RegisterFile {
- fn new() -> RegisterFile {
- RegisterFile {
- registers: [0; 32],
- }
- }
-
- fn write_word<T: Into<isa::Register>>(&mut self, reg: T, value: isa::Word) {
- // TODO: should be safe to use unchecked index
- let reg = reg.into();
- if reg == isa::Register::X0 { return; }
- self.registers[reg.as_num()] = value;
- }
-
- fn read_word<T: Into<isa::Register>>(&mut self, reg: T) -> isa::Word {
- self.registers[reg.into().as_num()]
- }
+ syscall: T,
}
impl<'a> Core<'a> {
@@ -93,7 +55,7 @@ impl<'a> Core<'a> {
}
}
- fn step(&mut self, inst: isa::Instruction) {
+ fn step(&mut self, inst: isa::Instruction, system: &mut SyscallHandler) {
let pc = self.pc;
self.cycle_count += 1;
@@ -363,8 +325,9 @@ impl<'a> Core<'a> {
},
isa::opcodes::SYSTEM => match inst.i_imm() {
0x0 => {
- // System call
- println!("System call {}:", self.registers.read_word(isa::Register::X10));
+ if let Some(trap) = system.syscall(&mut self.registers) {
+ self.trap(trap);
+ }
}
_ => {
@@ -383,13 +346,14 @@ impl<'a> Core<'a> {
}
}
-impl<'a> Simulator<'a> {
- pub fn new(cores: Vec<Core<'a>>, memory: SharedMemory<'a>)
- -> Simulator<'a> {
+impl<'a, T: SyscallHandler> Simulator<'a, T> {
+ pub fn new(cores: Vec<Core<'a>>, memory: SharedMemory<'a>, syscall: T)
+ -> Simulator<'a, T> {
// TODO: initialize GP, registers (GP is in headers)
Simulator {
cores: cores,
memory: memory,
+ syscall: syscall,
}
}
@@ -405,7 +369,7 @@ impl<'a> Simulator<'a> {
let inst = self.memory.borrow_mut().read_instruction(pc);
if let Some(inst) = inst {
- core.step(inst);
+ core.step(inst, &mut self.syscall);
}
else {
// TODO: trap
diff --git a/src/syscall.rs b/src/syscall.rs
new file mode 100644
index 0000000..41a0fcd
--- /dev/null
+++ b/src/syscall.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 David Li
+// This file is part of rustv.
+
+// rustv is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// rustv is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with rustv. If not, see <http://www.gnu.org/licenses/>.
+
+use register_file::RegisterFile;
+use trap;
+
+pub trait SyscallHandler {
+ // Can't take cache because syscall can't stall
+ fn syscall(&mut self, registers: &mut RegisterFile) -> Option<trap::Trap>;
+}
diff --git a/src/trap.rs b/src/trap.rs
new file mode 100644
index 0000000..bb7a808
--- /dev/null
+++ b/src/trap.rs
@@ -0,0 +1,36 @@
+// Copyright 2016 David Li
+// This file is part of rustv.
+
+// rustv is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// rustv is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with rustv. If not, see <http://www.gnu.org/licenses/>.
+
+use isa;
+
+#[derive(Debug)]
+pub enum Trap {
+ IllegalInstruction {
+ address: isa::Address,
+ instruction: isa::Instruction,
+ },
+ IllegalRead {
+ address: isa::Address,
+ instruction: isa::Instruction,
+ memory_address: isa::Address,
+ },
+ IllegalWrite {
+ address: isa::Address,
+ instruction: isa::Instruction,
+ memory_address: isa::Address,
+ memory_value: isa::Word,
+ }
+}