commit 1b01ffcdd654ab25eb2da6f7a8eff5873ffb9b7f
parent 3fe35ea349c332e8be11382c42f2256aadbe6b3a
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date: Tue, 7 Jun 2022 00:15:09 -0700
Finish decode, fix compile errors, decode file.
Diffstat:
M | src/main.rs | | | 249 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- |
1 file changed, 236 insertions(+), 13 deletions(-)
diff --git a/src/main.rs b/src/main.rs
@@ -15,6 +15,11 @@
#[cfg(test)]
mod main_test;
+extern crate core;
+
+use core::convert::TryInto;
+use std::fs;
+
enum Conditional {
/// Greater than.
Gt,
@@ -79,23 +84,70 @@ enum ShortSource {
/// it is relative to PC (PC + imm19). If it has the letter `x` instead,
/// the load is register indexed.
enum Instruction {
- /// Privileged instruction: call
- Calli(bool, u8, u8, ShortSource),
-
+ /// 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(bool, u8),
+ /// Get pointer to window. rd := (-1)<31:13> & PSW<12:0>;
GetPSW(bool, u8, u8, ShortSource),
-
+ /// 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),
-
+ /// 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(bool, u8, u8, ShortSource),
-
+ /// 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(bool, u8, u8, ShortSource),
-
+ /// 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(bool, u8, u32),
-
+ /// If conditional is true: PC := `rs1` + `shortSource`;
Jmpx(bool, Conditional, u8, ShortSource),
+ /// If conditional is true: PC += `imm19`;
+ /// Test alignment: if newPC<0> == 1 then abort instruction and jump
+ /// to 0x80000000.
Jmpr(bool, Conditional, u32),
- Ret(bool, u8, u8, ShortSource),
- Reti(bool, u8, u8, ShortSource),
+ /// 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),
+ /// 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(bool, Conditional, u8, ShortSource),
/// Shift left logical.
Sll(bool, u8, u8, ShortSource),
@@ -122,11 +174,11 @@ enum Instruction {
/// Subtract inverse: d := s2 - s1; (d := s2 + NOT(s1))
Subi(bool, u8, u8, ShortSource),
/// Subtract inverse with constant: d := s2 - s1 - NOT(C); (d := s2 - s1 - NOT(C))
- Subic(bool, u8, u8, ShortSource),
+ Subci(bool, u8, u8, ShortSource),
/// Load high: Load 19 bit immediate into top 19 bits of destination register,
- /// leaving the bottom 13 bits untouched.
- Ldhi(bool, u8, u8, ShortSource),
+ /// and set the bottom 13 bits to 0.
+ Ldhi(bool, u8, u32),
/// Load word, register indexed.
Ldxw(bool, u8, u8, ShortSource),
/// Load word, long-immediate.
@@ -166,6 +218,177 @@ enum Instruction {
Strb(bool, u8, u32),
}
+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,
+
+ /// Indicates some bug in this program with a string description.
+ 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) >> 18 {
+ 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),
+ })
+}
+
+fn decode(opcode: u32) -> Result<Instruction, DecodeError> {
+ type I = Instruction;
+ // SCC flag (<24>).
+ let scc = opcode & 0x1000000 != 0;
+ // Destination bits (<23-19>).
+ let dest = ((opcode & 0xF80000) >> 18) as u8;
+ // Short-immediate RS1 value (<18-14>).
+ let rs1 = ((opcode & 0x7C000) >> 13) as u8;
+ // Immediate-mode bottom 19 bits <18-0>.
+ 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)
+ } else {
+ ShortSource::Reg((opcode & 0x1f) as u8)
+ }; // TODO fix ambiguous sign problem.
+ // The opcode itself.
+ let op = (opcode & 0xFE) >> 24;
+
+ let cond = get_cond_from_opcode(opcode);
+
+ // Math the opcode's prefix.
+ Ok(match op >> 5 {
+ // Match the bottom four bytes of the opcode's prefix.
+ 0 => match op & 0xF {
+ 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),
+ 5..=7 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 8 => I::Callx(scc, dest, rs1, short_source),
+ 9 => I::Callr(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),
+ // Should never be reached.
+ _ => {
+ return Err(DecodeError::CodeError(String::from(
+ "Match bottom four bytes of opcode prefix",
+ )))
+ }
+ },
+ 1 => match op & 0xF {
+ 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),
+ 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),
+ // Should never be reached.
+ _ => {
+ return Err(DecodeError::CodeError(String::from(
+ "Match bottom four bytes of opcode prefix",
+ )))
+ }
+ },
+ 2 => match op & 0xF {
+ 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),
+ // Should never be reached.
+ _ => {
+ return Err(DecodeError::CodeError(String::from(
+ "Match bottom four bytes of opcode prefix",
+ )))
+ }
+ },
+ 3 => match op & 0xF {
+ 0..=5 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 6 => I::Stxw(scc, dest, rs1, short_source),
+ 7 => I::Strw(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),
+ 12..=13 => return Err(DecodeError::InvalidInstruction(0x0f, opcode)),
+ 14 => I::Stxb(scc, dest, rs1, short_source),
+ 15 => I::Strb(scc, dest, imm19),
+ // Should never be reached.
+ _ => {
+ return Err(DecodeError::CodeError(String::from(
+ "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 Err(DecodeError::InvalidInstruction(0x8, opcode)),
+ })
+}
+
+fn load_firmware(file: &String) {}
+
+fn get_program(path: &String) -> Result<Vec<u8>, String> {
+ println!("Opening binary file {}.", path);
+
+ Ok(match fs::read(path) {
+ Ok(mut raw_p) => raw_p.to_vec(),
+ Err(raw_e) => return Err(raw_e.to_string()),
+ })
+}
+
+fn decode_file(file: &Vec<u8>, pos: usize) -> Result<(), DecodeError> {
+ let result = 0usize;
+
+ for i in (0..file.len()).step_by(4) {
+ decode(u32::from_ne_bytes(file[pos..pos + 4].try_into().unwrap()))?;
+ }
+
+ Ok(())
+}
+
fn main() -> Result<(), String> {
+ let program = get_program(&String::from("test.bin"))?;
+
Ok(())
}