properly flushes pipeline after jump

This commit is contained in:
2020-11-06 23:18:37 -07:00
parent c25b9bcb0f
commit 1290418aa3
4 changed files with 126 additions and 97 deletions

View File

@ -64,6 +64,10 @@ module core(
output dummy_out
);
parameter PIPELINED = 1;
localparam INST_NOP = 32'h00000013; // nop
// Register File
reg [31:0] regfile [0:31];
initial begin : init_regfile
@ -75,10 +79,8 @@ end
// Registers
reg [31:0] r_if_pc = 0, r_id_pc, r_ex_pc, r_mem_pc, r_wb_pc;
reg r_id_stall, r_ex_stall, r_mem_stall, r_wb_stall;
reg [31:0] r_id_inst, r_ex_inst, r_mem_inst, r_wb_inst;
reg [4:0] r_ex_rd, r_mem_rd, r_wb_rd;
reg r_ex_alu_seed;
reg [3:0] r_ex_aluop;
reg [31:0] r_ex_s1, r_ex_s2, r_mem_s1, r_mem_s2;
reg [31:0] r_mem_alu_out, r_wb_alu_out;
@ -86,22 +88,23 @@ reg r_mem_alu_zero;
reg r_ex_jump;
reg r_ex_store, r_mem_store;
reg r_ex_load, r_mem_load;
reg [31:0] r_mem_wdata, r_wb_wdata;
reg r_id_valid=0, r_ex_valid=0, r_mem_valid=0, r_wb_valid=0;
// IF
reg s_if_halt;
reg s_if_stall = 0;
reg [31:0] s_if_next_pc;
reg [31:0] s_if_inst;
reg s_if_stall;
always @(*) begin
s_if_halt = 0;
s_if_stall = s_id_stall || 0;
if (r_ex_jump) begin
if (r_ex_jump && r_ex_valid) begin
s_if_next_pc = s_ex_alu_out;
s_if_stall = 1'b1;
// s_if_stall = 1'b1;
end else begin
s_if_next_pc = r_if_pc + 4;
s_if_stall = 1'b0;
// s_if_stall = 1'b0;
end
mem_inst_addr = r_if_pc;
@ -109,7 +112,7 @@ always @(*) begin
end
// ID
reg s_id_halt;
reg s_id_stall;
reg [6:0] s_id_opcode;
reg [2:0] s_id_funct3;
reg [6:0] s_id_funct7;
@ -117,7 +120,6 @@ reg [4:0] s_id_rd, s_id_rs1, s_id_rs2;
reg [31:0] s_id_immed_itype, s_id_immed_stype, s_id_immed_utype, s_id_immed_btype, s_id_immed_jtype;
reg [31:0] s_id_s1, s_id_s2;
reg [3:0] s_id_aluop;
reg s_id_alu_seed;
reg s_id_invalid;
reg s_id_jump, s_id_branch;
reg s_id_store, s_id_load;
@ -154,7 +156,7 @@ localparam ALUOP_ADD = 4'b0000,
always @(*) begin
s_id_halt = 0;
s_id_stall = s_ex_stall || 0;
s_id_invalid = 0;
s_id_store = 0;
s_id_load = 0;
@ -272,21 +274,20 @@ always @(*) begin
if (s_id_invalid) begin
$display("%0t:\tInvalid instruction at PC=0x%h", $time, r_id_pc);
s_id_halt = 1'b1;
s_id_aluop = 3'hx;
s_id_alu_seed = 1'bx;
end
end
// EX
reg s_ex_halt;
reg s_ex_stall;
reg [31:0] s_ex_data1, s_ex_data2;
reg [31:0] s_ex_alu_out;
reg s_ex_alu_zero;
reg [31:0] s_ex_ra;
reg [31:0] s_ex_wdata;
always @(*) begin
s_ex_halt = 0;
s_ex_stall = s_mem_stall || 0;
// NOTE: s_ex_data* exist for adding data paths bypassing regfile in the future
s_ex_data1 = r_ex_s1;
@ -324,21 +325,25 @@ always @(*) begin
s_ex_alu_out = s_ex_data1 < s_ex_data2;
end
default: begin
s_ex_halt = 1;
s_ex_alu_out = 32'hxxxxxxxx;
end
endcase
s_ex_alu_zero = (s_ex_alu_out == 0);
s_ex_ra = r_ex_pc + 4;
if (r_ex_jump) begin
s_ex_wdata = s_ex_ra;
end else begin
s_ex_wdata = s_ex_alu_out;
end
end
// MEM
reg s_mem_halt;
reg s_mem_stall;
reg s_mem_bp;
always @(*) begin
s_mem_halt = 0;
s_mem_stall = s_wb_stall || 0;
s_mem_bp = 0;
// if (r_mem_store) begin
@ -357,74 +362,93 @@ always @(*) begin
end
// WB
reg s_wb_halt;
reg s_wb_stall;
reg [31:0] s_wb_data;
reg s_wb_write;
always @(*) begin
s_wb_halt = 0;
s_wb_stall = 1'b0;
// load instructions do not use output of alu in wb
s_wb_data = r_wb_alu_out;
s_wb_data = r_wb_wdata;
// FIXME: always writes!!!
s_wb_write = !r_wb_stall;
s_wb_write = 1; //!s_wb_stall;
end
// SYS
reg s_sys_halt;
always @(*) begin
s_sys_halt = s_if_halt || s_id_halt || s_ex_halt || s_mem_halt || s_wb_halt;
end
// Register update
always @(posedge clk) begin
always @(posedge clk) begin: pipeline_update
integer i;
if (reset) begin
r_if_pc <= 32'h00000000;
// rather than resetting all flip-flops just stall the pipeline so values are ignored.
r_id_stall <= 1;
r_ex_stall <= 1;
r_mem_stall <= 1;
r_wb_stall <= 1;
r_id_pc <= 0;
r_id_inst <= INST_NOP;
r_ex_pc <= 0;
r_ex_inst <= INST_NOP;
r_ex_rd <= 0;
r_ex_s1 <= 0;
r_ex_s2 <= 0;
r_ex_aluop <= 0;
r_ex_jump <= 0;
r_ex_store <= 0;
r_ex_load <= 0;
r_mem_pc <= 0;
r_mem_inst <= INST_NOP;
r_mem_rd <= 0;
r_mem_s1 <= 0;
r_mem_s2 <= 0;
r_mem_alu_out <= 0;
r_mem_alu_zero <= 0;
r_mem_store <= 0;
r_mem_load <= 0;
r_mem_wdata <= 0;
r_wb_pc <= 0;
r_wb_inst <= INST_NOP;
r_wb_rd <= 0;
r_wb_alu_out <= 0;
r_wb_wdata <= 0;
for (i=1; i<32; i=i+1) begin
regfile[i] <= 0;
end
end else begin
// NOTE: halt disabled because startup causes hault
// if (s_sys_halt && 0) begin
// // stay halted forever
// end else begin
// IF
// if (!s_mem_bp) begin
if (!s_if_stall) begin
r_if_pc <= s_if_next_pc;
// end
end
// ID
// if (!s_mem_bp) begin
r_id_stall <= s_if_stall;
if (!s_id_stall) begin
r_id_pc <= r_if_pc;
r_id_inst <= s_if_inst;
// end
r_id_valid <= ~(r_ex_jump && r_ex_valid);
end
// EX
// if (!s_mem_bp) begin
if (!s_ex_stall) begin
// TODO: also stall EX if taking branch
r_ex_stall <= r_id_stall;
r_ex_pc <= r_id_pc;
r_ex_inst <= r_id_inst;
r_ex_rd <= s_id_rd;
r_ex_s1 <= s_id_s1;
r_ex_s2 <= s_id_s2;
r_ex_aluop <= s_id_aluop;
r_ex_alu_seed <= s_id_alu_seed;
r_ex_jump <= s_id_jump;
r_ex_store <= s_id_store;
r_ex_load <= s_id_load;
// end
r_ex_valid <= r_id_valid && ~(r_ex_jump && r_ex_valid);
end
// MEM
// if (!s_mem_bp) begin
r_mem_stall <= r_ex_stall;
if (!s_mem_stall) begin
r_mem_pc <= r_ex_pc;
r_mem_inst <= r_ex_inst;
r_mem_rd <= r_ex_rd;
@ -434,21 +458,25 @@ always @(posedge clk) begin
r_mem_alu_zero <= s_ex_alu_zero;
r_mem_store <= r_ex_store;
r_mem_load <= r_ex_load;
// end
r_mem_wdata <= s_ex_wdata;
r_mem_valid <= r_ex_valid;
end
// WB
// if (!s_mem_bp) begin
r_wb_stall <= r_mem_stall;
if (!s_wb_stall) begin
r_wb_pc <= r_mem_pc;
r_wb_inst <= r_mem_inst;
r_wb_rd <= r_mem_rd;
r_wb_alu_out <= r_mem_alu_out;
// end
r_wb_wdata <= r_mem_wdata;
r_wb_valid <= r_mem_valid;
end
// Register File
if (r_wb_rd != 0 && s_wb_write) begin
// TODO: should I write if s_wb_stall=1?
if (r_wb_rd != 0 && s_wb_write && r_wb_valid) begin
regfile[r_wb_rd] <= s_wb_data;
end
// end
end
end