commit fc978975c6fb9a3fddd5dbb64cfdfd0bcc3ee9ee
parent 883e60896e55db7a2f512ca411fc1036dbc086d4
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date: Sat, 15 Oct 2022 13:03:11 -0700
Add more pipeline steps
Diffstat:
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
}