@@ -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),
0 commit comments