Skip to content

Commit

Permalink
Added implementation for Decode Stage
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanCostea committed Nov 30, 2024
1 parent 5c17f7f commit 25dc906
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 16 deletions.
91 changes: 79 additions & 12 deletions src/core/cpu/isa/Instruction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
#include <utility>
#include "utils/bitutils.hpp"

//Values are the opcodes for the matching instructions
enum class InstructionFormat {
R_TYPE,
I_TYPE,
S_TYPE,
B_TYPE,
U_TYPE,
J_TYPE
R_TYPE = 0x33,
I_TYPE = 0x13,
S_TYPE = 0x23,
B_TYPE = 0x63,
U_TYPE = 0x37,
J_TYPE = 0x6F,
INIVALID_TYPE = 0xFF
};

// Combines bit ranges from the instruction into a single immediate value
Expand All @@ -28,14 +30,50 @@ constexpr int32_t get_combined_immediate(const Instruction& instr,
return immediate;
}

// Base class for decoded instructions
class DecodedInstructionBase {
public:
static constexpr InstructionFormat format = InstructionFormat::INIVALID_TYPE;
union {
uint32_t raw; // Full 32-bit raw instruction
struct {
uint32_t opcode : 7; // Bits [6:0]
uint32_t rest : 25; // Bits [31:7]
};
};

DecodedInstructionBase() = default;

explicit DecodedInstructionBase(uint32_t raw_instruction) : raw(raw_instruction) {}

virtual ~DecodedInstructionBase() = default;
virtual uint32_t get_opcode() const {
return opcode;
}
};

// Base template for DecodedInstruction
template <InstructionFormat Format>
class DecodedInstruction;

//Specialization fro invalid type (just for initilization and throwing exceptions when something is not working properly)
template <>
class DecodedInstruction<InstructionFormat::INIVALID_TYPE> : public DecodedInstructionBase {
public:
static constexpr InstructionFormat format = InstructionFormat::INIVALID_TYPE;

explicit DecodedInstruction(uint32_t raw_instruction) : DecodedInstructionBase(raw_instruction) {}

uint32_t get_opcode() const override {
throw std::runtime_error("Attempting to access an invalid instruction format");
}
};

// Specialization for R-type instructions
template <>
class DecodedInstruction<InstructionFormat::R_TYPE> {
class DecodedInstruction<InstructionFormat::R_TYPE> : DecodedInstructionBase{
public:
static constexpr InstructionFormat format = InstructionFormat::R_TYPE;
union {
uint32_t raw; // Full 32-bit raw instruction
struct {
Expand All @@ -49,12 +87,17 @@ class DecodedInstruction<InstructionFormat::R_TYPE> {
};

explicit DecodedInstruction(uint32_t instruction) : raw(instruction) {}

uint32_t get_opcode() const override {
return opcode;
}
};

// Specialization for I-type instructions
template <>
class DecodedInstruction<InstructionFormat::I_TYPE> {
class DecodedInstruction<InstructionFormat::I_TYPE> : DecodedInstructionBase{
public:
static constexpr InstructionFormat format = InstructionFormat::I_TYPE;
union {
uint32_t raw; // Full 32-bit raw instruction
struct {
Expand All @@ -74,12 +117,17 @@ class DecodedInstruction<InstructionFormat::I_TYPE> {
{31, 20} // Immediate field
}), 12);
}

uint32_t get_opcode() const override {
return opcode;
}
};

// Specialization for S-type instructions
template <>
class DecodedInstruction<InstructionFormat::S_TYPE> {
class DecodedInstruction<InstructionFormat::S_TYPE> : DecodedInstructionBase {
public:
static constexpr InstructionFormat format = InstructionFormat::S_TYPE;
union {
uint32_t raw; // Full 32-bit raw instruction
struct {
Expand All @@ -101,12 +149,17 @@ class DecodedInstruction<InstructionFormat::S_TYPE> {
{11, 7} // Lower immediate [4:0]
}), 12);
}

uint32_t get_opcode() const override {
return opcode;
}
};

// Specialization for B-type instructions
template <>
class DecodedInstruction<InstructionFormat::B_TYPE> {
class DecodedInstruction<InstructionFormat::B_TYPE> : DecodedInstructionBase {
public:
static constexpr InstructionFormat format = InstructionFormat::B_TYPE;
union {
uint32_t raw; // Full 32-bit raw instruction
struct {
Expand All @@ -132,12 +185,17 @@ class DecodedInstruction<InstructionFormat::B_TYPE> {
{7, 7} // imm[11]
}), 13);
}

uint32_t get_opcode() const override {
return opcode;
}
};

// Specialization for U-type instructions
template <>
class DecodedInstruction<InstructionFormat::U_TYPE> {
class DecodedInstruction<InstructionFormat::U_TYPE> : DecodedInstructionBase{
public:
static constexpr InstructionFormat format = InstructionFormat::U_TYPE;
union {
uint32_t raw; // Full 32-bit raw instruction
struct {
Expand All @@ -155,12 +213,17 @@ class DecodedInstruction<InstructionFormat::U_TYPE> {
{31, 12} // Immediate field
}) << 12; // Shift left by 12 bits
}

uint32_t get_opcode() const override {
return opcode;
}
};

// Specialization for J-type instructions
template <>
class DecodedInstruction<InstructionFormat::J_TYPE> {
class DecodedInstruction<InstructionFormat::J_TYPE> : DecodedInstructionBase{
public:
static constexpr InstructionFormat format = InstructionFormat::J_TYPE;
union {
uint32_t raw; // Full 32-bit raw instruction
struct {
Expand All @@ -184,4 +247,8 @@ class DecodedInstruction<InstructionFormat::J_TYPE> {
{19, 12} // imm[19:12]
}), 21);
}

uint32_t get_opcode() const override {
return opcode;
}
};
50 changes: 50 additions & 0 deletions src/core/cpu/pipeline/decode/DecodeStage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "DecodeStage.hpp"
#include <stdexcept>
#include <cstdint>

// Constructor
DecodeStage::DecodeStage(RegisterBank& register_bank)
: fetched_instruction(0), register_bank(register_bank), decoded_instruction(DecodedInstruction<InstructionFormat::INIVALID_TYPE>(0)){}

// Process the fetched instruction and decode it
void DecodeStage::process() {
// Extract the opcode from the fetched instruction
uint32_t opcode = DecodedInstructionBase(fetched_instruction).get_opcode();

InstructionFormat format = static_cast<InstructionFormat>(opcode);
// Decode the instruction based on the opcode
using enum InstructionFormat;

switch (format) {
case R_TYPE:
decoded_instruction = DecodedInstruction<R_TYPE>(fetched_instruction);
break;
case I_TYPE:
decoded_instruction = DecodedInstruction<I_TYPE>(fetched_instruction);
break;
case S_TYPE:
decoded_instruction = DecodedInstruction<S_TYPE>(fetched_instruction);
break;
case B_TYPE:
decoded_instruction = DecodedInstruction<B_TYPE>(fetched_instruction);
break;
case U_TYPE:
decoded_instruction = DecodedInstruction<U_TYPE>(fetched_instruction);
break;
case J_TYPE:
decoded_instruction = DecodedInstruction<J_TYPE>(fetched_instruction);
break;
default:
throw std::invalid_argument("Unsupported instruction format");
}
}

// Get the decoded instruction (This is the output)
const DecodedInstructionVariant& DecodeStage::get_decoded_instruction() const {
return decoded_instruction;
}

// Set the fetched instruction (from FetchStage output)
void DecodeStage::set_fetched_instruction(uint32_t instruction) {
fetched_instruction = instruction;
}
33 changes: 33 additions & 0 deletions src/core/cpu/pipeline/decode/DecodeStage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

#include <variant>
#include "core/cpu/pipeline/PipelineStage.hpp"
#include "core/cpu/register_bank/RegisterBank.hpp"
#include "core/cpu/isa/Instruction.hpp"

// Define the variant type to hold all possible instruction formats
using DecodedInstructionVariant = std::variant<
DecodedInstruction<InstructionFormat::INIVALID_TYPE>,
DecodedInstruction<InstructionFormat::R_TYPE>,
DecodedInstruction<InstructionFormat::I_TYPE>,
DecodedInstruction<InstructionFormat::S_TYPE>,
DecodedInstruction<InstructionFormat::B_TYPE>,
DecodedInstruction<InstructionFormat::U_TYPE>,
DecodedInstruction<InstructionFormat::J_TYPE>
>;

class DecodeStage : public PipelineStage {
private:
uint32_t fetched_instruction; // Instruction fetched in FetchStage
RegisterBank& register_bank; // Reference to the register bank
DecodedInstructionVariant decoded_instruction; // Decoded instruction

public:
DecodeStage(RegisterBank& register_bank);

void process() override;

const DecodedInstructionVariant& get_decoded_instruction() const;

void set_fetched_instruction(uint32_t fetched_instruction);
};
16 changes: 16 additions & 0 deletions src/core/cpu/pipeline/fetch/FetchStage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "FetchStage.hpp"

FetchStage::FetchStage(Memory& memory, uint32_t& program_counter)
: memory(memory), program_counter(program_counter), fetched_instruction(0) {}

void FetchStage::process() {
// Fetch the instruction from memory at the current program counter
fetched_instruction = memory.read(program_counter);

// Increment the program counter to point to the next instruction
program_counter += 4;
}

uint32_t FetchStage::get_fetched_instruction() {
return fetched_instruction;
}
8 changes: 4 additions & 4 deletions src/core/cpu/pipeline/fetch/FetchStage.hpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#pragma once
#include <cstdint>
#include "core/cpu/pipeline/PipelineStage.hpp"
#include "core/memory/Memory.hpp"
#include "core/cpu/register_bank/RegisterBank.hpp"

class FetchStage : public PipelineStage {
private:
Memory* memory;
RegisterBank* registers;
Memory& memory;
uint32_t& program_counter;
uint32_t fetched_instruction;

public:
FetchStage(Memory* memory, RegisterBank* registers);
FetchStage(Memory& memory, uint32_t& program_counter);
void process() override;
uint32_t get_fetched_instruction();
};

0 comments on commit 25dc906

Please sign in to comment.