commit 0c561dfa0990290dd0fd286d1bca610083f27888
parent 7fabdd6a1ec4309862ccd16c01991015cf884180
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date: Sat, 18 Jun 2022 01:11:16 -0700
Dyn error system
Diffstat:
M | src/config.rs | | | 41 | +++++++++++++++++++---------------------- |
M | src/cpu.rs | | | 79 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | src/decode.rs | | | 115 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
M | src/decode_test.rs | | | 79 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
M | src/execute.rs | | | 52 | ++++++++++++++++++++++++++-------------------------- |
M | src/main.rs | | | 19 | +++++++------------ |
M | src/memory.rs | | | 94 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | src/sdl.rs | | | 3 | ++- |
M | src/system.rs | | | 13 | +++++++------ |
M | src/util.rs | | | 70 | ++++++++++++++++++++++++++++++++++++++++++---------------------------- |
10 files changed, 312 insertions(+), 253 deletions(-)
diff --git a/src/config.rs b/src/config.rs
@@ -23,10 +23,11 @@ use std::env;
use std::fmt;
use std::fs;
use std::path::Path;
-use util;
-use util::concat_paths;
+use util::{concat_paths, get_home_nofail, Result};
-use self::serde_derive::{Deserialize, Serialize};
+use berr;
+
+use self::serde_derive::Deserialize;
/// Configuration of the emulator.
#[derive(Deserialize)]
@@ -55,8 +56,8 @@ pub struct Config {
impl Config {
/// Create a new configuration object (with default settings) on success and a string on error.
- pub fn new() -> Result<Config, String> {
- let home_dir = util::get_home_nofail();
+ pub fn new() -> Result<Config> {
+ let home_dir = get_home_nofail();
// Find a configuration path specified on the command line.
let config_path = match env::var("XDG_CONFIG_HOME") {
Ok(v) => format!("{}", v),
@@ -77,7 +78,7 @@ impl Config {
}
/// Create an initialized configuration object on success and a string on error.
- pub fn init() -> Result<Config, String> {
+ pub fn init() -> Result<Config> {
let mut config = Self::new()?;
let args: Vec<String> = env::args().collect();
// Look for custom config file location first. Read it, then override with cmd args.
@@ -96,17 +97,17 @@ impl Config {
/// Read the user's configuration file and update configuration state
/// (default ~/.config/riscii/config.toml). Return void on success and a
/// string on error.
- fn read_config_file(&mut self) -> Result<(), String> {
+ fn read_config_file(&mut self) -> Result<()> {
// TODO do not exit if config.toml does not exist
// TODO get ~ in paths to expand
// Keep the data we want to survive the assignment.
let config_file_path = self.config_file_path.clone();
*self = match toml::from_str(&match fs::read_to_string(Path::new(&config_file_path)) {
- Err(e) => return Err(format!("Could not read {}, {}", config_file_path, e)),
+ Err(e) => return berr!(format!("Could not read {}, {}", config_file_path, e)),
Ok(r) => r,
}) {
Err(e) => {
- return Err(format!(
+ return berr!(format!(
"Could not parse config file {}, {}",
config_file_path, e
))
@@ -123,7 +124,7 @@ impl Config {
/// success and string on error.
/// # Arguments
/// * `args` - CMD argument vector.
- fn find_cmd_config_path(&self, args: &Vec<String>) -> Result<Option<String>, String> {
+ fn find_cmd_config_path(&self, args: &Vec<String>) -> Result<Option<String>> {
for (i, arg) in args.iter().enumerate() {
match arg.as_str() {
"--config_path" => {
@@ -141,7 +142,7 @@ impl Config {
/// and a string on error.
/// # Arguments
/// * `args` - CMD argument vector.
- fn parse_cmd_args(&mut self, args: &Vec<String>) -> Result<(), String> {
+ fn parse_cmd_args(&mut self, args: &Vec<String>) -> Result<()> {
let mut skips = 1i32;
for (i, arg) in args.iter().enumerate() {
if skips > 0 {
@@ -184,7 +185,7 @@ impl Config {
--ncpu Number of cores to emulate (default=1)
"
);
- return Err(format!("Invalid command line argument: {}", arg));
+ return berr!(format!("Invalid command line argument: {}", arg));
}
}
}
@@ -222,9 +223,9 @@ impl Config {
/// * `args` - CMD argument vector.
/// * `i` - Index of the current argument.
/// * `what` - String describing the current argument (for error message).
-fn args_check_size(args: &Vec<String>, i: usize, what: &String) -> Result<(), String> {
+fn args_check_size(args: &Vec<String>, i: usize, what: &String) -> Result<()> {
if i >= args.len() {
- Err(format!(
+ berr!(format!(
"Invalid command line argument: {} takes an argument.",
what
))
@@ -239,11 +240,7 @@ fn args_check_size(args: &Vec<String>, i: usize, what: &String) -> Result<(), St
/// * `args` - CMD argument vector.
/// * `i` - Index of the current argument.
/// * `what` - String describing the current argument (for error message).
-fn args_get_next_arg<'a>(
- args: &'a Vec<String>,
- i: usize,
- what: &String,
-) -> Result<&'a String, String> {
+fn args_get_next_arg<'a>(args: &'a Vec<String>, i: usize, what: &String) -> Result<&'a String> {
args_check_size(&args, i, &what)?;
Ok(&args[i + 1])
}
@@ -254,12 +251,12 @@ fn args_get_next_arg<'a>(
/// * `args` - CMD argument vector.
/// * `i` - Index of the current argument.
/// * `what` - String describing the current argument (for error message).
-fn args_get_next_uint(args: &Vec<String>, i: usize, what: &String) -> Result<u32, String> {
+fn args_get_next_uint(args: &Vec<String>, i: usize, what: &String) -> Result<u32> {
args_check_size(&args, i, &what)?;
Ok(match args[i + 1].parse::<u32>() {
core::result::Result::Ok(u) => u,
core::result::Result::Err(e) => {
- return Err(format!(
+ return berr!(format!(
"Invalid command line argument for {}: {}, err: {}.",
what,
args[i + 1],
@@ -301,7 +298,7 @@ fn default_ncpu() -> u32 {
}
fn default_cache() -> String {
- let home_dir = util::get_home_nofail();
+ let home_dir = get_home_nofail();
let cache_dir = ".cache/riscii".to_string();
match env::var("XDG_CACHE_HOME") {
diff --git a/src/cpu.rs b/src/cpu.rs
@@ -16,6 +16,9 @@ use instruction::ShortSource;
use memory::Memory;
use std::convert::TryInto;
use std::fmt;
+use util::Result;
+
+use berr;
/// The number of register windows the RISCII supports.
pub const NUM_REG_WINDOWS: usize = 8;
@@ -54,7 +57,7 @@ pub struct ProcessorStatusWord {
/// Saved window pointer (MOD 8).
swp: u32,
/// If interrupts are enabled.
- interrupt_enable_bit: bool,
+ interrupts_enabled: bool,
/// System bit, true if running in privileged state.
system_mode: bool,
/// The previous state of the `system_mode` bit the last time it was changed.
@@ -191,11 +194,13 @@ impl RegisterFile {
/// Anything outside this [0-31] range is an invalid argument.
/// # Arguments
/// * `which` - Which register. [0-31] are the only valid values.
- pub fn ru(&self, which: u32, psw: &ProcessorStatusWord) -> Result<u32, String> {
+ /// * `psw` - Processor status object, contains window information.
+ pub fn ru(&self, which: u32, psw: &ProcessorStatusWord) -> Result<u32> {
+ let which = which as usize;
Ok(match which {
0..=9 => self.globals[which],
- 10..=31 => self.window_regs[NUM_ADDED_PER_WINDOW * psw.get_cwp() + rd],
- _ => return Err(format!("Register {} is out of range", which)),
+ 10..=31 => self.window_regs[NUM_ADDED_PER_WINDOW * psw.get_cwp() as usize + which],
+ _ => return berr!(format!("Register {} is out of range", which)),
})
}
@@ -208,7 +213,8 @@ impl RegisterFile {
/// Anything outside this [0-31] range is an invalid argument.
/// # Arguments
/// * `which` - Which register. [0-31] are the only valid values.
- pub fn rs(&self, which: u32, psw: &ProcessorStatusWord) -> Result<i32, String> {
+ /// * `psw` - Processor status object, contains window information.
+ pub fn rs(&self, which: u32, psw: &ProcessorStatusWord) -> Result<i32> {
Ok(self.ru(which, psw)? as i32)
}
@@ -221,11 +227,15 @@ impl RegisterFile {
/// Anything outside this [0-31] range is an invalid argument.
/// # Arguments
/// * `which` - Which register. [0-31] are the only valid values.
- pub fn rus(&mut self, which: u32, value: u32, psw: ProcessorStatusWord) -> Result<u32, String> {
+ /// * `psw` - Processor status object, contains window information.
+ pub fn rus(&mut self, which: u32, value: u32, psw: ProcessorStatusWord) -> Result<u32> {
+ let which = which as usize;
match which {
0..=9 => self.globals[which] = value,
- 10..=31 => self.window_regs[NUM_ADDED_PER_WINDOW * psw.get_cwp() + rd] = value,
- _ => return Err(format!("Register {} is out of range", which)),
+ 10..=31 => {
+ self.window_regs[NUM_ADDED_PER_WINDOW * psw.get_cwp() as usize + which] = value
+ }
+ _ => return berr!(format!("Register {} is out of range", which)),
}
Ok(value)
}
@@ -250,14 +260,14 @@ impl RegisterFile {
pub fn branch_to(&mut self, to: u32) {
self.lstpc = self.pc;
- self.pc = nxtpc;
+ self.pc = self.nxtpc;
self.nxtpc = to;
}
- pub fn get_ss_val(&self, ss: ShortSource) -> Result<u32, String> {
+ pub fn get_ss_val(&self, ss: ShortSource, psw: &ProcessorStatusWord) -> Result<u32> {
type SS = ShortSource;
Ok(match ss {
- SS::Reg(r) => self.ru(r as u32)?,
+ SS::Reg(r) => self.ru(r as u32, psw)?,
SS::Imm13(u) => u,
})
}
@@ -283,7 +293,7 @@ impl ProcessorStatusWord {
Self {
cwp: 0,
swp: 0,
- interrupt_enable_bit: false,
+ interrupts_enabled: false,
system_mode: false,
previous_system_mode: false,
cc_zero: false,
@@ -297,9 +307,9 @@ impl ProcessorStatusWord {
Self {
cwp: (v & (0x7 << 7)) >> 7,
swp: (v & (0x7 << 10)) >> 10,
- interrupt_enabled_bit: v & (0x1 << 6) != 0,
- previous_system_bit: v & (0x1 << 5) != 0,
- system_bit: v & (0x1 << 4) != 0,
+ interrupts_enabled: v & (0x1 << 6) != 0,
+ previous_system_mode: v & (0x1 << 5) != 0,
+ system_mode: v & (0x1 << 4) != 0,
cc_zero: v & (0x1 << 3) != 0,
cc_neg: v & (0x1 << 2) != 0,
cc_overflow: v & (0x1 << 1) != 0,
@@ -310,9 +320,9 @@ impl ProcessorStatusWord {
pub fn init(
cwp: u32,
swp: u32,
- interrupt_enable_bit: bool,
- previous_system_bit: bool,
- system_bit: bool,
+ interrupts_enabled: bool,
+ previous_system_mode: bool,
+ system_mode: bool,
cc_zero: bool,
cc_neg: bool,
cc_overflow: bool,
@@ -321,9 +331,9 @@ impl ProcessorStatusWord {
Self {
cwp: cwp % 8,
swp: swp % 8,
- interrupt_enable_bit: interrupt_enable_bit,
- previous_system_bit: previous_system_bit,
- system_bit: system_bit,
+ interrupts_enabled: interrupts_enabled,
+ previous_system_mode: previous_system_mode,
+ system_mode: system_mode,
cc_zero: cc_zero,
cc_neg: cc_neg,
cc_overflow: cc_overflow,
@@ -350,7 +360,7 @@ impl ProcessorStatusWord {
| (self.cc_zero as u32) << 3
| (self.previous_system_mode as u32) << 4
| (self.system_mode as u32) << 5
- | (self.interrupt_enable_bit as u32) << 6
+ | (self.interrupts_enabled as u32) << 6
| (self.cwp) << 7
| (self.swp) << 10)
& 0x1fff
@@ -359,29 +369,29 @@ impl ProcessorStatusWord {
/// Push the register window stack. Set CWP to CWP-1 MOD 8. Push the top
/// window to memory and increment SWP if necessary.
pub fn push_reg_window(&mut self) {
- self.cwp = (self.cwp - 1) % NUM_REG_WINDOWS;
+ self.cwp = (self.cwp - 1) % NUM_REG_WINDOWS as u32;
if self.cwp == self.swp {
// TODO save windows to memory.
- self.swp = (self.swp + 1) % NUM_REG_WINDOWS;
+ self.swp = (self.swp + 1) % NUM_REG_WINDOWS as u32;
}
}
/// Pop the register window stack. Set CWP to CWP+1 MOD 8. Pull the bottom
/// window from memory and decrement SWP if necessary.
pub fn pop_reg_window(&mut self) {
- self.cwp = (self.cwp + 1) % NUM_REG_WINDOWS;
+ self.cwp = (self.cwp + 1) % NUM_REG_WINDOWS as u32;
if self.cwp == self.swp {
// TODO restore windows from memory.
- self.swp = (self.swp - 1) % NUM_REG_WINDOWS;
+ self.swp = (self.swp - 1) % NUM_REG_WINDOWS as u32;
}
}
pub fn set_cwp(&mut self, v: u32) {
- self.cwp = v % NUM_REG_WINDOWS;
+ self.cwp = v % NUM_REG_WINDOWS as u32;
}
pub fn set_swp(&mut self, v: u32) {
- self.swp = v % NUM_REG_WINDOWS;
+ self.swp = v % NUM_REG_WINDOWS as u32;
}
pub fn get_cwp(&self) -> u32 {
@@ -424,16 +434,16 @@ impl ProcessorStatusWord {
self.cc_neg = value;
}
- pub fn set_system_bit(&mut self, v: bool) {
+ pub fn set_system_mode(&mut self, v: bool) {
self.system_mode = v;
}
- pub fn set_previous_system_bit(&mut self, v: bool) {
+ pub fn set_previous_system_mode(&mut self, v: bool) {
self.previous_system_mode = v;
}
pub fn set_interrupt_enabled(&mut self, v: bool) {
- self.interrupt_enable_bit = v;
+ self.interrupts_enabled = v;
}
pub fn is_system_mode(&self) -> bool {
@@ -445,7 +455,7 @@ impl ProcessorStatusWord {
}
pub fn is_interrupt_enabled(&self) -> bool {
- self.interrupt_enable_bit
+ self.interrupts_enabled
}
}
@@ -464,6 +474,7 @@ CC Overflow: {}
CC Carry: {}",
self.cwp,
self.swp,
+ privilege_string(self.interrupts_enabled),
privilege_string(self.system_mode),
privilege_string(self.previous_system_mode),
bool_hl_string(self.cc_zero),
@@ -479,7 +490,7 @@ CC Carry: {}",
/// Create a descriptive string for the system's privilege state bits.
/// # Arguments
/// * `s` - Privilege state bit.
-fn privilege_string(s: bool) -> &str {
+fn privilege_string(s: bool) -> &'static str {
if s {
"Privileged"
} else {
@@ -490,7 +501,7 @@ fn privilege_string(s: bool) -> &str {
/// Stringify booleans with hardware terminology.
/// # Arguments
/// * `s` - Boolean.
-fn bool_hl_string(s: bool) -> &str {
+fn bool_hl_string(s: bool) -> &'static str {
if s {
"High"
} else {
diff --git a/src/decode.rs b/src/decode.rs
@@ -16,27 +16,60 @@
extern crate core;
use core::convert::TryInto;
+use std::error::Error;
use std::fmt;
+use util::Result;
use instruction::*;
+macro_rules! bdeii {
+ ( $( $loc:expr, $opcode:expr ),* ) => {
+ {
+ Err(Box::new($( DecodeError::InvalidInstruction { loc: $loc, opcode: $opcode } )*))
+ }
+ };
+}
+
+macro_rules! bdeij {
+ ( $( $code:expr ),* ) => {
+ {
+ Err(Box::new($( DecodeError::InvalidJumpCondition { code: $code } )*))
+ }
+ };
+}
+
+macro_rules! bdece {
+ ( $( $descr:expr ),* ) => {
+ {
+ Err(Box::new($( DecodeError::CodeError { descr: $descr } )*))
+ }
+ };
+}
+
// Struct declarations.
/// Opcode errors.
-#[derive(PartialEq, Eq, Clone)]
+#[derive(Debug, PartialEq, Eq, Clone)]
pub enum DecodeError {
/// Indicates an invalid instruction. The first u32 indicates which bits are invalid,
/// the final u32 is the whole opcode.
- InvalidInstruction(u32, u32),
- InvalidJumpCondition,
+ InvalidInstruction {
+ loc: u32,
+ opcode: u32,
+ },
+ InvalidJumpCondition {
+ code: u32,
+ },
/// Indicates some bug in this program with a string description.
- CodeError(String),
+ CodeError {
+ descr: String,
+ },
}
// Public function declarations.
-pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
+pub fn decode(opcode: u32) -> Result<Instruction> {
type I = Instruction;
// SCC flag (<24>).
let scc = opcode & 0x1000000 != 0;
@@ -48,7 +81,7 @@ pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
let imm19 = opcode & 0x7FFFF;
// Short source immediate-mode bottom 13 bits <12-0> or rs1 <4-0>.
let short_source = if opcode & 0x2000 != 0 {
- ShortSource::UImm13(opcode & 0x1fff)
+ ShortSource::Imm13(opcode & 0x1fff)
} else {
ShortSource::Reg((opcode & 0x1f) as u8)
}; // TODO fix ambiguous sign problem.
@@ -62,28 +95,24 @@ pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
Ok(match op >> 4 {
// Match the bottom four bytes of the opcode's prefix.
0 => match bottom_nibble {
- 0 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 0 => return bdeii!(0xf, opcode),
1 => I::Calli(ShortInstruction::new(scc, dest, rs1, short_source)),
2 => I::GetPSW(ShortInstruction::new(scc, dest, rs1, short_source)),
3 => I::GetLPC(ShortInstruction::new(scc, dest, rs1, short_source)),
4 => I::PutPSW(ShortInstruction::new(scc, dest, rs1, short_source)),
- 5..=7 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 5..=7 => return bdeii!(0xf, opcode),
8 => I::Callx(ShortInstruction::new(scc, dest, rs1, short_source)),
9 => I::Callr(LongInstruction::new(scc, dest, imm19)),
- 10..=11 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 10..=11 => return bdeii!(0xf, opcode),
12 => I::Jmpx(ShortConditional::new(scc, cond?, rs1, short_source)),
13 => I::Jmpr(LongConditional::new(scc, cond?, imm19)),
14 => I::Ret(ShortConditional::new(scc, cond?, rs1, short_source)),
15 => I::Reti(ShortConditional::new(scc, cond?, rs1, short_source)),
// Should never be reached.
- _ => {
- return Err(DecodeError::CodeError(String::from(
- "Match bottom four bytes of opcode prefix",
- )))
- }
+ _ => return bdece!(format!("Match bottom four bytes of opcode prefix")),
},
1 => match bottom_nibble {
- 0 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 0 => return bdeii!(0xf, opcode),
1 => I::Sll(ShortInstruction::new(scc, dest, rs1, short_source)),
2 => I::Sra(ShortInstruction::new(scc, dest, rs1, short_source)),
3 => I::Srl(ShortInstruction::new(scc, dest, rs1, short_source)),
@@ -93,20 +122,16 @@ pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
7 => I::Xor(ShortInstruction::new(scc, dest, rs1, short_source)),
8 => I::Add(ShortInstruction::new(scc, dest, rs1, short_source)),
9 => I::Addc(ShortInstruction::new(scc, dest, rs1, short_source)),
- 10..=11 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 10..=11 => return bdeii!(0xf, opcode),
12 => I::Sub(ShortInstruction::new(scc, dest, rs1, short_source)),
13 => I::Subc(ShortInstruction::new(scc, dest, rs1, short_source)),
14 => I::Subi(ShortInstruction::new(scc, dest, rs1, short_source)),
15 => I::Subci(ShortInstruction::new(scc, dest, rs1, short_source)),
// Should never be reached.
- _ => {
- return Err(DecodeError::CodeError(String::from(
- "Match bottom four bytes of opcode prefix",
- )))
- }
+ _ => return bdece!(format!("Match bottom four bytes of opcode prefix")),
},
2 => match bottom_nibble {
- 0..=5 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 0..=5 => return bdeii!(0xf, opcode),
6 => I::Ldxw(ShortInstruction::new(scc, dest, rs1, short_source)),
7 => I::Ldrw(LongInstruction::new(scc, dest, imm19)),
8 => I::Ldxhu(ShortInstruction::new(scc, dest, rs1, short_source)),
@@ -118,39 +143,31 @@ pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
14 => I::Ldxbs(ShortInstruction::new(scc, dest, rs1, short_source)),
15 => I::Ldrbs(LongInstruction::new(scc, dest, imm19)),
// Should never be reached.
- _ => {
- return Err(DecodeError::CodeError(String::from(
- "Match bottom four bytes of opcode prefix",
- )))
- }
+ _ => return bdece!(format!("Match bottom four bytes of opcode prefix")),
},
3 => match bottom_nibble {
- 0..=5 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 0..=5 => return bdeii!(0xf, opcode),
6 => I::Stxw(ShortInstruction::new(scc, dest, rs1, short_source)),
7 => I::Strw(LongInstruction::new(scc, dest, imm19)),
- 8..=9 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 8..=9 => return bdeii!(0xf, opcode),
10 => I::Stxh(ShortInstruction::new(scc, dest, rs1, short_source)),
11 => I::Strh(LongInstruction::new(scc, dest, imm19)),
- 12..=13 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 12..=13 => return bdeii!(0xf, opcode),
14 => I::Stxb(ShortInstruction::new(scc, dest, rs1, short_source)),
15 => I::Strb(LongInstruction::new(scc, dest, imm19)),
// Should never be reached.
- _ => {
- return Err(DecodeError::CodeError(String::from(
- "Match bottom four bytes of opcode prefix",
- )))
- }
+ _ => return bdece!(format!("Match bottom four bytes of opcode prefix")),
},
// Top bit is 1, meaning an extension opcode.
4..=8 => match opcode {
// TODO
- _ => return Err(DecodeError::CodeError(String::from("Not yet implemented!"))),
+ _ => return bdece!(format!("Not yet implemented!")),
},
- _ => return Err(DecodeError::InvalidInstruction(0x8, opcode)),
+ _ => return bdeii!(0x8, opcode),
})
}
-pub fn decode_file(file: &Vec<u8>, pos: usize) -> Result<(), DecodeError> {
+pub fn decode_file(file: &Vec<u8>, pos: usize) -> Result<()> {
let result = 0usize;
for i in (0..file.len()).step_by(4) {
@@ -164,20 +181,28 @@ pub fn decode_file(file: &Vec<u8>, pos: usize) -> Result<(), DecodeError> {
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- Self::InvalidInstruction(i, op) => write!(f, "Invalid: 0x{:x}, opcode: 0x{:x}", i, op),
- Self::InvalidJumpCondition => write!(f, "Invalid jump condition"),
- Self::CodeError(s) => write!(f, "Error in RISC II emulator: {}", s),
- }
+ write!(
+ f,
+ "Error in decoding instruction: {}",
+ match self {
+ Self::InvalidInstruction { loc: i, opcode: op } =>
+ format!("Invalid bits: 0x{:x}, opcode: 0x{:x}", i, op),
+ Self::InvalidJumpCondition { code: code } =>
+ format!("Invalid jump condition: {} (should be 0-15)", code),
+ Self::CodeError { descr: s } => format!("Error in RISC II emulator: {}", s),
+ }
+ )
}
}
+impl Error for DecodeError {}
+
// Private functions.
/// Get the RISC-II conditional type from a opcode<22-19>.
/// opcode A RISC-II opcode.
/// return RISC-II conditional, or DecodeError if 0.
-fn get_cond_from_opcode(opcode: u32) -> Result<Conditional, DecodeError> {
+fn get_cond_from_opcode(opcode: u32) -> Result<Conditional> {
type C = Conditional;
Ok(match (opcode & 0x780000) >> 19 {
1 => C::Gt,
@@ -195,6 +220,6 @@ fn get_cond_from_opcode(opcode: u32) -> Result<Conditional, DecodeError> {
13 => C::Nv,
14 => C::V,
15 => C::Alw,
- _ => return Err(DecodeError::InvalidJumpCondition),
+ code => return bdeij!(code),
})
}
diff --git a/src/decode_test.rs b/src/decode_test.rs
@@ -17,6 +17,7 @@
#[path = "decode.rs"]
mod test {
use super::super::*;
+ use util::Result;
use decode::*;
use instruction::*;
@@ -28,7 +29,7 @@ mod test {
// Privileged instructions.
#[test]
- fn decode_calli() -> Result<(), DecodeError> {
+ fn decode_calli() -> Result<()> {
assert_eq!(
decode(0x0329f00f)?,
I::Calli(ShortInstruction::new(true, 5, 7, SS::UImm13(4111)))
@@ -37,7 +38,7 @@ mod test {
}
#[test]
- fn decode_getpsw() -> Result<(), DecodeError> {
+ fn decode_getpsw() -> Result<()> {
assert_eq!(
decode(0x05293fff)?,
I::GetPSW(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1fff)))
@@ -46,7 +47,7 @@ mod test {
}
#[test]
- fn decode_getipc() -> Result<(), DecodeError> {
+ fn decode_getipc() -> Result<()> {
assert_eq!(
decode(0x07293f69)?,
I::GetLPC(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -55,7 +56,7 @@ mod test {
}
#[test]
- fn decode_putpsw() -> Result<(), DecodeError> {
+ fn decode_putpsw() -> Result<()> {
assert_eq!(
decode(0x09293f69)?,
I::PutPSW(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -66,7 +67,7 @@ mod test {
// (unpriveleged) Call/jump/ret instructions.
#[test]
- fn decode_callx() -> Result<(), DecodeError> {
+ fn decode_callx() -> Result<()> {
assert_eq!(
decode(0x11293f69)?,
I::Callx(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -75,7 +76,7 @@ mod test {
}
#[test]
- fn decode_callr() -> Result<(), DecodeError> {
+ fn decode_callr() -> Result<()> {
assert_eq!(
decode(0x132b3420)?,
I::Callr(LongInstruction::new(true, 5, 0x33420))
@@ -84,7 +85,7 @@ mod test {
}
#[test]
- fn decode_jmpx() -> Result<(), DecodeError> {
+ fn decode_jmpx() -> Result<()> {
assert_eq!(
decode(0x19293f69)?,
I::Jmpx(ShortConditional::new(
@@ -98,7 +99,7 @@ mod test {
}
#[test]
- fn decode_jmpr() -> Result<(), DecodeError> {
+ fn decode_jmpr() -> Result<()> {
assert_eq!(
decode(0x1bfb3420)?,
I::Jmpr(LongConditional::new(true, Conditional::Alw, 0x33420))
@@ -107,7 +108,7 @@ mod test {
}
#[test]
- fn decode_ret() -> Result<(), DecodeError> {
+ fn decode_ret() -> Result<()> {
assert_eq!(
decode(0x1d293f69)?,
I::Ret(ShortConditional::new(
@@ -121,7 +122,7 @@ mod test {
}
#[test]
- fn decode_reti() -> Result<(), DecodeError> {
+ fn decode_reti() -> Result<()> {
assert_eq!(
decode(0x1f293f69)?,
I::Reti(ShortConditional::new(
@@ -137,7 +138,7 @@ mod test {
// Arithmetic and logic instructions (except ldhi).
#[test]
- fn decode_sll() -> Result<(), DecodeError> {
+ fn decode_sll() -> Result<()> {
assert_eq!(
decode(0x23293f69)?,
I::Sll(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -146,7 +147,7 @@ mod test {
}
#[test]
- fn decode_sra() -> Result<(), DecodeError> {
+ fn decode_sra() -> Result<()> {
assert_eq!(
decode(0x25293f69)?,
I::Sra(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -155,7 +156,7 @@ mod test {
}
#[test]
- fn decode_srl() -> Result<(), DecodeError> {
+ fn decode_srl() -> Result<()> {
assert_eq!(
decode(0x27293f69)?,
I::Srl(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -164,7 +165,7 @@ mod test {
}
#[test]
- fn decode_ldhi() -> Result<(), DecodeError> {
+ fn decode_ldhi() -> Result<()> {
assert_eq!(
decode(0x292b3f69)?,
I::Ldhi(LongInstruction::new(true, 5, 0x33f69))
@@ -173,7 +174,7 @@ mod test {
}
#[test]
- fn decode_and() -> Result<(), DecodeError> {
+ fn decode_and() -> Result<()> {
assert_eq!(
decode(0x2b293f69)?,
I::And(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -182,7 +183,7 @@ mod test {
}
#[test]
- fn decode_or() -> Result<(), DecodeError> {
+ fn decode_or() -> Result<()> {
assert_eq!(
decode(0x2d293f69)?,
I::Or(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -191,7 +192,7 @@ mod test {
}
#[test]
- fn decode_xor() -> Result<(), DecodeError> {
+ fn decode_xor() -> Result<()> {
assert_eq!(
decode(0x2f293f69)?,
I::Xor(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -200,7 +201,7 @@ mod test {
}
#[test]
- fn decode_add() -> Result<(), DecodeError> {
+ fn decode_add() -> Result<()> {
assert_eq!(
decode(0x31293f69)?,
I::Add(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -209,7 +210,7 @@ mod test {
}
#[test]
- fn decode_addc() -> Result<(), DecodeError> {
+ fn decode_addc() -> Result<()> {
assert_eq!(
decode(0x33293f69)?,
I::Addc(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -218,7 +219,7 @@ mod test {
}
#[test]
- fn decode_sub() -> Result<(), DecodeError> {
+ fn decode_sub() -> Result<()> {
assert_eq!(
decode(0x39293f69)?,
I::Sub(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -227,7 +228,7 @@ mod test {
}
#[test]
- fn decode_subc() -> Result<(), DecodeError> {
+ fn decode_subc() -> Result<()> {
assert_eq!(
decode(0x3b293f69)?,
I::Subc(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -236,7 +237,7 @@ mod test {
}
#[test]
- fn decode_subi() -> Result<(), DecodeError> {
+ fn decode_subi() -> Result<()> {
assert_eq!(
decode(0x3d293f69)?,
I::Subi(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -245,7 +246,7 @@ mod test {
}
#[test]
- fn decode_subci() -> Result<(), DecodeError> {
+ fn decode_subci() -> Result<()> {
assert_eq!(
decode(0x3f293f69)?,
I::Subci(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -256,7 +257,7 @@ mod test {
// Load instructions.
#[test]
- fn decode_ldxw() -> Result<(), DecodeError> {
+ fn decode_ldxw() -> Result<()> {
assert_eq!(
decode(0x4d293f69)?,
I::Ldxw(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -265,7 +266,7 @@ mod test {
}
#[test]
- fn decode_ldrw() -> Result<(), DecodeError> {
+ fn decode_ldrw() -> Result<()> {
assert_eq!(
decode(0x4f2b3f69)?,
I::Ldrw(LongInstruction::new(true, 5, 0x33f69))
@@ -274,7 +275,7 @@ mod test {
}
#[test]
- fn decode_ldxhu() -> Result<(), DecodeError> {
+ fn decode_ldxhu() -> Result<()> {
assert_eq!(
decode(0x51293f69)?,
I::Ldxhu(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -283,7 +284,7 @@ mod test {
}
#[test]
- fn decode_ldrhu() -> Result<(), DecodeError> {
+ fn decode_ldrhu() -> Result<()> {
assert_eq!(
decode(0x532b3f69)?,
I::Ldrhu(LongInstruction::new(true, 5, 0x33f69))
@@ -292,7 +293,7 @@ mod test {
}
#[test]
- fn decode_ldxhs() -> Result<(), DecodeError> {
+ fn decode_ldxhs() -> Result<()> {
assert_eq!(
decode(0x55293f69)?,
I::Ldxhs(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -301,7 +302,7 @@ mod test {
}
#[test]
- fn decode_ldrhs() -> Result<(), DecodeError> {
+ fn decode_ldrhs() -> Result<()> {
assert_eq!(
decode(0x572b3f69)?,
I::Ldrhs(LongInstruction::new(true, 5, 0x33f69))
@@ -310,7 +311,7 @@ mod test {
}
#[test]
- fn decode_ldxbu() -> Result<(), DecodeError> {
+ fn decode_ldxbu() -> Result<()> {
assert_eq!(
decode(0x59293f69)?,
I::Ldxbu(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -319,7 +320,7 @@ mod test {
}
#[test]
- fn decode_ldrbu() -> Result<(), DecodeError> {
+ fn decode_ldrbu() -> Result<()> {
assert_eq!(
decode(0x5b2b3f69)?,
I::Ldrbu(LongInstruction::new(true, 5, 0x33f69))
@@ -328,7 +329,7 @@ mod test {
}
#[test]
- fn decode_ldxbs() -> Result<(), DecodeError> {
+ fn decode_ldxbs() -> Result<()> {
assert_eq!(
decode(0x5d293f69)?,
I::Ldxbs(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -337,7 +338,7 @@ mod test {
}
#[test]
- fn decode_ldrbs() -> Result<(), DecodeError> {
+ fn decode_ldrbs() -> Result<()> {
assert_eq!(
decode(0x5f2b3f69)?,
I::Ldrbs(LongInstruction::new(true, 5, 0x33f69))
@@ -348,7 +349,7 @@ mod test {
// Store instructions.
#[test]
- fn decode_stxw() -> Result<(), DecodeError> {
+ fn decode_stxw() -> Result<()> {
assert_eq!(
decode(0x6d293f69)?,
I::Stxw(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -357,7 +358,7 @@ mod test {
}
#[test]
- fn decode_Strw() -> Result<(), DecodeError> {
+ fn decode_Strw() -> Result<()> {
assert_eq!(
decode(0x6f2b3f69)?,
I::Strw(LongInstruction::new(true, 5, 0x33f69))
@@ -366,7 +367,7 @@ mod test {
}
#[test]
- fn decode_stxh() -> Result<(), DecodeError> {
+ fn decode_stxh() -> Result<()> {
assert_eq!(
decode(0x75293f69)?,
I::Stxh(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -375,7 +376,7 @@ mod test {
}
#[test]
- fn decode_Strh() -> Result<(), DecodeError> {
+ fn decode_Strh() -> Result<()> {
assert_eq!(
decode(0x772b3f69)?,
I::Strh(LongInstruction::new(true, 5, 0x33f69))
@@ -384,7 +385,7 @@ mod test {
}
#[test]
- fn decode_stxb() -> Result<(), DecodeError> {
+ fn decode_stxb() -> Result<()> {
assert_eq!(
decode(0x7d293f69)?,
I::Stxb(ShortInstruction::new(true, 5, 4, SS::UImm13(0x1f69)))
@@ -393,7 +394,7 @@ mod test {
}
#[test]
- fn decode_Strb() -> Result<(), DecodeError> {
+ fn decode_Strb() -> Result<()> {
assert_eq!(
decode(0x7f2b3f69)?,
I::Strb(LongInstruction::new(true, 5, 0x33f69))
diff --git a/src/execute.rs b/src/execute.rs
@@ -31,13 +31,13 @@ pub struct ExecResult {
// Public functions.
// TODO timing and memory reads/writes. Need to emulate the pipeline and cpu clock.
-pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecResult, String> {
+pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecResult> {
type I = Instruction;
let mut result = ExecResult::from_system(system);
let mut register_file = result.get_register_file();
let cur_pc = register_file.get_pc();
-
+ let cur_psw = system.get_psw();
let mut memory = system.get_mem_ref();
match *instruction {
@@ -65,7 +65,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
rs1: _,
short_source: ss,
} => {
- let psw = system.get_psw12() & 0xffff7;
+ let psw = cur_psw & 0xffff7;
register_file.rus(dest, psw)?;
if scc {
let dest_val = register_file.ru(dest)?;
@@ -104,7 +104,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
// TODO error
}
- let val = register_file.get_ss_val(ss)?;
+ let val = register_file.get_ss_val(ss, cur_psw)?;
result.set_psw(register_file.ru(rs1)? + val);
}
I::Callx {
@@ -115,7 +115,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
} => {
// TODO test alignment (addr[0] == 1).
let rs_val = register_file.ru(rs1)?;
- let addr = register_file.get_ss_val(ss)? + rs_val;
+ let addr = register_file.get_ss_val(ss, cur_psw)? + rs_val;
register_file.push_reg_window();
register_file.branch_to(addr);
result.rus(cur_pc)?;
@@ -140,7 +140,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
if exec_conditional(cond, result.get_psw()) {
result.set_branch(true);
let rs_val = register_file.ru(rs1)?;
- let addr = register_file.get_ss_val(ss)? + rs_val;
+ let addr = register_file.get_ss_val(ss, cur_psw)? + rs_val;
register_file.branch_to(addr);
}
}
@@ -190,7 +190,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, s1_val << s2_val)?;
if scc {
set_shift_cc(result.get_psw_ref(), d);
@@ -203,7 +203,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, s1_val >> s2_val)?;
if scc {
set_shift_cc(scc, result.get_psw_ref(), d);
@@ -216,7 +216,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, s1_val as i32 >> s2_val)?;
if scc {
set_shift_cc(result.get_psw_ref(), d);
@@ -229,7 +229,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, s1_val | s2_val)?;
if scc {
set_shift_cc(result.get_psw_ref(), d);
@@ -242,7 +242,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, s1_val & s2_val)?;
if scc {
set_shift_cc(result.get_psw_ref(), d);
@@ -255,7 +255,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, s1_val ^ s2_val)?;
if scc {
set_shift_cc(result.get_psw_ref(), d);
@@ -268,7 +268,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let (res, o) = s1_val.overflowing_add(s2_val);
let d = register_file.rus(dest, res)?;
if scc {
@@ -285,7 +285,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let mut psw = result.get_psw_ref();
let (r1, o1) = s1_val.overflowing_add(s2_val);
let (res, o2) = r1.overflowing_add(psw.get_cc_carry() as u32);
@@ -304,7 +304,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let (res, o) = s1_val.overflowing_sub(s2_val);
let d = register_file.rus(dest, res)?;
if scc {
@@ -321,7 +321,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let mut psw = result.get_psw_ref();
let (r1, o1) = s1_val.overflowing_sub(s2_val);
let (res, o2) = r1.overflowing_sub(!psw.get_cc_carry() as u32);
@@ -341,7 +341,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let (res, o) = s2_val.overflowing_sub(s1_val);
let d = register_file.rus(dest, res)?;
if scc {
@@ -359,7 +359,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
let s1_val = register_file.ru(rs1)?;
- let s2_val = register_file.get_ss_val(ss)?;
+ let s2_val = register_file.get_ss_val(ss, cur_psw)?;
let mut psw = result.get_psw_ref();
let (r1, o1) = s2_val.overflowing_sub(s1_val);
let (res, o2) = r1.overflowing_sub(!psw.get_cc_carry() as u32);
@@ -390,7 +390,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
short_source: ss,
} => {
// TODO Test alignment
- let ss_val = register_file.get_ss_val(ss)?;
+ let ss_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, memory.get_word(ss_val)?)?;
if scc {
set_load_cc(result.get_psw_ref(), d);
@@ -413,7 +413,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
rs1: rs1,
short_source: ss,
} => {
- let ss_val = register_file.get_ss_val(ss)?;
+ let ss_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, memory.get_hword(ss_val)? as i32 as u32)?;
if scc {
set_load_cc(result.get_psw_ref(), d);
@@ -436,7 +436,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
rs1: rs1,
short_source: ss,
} => {
- let ss_val = register_file.get_ss_val(ss)?;
+ let ss_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, memory.get_hword(ss_val)? as u32)?;
if scc {
set_load_cc(result.get_psw_ref(), d);
@@ -459,7 +459,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
rs1: rs1,
short_source: ss,
} => {
- let ss_val = register_file.get_ss_val(ss)?;
+ let ss_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, memory.get_byte(ss_val)? as i32 as u32)?;
if scc {
set_load_cc(result.get_psw_ref(), d);
@@ -482,7 +482,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
rs1: rs1,
short_source: ss,
} => {
- let ss_val = register_file.get_ss_val(ss)?;
+ let ss_val = register_file.get_ss_val(ss, cur_psw)?;
let d = register_file.rus(dest, memory.get_byte(ss_val)? as u32)?;
if scc {
set_load_cc(result.get_psw_ref(), d);
@@ -509,7 +509,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
// warn
// return Err("Store instructions should be immediate only (not registers)");
}
- let ss_val = register_file.get_ss_val(ss)?;
+ let ss_val = register_file.get_ss_val(ss, cur_psw)?;
let rs1_val = register_file.ru(rs1);
let dest_val = register_file.ru(dest);
memory.set_word(ss_val + rs1_val, dest_val);
@@ -542,7 +542,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
// warn
// return Err("Store instructions should be immediate only (not registers)");
}
- let ss_val = register_file.get_ss_val(ss)?;
+ let ss_val = register_file.get_ss_val(ss, cur_psw)?;
let rs1_val = register_file.ru(rs1);
let dest_val = register_file.ru(dest);
memory.set_hword(ss_val + rs1_val, dest_val as u16);
@@ -575,7 +575,7 @@ pub fn execute(instruction: &Instruction, system: &mut System) -> Result<ExecRes
// warn
// return Err("Store instructions should be immediate only (not registers)");
}
- let ss_val = register_file.get_ss_val(ss)?;
+ let ss_val = register_file.get_ss_val(ss, cur_psw)?;
let rs1_val = register_file.ru(rs1);
let dest_val = register_file.ru(dest);
memory.set_byte(ss_val + rs1_val, dest_val as u8);
diff --git a/src/main.rs b/src/main.rs
@@ -21,31 +21,25 @@ mod decode_test;
mod main_test;
mod config;
+mod cpu;
mod decode;
mod instruction;
mod memory;
-mod register;
mod sdl;
+mod system;
mod util;
use decode::decode_file;
use std::fs;
use config::Config;
+use std::boxed::Box;
+use std::error::Error;
use system::System;
// Struct/enum declarations.
-fn get_program(path: &String) -> Result<Vec<u8>, String> {
- println!("Opening binary file {}.", path);
-
- match fs::read(path) {
- Ok(raw_p) => Ok(raw_p.to_vec()),
- Err(raw_e) => Err(raw_e.to_string()),
- }
-}
-
-fn main() -> Result<(), String> {
+fn main() -> Result<(), Box<dyn Error>> {
let config = Config::init()?;
let context = sdl::Context::new(&config)?;
@@ -54,7 +48,8 @@ fn main() -> Result<(), String> {
"Running emulator with the following configuration: \n{}\n",
config
);
- //let program = get_program(&String::from("test.bin"))?;
+ //println!("Opening binary file {}.", path);
+ //let program = fs::read(path)?;
Ok(())
}
diff --git a/src/memory.rs b/src/memory.rs
@@ -16,10 +16,13 @@
// Struct definitions.
use config::Config;
-use util::{check_hword_alignment, check_word_alignment, File};
+use std::convert::TryInto;
+use util::{check_hword_alignment, check_word_alignment, File, Result};
+
+use berr;
/// The real memory of the RISC II emulator.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
pub struct Memory(Vec<u8>);
// Struct impls.
@@ -35,101 +38,112 @@ impl Memory {
}
}
+ pub fn from_size(size: u32) -> Self {
+ Self {
+ 0: vec![0u8; size as usize],
+ }
+ }
+
pub fn from_vec(memory: &Vec<u8>) -> Self {
Self { 0: memory.clone() }
}
- pub fn write_to_file(&mut self, file: &mut File) -> Result<(), String> {
- file.write_vec(&self.0)?;
- Ok(())
+ pub fn write_to_file(&mut self, file: &mut File) -> Result<()> {
+ file.write_vec(&self.0)
}
pub fn write_buf(&mut self, addr: u32, buf: &[u8]) {
- self[addr..buf.len()].copy_from_slice(buf);
+ self.0[addr as usize..buf.len()].copy_from_slice(buf);
}
- pub fn get_byte(&self, addr: u32) -> Result<u8, String> {
- if addr >= self.len() {
- Err(format!(
+ pub fn get_byte(&self, addr: u32) -> Result<u8> {
+ let addr = addr as usize;
+ if addr >= self.0.len() {
+ berr!(format!(
"Memory read: address 0x{:x} is out range (memory is of size 0x{:x})",
addr,
- self.len()
+ self.0.len()
))
} else {
Ok(self.0[addr])
}
}
- pub fn get_hword(&self, addr: u32) -> Result<u16, String> {
+ pub fn get_hword(&self, addr: u32) -> Result<u16> {
check_hword_alignment(addr)?;
- if addr >= self.len() {
- Err(format!(
+ let addr = addr as usize;
+ if addr >= self.0.len() {
+ berr!(format!(
"Memory read: address 0x{:x} is out range (memory is of size 0x{:x})",
addr,
- self.len()
+ self.0.len()
))
} else {
- Ok(u16::from_be_bytes(self.0[addr..addr + 1]))
+ Ok(u16::from_be_bytes(self.0[addr..addr + 1].try_into()?))
}
}
- pub fn get_word(&self, addr: u32) -> Result<u32, String> {
+ pub fn get_word(&self, addr: u32) -> Result<u32> {
check_word_alignment(addr)?;
- if addr >= self.len() {
- Err(format!(
+ let addr = addr as usize;
+ if addr >= self.0.len() {
+ berr!(format!(
"Memory read: address 0x{:x} is out range (memory is of size 0x{:x})",
addr,
- self.len()
+ self.0.len()
))
} else {
- Ok(self.0[addr])
+ Ok(u32::from_be_bytes(self.0[addr..addr + 4].try_into()?))
}
}
- pub fn set_word(&mut self, addr: u32, what: u32) -> Result<u32, String> {
- check_word_alignment()?;
- if addr >= self.len() - 4 {
- Err(format!(
+ pub fn set_word(&mut self, addr: u32, what: u32) -> Result<u32> {
+ check_word_alignment(addr)?;
+ let addr = addr as usize;
+ if addr >= self.0.len() - 4 {
+ berr!(format!(
"Memory write: address 0x{:x} is out range (memory is of size 0x{:x})",
addr,
- self.len()
+ self.0.len()
))
} else {
let what_bytes = if cfg!(target_endian = "little") {
- u32::from_ne_bytes(what.swap_bytes())
+ u32::to_ne_bytes(what.swap_bytes())
} else {
- u32::from_ne_bytes(what)
+ u32::to_ne_bytes(what)
};
- self.0[addr..addr + 4].copy_from_slice(what_bytes);
+ self.0[addr..addr + 4].copy_from_slice(&what_bytes);
Ok(what)
}
}
- pub fn set_hword(&mut self, addr: u32, what: u16) -> Result<u32, String> {
- check_word_alignment()?;
- if addr >= self.len() - 2 {
- Err(format!(
+ pub fn set_hword(&mut self, addr: u32, what: u16) -> Result<u16> {
+ check_word_alignment(addr)?;
+ let addr = addr as usize;
+ if addr >= self.0.len() - 2 {
+ berr!(format!(
"Memory write: address 0x{:x} is out range (memory is of size 0x{:x})",
addr,
- self.len()
+ self.0.len()
))
} else {
let what_bytes = if cfg!(target_endian = "little") {
- u16::from_ne_bytes(what.swap_bytes())
+ u16::to_ne_bytes(what.swap_bytes())
} else {
- u16::from_ne_bytes(what)
+ u16::to_ne_bytes(what)
};
- self.0[addr..addr + 2].copy_from_slice(what_bytes);
+ self.0[addr..addr + 2].copy_from_slice(&what_bytes);
Ok(what)
}
}
- pub fn set_byte(&mut self, addr: u32, what: u8) -> Result<u32, String> {
- if addr >= self.len() {
- Err(format!(
+ pub fn set_byte(&mut self, addr: u32, what: u8) -> Result<u8> {
+ let addr = addr as usize;
+ if addr >= self.0.len() {
+ berr!(format!(
"Memory write: address 0x{:x} is out range (memory is of size 0x{:x})",
addr,
- self.len()
+ self.0.len()
))
} else {
self.0[addr] = what;
diff --git a/src/sdl.rs b/src/sdl.rs
@@ -27,6 +27,7 @@ use sdl2::video::Window;
use sdl2::EventPump;
use sdl2::Sdl;
use sdl2::VideoSubsystem;
+use util::Result;
// Struct definitions.
@@ -47,7 +48,7 @@ pub struct Context {
impl Context {
/// Create a new SDL window/context. Return context on success and a
/// string on error.
- pub fn new(config: &Config) -> Result<Self, String> {
+ pub fn new(config: &Config) -> Result<Self> {
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
let window = video_subsystem
diff --git a/src/system.rs b/src/system.rs
@@ -18,9 +18,10 @@ use config::Config;
use cpu::{ProcessorStatusWord, RegisterFile};
use memory::Memory;
use std::fmt;
+use util::Result;
/// RISC II emulated system.
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Debug, Clone)]
pub struct System {
/// RISC II register file.
regs: RegisterFile,
@@ -37,7 +38,7 @@ impl System {
/// a string on error.
/// # Arguments
/// * `config` - Emulator configuration.
- pub fn new(config: &Config) -> Result<Self, String> {
+ pub fn new(config: &Config) -> Result<Self> {
Ok(Self {
regs: RegisterFile::new(),
psw: ProcessorStatusWord::new(),
@@ -62,11 +63,11 @@ impl System {
}
pub fn call(&mut self, addr: u32) {
- self.regs.push_reg_window();
+ self.psw.push_reg_window();
}
pub fn ret(&mut self) {
- self.regs.pop_reg_window();
+ self.psw.pop_reg_window();
}
pub fn get_register_file(&mut self) -> &mut RegisterFile {
@@ -106,12 +107,12 @@ impl System {
System {
regs: self.regs,
psw: self.psw,
- mem: vec![0; 0],
+ mem: Memory::from_size(0),
}
}
pub fn get_mem_ref(&mut self) -> &mut Memory {
- &mut self.memory
+ &mut self.mem
}
}
diff --git a/src/util.rs b/src/util.rs
@@ -13,13 +13,27 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
+use std::boxed::Box;
use std::env;
+use std::error::Error;
use std::ffi::OsString;
use std::fs;
use std::fs::{Metadata, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
-use std::time::{Duration, SystemTime, SystemTimeError, UNIX_EPOCH};
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
+
+pub type Result<T> = std::result::Result<T, Box<dyn Error>>;
+
+#[macro_export]
+macro_rules! berr {
+ ( $( $x:expr ),* ) => {
+ {
+ let b: Box<dyn std::error::Error> = $( $x.into() )*;
+ Err(b)
+ }
+ };
+}
// Public constants.
@@ -41,7 +55,7 @@ pub struct File {
/// Return a file's contents as a byte vector on success and a string on error.
/// # Arguments
/// * `path` - Path to the file.
-pub fn read_file_path(path: &String) -> Result<Vec<u8>, String> {
+pub fn read_file_path(path: &String) -> Result<Vec<u8>> {
File::open(&path)?.read_file()
}
@@ -49,28 +63,28 @@ pub fn read_file_path(path: &String) -> Result<Vec<u8>, String> {
/// # Arguments
/// * `base` - Base path.
/// * `rest` - Rest of the path.
-pub fn concat_paths(base: &String, rest: &String) -> Result<String, String> {
+pub fn concat_paths(base: &String, rest: &String) -> Result<String> {
let p = Path::new(&base).join(&rest);
match p.to_str() {
- None => Err(format!("{} and {} joined is not valid utf8", base, rest)),
+ None => berr!(format!("{} and {} joined is not valid utf8", base, rest)),
Some(s) => Ok(s.to_string()),
}
}
/// Get the current unix timestamp on success and a string on error.
-pub fn get_unix_timestamp() -> Result<Duration, String> {
+pub fn get_unix_timestamp() -> Result<Duration> {
match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(r) => Ok(r),
- Err(e) => Err(format!("Could not format unix timestamp: {}", e)),
+ Err(e) => berr!(format!("Could not format unix timestamp: {}", e)),
}
}
-/// Convert a `Result<OsString, String>` to a `Result<String, String>`.
+/// Convert a `Result<OsString, String>` to a `Result<String>`.
/// # Arguments
/// * `r` - Result to convert.
-pub fn os_string_result_to_strings(r: Result<String, OsString>) -> Result<String, String> {
+pub fn os_string_result_to_strings(r: std::result::Result<String, OsString>) -> Result<String> {
match r {
- Err(e) => Err(match e.into_string() {
+ Err(e) => berr!(match e.into_string() {
Ok(s) => s,
Err(ee) => "Could not coerce OS string into utf8 string".to_string(),
}),
@@ -102,17 +116,17 @@ pub fn get_home_nofail() -> String {
}
}
-pub fn check_hword_alignment(addr: u32) -> Result<(), String> {
+pub fn check_hword_alignment(addr: u32) -> Result<()> {
if addr & 0x1 != 0 {
- Err(format!("Bad half word alignment: 0x{:x}", addr))
+ berr!(format!("Bad half word alignment: 0x{:x}", addr))
} else {
Ok(())
}
}
-pub fn check_word_alignment(addr: u32) -> Result<(), String> {
+pub fn check_word_alignment(addr: u32) -> Result<()> {
if addr & 0x3 != 0 {
- Err(format!("Bad word alignment: 0x{:x}", addr))
+ berr!(format!("Bad word alignment: 0x{:x}", addr))
} else {
Ok(())
}
@@ -124,13 +138,13 @@ impl File {
/// Open a file from a path. Return File on success and a string on error.
/// # Arguments
/// * `path` - Path to file.
- pub fn open(path: &String) -> Result<Self, String> {
+ pub fn open(path: &String) -> Result<Self> {
match fs::File::open(&path) {
Ok(r) => Ok(Self {
file: r,
path: format!("{}", path),
}),
- Err(e) => Err(format!("Could not open file {}: {}", path, e)),
+ Err(e) => berr!(format!("Could not open file {}: {}", path, e)),
}
}
@@ -138,13 +152,13 @@ impl File {
/// # Arguments
/// * `path` - Path to file.
/// * `ops` - File open options.
- pub fn open_ops(path: &String, ops: &OpenOptions) -> Result<Self, String> {
+ pub fn open_ops(path: &String, ops: &OpenOptions) -> Result<Self> {
match ops.open(&path) {
Ok(r) => Ok(Self {
file: r,
path: format!("{}", path),
}),
- Err(e) => Err(format!("Could not open file {}: {}", path, e)),
+ Err(e) => berr!(format!("Could not open file {}: {}", path, e)),
}
}
@@ -153,16 +167,16 @@ impl File {
/// a string on error.
/// # Arguments
/// * `buf` - Byte vector to read `self` into.
- pub fn read_into_vec(&mut self, buf: &mut Vec<u8>) -> Result<(), String> {
+ pub fn read_into_vec(&mut self, buf: &mut Vec<u8>) -> Result<()> {
match self.file.read_exact(&mut buf[..]) {
Ok(r) => Ok(()),
- Err(e) => Err(format!("Failed to read file {}, {}", self.path, e)),
+ Err(e) => berr!(format!("Failed to read file {}, {}", self.path, e)),
}
}
/// Read `self`'s contents into a byte vector. Return byte vector on success and
/// a string on error.
- pub fn read_file(&mut self) -> Result<Vec<u8>, String> {
+ pub fn read_file(&mut self) -> Result<Vec<u8>> {
let metadata = self.get_metadata()?;
let mut result = vec![0u8; metadata.len() as usize];
self.read_into_vec(&mut result)?;
@@ -172,10 +186,10 @@ impl File {
/// Read `self`'s contents into a byte vector. Return byte vector on success and
/// a string on error.
- pub fn get_metadata(&mut self) -> Result<Metadata, String> {
+ pub fn get_metadata(&mut self) -> Result<Metadata> {
match self.file.metadata() {
Ok(r) => Ok(r),
- Err(e) => Err(format!("Could not read metadata for {}: {}", self.path, e)),
+ Err(e) => berr!(format!("Could not read metadata for {}: {}", self.path, e)),
}
}
@@ -184,10 +198,10 @@ impl File {
/// a string on error.
/// # Arguments
/// * `buf` - Byte buffer to read `self` into.
- pub fn read(&mut self, buf: &mut [u8]) -> Result<(), String> {
+ pub fn read(&mut self, buf: &mut [u8]) -> Result<()> {
match self.file.read_exact(buf) {
Ok(r) => Ok(()),
- Err(e) => Err(format!("Could not read buffer from {}: {}", self.path, e)),
+ Err(e) => berr!(format!("Could not read buffer from {}: {}", self.path, e)),
}
}
@@ -195,10 +209,10 @@ impl File {
/// Return void on success and string on error.
/// # Arguments
/// * `buf` - Byte buffer to write to `self`.
- pub fn write_buf(&mut self, buf: &[u8]) -> Result<(), String> {
+ pub fn write_buf(&mut self, buf: &[u8]) -> Result<()> {
match self.file.write_all(buf) {
Ok(r) => Ok(()),
- Err(e) => Err(format!(
+ Err(e) => berr!(format!(
"Could not write byte buffer to {}: {}",
self.path, e
)),
@@ -209,10 +223,10 @@ impl File {
/// Return void on success and string on error.
/// # Arguments
/// * `buf` - Byte vector to write to `self`.
- pub fn write_vec(&mut self, buf: &Vec<u8>) -> Result<(), String> {
+ pub fn write_vec(&mut self, buf: &Vec<u8>) -> Result<()> {
match self.file.write_all(&buf[..]) {
Ok(r) => Ok(()),
- Err(e) => Err(format!(
+ Err(e) => berr!(format!(
"Could not write byte buffer to {}: {}",
self.path, e
)),