Skip to content

Commit a4711b6

Browse files
committed
load hazard handled
1 parent d256837 commit a4711b6

File tree

2 files changed

+66
-23
lines changed

2 files changed

+66
-23
lines changed

pipelined/verilog/cpu_pipelined.v

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ module cpu_pipelined(
4343
wire branch_mispredicted;
4444
wire flush;
4545

46+
// Add a one-cycle stall flag for load hazards
47+
reg stalled_last_cycle;
48+
4649
// Program Counter
4750
wire [63:0] pc_next;
4851
wire [63:0] pc_current;
@@ -75,7 +78,6 @@ module cpu_pipelined(
7578
// Key change: Use branch prediction only for branch instructions
7679
assign predicted_pc = branch_predicted ? if_branch_target : (pc_current + 4);
7780

78-
7981
wire nop_instruction;
8082
assign nop_instruction = (instruction == 32'b0);
8183

@@ -88,12 +90,18 @@ module cpu_pipelined(
8890

8991
wire [31:0] instr_to_use = flush ? 32'h00000013 : instruction; // NOP when flush
9092

93+
// Updated to handle one-cycle stall
9194
if_id_register if_id(
9295
.clk(clk),
9396
.reset(reset | flush),
94-
// No stall on branch taken to ensure target instruction proceeds
95-
.en(~stall | branch_predicted),
96-
.d({pc_current, instr_to_use, nop_instruction, branch_predicted, predicted_pc}),
97+
.en(~stall | stalled_last_cycle | branch_predicted), // Enable if we stalled last cycle
98+
.d({
99+
pc_current,
100+
stall & ~stalled_last_cycle ? 32'h00000013 : instr_to_use, // Insert NOP during initial stall
101+
stall & ~stalled_last_cycle ? 1'b1 : nop_instruction,
102+
branch_predicted,
103+
predicted_pc
104+
}),
97105
.q({if_id_pc, if_id_instruction, if_id_nop_instruction, if_id_branch_predicted, if_id_predicted_pc})
98106
);
99107

@@ -143,16 +151,27 @@ module cpu_pipelined(
143151
wire id_ex_branch_predicted;
144152
wire [63:0] id_ex_predicted_pc;
145153

154+
// Load hazard detection
146155
wire [4:0] id_ex_rd = id_ex_instruction[11:7];
156+
// Only detect hazard if we haven't stalled for it already
147157
wire load_hazard = id_ex_mem_read &
148158
((id_ex_rd == rs1) | (id_ex_rd == rs2)) &
149-
(id_ex_rd != 0);
159+
(id_ex_rd != 0) &
160+
~stalled_last_cycle;
150161
wire stall = load_hazard;
151162

163+
// Stalled cycle tracking
164+
always @(posedge clk or posedge reset) begin
165+
if (reset)
166+
stalled_last_cycle <= 1'b0;
167+
else
168+
stalled_last_cycle <= stall; // Track if we stalled in the previous cycle
169+
end
170+
152171
id_ex_register id_ex(
153172
.clk(clk),
154173
.reset(reset | flush),
155-
.en(~stall),
174+
.en(~stall | stalled_last_cycle), // Always enable after one stall cycle
156175
.d({
157176
if_id_pc,
158177
reg_read_data1,
@@ -186,26 +205,48 @@ module cpu_pipelined(
186205
);
187206

188207
// Forwarding Logic (EX stage)
189-
reg [1:0] forwardA, forwardB;
190208
wire [4:0] ex_mem_rd = ex_mem_instruction[11:7];
191209
wire [4:0] mem_wb_rd = mem_wb_instruction[11:7];
192210
wire [4:0] id_ex_rs1 = id_ex_instruction[19:15];
193211
wire [4:0] id_ex_rs2 = id_ex_instruction[24:20];
194-
212+
213+
// Improved forwarding logic
214+
reg [1:0] forwardA, forwardB;
215+
195216
always @(*) begin
196-
forwardA = 2'b00;
197-
if (ex_mem_reg_write && ex_mem_rd != 0 && ex_mem_rd == id_ex_rs1)
198-
forwardA = 2'b10;
199-
else if (mem_wb_reg_write && mem_wb_rd != 0 && mem_wb_rd == id_ex_rs1)
200-
forwardA = 2'b01;
217+
forwardA = 2'b00; // Default: no forwarding
218+
219+
// Most recent data (EX/MEM) except in case of loads
220+
if (ex_mem_reg_write && ex_mem_rd != 0 && ex_mem_rd == id_ex_rs1) begin
221+
// Special handling: don't forward from EX/MEM if it's a load (data not ready yet)
222+
if (!ex_mem_mem_to_reg)
223+
forwardA = 2'b10; // Forward from EX/MEM
224+
end
225+
226+
// Data from MEM/WB (includes load results)
227+
if (mem_wb_reg_write && mem_wb_rd != 0 && mem_wb_rd == id_ex_rs1) begin
228+
// Always forward from MEM/WB if matching
229+
// This overrides EX/MEM forwarding for loads (after stall)
230+
forwardA = 2'b01; // Forward from MEM/WB
231+
end
201232
end
202233

203234
always @(*) begin
204-
forwardB = 2'b00;
205-
if (ex_mem_reg_write && ex_mem_rd != 0 && ex_mem_rd == id_ex_rs2)
206-
forwardB = 2'b10;
207-
else if (mem_wb_reg_write && mem_wb_rd != 0 && mem_wb_rd == id_ex_rs2)
208-
forwardB = 2'b01;
235+
forwardB = 2'b00; // Default: no forwarding
236+
237+
// Most recent data (EX/MEM) except in case of loads
238+
if (ex_mem_reg_write && ex_mem_rd != 0 && ex_mem_rd == id_ex_rs2) begin
239+
// Special handling: don't forward from EX/MEM if it's a load (data not ready yet)
240+
if (!ex_mem_mem_to_reg)
241+
forwardB = 2'b10; // Forward from EX/MEM
242+
end
243+
244+
// Data from MEM/WB (includes load results)
245+
if (mem_wb_reg_write && mem_wb_rd != 0 && mem_wb_rd == id_ex_rs2) begin
246+
// Always forward from MEM/WB if matching
247+
// This overrides EX/MEM forwarding for loads (after stall)
248+
forwardB = 2'b01; // Forward from MEM/WB
249+
end
209250
end
210251

211252
// ALU Operand Forwarding
@@ -282,12 +323,11 @@ module cpu_pipelined(
282323
// Flush pipeline on misprediction
283324
assign flush = branch_mispredicted & ~id_ex_branch_predicted;
284325

285-
// 2. Fix PC selection logic - ensure branch target instructions proceed correctly
286-
wire [63:0] pc_to_use = stall ? pc_current :
326+
// PC update with stall for exactly one cycle then force progress
327+
wire [63:0] pc_to_use = stall & ~stalled_last_cycle ? pc_current :
287328
(branch_mispredicted ? correct_pc : predicted_pc);
288329
assign pc_next = pc_to_use;
289330

290-
291331
// EX/MEM Pipeline Register
292332
ex_mem_register ex_mem(
293333
.clk(clk),

pipelined/verilog/testbench_pipelined.v

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ module testbench_pipelined();
1616
reset = 1;
1717

1818
// Initialize instruction memory first
19-
cpu.imem.memory[0] = 32'b00000000000000000010000100000011;
20-
cpu.imem.memory[1] = 32'b00000000000000000000000000000000;
19+
cpu.imem.memory[0] = 32'b00000000010100000000000010010011;
20+
cpu.imem.memory[1] = 32'b00000000000100001000000100010011;
21+
cpu.imem.memory[2] = 32'b00000000000100000000000110110011;
22+
cpu.imem.memory[3] = 32'b00000000000100001000001000010011;
23+
cpu.imem.memory[4] = 32'b00000000000000000000000000000000;
2124

2225
// promper initialization
2326
#10 reset = 0;

0 commit comments

Comments
 (0)