`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