commit 5b4146fe2962b736541411ad06cf71b0a71e2616
parent 36179599c65b09c5b75075614773c1dc6d1a82cf
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date: Fri, 7 Oct 2022 19:10:44 -0700
Encoding instructions
Diffstat:
4 files changed, 149 insertions(+), 7 deletions(-)
diff --git a/src/cpu.rs b/src/cpu.rs
@@ -49,6 +49,7 @@ pub const SIZEOF_INSTRUCTION: u32 = 4;
/// A RISC II 32bit register.
type Register = u32;
+// TODO maybe convert this into a u16?
/// PSW. Contains internal state that is usually opaque to the system.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ProcessorStatusWord {
@@ -77,14 +78,14 @@ pub struct ProcessorStatusWord {
pub struct RegisterFile {
/// Next program counter, holds the address of the instruction being
/// fetched for the next cycle.
- nxtpc: Register,
+ pub nxtpc: Register,
/// Program counter, holds the address of current instruction being
/// executed.
- pc: Register,
+ pub pc: Register,
/// The lastpc, holds the address of the last executed instruction
/// (or last attempted to be executed). When running an interrupt `lstpc`
/// holds the address of the instruction that was aborted.
- lstpc: Register,
+ pub lstpc: Register,
/// Global registers.
globals: [Register; NUM_GLOBALS],
/// Register window stack.
diff --git a/src/decode.rs b/src/decode.rs
@@ -75,16 +75,71 @@ impl fmt::Debug for DecodeError {
}
}
+pub fn encode(inst: Instruction) -> u32 {
+ type I = Instruction;
+ match inst {
+ I::Calli(s) => s.encode(0b0000001),
+ I::GetPSW(s) => s.encode(0b0000010),
+ I::PutPSW(s) => s.encode(0b0000100),
+ I::GetLPC(s) => s.encode(0b0000011),
+ I::Callx(s) => s.encode(0b0000100),
+ I::Sll(s) => s.encode(0b0010001),
+ I::Srl(s) => s.encode(0b0010011),
+ I::Sra(s) => s.encode(0b0010010),
+ I::Or(s) => s.encode(0b0010110),
+ I::And(s) => s.encode(0b0010101),
+ I::Xor(s) => s.encode(0b0010111),
+ I::Add(s) => s.encode(0b0011000),
+ I::Addc(s) => s.encode(0b0011001),
+ I::Sub(s) => s.encode(0b0011100),
+ I::Subc(s) => s.encode(0b0011101),
+ I::Subi(s) => s.encode(0b0011110),
+ I::Subci(s) => s.encode(0b0011111),
+ I::Ldxw(s) => s.encode(0b0100110),
+ I::Ldxhu(s) => s.encode(0b0101000),
+ I::Ldxhs(s) => s.encode(0b0101010),
+ I::Ldxbu(s) => s.encode(0b0101100),
+ I::Ldxbs(s) => s.encode(0b0101110),
+ I::Stxw(s) => s.encode(0b0110110),
+ I::Stxh(s) => s.encode(0b0111010),
+ I::Stxb(s) => s.encode(0b0111011),
+ I::Jmpx(s) => s.encode(0b0001100),
+ I::Ret(s) => s.encode(0b0001110),
+ I::Reti(s) => s.encode(0b0001111),
+
+ I::Jmpr(l) => l.encode(0b0001101),
+ I::Callr(l) => l.encode(0b0001001),
+ I::Ldhi(l) => l.encode(0b0010100),
+ I::Ldrw(l) => l.encode(0b0100111),
+ I::Ldrhu(l) => l.encode(0b0101001),
+ I::Ldrhs(l) => l.encode(0b0101011),
+ I::Ldrbu(l) => l.encode(0b0101101),
+ I::Ldrbs(l) => l.encode(0b0101111),
+ I::Strw(l) => l.encode(0b0110111),
+ I::Strh(l) => l.encode(0b0111011),
+ I::Strb(l) => l.encode(0b0111111),
+ }
+}
+
+pub fn noop() -> u32 {
+ encode(Instruction::And(ShortInstruction::new(
+ false,
+ 0,
+ 0,
+ ShortSource::Imm13(0),
+ )))
+}
+
pub fn decode(opcode: u32) -> Result<Instruction> {
type I = Instruction;
// SCC flag (<24>).
- let scc = opcode & 0x1000000 != 0;
+ let scc = opcode & SCC_LOC != 0;
// Destination bits (<23-19>).
- let dest = ((opcode & 0x00F80000) >> 19) as u8;
+ let dest = ((opcode & DEST_LOC) >> 19) as u8;
// Short-immediate RS1 value (<18-14>).
- let rs1 = ((opcode & 0x7c000) >> 14) as u8;
+ let rs1 = ((opcode & RS1_LOC) >> 14) as u8;
// Immediate-mode bottom 19 bits <18-0>.
- let imm19 = opcode & 0x7FFFF;
+ let imm19 = opcode & IMM19_LOC;
// Short source immediate-mode bottom 13 bits <12-0> or rs1 <4-0>.
let short_source = if opcode & 0x2000 != 0 {
ShortSource::Imm13(opcode & 0x1fff)
diff --git a/src/instruction.rs b/src/instruction.rs
@@ -17,6 +17,11 @@
use std::fmt;
use std::fmt::LowerHex;
+pub const SCC_LOC: u32 = 0x1000000;
+pub const DEST_LOC: u32 = 0x00F80000;
+pub const RS1_LOC: u32 = 0x7c000;
+pub const IMM19_LOC: u32 = 0x7FFFF;
+
/// Types of conditionals the RISC II supports.
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum Conditional {
@@ -353,6 +358,13 @@ impl LowerHex for ShortSource {
}
impl LongInstruction {
+ pub fn encode(&self, opcode: u8) -> u32 {
+ let scc = if self.scc { SCC_LOC } else { 0 };
+ let dest = (self.dest as u32) << 19;
+ let imm19 = self.imm19;
+
+ ((opcode as u32) << 25) & scc & dest & imm19
+ }
/// Create a new long instruction.
/// # Arguments
/// * `scc` - Should update CC's.
@@ -378,6 +390,12 @@ impl fmt::Display for LongInstruction {
}
impl LongConditional {
+ pub fn encode(&self, opcode: u8) -> u32 {
+ let scc = if self.scc { SCC_LOC } else { 0 };
+ let dest = (get_opdata_from_cond(self.dest) as u32) << 19;
+ let imm19 = self.imm19;
+ ((opcode as u32) << 25) & scc & dest & imm19
+ }
/// Create a new long conditional instruction.
/// # Arguments
/// * `scc` - Should update CC's.
@@ -403,6 +421,17 @@ impl fmt::Display for LongConditional {
}
impl ShortInstruction {
+ pub fn encode(&self, opcode: u8) -> u32 {
+ let scc = if self.scc { SCC_LOC } else { 0 };
+ let dest = (self.dest as u32) << 19;
+ let rs1 = (self.rs1 as u32) << 14;
+ let ss = match self.short_source {
+ ShortSource::Reg(r) => r as u32,
+ ShortSource::Imm13(i) => i,
+ };
+
+ ((opcode as u32) << 25) & scc & dest & rs1 & ss
+ }
/// Create a new long conditional instruction.
/// # Arguments
/// * `scc` - Should update CC's.
@@ -430,6 +459,17 @@ impl fmt::Display for ShortInstruction {
}
impl ShortConditional {
+ pub fn encode(&self, opcode: u8) -> u32 {
+ let scc = if self.scc { SCC_LOC } else { 0 };
+ let dest = (get_opdata_from_cond(self.dest) as u32) << 19;
+ let rs1 = (self.rs1 as u32) << 14;
+ let ss = match self.short_source {
+ ShortSource::Reg(r) => r as u32,
+ ShortSource::Imm13(i) => i,
+ };
+
+ ((opcode as u32) << 25) & scc & dest & rs1
+ }
/// Create a new long conditional instruction.
/// # Arguments
/// * `scc` - Should update CC's.
@@ -477,3 +517,24 @@ impl fmt::Display for Conditional {
}
}
}
+
+fn get_opdata_from_cond(cond: Conditional) -> u8 {
+ type C = Conditional;
+ (match cond {
+ C::Gt => 1,
+ C::Le => 2,
+ C::Ge => 3,
+ C::Lt => 4,
+ C::Hi => 5,
+ C::Los => 6,
+ C::Lonc => 7,
+ C::Hisc => 8,
+ C::Pl => 9,
+ C::Mi => 10,
+ C::Ne => 11,
+ C::Eq => 12,
+ C::Nv => 13,
+ C::V => 14,
+ C::Alw => 15,
+ })
+}
diff --git a/src/system.rs b/src/system.rs
@@ -16,6 +16,7 @@
use config::Config;
use cpu::{ProcessorStatusWord, RegisterFile};
+use decode::noop;
use memory::Memory;
use std::fmt;
use util::Result;
@@ -29,6 +30,10 @@ pub struct System {
psw: ProcessorStatusWord,
/// Memory state.
mem: Memory,
+ /// Temporary latch for destination register.
+ tmp_latch: u32,
+ /// Next instruction.
+ next_instruction: u32,
}
// Impls.
@@ -43,6 +48,8 @@ impl System {
regs: RegisterFile::new(),
psw: ProcessorStatusWord::new(),
mem: Memory::new(config),
+ tmp_latch: 0,
+ next_instruction: noop(),
})
}
@@ -108,12 +115,30 @@ impl System {
regs: self.regs,
psw: self.psw,
mem: Memory::from_size(0),
+ next_instruction: self.next_instruction,
+ tmp_latch: self.tmp_latch,
}
}
pub fn get_mem_ref(&mut self) -> &mut Memory {
&mut self.mem
}
+
+ /// Run for a single clock cycle.
+ pub fn step(&mut self) {
+ self.fetch();
+ self.execute();
+ self.commit();
+ }
+
+ fn fetch(&mut self) -> Result<()> {
+ self.next_instruction = self.mem.get_word(self.regs.nxtpc)?;
+ Ok(())
+ }
+
+ fn execute(&mut self) {}
+
+ fn commit(&mut self) {}
}
impl fmt::Display for System {