commit a75c3cb341f967507f918ba46dfc03e9eb0ec2e4
parent d25a0b2dc9128231a30ef3300d94dd0e07f49519
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date: Sun, 12 Jun 2022 19:02:55 -0700
Refactor instruction structs to their own file
Diffstat:
5 files changed, 464 insertions(+), 414 deletions(-)
diff --git a/src/decode.rs b/src/decode.rs
@@ -17,239 +17,10 @@ extern crate core;
use core::convert::TryInto;
use std::fmt;
-use std::fmt::LowerHex;
-/// Types of conditionals the RISC II supports.
-#[derive(PartialEq, Eq, Copy, Clone)]
-pub enum Conditional {
- /// Greater than (signed >).
- Gt = 1,
- /// Less than or equal to (signed <=).
- Le = 2,
- /// Greater than or equal to (signed >=).
- Ge = 3,
- /// Less than (signed <).
- Lt = 4,
- /// Higher than (unsigned >).
- Hi = 5,
- /// Lower than or same (unsigned <=).
- Los = 6,
- /// Lower than no carry (unsigned <).
- Lonc = 7,
- /// Higher than, carry (unsigned >=).
- Hisc = 8,
- /// Plus (test sign).
- Pl = 9,
- /// Minus (test sign).
- Mi = 10,
- /// Not equal.
- Ne = 11,
- /// Equal.
- Eq = 12,
- /// No overflow (signed arithmetic).
- Nv = 13,
- /// Overflow (signed arithmetic).
- V = 14,
- /// Always (constant 1).
- Alw = 15,
-}
-
-/// 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),
- /// Unsigned 13 bit immediate, 0-padded to 32 bits.
- UImm13(u32),
- /// Signed 13 bit immediate, Sign-extended to 32 bits.
- 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.
-///
-/// Short source has the following members: (SCC: bool, dest: u8, rs1: u8, short source: u16).
-/// The short source can either be a 13 bit immediate value or a 5 bit register name.
-///
-/// The long immediate format has the following members: (SCC: bool, dest: u8, imm: 19).
-///
-/// For both formats, if SCC is true, then update conditional registers (CC's).
-///
-/// Shift CC's: shift, logical instructions: V := 0; C := 0;
-/// Arithmetic instructions update CC's as follows: Z := [d == 0]; N := d<31>;
-/// Arithmetic's V := [32 bit 2's-complement overflow occurred].
-/// additions: C := carry<31>to<32> (assuming s1, s2: unsigned).
-/// subtractions: C := NOT[borrow<31>to<32>] (for s1, s2: unsigned).
-///
-/// 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:
- /// - PRIVILEGED INSTRUCTION.
- /// - The `RS1` and `RS1` registers are read from the OLD window.
- /// - The PC instruction saved is the `PC` at the `CALLI`.
- /// - The `Rd` refers to the destination register in the NEW window.
- /// - 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(ShortInstruction),
- /// Get pointer to window. rd := (-1)<31:13> & PSW<12:0>;
- 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(ShortInstruction),
- /// Set PSW. PSW := [rs1 + ShortSource2]<12:0>;
- /// Notes:
- /// - PRIVILEGED INSTRUCTION.
- /// - SCC-bit MUST be false.
- /// - The next instruction CANNOT be `CALLX`, `CALLR`, CALLI`, `RET`, `RETI`,
- /// i.e. it cannot modify CWP. It also must not set the CC's.
- /// - Rd is discarded.
- /// - New PSW is not in effect until AFTER the next cycle following execution
- /// of this instruction.
- 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`.
- /// - The `Rd` refers to the destination register in the NEW window.
- /// - 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(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`.
- /// - The `Rd` refers to the destination register in the NEW window.
- /// - 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(LongInstruction),
- /// If conditional is true: PC := `rs1` + `shortSource`;
- Jmpx(ShortConditional),
- /// If conditional is true: PC += `imm19`;
- /// Test alignment: if newPC<0> == 1 then abort instruction and jump
- /// to 0x80000000.
- 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(ShortConditional),
- /// Return from interrupt if condition is true.
- /// CWP := CWP + 1 MOD 8.
- /// Notes:
- /// - PRIVILEGED 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(ShortConditional),
-
- /// Shift left logical.
- Sll(ShortInstruction),
- /// Shift right logical.
- Srl(ShortInstruction),
- /// Shift right arithmetic.
- Sra(ShortInstruction),
-
- /// Bitwise OR.
- Or(ShortInstruction),
- /// Bitwise And.
- And(ShortInstruction),
- /// Bitwise Xor.
- Xor(ShortInstruction),
-
- /// Arithmetic add: d := s1 + s2;
- Add(ShortInstruction),
- /// Arithmetic add with constant: d := s1 + s2 + C;
- Addc(ShortInstruction),
- /// Arithmetic sub: d := s1 - s2; (d := s1 + NOT(s2) + 1)
- Sub(ShortInstruction),
- /// Arithmetic sub with constant: d := s1 - s2 - NOT(C); (d := s1 + NOT(s2) + C)
- Subc(ShortInstruction),
- /// Subtract inverse: d := s2 - s1; (d := s2 + NOT(s1))
- Subi(ShortInstruction),
- /// Subtract inverse with constant: d := s2 - s1 - NOT(C); (d := s2 - s1 - NOT(C))
- Subci(ShortInstruction),
-
- /// Load high: Load 19 bit immediate into top 19 bits of destination register,
- /// and set the bottom 13 bits to 0.
- Ldhi(LongInstruction),
- /// Load word, register indexed.
- Ldxw(ShortInstruction),
- /// Load word, long-immediate.
- Ldrw(LongInstruction),
+use instruction::*;
- /// Load half signed, register indexed.
- Ldxhs(ShortInstruction),
- /// Load half signed, long-immediate.
- Ldrhs(LongInstruction),
- /// Load half unsigned, register indexed.
- Ldxhu(ShortInstruction),
- /// Load half unsigned, long-immediate.
- Ldrhu(LongInstruction),
-
- /// Load byte signed, register indexed.
- Ldxbs(ShortInstruction),
- /// Load byte signed, long-immediate.
- Ldrbs(LongInstruction),
- /// Load byte unsigned, register indexed.
- Ldxbu(ShortInstruction),
- /// Load byte unsigned, long-immediate.
- Ldrbu(LongInstruction),
-
- /// Store word, register indexed.
- Stxw(ShortInstruction),
- /// Store word, long-immediate.
- Strw(LongInstruction),
-
- /// Store half, register indexed.
- Stxh(ShortInstruction),
- /// Store half, long-immediate.
- Strh(LongInstruction),
-
- /// Store byte, register indexed.
- Stxb(ShortInstruction),
- /// Store byte, long-immediate.
- Strb(LongInstruction),
-}
+// Struct declarations.
/// Opcode errors.
#[derive(PartialEq, Eq, Clone)]
@@ -263,31 +34,6 @@ pub enum DecodeError {
CodeError(String),
}
-/// 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> {
- type C = Conditional;
- Ok(match (opcode & 0x780000) >> 19 {
- 1 => C::Gt,
- 2 => C::Le,
- 3 => C::Ge,
- 4 => C::Lt,
- 5 => C::Hi,
- 6 => C::Los,
- 7 => C::Lonc,
- 8 => C::Hisc,
- 9 => C::Pl,
- 10 => C::Mi,
- 11 => C::Ne,
- 12 => C::Eq,
- 13 => C::Nv,
- 14 => C::V,
- 15 => C::Alw,
- _ => return Err(DecodeError::InvalidJumpCondition),
- })
-}
-
// Public function declarations.
pub fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
@@ -414,58 +160,7 @@ pub fn decode_file(file: &Vec<u8>, pos: usize) -> Result<(), DecodeError> {
Ok(())
}
-// Impls.
-
-impl ShortSource {
- pub fn new(opcode: u32, signed: bool) -> Self {
- // Short source immediate-mode bottom 13 bits <12-0> or rs1 <4-0>.
- if opcode & 0x2000 != 0 {
- let mut tmp = Self::UImm13(opcode & 0x1fff);
- if signed {
- tmp.uimm_to_simm()
- } else {
- tmp
- }
- } else {
- Self::Reg((opcode & 0x1f) as u8)
- }
- }
-
- pub fn uimm_to_simm(&self) -> Self {
- match *self {
- Self::UImm13(u) => {
- if u & 0x1000 != 0 {
- // Sign-extend the 13 bit value to 32 bits.
- Self::SImm13(-(u as i32))
- } else {
- Self::SImm13(u as i32)
- }
- }
- Self::SImm13(s) => *self,
- Self::Reg(r) => *self,
- }
- }
-}
-
-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 LowerHex for ShortSource {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Self::Reg(r) => write!(f, "Register {:x}", r),
- Self::UImm13(u) => write!(f, "(UImm) {:x}", u),
- Self::SImm13(i) => write!(f, "(SImm) {:x}", i),
- }
- }
-}
+// Struct impls.
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -477,106 +172,29 @@ impl fmt::Display for DecodeError {
}
}
-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: 0x{:x} ({})",
- self.scc, self.dest, self.imm19, 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: 0x{:x} ({})",
- self.scc, self.dest, self.imm19, 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: 0x{:x} ({})",
- self.scc, self.dest, self.rs1, self.short_source, 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,
- }
- }
-}
+// Private functions.
-impl fmt::Display for ShortConditional {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "Scc: {}, conditional: {}, rs1: {}, short_source: 0x{:x} {}",
- self.scc, self.dest, self.rs1, self.short_source, self.short_source
- )
- }
-}
-
-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)"),
- }
- }
+/// 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> {
+ type C = Conditional;
+ Ok(match (opcode & 0x780000) >> 19 {
+ 1 => C::Gt,
+ 2 => C::Le,
+ 3 => C::Ge,
+ 4 => C::Lt,
+ 5 => C::Hi,
+ 6 => C::Los,
+ 7 => C::Lonc,
+ 8 => C::Hisc,
+ 9 => C::Pl,
+ 10 => C::Mi,
+ 11 => C::Ne,
+ 12 => C::Eq,
+ 13 => C::Nv,
+ 14 => C::V,
+ 15 => C::Alw,
+ _ => return Err(DecodeError::InvalidJumpCondition),
+ })
}
diff --git a/src/decode_test.rs b/src/decode_test.rs
@@ -18,12 +18,13 @@
mod test {
use super::super::*;
- type I = decode::Instruction;
- type SS = decode::ShortSource;
-
use decode::*;
+ use instruction::*;
use std::fmt;
+ type I = Instruction;
+ type SS = ShortSource;
+
// Privileged instructions.
#[test]
diff --git a/src/execute.rs b/src/execute.rs
@@ -0,0 +1,23 @@
+// Instruction execution. The second step in the three step RISC II pipeline.
+// See `decode.rs` for the first step, and `commit.rs` for the third step.
+// (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/>.
+
+use instruction::*;
+
+// Public functions.
+
+pub fn execute(instruction: Instruction) -> Result<(), String> {
+ Ok(())
+}
diff --git a/src/instruction.rs b/src/instruction.rs
@@ -0,0 +1,407 @@
+// RISC II cpu instruction info.
+// "execute" and then "commit".
+// (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/>.
+
+use std::fmt;
+use std::fmt::LowerHex;
+
+/// Types of conditionals the RISC II supports.
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub enum Conditional {
+ /// Greater than (signed >).
+ Gt = 1,
+ /// Less than or equal to (signed <=).
+ Le = 2,
+ /// Greater than or equal to (signed >=).
+ Ge = 3,
+ /// Less than (signed <).
+ Lt = 4,
+ /// Higher than (unsigned >).
+ Hi = 5,
+ /// Lower than or same (unsigned <=).
+ Los = 6,
+ /// Lower than no carry (unsigned <).
+ Lonc = 7,
+ /// Higher than, carry (unsigned >=).
+ Hisc = 8,
+ /// Plus (test sign).
+ Pl = 9,
+ /// Minus (test sign).
+ Mi = 10,
+ /// Not equal.
+ Ne = 11,
+ /// Equal.
+ Eq = 12,
+ /// No overflow (signed arithmetic).
+ Nv = 13,
+ /// Overflow (signed arithmetic).
+ V = 14,
+ /// Always (constant 1).
+ Alw = 15,
+}
+
+/// 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),
+ /// Unsigned 13 bit immediate, 0-padded to 32 bits.
+ UImm13(u32),
+ /// Signed 13 bit immediate, Sign-extended to 32 bits.
+ 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.
+///
+/// Short source has the following members: (SCC: bool, dest: u8, rs1: u8, short source: u16).
+/// The short source can either be a 13 bit immediate value or a 5 bit register name.
+///
+/// The long immediate format has the following members: (SCC: bool, dest: u8, imm: 19).
+///
+/// For both formats, if SCC is true, then update conditional registers (CC's).
+///
+/// Shift CC's: shift, logical instructions: V := 0; C := 0;
+/// Arithmetic instructions update CC's as follows: Z := [d == 0]; N := d<31>;
+/// Arithmetic's V := [32 bit 2's-complement overflow occurred].
+/// additions: C := carry<31>to<32> (assuming s1, s2: unsigned).
+/// subtractions: C := NOT[borrow<31>to<32>] (for s1, s2: unsigned).
+///
+/// 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:
+ /// - PRIVILEGED INSTRUCTION.
+ /// - The `RS1` and `RS1` registers are read from the OLD window.
+ /// - The PC instruction saved is the `PC` at the `CALLI`.
+ /// - The `Rd` refers to the destination register in the NEW window.
+ /// - 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(ShortInstruction),
+ /// Get pointer to window. rd := (-1)<31:13> & PSW<12:0>;
+ 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(ShortInstruction),
+ /// Set PSW. PSW := [rs1 + ShortSource2]<12:0>;
+ /// Notes:
+ /// - PRIVILEGED INSTRUCTION.
+ /// - SCC-bit MUST be false.
+ /// - The next instruction CANNOT be `CALLX`, `CALLR`, CALLI`, `RET`, `RETI`,
+ /// i.e. it cannot modify CWP. It also must not set the CC's.
+ /// - Rd is discarded.
+ /// - New PSW is not in effect until AFTER the next cycle following execution
+ /// of this instruction.
+ 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`.
+ /// - The `Rd` refers to the destination register in the NEW window.
+ /// - 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(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`.
+ /// - The `Rd` refers to the destination register in the NEW window.
+ /// - 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(LongInstruction),
+ /// If conditional is true: PC := `rs1` + `shortSource`;
+ Jmpx(ShortConditional),
+ /// If conditional is true: PC += `imm19`;
+ /// Test alignment: if newPC<0> == 1 then abort instruction and jump
+ /// to 0x80000000.
+ 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(ShortConditional),
+ /// Return from interrupt if condition is true.
+ /// CWP := CWP + 1 MOD 8.
+ /// Notes:
+ /// - PRIVILEGED 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(ShortConditional),
+
+ /// Shift left logical.
+ Sll(ShortInstruction),
+ /// Shift right logical.
+ Srl(ShortInstruction),
+ /// Shift right arithmetic.
+ Sra(ShortInstruction),
+
+ /// Bitwise OR.
+ Or(ShortInstruction),
+ /// Bitwise And.
+ And(ShortInstruction),
+ /// Bitwise Xor.
+ Xor(ShortInstruction),
+
+ /// Arithmetic add: d := s1 + s2;
+ Add(ShortInstruction),
+ /// Arithmetic add with constant: d := s1 + s2 + C;
+ Addc(ShortInstruction),
+ /// Arithmetic sub: d := s1 - s2; (d := s1 + NOT(s2) + 1)
+ Sub(ShortInstruction),
+ /// Arithmetic sub with constant: d := s1 - s2 - NOT(C); (d := s1 + NOT(s2) + C)
+ Subc(ShortInstruction),
+ /// Subtract inverse: d := s2 - s1; (d := s2 + NOT(s1))
+ Subi(ShortInstruction),
+ /// Subtract inverse with constant: d := s2 - s1 - NOT(C); (d := s2 - s1 - NOT(C))
+ Subci(ShortInstruction),
+
+ /// Load high: Load 19 bit immediate into top 19 bits of destination register,
+ /// and set the bottom 13 bits to 0.
+ Ldhi(LongInstruction),
+ /// Load word, register indexed.
+ Ldxw(ShortInstruction),
+ /// Load word, long-immediate.
+ Ldrw(LongInstruction),
+
+ /// Load half signed, register indexed.
+ Ldxhs(ShortInstruction),
+ /// Load half signed, long-immediate.
+ Ldrhs(LongInstruction),
+ /// Load half unsigned, register indexed.
+ Ldxhu(ShortInstruction),
+ /// Load half unsigned, long-immediate.
+ Ldrhu(LongInstruction),
+
+ /// Load byte signed, register indexed.
+ Ldxbs(ShortInstruction),
+ /// Load byte signed, long-immediate.
+ Ldrbs(LongInstruction),
+ /// Load byte unsigned, register indexed.
+ Ldxbu(ShortInstruction),
+ /// Load byte unsigned, long-immediate.
+ Ldrbu(LongInstruction),
+
+ /// Store word, register indexed.
+ Stxw(ShortInstruction),
+ /// Store word, long-immediate.
+ Strw(LongInstruction),
+
+ /// Store half, register indexed.
+ Stxh(ShortInstruction),
+ /// Store half, long-immediate.
+ Strh(LongInstruction),
+
+ /// Store byte, register indexed.
+ Stxb(ShortInstruction),
+ /// Store byte, long-immediate.
+ Strb(LongInstruction),
+}
+
+// Impls.
+
+impl ShortSource {
+ pub fn new(opcode: u32, signed: bool) -> Self {
+ // Short source immediate-mode bottom 13 bits <12-0> or rs1 <4-0>.
+ if opcode & 0x2000 != 0 {
+ let mut tmp = Self::UImm13(opcode & 0x1fff);
+ if signed {
+ tmp.uimm_to_simm()
+ } else {
+ tmp
+ }
+ } else {
+ Self::Reg((opcode & 0x1f) as u8)
+ }
+ }
+
+ pub fn uimm_to_simm(&self) -> Self {
+ match *self {
+ Self::UImm13(u) => {
+ if u & 0x1000 != 0 {
+ // Sign-extend the 13 bit value to 32 bits.
+ Self::SImm13(-(u as i32))
+ } else {
+ Self::SImm13(u as i32)
+ }
+ }
+ Self::SImm13(s) => *self,
+ Self::Reg(r) => *self,
+ }
+ }
+}
+
+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 LowerHex for ShortSource {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Self::Reg(r) => write!(f, "Register {:x}", r),
+ Self::UImm13(u) => write!(f, "(UImm) {:x}", u),
+ Self::SImm13(i) => write!(f, "(SImm) {:x}", i),
+ }
+ }
+}
+
+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: 0x{:x} ({})",
+ self.scc, self.dest, self.imm19, 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: 0x{:x} ({})",
+ self.scc, self.dest, self.imm19, 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: 0x{:x} ({})",
+ self.scc, self.dest, self.rs1, self.short_source, 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: 0x{:x} {}",
+ self.scc, self.dest, self.rs1, self.short_source, self.short_source
+ )
+ }
+}
+
+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/main.rs b/src/main.rs
@@ -16,12 +16,13 @@
extern crate core;
extern crate sdl2;
#[cfg(test)]
-mod main_test;
-#[cfg(test)]
mod decode_test;
+#[cfg(test)]
+mod main_test;
mod config;
mod decode;
+mod instruction;
mod memory;
mod register;
mod sdl;