Fix some bugs, too tired to list them, look at the diff
This commit is contained in:
parent
0766ec6f8a
commit
f8aad6d2f3
|
@ -108,6 +108,8 @@ wire [W_ADDR-1:0] x_btb_set_src_addr;
|
||||||
wire [W_ADDR-1:0] x_btb_set_target_addr;
|
wire [W_ADDR-1:0] x_btb_set_target_addr;
|
||||||
wire x_btb_clear;
|
wire x_btb_clear;
|
||||||
|
|
||||||
|
wire [W_ADDR-1:0] d_btb_target_addr;
|
||||||
|
|
||||||
assign bus_aph_panic_i = 1'b0;
|
assign bus_aph_panic_i = 1'b0;
|
||||||
|
|
||||||
wire f_mem_size;
|
wire f_mem_size;
|
||||||
|
@ -138,6 +140,7 @@ hazard3_frontend #(
|
||||||
.btb_set_src_addr (x_btb_set_src_addr),
|
.btb_set_src_addr (x_btb_set_src_addr),
|
||||||
.btb_set_target_addr (x_btb_set_target_addr),
|
.btb_set_target_addr (x_btb_set_target_addr),
|
||||||
.btb_clear (x_btb_clear),
|
.btb_clear (x_btb_clear),
|
||||||
|
.btb_target_addr_out (d_btb_target_addr),
|
||||||
|
|
||||||
.cir (fd_cir),
|
.cir (fd_cir),
|
||||||
.cir_err (fd_cir_err),
|
.cir_err (fd_cir_err),
|
||||||
|
@ -226,6 +229,7 @@ hazard3_decode #(
|
||||||
.x_stall (x_stall),
|
.x_stall (x_stall),
|
||||||
.f_jump_now (f_jump_now),
|
.f_jump_now (f_jump_now),
|
||||||
.f_jump_target (f_jump_target),
|
.f_jump_target (f_jump_target),
|
||||||
|
.d_btb_target_addr (d_btb_target_addr),
|
||||||
|
|
||||||
.d_imm (d_imm),
|
.d_imm (d_imm),
|
||||||
.d_rs1 (d_rs1),
|
.d_rs1 (d_rs1),
|
||||||
|
@ -738,7 +742,8 @@ wire x_jump_req_unchecked = !x_stall_on_raw && (
|
||||||
assign x_jump_req = x_jump_req_unchecked && !x_jump_misaligned && !x_exec_pmp_fail;
|
assign x_jump_req = x_jump_req_unchecked && !x_jump_misaligned && !x_exec_pmp_fail;
|
||||||
|
|
||||||
assign x_btb_set = |BRANCH_PREDICTOR && (
|
assign x_btb_set = |BRANCH_PREDICTOR && (
|
||||||
x_jump_req_unchecked && d_addr_offs[W_ADDR - 1] && !x_branch_was_predicted
|
x_jump_req_unchecked && d_addr_offs[W_ADDR - 1] && !x_branch_was_predicted &&
|
||||||
|
(d_branchcond == BCOND_NZERO || d_branchcond == BCOND_ZERO)
|
||||||
);
|
);
|
||||||
|
|
||||||
assign x_btb_clear = d_fence_i || (m_trap_enter_vld && m_trap_enter_rdy) || (|BRANCH_PREDICTOR && (
|
assign x_btb_clear = d_fence_i || (m_trap_enter_vld && m_trap_enter_rdy) || (|BRANCH_PREDICTOR && (
|
||||||
|
|
|
@ -30,6 +30,7 @@ module hazard3_decode #(
|
||||||
input wire f_jump_now,
|
input wire f_jump_now,
|
||||||
input wire [W_ADDR-1:0] f_jump_target,
|
input wire [W_ADDR-1:0] f_jump_target,
|
||||||
input wire x_jump_not_except,
|
input wire x_jump_not_except,
|
||||||
|
input wire [W_ADDR-1:0] d_btb_target_addr,
|
||||||
|
|
||||||
output reg [W_DATA-1:0] d_imm,
|
output reg [W_DATA-1:0] d_imm,
|
||||||
output reg [W_REGADDR-1:0] d_rs1,
|
output reg [W_REGADDR-1:0] d_rs1,
|
||||||
|
@ -123,31 +124,39 @@ always @ (posedge clk or negedge rst_n) begin
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
reg [W_ADDR-1:0] pc;
|
reg [W_ADDR-1:0] pc;
|
||||||
wire [W_ADDR-1:0] pc_next = pc + (d_instr_is_32bit ? 32'h4 : 32'h2);
|
wire [W_ADDR-1:0] pc_seq_next = pc + (d_instr_is_32bit ? 32'h4 : 32'h2);
|
||||||
assign d_pc = pc;
|
assign d_pc = pc;
|
||||||
|
|
||||||
|
wire predicted_branch = fd_cir_predbranch[d_instr_is_32bit] && |BRANCH_PREDICTOR;
|
||||||
|
|
||||||
always @ (posedge clk or negedge rst_n) begin
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
if (!rst_n) begin
|
if (!rst_n) begin
|
||||||
pc <= RESET_VECTOR;
|
pc <= RESET_VECTOR;
|
||||||
end else begin
|
end else begin
|
||||||
if ((f_jump_now && !assert_cir_lock) || (cir_lock_prev && deassert_cir_lock)) begin
|
if ((f_jump_now && !assert_cir_lock) || (cir_lock_prev && deassert_cir_lock)) begin
|
||||||
pc <= f_jump_target;
|
pc <= f_jump_target;
|
||||||
`ifdef FORMAL
|
|
||||||
// Being cheeky above to save a 32 bit mux. Check that we never get an M target by mistake.
|
|
||||||
|
|
||||||
// FIXME disabled this for now -- we do sometimes see an exception taking
|
|
||||||
// place during the stall, which then leads to a different branch target
|
|
||||||
// appearing. (i.e. f_jump_now is asserted for two cycles, the first one
|
|
||||||
// from this instruction and the second from the exception; this is ok,
|
|
||||||
// because the exception will return to this branch when done.)
|
|
||||||
|
|
||||||
// if (cir_lock_prev && deassert_cir_lock)
|
|
||||||
// assert(f_jump_target == d_jump_target);
|
|
||||||
`endif
|
|
||||||
end else if (!d_stall && !cir_lock) begin
|
end else if (!d_stall && !cir_lock) begin
|
||||||
pc <= pc_next;
|
// If this instruction is a predicted-taken branch (and has not
|
||||||
|
// generated a mispredict recovery jump) then set PC to the
|
||||||
|
// prediction target instead of the sequentially next PC
|
||||||
|
pc <= predicted_branch ? d_btb_target_addr : pc_seq_next;
|
||||||
end
|
end
|
||||||
|
// If the current instruction is marked as being a predicted-taken
|
||||||
|
// branch, it *must* be a valid branch instruction, because executing
|
||||||
|
// the branch is how we recover from misprediction
|
||||||
|
`ifdef FORMAL
|
||||||
|
// This can be defeated if you branch backward halfway into a 32-bit instruction that immediately precedes the branch.
|
||||||
|
if (predicted_branch && !d_starved && !debug_mode) begin
|
||||||
|
assert(!d_invalid);
|
||||||
|
assert(d_branchcond == BCOND_ZERO || d_branchcond == BCOND_NZERO);
|
||||||
|
end
|
||||||
|
if (&fd_cir_predbranch && !d_instr_is_32bit) begin
|
||||||
|
// Only way to get two back-to-back predicted-taken instructions
|
||||||
|
// is if they are the same instruction
|
||||||
|
assert(d_btb_target_addr == pc);
|
||||||
|
end
|
||||||
|
`endif
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ module hazard3_frontend #(
|
||||||
input wire [W_ADDR-1:0] btb_set_src_addr,
|
input wire [W_ADDR-1:0] btb_set_src_addr,
|
||||||
input wire [W_ADDR-1:0] btb_set_target_addr,
|
input wire [W_ADDR-1:0] btb_set_target_addr,
|
||||||
input wire btb_clear,
|
input wire btb_clear,
|
||||||
|
output wire [W_ADDR-1:0] btb_target_addr_out,
|
||||||
|
|
||||||
// Interface to Decode
|
// Interface to Decode
|
||||||
// Note reg/wire distinction
|
// Note reg/wire distinction
|
||||||
|
@ -181,12 +182,14 @@ if (BRANCH_PREDICTOR) begin: have_btb
|
||||||
btb_src_addr <= {W_ADDR{1'b0}};
|
btb_src_addr <= {W_ADDR{1'b0}};
|
||||||
btb_target_addr <= {W_ADDR{1'b0}};
|
btb_target_addr <= {W_ADDR{1'b0}};
|
||||||
btb_valid <= 1'b0;
|
btb_valid <= 1'b0;
|
||||||
|
end else if (btb_clear) begin
|
||||||
|
// Clear takes precedences over set. E.g. if a taken branch is in
|
||||||
|
// stage 2 and an exception is in stage 3, we must clear the BTB.
|
||||||
|
btb_valid <= 1'b0;
|
||||||
end else if (btb_set) begin
|
end else if (btb_set) begin
|
||||||
btb_src_addr <= btb_set_src_addr;
|
btb_src_addr <= btb_set_src_addr;
|
||||||
btb_target_addr <= btb_set_target_addr;
|
btb_target_addr <= btb_set_target_addr;
|
||||||
btb_valid <= 1'b1;
|
btb_valid <= 1'b1;
|
||||||
end else if (btb_clear) begin
|
|
||||||
btb_valid <= 1'b0;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end else begin: no_btb
|
end else begin: no_btb
|
||||||
|
@ -198,6 +201,17 @@ end else begin: no_btb
|
||||||
end
|
end
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
||||||
|
// Decode uses the target address to set the PC to the correct branch target
|
||||||
|
// value following a predicted-taken branch (as normally it would update PC
|
||||||
|
// by following an X jump request, and in this case there is none).
|
||||||
|
//
|
||||||
|
// Note this assumes the BTB target has not changed by the time the predicted
|
||||||
|
// branch arrives at decode! This is always true because the only way for the
|
||||||
|
// target address to change is when an older branch is taken, which would
|
||||||
|
// flush the younger predicted-taken branch before it reaches decode.
|
||||||
|
|
||||||
|
assign btb_target_addr_out = btb_target_addr;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Fetch request generation
|
// Fetch request generation
|
||||||
|
|
||||||
|
@ -330,25 +344,30 @@ always @ (posedge clk or negedge rst_n) begin
|
||||||
mem_data_hwvld <= 2'b11;
|
mem_data_hwvld <= 2'b11;
|
||||||
mem_aph_hwvld <= 2'b11;
|
mem_aph_hwvld <= 2'b11;
|
||||||
mem_data_predbranch <= 1'b0;
|
mem_data_predbranch <= 1'b0;
|
||||||
end else if (EXTENSION_C) begin
|
end else begin
|
||||||
if (jump_now) begin
|
if (jump_now) begin
|
||||||
if (mem_addr_rdy) begin
|
if (|EXTENSION_C) begin
|
||||||
mem_data_hwvld <= {1'b1, !jump_target[1]};
|
if (mem_addr_rdy) begin
|
||||||
end else begin
|
mem_data_hwvld <= {1'b1, !jump_target[1]};
|
||||||
mem_aph_hwvld <= {1'b1, !jump_target[1]};
|
end else begin
|
||||||
|
mem_aph_hwvld <= {1'b1, !jump_target[1]};
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
mem_data_predbranch <= 1'b0;
|
||||||
end else if (mem_addr_vld && mem_addr_rdy) begin
|
end else if (mem_addr_vld && mem_addr_rdy) begin
|
||||||
// If a predicted-taken branch instruction only spans the first
|
if (|EXTENSION_C) begin
|
||||||
// half of a word, need to flag the second half as invalid.
|
// If a predicted-taken branch instruction only spans the first
|
||||||
mem_data_hwvld <= mem_aph_hwvld & {
|
// half of a word, need to flag the second half as invalid.
|
||||||
!(|BRANCH_PREDICTOR && btb_match_now && !btb_src_addr[1]),
|
mem_data_hwvld <= mem_aph_hwvld & {
|
||||||
1'b1
|
!(|BRANCH_PREDICTOR && btb_match_now && !btb_src_addr[1]),
|
||||||
};
|
1'b1
|
||||||
// Also need to take the alignment of the destination into account.
|
};
|
||||||
mem_aph_hwvld <= {
|
// Also need to take the alignment of the destination into account.
|
||||||
1'b1,
|
mem_aph_hwvld <= {
|
||||||
!(|BRANCH_PREDICTOR && btb_match_now && btb_target_addr[1])
|
1'b1,
|
||||||
};
|
!(|BRANCH_PREDICTOR && btb_match_now && btb_target_addr[1])
|
||||||
|
};
|
||||||
|
end
|
||||||
mem_data_predbranch <= |BRANCH_PREDICTOR && btb_match_now;
|
mem_data_predbranch <= |BRANCH_PREDICTOR && btb_match_now;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -397,7 +416,6 @@ wire [3*W_BUNDLE-1:0] instr_data_plus_fetch =
|
||||||
// may be buffered in the prefetch queue.
|
// may be buffered in the prefetch queue.
|
||||||
|
|
||||||
wire fetch_bus_err = fifo_empty ? mem_data_err : fifo_err[0];
|
wire fetch_bus_err = fifo_empty ? mem_data_err : fifo_err[0];
|
||||||
wire fetch_predbranch = fifo_empty ? mem_data_predbranch : fifo_predbranch[0];
|
|
||||||
|
|
||||||
reg [2:0] cir_bus_err;
|
reg [2:0] cir_bus_err;
|
||||||
wire [2:0] cir_bus_err_shifted =
|
wire [2:0] cir_bus_err_shifted =
|
||||||
|
@ -413,6 +431,10 @@ wire [2:0] cir_bus_err_plus_fetch =
|
||||||
// And the same thing again for whether CIR contains a predicted-taken branch.
|
// And the same thing again for whether CIR contains a predicted-taken branch.
|
||||||
// One day I should clean up this copy/paste.
|
// One day I should clean up this copy/paste.
|
||||||
|
|
||||||
|
wire fetch_predbranch = fifo_empty ? mem_data_predbranch : fifo_predbranch[0];
|
||||||
|
// We mark only the last halfword of the branch instruction as being predicted.
|
||||||
|
wire [1:0] fetch_predbranch_hw = &fetch_data_hwvld ? {fetch_predbranch, 1'b0} : {1'b0, fetch_predbranch};
|
||||||
|
|
||||||
reg [2:0] cir_predbranch_reg;
|
reg [2:0] cir_predbranch_reg;
|
||||||
wire [2:0] cir_predbranch_shifted =
|
wire [2:0] cir_predbranch_shifted =
|
||||||
cir_use[1] ? cir_predbranch_reg >> 2 :
|
cir_use[1] ? cir_predbranch_reg >> 2 :
|
||||||
|
@ -420,9 +442,9 @@ wire [2:0] cir_predbranch_shifted =
|
||||||
|
|
||||||
wire [2:0] cir_predbranch_plus_fetch =
|
wire [2:0] cir_predbranch_plus_fetch =
|
||||||
!cir_room_for_fetch ? cir_predbranch_shifted :
|
!cir_room_for_fetch ? cir_predbranch_shifted :
|
||||||
level_next_no_fetch[1] && |EXTENSION_C ? {fetch_predbranch, cir_predbranch_shifted[1:0]} :
|
level_next_no_fetch[1] && |EXTENSION_C ? {fetch_predbranch_hw[0], cir_predbranch_shifted[1:0]} :
|
||||||
level_next_no_fetch[0] && |EXTENSION_C ? {{2{fetch_predbranch}}, cir_predbranch_shifted[0]} :
|
level_next_no_fetch[0] && |EXTENSION_C ? {fetch_predbranch_hw, cir_predbranch_shifted[0]} :
|
||||||
{cir_predbranch_shifted[2], {2{fetch_predbranch}}};
|
{cir_predbranch_shifted[2], fetch_predbranch_hw};
|
||||||
|
|
||||||
wire [1:0] fetch_fill_amount = cir_room_for_fetch && fetch_data_vld ? (
|
wire [1:0] fetch_fill_amount = cir_room_for_fetch && fetch_data_vld ? (
|
||||||
&fetch_data_hwvld ? 2'h2 : 2'h1
|
&fetch_data_hwvld ? 2'h2 : 2'h1
|
||||||
|
|
|
@ -59,7 +59,12 @@ assign expect_cir[31:16] = instr_mem[(d_pc + 2) / 4] >> (d_pc[1] ? 0 : 16);
|
||||||
// Note we can get a mismatch in the upper halfword during a CIR lock of a
|
// Note we can get a mismatch in the upper halfword during a CIR lock of a
|
||||||
// jump in the lower halfword -- the fetch will tumble into the top and this
|
// jump in the lower halfword -- the fetch will tumble into the top and this
|
||||||
// is fine as long as we correctly update the PC when the lock clears.
|
// is fine as long as we correctly update the PC when the lock clears.
|
||||||
wire allow_upper_half_mismatch = fd_cir[15:0] == expect_cir[15:0] && fd_cir[1:0] != 2'b11;
|
|
||||||
|
// Note also following a predicted branch the upper half of CIR may be
|
||||||
|
// nonsequential, so we can't check it.
|
||||||
|
wire allow_upper_half_mismatch = fd_cir[15:0] == expect_cir[15:0] && (
|
||||||
|
fd_cir[1:0] != 2'b11 || fd_cir_predbranch[0]
|
||||||
|
);
|
||||||
|
|
||||||
always @ (posedge clk) if (rst_n) begin
|
always @ (posedge clk) if (rst_n) begin
|
||||||
if (fd_cir_vld >= 2'd1)
|
if (fd_cir_vld >= 2'd1)
|
||||||
|
|
Loading…
Reference in New Issue