riscii

An emulator for the RISC II
Log | Files | Refs | LICENSE

commit 5b4146fe2962b736541411ad06cf71b0a71e2616
parent 36179599c65b09c5b75075614773c1dc6d1a82cf
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date:   Fri,  7 Oct 2022 19:10:44 -0700

Encoding instructions

Diffstat:
Msrc/cpu.rs | 7++++---
Msrc/decode.rs | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/instruction.rs | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/system.rs | 25+++++++++++++++++++++++++
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 {