riscii

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

commit fc978975c6fb9a3fddd5dbb64cfdfd0bcc3ee9ee
parent 883e60896e55db7a2f512ca411fc1036dbc086d4
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date:   Sat, 15 Oct 2022 13:03:11 -0700

Add more pipeline steps

Diffstat:
Msrc/cpu.rs | 44++++++++++++++++++++++++++++++++------------
Msrc/data_path.rs | 51+++++++++++++++++++++++++++++++++++++++++++--------
Msrc/instruction.rs | 1+
Msrc/system.rs | 16++++++++++++----
4 files changed, 88 insertions(+), 24 deletions(-)

diff --git a/src/cpu.rs b/src/cpu.rs @@ -16,7 +16,6 @@ use instruction::ShortSource; use memory::Memory; use std::convert::TryInto; use std::fmt; -use util::Result; use berr; @@ -208,18 +207,37 @@ impl RegisterFile { /// [31-26] -> Ins /// Anything outside this [0-31] range is an invalid argument. /// # Arguments - /// * `which` - Which register. [0-31] are the only valid values. - /// * `psw` - Processor status object, contains window information. - pub fn read(&self, address: u32, cwp: u8) -> u32 { + /// * `address` - Which register. [0-31] are the only valid values. + /// * `cwp` - Current window pointer. Used to determine real address of the register. + pub fn read(&self, address: u8, cwp: u8) -> u32 { let addr = address as usize; let ptr = cwp as usize; - match addr { - 0..=9 => self.0[addr], - 10..=31 => self.0[NUM_ADDED_PER_WINDOW * ptr + addr + NUM_GLOBALS], - _ => 0, + match self.get_real_address(address, cwp) { + Ok(a) => self.0[a], + Err(_) => 0, // TODO figure out what to do here. } } + /// Get a register's real address in the register window. Returns + /// Err(()) if address is out of range. + /// Register mapping: [0-9] -> Globals + /// [10-15] -> Outs + /// [16-25] -> Locals + /// [31-26] -> Ins + /// Anything outside this [0-31] range is an invalid argument. + /// # Arguments + /// * `address` - Which register. [0-31] are the only valid values. + /// * `cwp` - Current window pointer. Used to determine real address of the register. + pub fn get_real_address(&self, address: u8, cwp: u8) -> Result<usize, ()> { + let addr = address as usize; + let ptr = cwp as usize; + Ok(match addr { + 0..=9 => addr, + 10..=31 => NUM_ADDED_PER_WINDOW * ptr + addr + NUM_GLOBALS, + _ => return Err(()), + }) + } + /// Set a register's value (unsigned). Return the register's value on /// success and a string message on error. /// Register mapping: [0-9] -> Globals @@ -227,6 +245,7 @@ impl RegisterFile { /// [16-25] -> Locals /// [31-26] -> Ins /// Anything outside this [0-31] range is an invalid argument. + /// Note: writes to register 0 are a no op. /// # Arguments /// * `address` - Which register. [0-31] are the only valid values. /// * `value` - Value to write into the register. @@ -234,11 +253,12 @@ impl RegisterFile { pub fn write(&mut self, address: u8, value: u32, cwp: u8) { let addr = address as usize; let ptr = cwp as usize; - match addr { - 0..=9 => self.0[addr] = value, - 10..=31 => self.0[NUM_ADDED_PER_WINDOW * ptr + addr + NUM_GLOBALS] = value, - _ => {} + match self.get_real_address(address, cwp) { + Ok(a) => self.0[a] = value, + Err(_) => {} // TODO figure out what to do here. } + // Ensure register is 0. + self.0[0] = 0; } } diff --git a/src/data_path.rs b/src/data_path.rs @@ -16,12 +16,18 @@ use config::Config; use cpu::{OutputPins, ProcessorStatusWord, RegisterFile, SIZEOF_INSTRUCTION}; -use instruction::noop; +use instruction::*; use memory::Memory; use std::fmt; use util::Result; use crate::cpu; +use crate::instruction::DEST_LOC; +use crate::instruction::IMM19_LOC; +use crate::instruction::RS1_LOC; +use crate::instruction::RS2_LOC; +use crate::instruction::SCC_LOC; +use crate::instruction::SHORT_SOURCE_TYPE_LOC; /// RISC II emulated data path. #[derive(Debug, Clone)] @@ -48,7 +54,10 @@ pub struct DataPath { pins_in: u32, /// Pins for communicating with the outside world (memory). output_pins: OutputPins, - + /// Input latch 1 for the ALU (fed by src1). + ai: u32, + /// Input latch 2 for the ALU (fed by src2). + bi: u32, // Control unit latches and registers. /// Data from memory. dimm: u32, @@ -64,10 +73,14 @@ pub struct DataPath { rd2: u8, /// Destination register address (for commiting/previous instruction). rd3: u8, - /// Source register one. - ra: u8, - /// Source register two. - rb: u8, + /// Source register one (for instruction being decoded). + rs1_1: u8, + /// Source register two (for instruction being decoded). + rs2_1: u8, + /// Source register one (for currently executing instruction). + rs1_2: u8, + /// Source register two (for currently executing instruction). + rs2_2: u8, /// Opcode register (for instruction being decoded). op1: u8, /// Opcode register (for currently executing instruction). @@ -97,12 +110,16 @@ impl DataPath { psw: ProcessorStatusWord::new(), src_latch: 0, dst_latch: 0, + ai: 0, + bi: 0, bar: 0, rd1: 0, rd2: 0, rd3: 0, - ra: 0, - rb: 0, + rs1_1: 0, + rs2_1: 0, + rs1_2: 0, + rs2_2: 0, op1: 0, op2: 0, dimm: 0, @@ -128,6 +145,16 @@ impl DataPath { self.regs.write(dest_reg, dest_value, cwp); } + pub fn route_regs_to_alu(&mut self) { + let src1 = self.rs1_2; + let src2 = self.rs1_2; + let cwp = self.psw.get_cwp(); + let read1 = self.regs.read(src1, cwp); + let read2 = self.regs.read(src2, cwp); + self.ai = read1; + self.bi = read2; + } + /// Decode the next instruction's (in `self.pins_in`) source registers. pub fn decode_input_regs(&mut self) { let next_instruction = self.pins_in; @@ -135,6 +162,14 @@ impl DataPath { pub fn set_input_pins(&mut self, value: u32) { self.pins_in = value; + // Set other latches hooked up to memory data path. + self.op1 = ((value & 0xFE000000) >> 25) as u8; + self.imm_flag1 = value & SHORT_SOURCE_TYPE_LOC != 0; + self.scc_flag1 = value & SCC_LOC != 0; + self.rd1 = ((value & DEST_LOC) >> 19) as u8; + self.rs1_1 = ((value & RS1_LOC) >> 14) as u8; + self.rs2_1 = (value & RS2_LOC) as u8; + self.imm1 = value & IMM19_LOC; } pub fn get_out_address(&self) -> u32 { diff --git a/src/instruction.rs b/src/instruction.rs @@ -26,6 +26,7 @@ use crate::data_path; pub const SCC_LOC: u32 = 0x1000000; pub const DEST_LOC: u32 = 0x00F80000; pub const RS1_LOC: u32 = 0x7c000; +pub const RS2_LOC: u32 = 0x1f; pub const IMM19_LOC: u32 = 0x7FFFF; pub const SHORT_SOURCE_TYPE_LOC: u32 = 0x2000; diff --git a/src/system.rs b/src/system.rs @@ -68,17 +68,24 @@ impl System { let dp = &mut self.data_path; self.phase = match self.phase { - Phase::One => Phase::Two, + Phase::One => { + // Registers are read and then send to the input latches of the ALU. + dp.route_regs_to_alu(); + Phase::Two + } Phase::Two => { + // Memory copies output pin data for writing (if any writing is to be done). dp.get_output_pins_ref().phase_two_copy(&mut self.pins_out); - Phase::Two + + // Route sources and immediate thru shifter. + Phase::Three } Phase::Three => { // Finish read from last cycle. let mem = &self.mem; let addr = self.pins_out.address; // TODO check for invalid address from MMU. - self.data_path.set_input_pins(match mem.get_word(addr) { + dp.set_input_pins(match mem.get_word(addr) { Ok(v) => v, Err(_) => { eprint!("Bad mem read: {}", addr); @@ -89,7 +96,8 @@ impl System { Phase::Four } Phase::Four => { - dp.decode_input_regs(); + // In actual RISCII this is where the source and dest registers are decoded + // for the next instruction, but that is unnecessary here. self.pins_out.address = dp.get_out_address(); Phase::One }