summaryrefslogtreecommitdiff
path: root/verilog/datapath.v
diff options
context:
space:
mode:
Diffstat (limited to 'verilog/datapath.v')
-rw-r--r--verilog/datapath.v249
1 files changed, 249 insertions, 0 deletions
diff --git a/verilog/datapath.v b/verilog/datapath.v
new file mode 100644
index 0000000..1992e75
--- /dev/null
+++ b/verilog/datapath.v
@@ -0,0 +1,249 @@
+`default_nettype none
+`timescale 1ns/1ps
+
+module datapath
+(
+ input wire clk, rst
+);
+
+// Pipeline Signals
+wire stall_f;
+wire stall_d;
+wire flush_d;
+wire flush_e;
+wire [1:0] r1forward_e, r2forward_e;
+
+// Fetch Signals
+wire [31:0] pc_f;
+wire [31:0] pc_4_f = pc_f + 4;
+wire [31:0] pc_new = branch_pc ? pc_b_j : pc_4_f;
+
+// Decode Signals
+// From fetch
+reg [31:0] instr_d;
+reg [31:0] pc_d, pc_4_d;
+// Controller Decode Signals
+wire wb_pc_d, wb_mem_d;
+wire wr_mem_d, wr_reg_d;
+wire [4:0] alu_op_d;
+wire alu_1_d, alu_2_d;
+wire branch_d, jump_d, jump_r_d;
+wire [3:0] i_b_j_u;
+// Register Signals
+wire [31:0] r1data_d, r2data_d;
+wire [4:0] waddr_d = instr_d[11:7];
+wire [4:0] r1addr_d = instr_d[19:15];
+wire [4:0] r2addr_d = instr_d[24:20];
+// Immediate Generation
+wire [31:0] imm_d;
+
+// Execute Signals
+// PC and PC+4
+reg [31:0] pc_e, pc_4_e;
+// Control Signals
+reg wb_pc_e, wb_mem_e;
+reg wr_mem_e, wr_reg_e;
+reg [4:0] alu_op_e;
+reg alu_1_e, alu_2_e;
+reg branch_e, jump_e, jump_r_e;
+// Registers
+reg [31:0] r1data_e, r2data_e;
+reg [4:0] waddr_e, r1addr_e, r2addr_e;
+//Immediate
+reg [31:0] imm_e;
+// ALU signals
+wire [31:0] r1forward_reg_e = r1forward_e[1] ? reg_write_w : (r1forward_e[0] ? alu_out_m : r1data_e);
+wire [31:0] r2forward_reg_e = r2forward_e[1] ? reg_write_w : (r2forward_e[0] ? alu_out_m : r2data_e);
+wire [31:0] alu_in_1 = alu_1_e ? r1forward_reg_e : pc_e;
+wire [31:0] alu_in_2 = alu_2_e ? r2forward_reg_e : imm_e;
+wire [31:0] alu_out_e;
+// Control flow signals
+wire alu_branch;
+wire branch_pc = jump_e | (branch_e & alu_branch);
+wire [31:0] pc_b_j = imm_e + (jump_r_e ? r1data_e : pc_e);
+
+// Memory Signals
+// PC+4
+reg [31:0] pc_4_m;
+// Control Signals
+reg wb_pc_m, wb_mem_m;
+reg wr_mem_m, wr_reg_m;
+//Registers
+reg [31:0] r2data_m;
+reg [4:0] waddr_m;
+// ALU Out
+reg [31:0] alu_out_m;
+
+// WB signals
+// Reg write back
+reg wb_pc_w, wb_mem_w;
+reg wr_reg_w;
+reg [4:0] waddr_w;
+reg [31:0] pc_4_w;
+reg [31:0] alu_out_w, mem_out_w;
+wire [31:0] reg_write_w = wb_pc_w ? pc_4_w : (wb_mem_w ? mem_out_w : alu_out_w);
+
+
+always @ (posedge clk) begin
+
+ // IF/ID Pipeline Stage
+ if (flush_d) begin
+ // Insert NOP
+ instr_d <= 32'b0000000000000000000000010011;
+ pc_d <= 32'hXXXXXXXX;
+ pc_4_d <= 32'hXXXXXXXX;
+ end
+ else if (stall_d) begin
+ instr_d <= instr_d;
+ pc_d <= pc_d;
+ pc_4_d <= pc_4_d;
+ end
+ else begin
+ pc_d <= pc_f;
+ pc_4_d <= pc_4_f;
+ end
+
+ // ID/IE stage
+ // These Control signals don't affect arch state if left alone
+ // So don't need to be flushed
+ pc_e <= pc_d;
+ pc_4_e <= pc_4_d;
+ wb_pc_e <= wb_pc_d;
+ wb_mem_e <= wb_mem_d;
+ alu_op_e <= alu_op_d;
+ alu_1_e <= alu_1_d;
+ alu_2_e <= alu_2_d;
+ r1data_e <= r1data_d;
+ r2data_e <= r2data_d;
+ r1addr_e <= r1addr_d;
+ r2addr_e <= r2addr_d;
+ waddr_e <= waddr_d;
+ imm_e <= imm_d;
+ if (flush_e) begin
+
+ wr_mem_e <= 1'b0;
+ wr_reg_e <= 1'b0;
+ branch_e <= 1'b0;
+ jump_e <= 1'b0;
+ jump_r_e <= 1'b0;
+ end
+ else begin
+ wr_mem_e <= wr_mem_d;
+ wr_reg_e <= wr_reg_d;
+ branch_e <= branch_d;
+ jump_e <= jump_d;
+ jump_r_e <= jump_r_d;
+ end
+
+ // IE/M Stage
+ // Never flushed or stalled
+ pc_4_m <= pc_4_e;
+ wb_pc_m <= wb_pc_e;
+ wb_mem_m <= wb_mem_e;
+ wr_reg_m <= wr_reg_e;
+ wr_mem_m <= wr_mem_e;
+ waddr_m <= waddr_e;
+ r2data_m <= r2forward_reg_e;
+ alu_out_m <= alu_out_e;
+
+ // M/W Stage
+ // Never flushed or stalled
+ pc_4_w <= pc_4_m;
+ wb_pc_w <= wb_pc_m;
+ wb_mem_w <= wb_mem_m;
+ wr_reg_w <= wr_reg_m;
+ waddr_w <= waddr_m;
+ alu_out_w <= alu_out_m;
+end
+
+
+// Pipeline Control
+hazard hazard0
+(
+ .r1addr_e(r1addr_e), .r2addr_e(r2addr_e),
+ .waddr_e(waddr_e), .waddr_m(waddr_m), .waddr_w(waddr_w),
+ .wr_reg_m(wr_reg_m), .wr_reg_w(wr_reg_w),
+ .r1forward_e(r1forward_e), .r2forward_e(r2forward_e),
+ .r1addr_d(r1addr_d), .r2addr_d(r2addr_d),
+ .wb_mem_e(wb_mem_e),
+ .stall_f(stall_f), .stall_d(stall_d), .flush_e(flush_e), .flush_d(flush_d),
+ .branch_pc(branch_pc)
+);
+
+// FETCH STAGE
+
+pc pc0(
+ .clk(clk), .we(~stall_f), .rst(rst),
+ .pc_new(pc_new), .pc(pc_f)
+);
+
+memory #(.ADDR_WIDTH(8), .FILE_NAME("instr_mem.mem")) instr_mem
+(
+ .clk(clk), .we(1'b0),
+ .be(4'b1111),
+ .addr(pc_f[7:0]),
+ .din(32'b0),
+ .dout(instr_d)
+);
+
+// DECODE STAGE
+
+decode dec0
+(
+ .opcode(instr_d[6:2]), .func3(instr_d[14:12]), .func7(instr_d[31]),
+ .wb_pc_d(wb_pc_d), .wb_mem_d(wb_mem_d),
+ .wr_mem_d(wr_mem_d), .wr_reg_d(wr_reg_d),
+ .alu_op_d(alu_op_d), .alu_1_d(alu_1_d), .alu_2_d(alu_2_d),
+ .branch_d(branch_d), .jump_d(jump_d), .jump_r_d(jump_r_d),
+ .i_b_j_u(i_b_j_u)
+);
+
+regfile reg0
+(
+ .clk(clk), .we(wr_reg_w),
+ .waddr(waddr_w), .wdata(reg_write_w),
+ .r1addr(r1addr_d), .r2addr(r2addr_d), .r1data(r1data_d), .r2data(r2data_d)
+);
+
+immediate imm0
+(
+ .instr(instr_d[31:7]),
+ .i(i_b_j_u[3]), .b(i_b_j_u[2]), .j(i_b_j_u[1]), .u(i_b_j_u[0]),
+ .imm(imm_d)
+);
+
+// EXECUTE STAGE
+
+alu alu0
+(
+ .A(alu_in_1),
+ .B(alu_in_2),
+ .C(alu_out_e),
+ .OP(alu_op_e),
+ .Branch(alu_branch)
+);
+
+// MEMORY STAGE
+memory #(.ADDR_WIDTH(8), .FILE_NAME("data_mem.mem")) data_mem
+(
+ .clk(clk), .we(wr_mem_m),
+ .be(4'b1111), // TODO Add support for smaller byte writes
+ .addr(alu_out_m[7:0]),
+ .din(r2data_m),
+ .dout(mem_out_w)
+);
+
+// WB Stage has no modules only a mux
+
+
+// Debug Waveforms
+`ifdef verilator
+
+initial begin
+ $dumpfile("./log_datapath/datapath.vcd");
+ $dumpvars(0, datapath);
+end
+
+`endif
+
+endmodule