aboutsummaryrefslogtreecommitdiffstats
path: root/sources/hdl/verilog/exe_pipeline.v
diff options
context:
space:
mode:
authorAtaberk <olgunataberk@gmail.com>2022-09-25 17:22:03 +0200
committerAtaberk <olgunataberk@gmail.com>2022-09-25 17:22:03 +0200
commitdc0b3db1b4f1895a07e5fe280ee3790e87f97b9f (patch)
treeb47203aa281bdd959def4451c84d310cd9cf2e12 /sources/hdl/verilog/exe_pipeline.v
downloaddram-bender-dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f.tar.gz
Initial commit
Diffstat (limited to 'sources/hdl/verilog/exe_pipeline.v')
-rw-r--r--sources/hdl/verilog/exe_pipeline.v191
1 files changed, 191 insertions, 0 deletions
diff --git a/sources/hdl/verilog/exe_pipeline.v b/sources/hdl/verilog/exe_pipeline.v
new file mode 100644
index 0000000..e2111a3
--- /dev/null
+++ b/sources/hdl/verilog/exe_pipeline.v
@@ -0,0 +1,191 @@
+`include "parameters.vh"
+`include "encoding.vh"
+
+module exe_pipeline(
+ // common signals
+ input clk,
+ input rst,
+
+ // exe_pipeline <-> execution stage if
+ input exe_valid,
+ input [`EXE_UOP_WIDTH-1:0] exe_uop,
+ input [`IMEM_ADDR_WIDTH-1:0] exe_pc,
+
+ // branch unit if
+ output br_resolve,
+ output [`IMEM_ADDR_WIDTH-1:0] br_target,
+
+ // exe_pipeline <-> register file if
+ output wide_wen,
+ output [31:0] rf_wdata,
+ output rf_wen,
+ output [7:0] rf_raddr,
+ output [3:0] rf_waddr,
+ input [2*32-1:0] rf_rdata,
+ input [32*7-1:0] ddr_stat,
+
+ // exe_pipeline <-> scratchpad
+ output mem_wen,
+ output mem_ren,
+ output [9:0] mem_addr,
+ output [31:0] mem_wdata,
+ input [31:0] mem_rdata
+ );
+
+ // calculated at stage one, registers
+ reg s2_valid;
+ reg [`EXE_UOP_WIDTH-1:0] s2_uop;
+ reg [`IMEM_ADDR_WIDTH-1:0] s2_pc;
+ reg [3:0] s2_rs1;
+ reg [3:0] s2_rs2;
+ reg [3:0] s2_rt;
+ reg s2_wen;
+ reg s2_mem_ren;
+ reg s2_mem_wen;
+ reg s3_wen; // for loads
+ reg [3:0] s3_rt; // for loads
+ reg s2_wide_wen;
+ reg [31:0] s2_imd_r, s2_imd_ns;
+
+ // delayed branch resolution signals
+ // calculated at stage two, registers
+ reg s3_br_resolve;
+ reg [`IMEM_ADDR_WIDTH-1:0] s3_br_target;
+
+ // combinational elements
+ reg [31:0] s2_wdata;
+ wire [31:0] s2_rs1_data, s2_rs2_data;
+ reg [31:0] s2_mem_wdata;
+ reg [`IMEM_ADDR_WIDTH-1:0] fetch_pc;
+
+ assign wide_wen = s2_wide_wen;
+ assign rf_wdata = s3_wen ? mem_rdata : s2_wdata;
+ assign rf_wen = s2_wen || s3_wen;
+ assign rf_raddr[0+:4] = s2_rs1;
+ assign rf_raddr[4+:4] = s2_rs2;
+ assign rf_waddr = s3_wen ? s3_rt : s2_rt;
+
+ assign s2_rs1_data = rf_rdata[0+:32];
+ assign s2_rs2_data = rf_rdata[32+:32];
+ assign br_resolve = s3_br_resolve;
+ assign br_target = s3_br_target;
+
+ assign mem_addr = s2_rs1_data + s2_imd_r;
+ assign mem_wen = s2_mem_wen;
+ assign mem_ren = s2_mem_ren;
+ assign mem_wdata = s2_mem_wdata;
+
+ always @* begin
+ // stage one, decode immediate value
+ s2_mem_wen = `LOW;
+ s2_imd_ns = s2_imd_r;
+ fetch_pc = {`IMEM_ADDR_WIDTH{1'bX}};
+ s2_wdata = 32'bX;
+ s2_mem_wen = `LOW;
+ s2_mem_ren = `LOW;
+ if(exe_uop[`HAS_IMD]) begin
+ s2_imd_ns[15:0] = exe_uop[`IMD +: 16];
+ s2_imd_ns[31:16] = {16{`LOW}};
+ end
+ if(exe_uop[`IS_LI]) begin
+ s2_imd_ns[31:16] = exe_uop[`IMD2 +: 16];
+ end
+ if(exe_uop[`IS_BL] | exe_uop[`IS_BEQ]) begin
+ s2_imd_ns[31:0] = exe_uop[`IMD +: 19];
+ end
+ if(exe_uop[`IS_JUMP]) begin
+ s2_imd_ns[31:0] = exe_uop[`IMD +: 27];
+ end
+ // stage two, actual computation
+ if(s2_uop[`IS_ADD]) begin
+ if(s2_uop[`HAS_IMD])
+ s2_wdata = s2_rs1_data + s2_imd_r;
+ else
+ s2_wdata = s2_rs1_data + s2_rs2_data;
+ end
+ if(s2_uop[`IS_SUB]) begin
+ if(s2_uop[`HAS_IMD])
+ s2_wdata = s2_rs1_data - s2_imd_r;
+ else
+ s2_wdata = s2_rs1_data - s2_rs2_data;
+ end
+ if(s2_uop[`IS_MOV] || s2_uop[`IS_LDWD]) begin
+ s2_wdata = s2_rs1_data;
+ end
+ if(s2_uop[`IS_LI]) begin
+ s2_wdata = s2_imd_r;
+ end
+ if(s2_uop[`IS_LDPC]) begin
+ s2_wdata = ddr_stat[s2_rs1*32 +: 32];
+ end
+ if(s2_uop[`IS_SRC]) begin
+ s2_wdata[30:0] = s2_rs1_data[31:1];
+ s2_wdata[31] = s2_rs1_data[0];
+ end
+ // Bitwise ops
+ if(s2_uop[`IS_AND]) begin
+ s2_wdata = s2_rs1_data & s2_rs2_data;
+ end
+ if(s2_uop[`IS_OR]) begin
+ s2_wdata = s2_rs1_data | s2_rs2_data;
+ end
+ if(s2_uop[`IS_XOR]) begin
+ s2_wdata = s2_rs1_data ^ s2_rs2_data;
+ end
+ // mem unit
+ if(s2_uop[`IS_LD]) begin
+ s2_mem_ren = `HIGH;
+ end
+ if(s2_uop[`IS_ST]) begin
+ s2_mem_wdata = s2_rs2_data;
+ s2_mem_wen = `HIGH;
+ end
+
+ // branch unit
+ if(s2_uop[`IS_BL]) begin
+ if(s2_rs1_data < s2_rs2_data)
+ fetch_pc = s2_imd_r;
+ else // not taken
+ fetch_pc = s2_pc + 1;
+ end
+ if(s2_uop[`IS_BEQ]) begin
+ if(s2_rs1_data == s2_rs2_data)
+ fetch_pc = s2_imd_r;
+ else // not taken
+ fetch_pc = s2_pc + 1;
+ end
+ if(s2_uop[`IS_JUMP]) begin
+ fetch_pc = s2_imd_r;
+ end
+ if(s2_uop[`IS_SLEEP]) begin
+ // not implemented
+ // frontent/fetch handles api sleeps
+ end
+
+ end
+
+ always @(posedge clk) begin
+ // stage one, further decode
+ s2_valid <= exe_valid;
+ s2_uop <= exe_uop;
+ s2_pc <= exe_pc;
+ s2_rs1 <= exe_uop[`RS1 +: 4];
+ s2_rs2 <= exe_uop[`RS2 +: 4];
+ s2_rt <= exe_uop[`RT +: 4];
+ s2_imd_r <= s2_imd_ns;
+ s2_wen <= exe_uop[`IS_ADD] || exe_uop[`IS_SUB] ||
+ exe_uop[`IS_MOV] || exe_uop[`IS_LI] ||
+ exe_uop[`IS_LDWD] || exe_uop[`IS_SRC] ||
+ exe_uop[`IS_AND] || exe_uop[`IS_OR] ||
+ exe_uop[`IS_XOR] || exe_uop[`IS_LDPC];
+ s2_wide_wen <= exe_uop[`IS_LDWD];
+ // stage two, delayed branch signals
+ s3_br_resolve <= s2_valid && (s2_uop[`IS_BL] ||
+ s2_uop[`IS_BEQ] ||
+ s2_uop[`IS_JUMP]);
+ s3_br_target <= fetch_pc;
+ s3_wen <= s2_uop[`IS_LD]; // write path for loads
+ s3_rt <= s2_uop[`RT +: 4];
+ end
+
+endmodule