Work on Branch instruction support
ADD
branchnoforwarding.bin
branchnoforwarding.bin
Binary files /dev/null and b/branchnoforwarding.bin differ

MODIFY
src/mainmemory.h
src/mainmemory.h
@@ -22,7 +22,7 @@ public:
((*this)[address + 3] << 24));
return read;
}
- void reset(int textSize) {
+ void reset(uint32_t textSize) {
// Reset memory - erase all elements which is not part of the textsegment of the program
for (auto it = this->begin(); it != this->end();) {
// Use standard associative-container erasing. If erased, set iterator to iterator after the erased value

MODIFY
src/parser.cpp
src/parser.cpp
@@ -206,6 +206,8 @@ QString Parser::generateOpInstrString(uint32_t instr) const {
} else {
return QString("and x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
}
+ default:
+ return QString("Unknown instruction");
}
}
@@ -213,6 +215,10 @@ QString Parser::generateOpImmString(uint32_t instr) const {
std::vector<uint32_t> fields = decodeIInstr(instr);
switch (fields[2]) {
case 0b000: // ADDI
+ if (fields[3] == 0 && fields[1] == 0) {
+ // nop special case
+ return QString("nop");
+ }
return QString("addi x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(signextend<int32_t, 12>(fields[0]));
case 0b001: // SLLI
return QString("slli x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(fields[0] & 0b11111);

MODIFY
src/pipeline.cpp
src/pipeline.cpp
#include "parser.h"
+#include <QDebug>
+
Pipeline::Pipeline() {
// Connect pipeline
// ------ IF ---------
// Connect alu to PC and a constant "4" signal, and set operator to "Add"
- c_4 = Signal<32>(4);
alu_pc4.setInputs(r_PC_IF.getOutput(), &c_4);
alu_pc4.setControl(&s_alu_const_add);
- r_PC_IF.setInput(alu_pc4.getOutput());
- r_instr_IFID.setInput(&instr_IF);
+ r_PC_IF.setInput(mux_PCSrc.getOutput());
+ r_instr_IFID.setInput(&s_instr_IF);
+ r_instr_IFID.setReset(&s_PCSrc);
+ mux_PCSrc.setControl(&s_PCSrc);
+ mux_PCSrc.setInput(0, alu_pc4.getOutput());
+ mux_PCSrc.setInput(1, alu_pc_target.getOutput());
// ------ ID ---------
m_reg.setInputs(r_instr_IFID.getOutput(), r_writeReg_MEMWB.getOutput(), mux_memToReg.getOutput(),
@@ -21,6 +26,9 @@ Pipeline::Pipeline() {
r_rd2_IDEX.setInput(m_reg.getOutput(2));
r_writeReg_IDEX.setInput(&writeReg);
+ alu_pc_target.setControl(&s_alu_const_add);
+ alu_pc_target.setInputs(r_PC_IDEX.getOutput(), &imm_ID_shifted);
+
// Control signals
r_regWrite_IDEX.setInput(&s_RegWrite);
r_ALUOP_IDEX.setInput(&s_ALUOP);
@@ -67,7 +75,7 @@ Pipeline::Pipeline() {
}
void Pipeline::immGen() {
- if ((uint32_t)r_instr_IFID & 0b1111111 == 0b0110111) {
+ if (((uint32_t)r_instr_IFID & 0b1111111) == 0b0110111) {
// LUI
imm_ID = Signal<32>((uint32_t)r_instr_IFID & 0xfffff000);
} else {
@@ -94,6 +102,7 @@ void Pipeline::immGen() {
}
}
}
+ imm_ID_shifted = imm_ID; //((uint32_t)imm_ID) << 1;
}
namespace {
@@ -102,25 +111,41 @@ namespace {
s_MemToReg = 0; \
s_RegWrite = 1; \
s_MemRead = 0; \
- s_MemWrite = 0;
+ s_MemWrite = 0; \
+ s_Branch = 0; \
+ s_CompOp = 0;
#define CTRL_R_TYPE \
s_ALUSrc = 0; \
s_MemToReg = 0; \
s_RegWrite = 1; \
s_MemRead = 0; \
- s_MemWrite = 0;
+ s_MemWrite = 0; \
+ s_Branch = 0; \
+ s_CompOp = 0;
+
#define CTRL_STORE \
s_ALUSrc = 1; \
s_MemToReg = 0; \
s_RegWrite = 0; \
- s_MemRead = 0;
+ s_MemRead = 0; \
+ s_Branch = 0; \
+ s_CompOp = 0;
#define CTRL_LOAD \
s_ALUSrc = 1; \
s_MemToReg = 1; \
s_RegWrite = 1; \
- s_MemWrite = 0;
+ s_MemWrite = 0; \
+ s_Branch = 0; \
+ s_CompOp = 0;
+
+#define CTRL_BRANCH \
+ s_ALUSrc = 0; \
+ s_MemToReg = 0; \
+ s_RegWrite = 0; \
+ s_MemWrite = 0; \
+ s_Branch = 1;
}
void Pipeline::controlGen() {
@@ -294,6 +319,44 @@ void Pipeline::controlGen() {
CTRL_STORE
break;
}
+ case 0b1100011: {
+ // Branch instruction
+ auto fields = Parser::getParser()->decodeBInstr((uint32_t)r_instr_IFID);
+ switch (fields[4]) {
+ case 0b000: {
+ // BEQ
+ s_CompOp = CompOp::BEQ;
+ break;
+ }
+ case 0b001: {
+ // BNE
+ s_CompOp = CompOp::BNE;
+ break;
+ }
+ case 0b100: {
+ // BLT
+ s_CompOp = CompOp::BLT;
+ break;
+ }
+ case 0b101: {
+ // BGE
+ s_CompOp = CompOp::BGE;
+ break;
+ }
+ case 0b110: {
+ // BLTU
+ s_CompOp = CompOp::BLTU;
+ break;
+ }
+ case 0b111: {
+ // BGEU
+ s_CompOp = CompOp::BGEU;
+ break;
+ }
+ }
+ CTRL_BRANCH
+ break;
+ }
default: {
s_ALUOP = 0;
s_ALUSrc = 0;
@@ -301,6 +364,8 @@ void Pipeline::controlGen() {
s_RegWrite = 0;
s_MemRead = 0;
s_MemWrite = 0;
+ s_Branch = 0;
+ s_CompOp = 0;
break;
}
}
@@ -346,13 +411,47 @@ void Pipeline::propagateCombinational() {
// ----- ID -----
controlGen();
immGen();
+ alu_pc_target.update();
m_reg.update();
writeReg = Signal<5>(((uint32_t)r_instr_IFID >> 7) & 0b11111);
+ // Compare read register values and '&' with s_branch control signal
+ switch ((CompOp)(int)s_CompOp) {
+ case BEQ: {
+ s_PCSrc = s_Branch && ((uint32_t)*m_reg.getOutput(1) == (uint32_t)*m_reg.getOutput(2));
+ break;
+ }
+ case BNE: {
+ s_PCSrc = s_Branch && ((uint32_t)*m_reg.getOutput(1) != (uint32_t)*m_reg.getOutput(2));
+ break;
+ }
+ case BLT: {
+ s_PCSrc = s_Branch && ((int32_t)*m_reg.getOutput(1) < (int32_t)*m_reg.getOutput(2));
+ break;
+ }
+ case BLTU: {
+ s_PCSrc = s_Branch && ((uint32_t)*m_reg.getOutput(1) < (uint32_t)*m_reg.getOutput(2));
+ break;
+ }
+ case BGE: {
+ s_PCSrc = s_Branch && ((int32_t)*m_reg.getOutput(1) >= (int32_t)*m_reg.getOutput(2));
+ break;
+ }
+ case BGEU: {
+ s_PCSrc = s_Branch && ((uint32_t)*m_reg.getOutput(1) >= (uint32_t)*m_reg.getOutput(2));
+ break;
+ }
+ default: { s_PCSrc = 0; }
+ }
+
// ----- IF -----
alu_pc4.update();
+ mux_PCSrc.update();
+ if ((uint32_t)s_PCSrc == 1) {
+ qDebug() << "a";
+ }
// Load nops if PC is greater than text size
- instr_IF = Signal<32>(
+ s_instr_IF = Signal<32>(
(uint32_t)r_PC_IF > m_textSize ? 0 : m_memory.read((uint32_t)r_PC_IF)); // Read instruction at current PC
}

MODIFY
src/pipeline.h
src/pipeline.h
@@ -50,8 +50,9 @@ private:
// Combinatorial items & signals
ALU<32> alu_pc4 = ALU<32>("ADD PC 4"); // ALU for incrementing PC by 4
- Signal<32> c_4 = Signal<32>("4");
-
+ Signal<32> c_4 = Signal<32>(4, "4");
+ Mux<2, 32> mux_PCSrc;
+ Signal<1> s_PCSrc;
ALU<32> alu_pc_target = ALU<32>("ALU PC target"); // ALU for PC target computation
ALU<32> alu_mainALU = ALU<32>("Main ALU"); // Arithmetic ALU
@@ -61,7 +62,8 @@ private:
Signal<1> ctrl_memToReg;
Signal<32> imm_ID = Signal<32>("Immediate");
- Signal<32> instr_IF = Signal<32>("Instruction");
+ Signal<32> imm_ID_shifted = Signal<32>("Immediate SL1");
+ Signal<32> s_instr_IF = Signal<32>("Instruction");
Signal<32> readData_MEM;
// Registers
@@ -85,10 +87,12 @@ private:
(uint32_t)ALUDefs::OPCODE::ADD); // A constant "ADD" control signal, to turn an ALU into an adder
Signal<3> s_MemRead;
Signal<2> s_MemWrite;
- Signal<1> s_RegWrite, s_ALUSrc, s_MemToReg;
+ Signal<1> s_RegWrite, s_ALUSrc, s_MemToReg, s_Branch;
Signal<ALUDefs::CTRL_SIZE> s_ALUOP;
+ Signal<3> s_CompOp;
// Control signal enums
+ enum CompOp { BEQ = 1, BNE = 2, BLT = 3, BLTU = 4, BGE = 5, BGEU = 6 };
enum MemRead { LB = 1, LH = 2, LW = 3, LBU = 4, LHU = 5 };
enum MemWrite { SB = 1, SH = 2, SW = 3 };
};

MODIFY
src/pipelineobjects.h
src/pipelineobjects.h
@@ -72,6 +72,7 @@ private:
// The Reg class is used for sequential signal assignment. Has a single input/output of a given signal size.
// Upon construction, new registers are added to "registers", which is used when clocking the pipeline
+// input reset is a synchronous reset
class RegBase {
public:
static std::vector<RegBase*> registers;
@@ -109,9 +110,18 @@ public:
explicit operator uint32_t() const { return (uint32_t)m_current; }
explicit operator bool() const { return (bool)m_current; }
void setInput(const Signal<n>* in) { m_next = in; }
+ void setReset(const Signal<1>* in) { m_reset = in; }
protected:
- void clock() override { m_current = m_nextSaved; }
+ void clock() override {
+ if (m_reset == nullptr)
+ m_current = m_nextSaved;
+ else if ((bool)*m_reset == true) {
+ m_current = 0;
+ } else {
+ m_current = m_nextSaved;
+ }
+ }
void save() override {
assert(m_next != nullptr);
m_nextSaved = *m_next;
@@ -124,11 +134,10 @@ protected:
private:
Signal<n> m_current;
Signal<n> m_nextSaved;
+ const Signal<1>* m_reset;
const Signal<n>* m_next;
};
-// Multiplexor class
-// the output of the multiplexor is dependant of the input select signal
template <int inputs, int n>
class Combinational {
public:
@@ -161,6 +170,8 @@ protected:
}
};
+// Multiplexor class
+// the output of the multiplexor is dependant of the input select signal
template <int inputs, int n>
class Mux : public Combinational<inputs, n> {
public:

Work on Branch instruction support