commit 47fc305a8771aa792198aecddf538c9b79576ac8
parent 528a2619207271d315330e34958f280110f0e84f
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date: Fri, 10 Jun 2022 18:54:29 -0700
Print debugging, fix opcode decode bitshift error
Diffstat:
5 files changed, 346 insertions(+), 90 deletions(-)
diff --git a/src/decode.rs b/src/decode.rs
@@ -15,8 +15,10 @@
extern crate core;
use core::convert::TryInto;
+use std::fmt;
/// Types of conditionals the RISC II supports.
+#[derive(PartialEq, Eq, Copy, Clone)]
pub enum Conditional {
/// Greater than.
Gt,
@@ -42,7 +44,7 @@ pub enum Conditional {
Ne,
/// Equal.
Eq,
- /// Now overflow (signed arithmetic).
+ /// No overflow (signed arithmetic).
Nv,
/// Overflow (signed arithmetic).
V,
@@ -52,6 +54,7 @@ pub enum Conditional {
/// The 'source' of the instruction, which can either be a register name,
/// or a 13 bit immediate (signed or unsigned).
+#[derive(PartialEq, Eq, Copy, Clone)]
pub enum ShortSource {
/// Register name.
Reg(u8),
@@ -61,6 +64,36 @@ pub enum ShortSource {
SImm13(i32),
}
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub struct ShortInstruction {
+ scc: bool,
+ dest: u8,
+ rs1: u8,
+ short_source: ShortSource,
+}
+
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub struct LongInstruction {
+ scc: bool,
+ dest: u8,
+ imm19: u32,
+}
+
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub struct ShortConditional {
+ scc: bool,
+ dest: Conditional,
+ rs1: u8,
+ short_source: ShortSource,
+}
+
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub struct LongConditional {
+ scc: bool,
+ dest: Conditional,
+ imm19: u32,
+}
+
/// A RISC-II Instruction.
/// A RISC-II instruction is in one of two formats: short source and long immediate.
///
@@ -80,6 +113,7 @@ pub enum ShortSource {
/// Load instructions: If the instruction has the letter `r` in the name
/// it is relative to PC (PC + imm19). If it has the letter `x` instead,
/// the load is register indexed.
+#[derive(PartialEq, Eq, Copy, Clone)]
pub enum Instruction {
/// Call interrupt.
/// Notes:
@@ -90,14 +124,14 @@ pub enum Instruction {
/// - If the change to `CWP` makes it equal to `SWP`: stop execution,
/// generate a trap, and go to address 0x80000020.
/// CWP := CWP - 1 MOD 8, rd := LSTPC; CC's have same rules as getipc.
- Calli(bool, u8),
+ Calli(ShortInstruction),
/// Get pointer to window. rd := (-1)<31:13> & PSW<12:0>;
- GetPSW(bool, u8, u8, ShortSource),
+ GetPSW(ShortInstruction),
/// Get the last Program Counter. rd := LSTPC.
/// Iff SCC == true, Z := [LSTPC == 0]; N := LSTPC<31>; V,C := garbage.
/// Notes:
/// - PRIVILEGED INSTRUCTION.
- GetIPC(bool, u8, u8, ShortSource),
+ GetIPC(ShortInstruction),
/// Set PSW. PSW := [rs1 + ShortSource2]<12:0>;
/// Notes:
/// - PRIVILEGED INSTRUCTION.
@@ -107,7 +141,7 @@ pub enum Instruction {
/// - Rd is discarded.
/// - New PSW is not in effect until AFTER the next cycle following execution
/// of this instruction.
- PutPSW(bool, u8, u8, ShortSource),
+ PutPSW(ShortInstruction),
/// Call procedure at `shortSource` + `rs1`.
/// - The `RS1` and `RS1` registers are read from the OLD window.
/// - The PC instruction saved is the `PC` at the `CALLI`.
@@ -115,7 +149,7 @@ pub enum Instruction {
/// - If the change to `CWP` makes it equal to `SWP`: stop execution,
/// generate a trap, and go to address 0x80000020.
/// CWP := CWP - 1 MOD 8, rd := PC; CC's have same rules as getipc.
- Callx(bool, u8, u8, ShortSource),
+ Callx(ShortInstruction),
/// Call procedure at `PC` + `imm19`.
/// - The `RS1` and `RS1` registers are read from the OLD window.
/// - The PC instruction saved is the `PC` at the `CALLI`.
@@ -123,20 +157,20 @@ pub enum Instruction {
/// - If the change to `CWP` makes it equal to `SWP`: stop execution,
/// generate a trap, and go to address 0x80000020.
/// CWP := CWP - 1 MOD 8, rd := PC; CC's have same rules as getipc.
- Callr(bool, u8, u32),
+ Callr(LongInstruction),
/// If conditional is true: PC := `rs1` + `shortSource`;
- Jmpx(bool, Conditional, u8, ShortSource),
+ Jmpx(ShortConditional),
/// If conditional is true: PC += `imm19`;
/// Test alignment: if newPC<0> == 1 then abort instruction and jump
/// to 0x80000000.
- Jmpr(bool, Conditional, u32),
+ Jmpr(LongConditional),
/// Return from the current procedure if conditional is true.
/// CWP := CWP + 1 MOD 8.
/// Notes:
/// - `rs1` and `rs1` are read from the OLD window.
/// - The usual use case of this instruction is with target address
/// `rs1` + 8 (with `rs1`=`rd` of the call).
- Ret(bool, Conditional, u8, ShortSource),
+ Ret(ShortConditional),
/// Return from interrupt if condition is true.
/// CWP := CWP + 1 MOD 8.
/// Notes:
@@ -144,78 +178,79 @@ pub enum Instruction {
/// - `rs1` and `rs1` are read from the OLD window.
/// - The usual use case of this instruction is with target address
/// `rs1` + 8 (with `rs1`=`rd` of the call).
- Reti(bool, Conditional, u8, ShortSource),
+ Reti(ShortConditional),
/// Shift left logical.
- Sll(bool, u8, u8, ShortSource),
+ Sll(ShortInstruction),
/// Shift right logical.
- Srl(bool, u8, u8, ShortSource),
+ Srl(ShortInstruction),
/// Shift right arithmetic.
- Sra(bool, u8, u8, ShortSource),
+ Sra(ShortInstruction),
/// Bitwise OR.
- Or(bool, u8, u8, ShortSource),
+ Or(ShortInstruction),
/// Bitwise And.
- And(bool, u8, u8, ShortSource),
+ And(ShortInstruction),
/// Bitwise Xor.
- Xor(bool, u8, u8, ShortSource),
+ Xor(ShortInstruction),
/// Arithmetic add: d := s1 + s2;
- Add(bool, u8, u8, ShortSource),
+ Add(ShortInstruction),
/// Arithmetic add with constant: d := s1 + s2 + C;
- Addc(bool, u8, u8, ShortSource),
+ Addc(ShortInstruction),
/// Arithmetic sub: d := s1 - s2; (d := s1 + NOT(s2) + 1)
- Sub(bool, u8, u8, ShortSource),
+ Sub(ShortInstruction),
/// Arithmetic sub with constant: d := s1 - s2 - NOT(C); (d := s1 + NOT(s2) + C)
- Subc(bool, u8, u8, ShortSource),
+ Subc(ShortInstruction),
/// Subtract inverse: d := s2 - s1; (d := s2 + NOT(s1))
- Subi(bool, u8, u8, ShortSource),
+ Subi(ShortInstruction),
/// Subtract inverse with constant: d := s2 - s1 - NOT(C); (d := s2 - s1 - NOT(C))
- Subci(bool, u8, u8, ShortSource),
+ Subci(ShortInstruction),
/// Load high: Load 19 bit immediate into top 19 bits of destination register,
/// and set the bottom 13 bits to 0.
- Ldhi(bool, u8, u32),
+ Ldhi(LongInstruction),
/// Load word, register indexed.
- Ldxw(bool, u8, u8, ShortSource),
+ Ldxw(ShortInstruction),
/// Load word, long-immediate.
- Ldrw(bool, u8, u32),
+ Ldrw(LongInstruction),
/// Load half signed, register indexed.
- Ldxhs(bool, u8, u8, ShortSource),
+ Ldxhs(ShortInstruction),
/// Load half signed, long-immediate.
- Ldrhs(bool, u8, u32),
+ Ldrhs(LongInstruction),
/// Load half unsigned, register indexed.
- Ldxhu(bool, u8, u8, ShortSource),
+ Ldxhu(ShortInstruction),
/// Load half unsigned, long-immediate.
- Ldrhu(bool, u8, u32),
+ Ldrhu(LongInstruction),
/// Load byte signed, register indexed.
- Ldxbs(bool, u8, u8, ShortSource),
+ Ldxbs(ShortInstruction),
/// Load byte signed, long-immediate.
- Ldrbs(bool, u8, u32),
+ Ldrbs(LongInstruction),
/// Load byte unsigned, register indexed.
- Ldxbu(bool, u8, u8, ShortSource),
+ Ldxbu(ShortInstruction),
/// Load byte unsigned, long-immediate.
- Ldrbu(bool, u8, u32),
+ Ldrbu(LongInstruction),
/// Store word, register indexed.
- Stxw(bool, u8, u8, ShortSource),
+ Stxw(ShortInstruction),
/// Store word, long-immediate.
- Strw(bool, u8, u32),
+ Strw(LongInstruction),
/// Store half, register indexed.
- Stxh(bool, u8, u8, ShortSource),
+ Stxh(ShortInstruction),
/// Store half, long-immediate.
- Strh(bool, u8, u32),
+ Strh(LongInstruction),
/// Store byte, register indexed.
- Stxb(bool, u8, u8, ShortSource),
+ Stxb(ShortInstruction),
/// Store byte, long-immediate.
- Strb(bool, u8, u32),
+ Strb(LongInstruction),
}
/// Opcode errors.
+#[derive(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.
@@ -270,27 +305,28 @@ pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
ShortSource::Reg((opcode & 0x1f) as u8)
}; // TODO fix ambiguous sign problem.
// The opcode itself.
- let op = (opcode & 0xFE) >> 24;
+ let op = (opcode & 0xFE000000) >> 25;
let cond = get_cond_from_opcode(opcode);
- // Math the opcode's prefix.
+ let bottom_nibble = op & 0xf;
+ // Match the opcode's prefix.
Ok(match op >> 5 {
// Match the bottom four bytes of the opcode's prefix.
- 0 => match op & 0xF {
+ 0 => match bottom_nibble {
0 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
- 1 => I::Calli(scc, dest),
- 2 => I::GetPSW(scc, dest, rs1, short_source),
- 3 => I::GetIPC(scc, dest, rs1, short_source),
- 4 => I::PutPSW(scc, dest, rs1, short_source),
+ 1 => I::Calli(ShortInstruction::new(scc, dest, rs1, short_source)),
+ 2 => I::GetPSW(ShortInstruction::new(scc, dest, rs1, short_source)),
+ 3 => I::GetIPC(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)),
- 8 => I::Callx(scc, dest, rs1, short_source),
- 9 => I::Callr(scc, dest, imm19),
+ 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)),
- 12 => I::Jmpx(scc, cond?, rs1, short_source),
- 13 => I::Jmpr(scc, cond?, imm19),
- 14 => I::Ret(scc, cond?, rs1, short_source),
- 15 => I::Reti(scc, cond?, rs1, short_source),
+ 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(
@@ -298,22 +334,22 @@ pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
)))
}
},
- 1 => match op & 0xF {
+ 1 => match bottom_nibble {
0 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
- 1 => I::Sll(scc, dest, rs1, short_source),
- 2 => I::Sra(scc, dest, rs1, short_source),
- 3 => I::Srl(scc, dest, rs1, short_source),
- 4 => I::Ldhi(scc, dest, imm19),
- 5 => I::And(scc, dest, rs1, short_source),
- 6 => I::Or(scc, dest, rs1, short_source),
- 7 => I::Xor(scc, dest, rs1, short_source),
- 8 => I::Add(scc, dest, rs1, short_source),
- 9 => I::Addc(scc, dest, rs1, short_source),
+ 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)),
+ 4 => I::Ldhi(LongInstruction::new(scc, dest, imm19)),
+ 5 => I::And(ShortInstruction::new(scc, dest, rs1, short_source)),
+ 6 => I::Or(ShortInstruction::new(scc, dest, rs1, short_source)),
+ 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)),
- 12 => I::Sub(scc, dest, rs1, short_source),
- 13 => I::Subc(scc, dest, rs1, short_source),
- 14 => I::Subi(scc, dest, rs1, short_source),
- 15 => I::Subci(scc, dest, rs1, short_source),
+ 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(
@@ -321,18 +357,18 @@ pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
)))
}
},
- 2 => match op & 0xF {
+ 2 => match bottom_nibble {
0..=5 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
- 6 => I::Ldxw(scc, dest, rs1, short_source),
- 7 => I::Ldrw(scc, dest, imm19),
- 8 => I::Ldxhu(scc, dest, rs1, short_source),
- 9 => I::Ldrhu(scc, dest, imm19),
- 10 => I::Ldxhs(scc, dest, rs1, short_source),
- 11 => I::Ldrhs(scc, dest, imm19),
- 12 => I::Ldxbu(scc, dest, rs1, short_source),
- 13 => I::Ldrbu(scc, dest, imm19),
- 14 => I::Ldxbs(scc, dest, rs1, short_source),
- 15 => I::Ldrbs(scc, dest, imm19),
+ 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)),
+ 9 => I::Ldrhu(LongInstruction::new(scc, dest, imm19)),
+ 10 => I::Ldxhs(ShortInstruction::new(scc, dest, rs1, short_source)),
+ 11 => I::Ldrhs(LongInstruction::new(scc, dest, imm19)),
+ 12 => I::Ldxbu(ShortInstruction::new(scc, dest, rs1, short_source)),
+ 13 => I::Ldrbu(LongInstruction::new(scc, dest, imm19)),
+ 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(
@@ -340,16 +376,16 @@ pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
)))
}
},
- 3 => match op & 0xF {
+ 3 => match bottom_nibble {
0..=5 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
- 6 => I::Stxw(scc, dest, rs1, short_source),
- 7 => I::Strw(scc, dest, imm19),
+ 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)),
- 10 => I::Stxh(scc, dest, rs1, short_source),
- 11 => I::Strh(scc, dest, imm19),
+ 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)),
- 14 => I::Stxb(scc, dest, rs1, short_source),
- 15 => I::Strb(scc, dest, imm19),
+ 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(
@@ -375,3 +411,129 @@ pub fn decode_file(file: &Vec<u8>, pos: usize) -> Result<(), DecodeError> {
Ok(())
}
+
+// Impls.
+
+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),
+ }
+ }
+}
+
+impl LongInstruction {
+ pub fn new(scc: bool, dest: u8, imm19: u32) -> Self {
+ Self {
+ scc: scc,
+ dest: dest,
+ imm19: imm19,
+ }
+ }
+}
+
+impl fmt::Display for LongInstruction {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "Scc: {}, dest: {}, imm19: {}",
+ self.scc, self.dest, self.imm19
+ )
+ }
+}
+
+impl LongConditional {
+ pub fn new(scc: bool, dest: Conditional, imm19: u32) -> Self {
+ Self {
+ scc: scc,
+ dest: dest,
+ imm19: imm19,
+ }
+ }
+}
+
+impl fmt::Display for LongConditional {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "Scc: {}, cond: {}, imm19: {}",
+ self.scc, self.dest, self.imm19
+ )
+ }
+}
+
+impl ShortInstruction {
+ pub fn new(scc: bool, dest: u8, rs1: u8, short_source: ShortSource) -> Self {
+ Self {
+ scc: scc,
+ dest: dest,
+ rs1: rs1,
+ short_source: short_source,
+ }
+ }
+}
+
+impl fmt::Display for ShortInstruction {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "Scc: {}, dest: {}, rs1: {}, short_source: {}",
+ self.scc, self.dest, self.rs1, self.short_source
+ )
+ }
+}
+
+impl ShortConditional {
+ pub fn new(scc: bool, dest: Conditional, rs1: u8, short_source: ShortSource) -> Self {
+ Self {
+ scc: scc,
+ dest: dest,
+ rs1: rs1,
+ short_source: short_source,
+ }
+ }
+}
+
+impl fmt::Display for ShortConditional {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "Scc: {}, conditional: {}, rs1: {}, short_source: {}",
+ self.scc, self.dest, self.rs1, self.short_source
+ )
+ }
+}
+
+impl fmt::Display for ShortSource {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Self::Reg(r) => write!(f, "Reg {}", r),
+ Self::UImm13(u) => write!(f, "U{}", u),
+ Self::SImm13(i) => write!(f, "S{}", i),
+ }
+ }
+}
+
+impl fmt::Display for Conditional {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Self::Gt => write!(f, "Greater than"),
+ Self::Le => write!(f, "Less than or equal to"),
+ Self::Ge => write!(f, "Greater than or equal to"),
+ Self::Lt => write!(f, "Less than"),
+ Self::Hi => write!(f, "Higher than"),
+ Self::Los => write!(f, "Lower than or same"),
+ Self::Lonc => write!(f, "Lower than no carry"),
+ Self::Hisc => write!(f, "Higher than no carry"),
+ Self::Pl => write!(f, "Plus"),
+ Self::Mi => write!(f, "Minus"),
+ Self::Ne => write!(f, "Not equal"),
+ Self::Eq => write!(f, "Equal"),
+ Self::Nv => write!(f, "No overflow (signed arithmetic)"),
+ Self::V => write!(f, "Overflow (signed arithmetic)"),
+ Self::Alw => write!(f, "Always (constant 1)"),
+ }
+ }
+}
diff --git a/src/decode_test.rs b/src/decode_test.rs
@@ -0,0 +1,92 @@
+// Test code for the RISC II decoder.
+// (C) Ryan Jeffrey <ryan@ryanmj.xyz>, 2022
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+
+// This program 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 Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+#[cfg(test)]
+#[path = "decode.rs"]
+mod test {
+ use super::super::*;
+
+ type I = decode::Instruction;
+ type SS = decode::ShortSource;
+
+ use decode::*;
+ use std::fmt;
+
+ #[test]
+ fn decode_calli() -> Result<(), DecodeError> {
+ assert_eq!(
+ decode(0x02D00000)?,
+ I::Calli(ShortInstruction::new(true, 5, 0, SS::Reg(0)))
+ );
+ Ok(())
+ }
+
+ impl fmt::Debug for DecodeError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self)
+ }
+ }
+
+ impl fmt::Debug for I {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // Instruction to string conversion.
+ write!(
+ f,
+ "{}",
+ match *self {
+ I::Calli(o) => format!("Calli {}", o),
+ I::GetPSW(o) => format!("GetPSW {}", o),
+ I::GetIPC(o) => format!("GetIPC {}", o),
+ I::PutPSW(o) => format!("GetPSW {}", o),
+ I::Callx(o) => format!("Callx {}", o),
+ I::Callr(o) => format!("Callr {}", o),
+ I::Jmpx(o) => format!("Jmpx {}", o),
+ I::Jmpr(o) => format!("Jmpr {}", o),
+ I::Ret(o) => format!("Ret {}", o),
+ I::Reti(o) => format!("Reti {}", o),
+ I::Sll(o) => format!("Sll {}", o),
+ I::Srl(o) => format!("Srl {}", o),
+ I::Sra(o) => format!("Sra {}", o),
+ I::Or(o) => format!("Or {}", o),
+ I::And(o) => format!("And {}", o),
+ I::Xor(o) => format!("Xor {}", o),
+ I::Add(o) => format!("Add {}", o),
+ I::Addc(o) => format!("Addc {}", o),
+ I::Sub(o) => format!("Sub {}", o),
+ I::Subc(o) => format!("Subc {}", o),
+ I::Subi(o) => format!("Subi {}", o),
+ I::Subci(o) => format!("Subci {}", o),
+ I::Ldhi(o) => format!("Ldhi {}", o),
+ I::Ldxw(o) => format!("Ldxw {}", o),
+ I::Ldrw(o) => format!("Ldrw {}", o),
+ I::Ldxhs(o) => format!("Ldxhs {}", o),
+ I::Ldrhs(o) => format!("Ldrhs {}", o),
+ I::Ldxhu(o) => format!("Ldxhu {}", o),
+ I::Ldrhu(o) => format!("Ldrhu {}", o),
+ I::Ldxbs(o) => format!("Ldxbs {}", o),
+ I::Ldrbs(o) => format!("Ldrbs {}", o),
+ I::Ldxbu(o) => format!("Ldxbu {}", o),
+ I::Ldrbu(o) => format!("Ldxbu {}", o),
+ I::Stxw(o) => format!("Stxw {}", o),
+ I::Strw(o) => format!("Strw {}", o),
+ I::Stxh(o) => format!("Stxh {}", o),
+ I::Strh(o) => format!("Strh {}", o),
+ I::Stxb(o) => format!("Stxb {}", o),
+ I::Strb(o) => format!("Strb {}", o),
+ }
+ )
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
@@ -17,6 +17,8 @@ extern crate core;
extern crate sdl2;
#[cfg(test)]
mod main_test;
+#[cfg(test)]
+mod decode_test;
mod config;
mod decode;
diff --git a/src/main_test.rs b/src/main_test.rs
@@ -1,5 +1,5 @@
-/// An emulator for the RISC-II microprocessor architecture.
-/// (C) Ryan Jeffrey <ryan@ryanmj.xyz>, 2022
+// Test code for the main module.
+// (C) Ryan Jeffrey <ryan@ryanmj.xyz>, 2022
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or (at
diff --git a/src/register.rs b/src/register.rs
@@ -1,5 +1,5 @@
-/// RISC II register system.
-/// (C) Ryan Jeffrey <ryan@ryanmj.xyz>, 2022
+// RISC II register system.
+// (C) Ryan Jeffrey <ryan@ryanmj.xyz>, 2022
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or (at
@@ -15,7 +15,7 @@
use std::convert::TryInto;
/// The number of register window_regs the RISCII supports.
-pub const NUM_WINDOW_REGS: usize = 6;
+pub const NUM_WINDOW_REGS: usize = 8;
/// The number of local registers per window.
pub const NUM_LOCALS: usize = 10;
/// The number of registers shared with the previous register window (input arguments).