Re-rewrite frontend to track the halfword-validity of in-flight transfers, and clean up the old cir_lock mechanism to be a modified flush
This commit is contained in:
parent
e3da922f8b
commit
26d54d0023
|
@ -100,7 +100,7 @@ wire [31:0] fd_cir;
|
|||
wire [1:0] fd_cir_err;
|
||||
wire [1:0] fd_cir_vld;
|
||||
wire [1:0] df_cir_use;
|
||||
wire df_cir_lock;
|
||||
wire df_cir_flush_behind;
|
||||
|
||||
assign bus_aph_panic_i = 1'b0;
|
||||
|
||||
|
@ -132,7 +132,7 @@ hazard3_frontend #(
|
|||
.cir_err (fd_cir_err),
|
||||
.cir_vld (fd_cir_vld),
|
||||
.cir_use (df_cir_use),
|
||||
.cir_lock (df_cir_lock),
|
||||
.cir_flush_behind (df_cir_flush_behind),
|
||||
|
||||
.predecode_rs1_coarse (f_rs1_coarse),
|
||||
.predecode_rs2_coarse (f_rs2_coarse),
|
||||
|
@ -200,7 +200,7 @@ hazard3_decode #(
|
|||
.fd_cir_err (fd_cir_err),
|
||||
.fd_cir_vld (fd_cir_vld),
|
||||
.df_cir_use (df_cir_use),
|
||||
.df_cir_lock (df_cir_lock),
|
||||
.df_cir_flush_behind (df_cir_flush_behind),
|
||||
.d_pc (d_pc),
|
||||
.x_jump_not_except (x_jump_not_except),
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ module hazard3_decode #(
|
|||
input wire [1:0] fd_cir_err,
|
||||
input wire [1:0] fd_cir_vld,
|
||||
output wire [1:0] df_cir_use,
|
||||
output wire df_cir_lock,
|
||||
output wire df_cir_flush_behind,
|
||||
output wire [W_ADDR-1:0] d_pc,
|
||||
|
||||
input wire debug_mode,
|
||||
|
@ -113,13 +113,16 @@ wire assert_cir_lock = jump_caused_by_d && d_stall;
|
|||
wire deassert_cir_lock = !d_stall;
|
||||
reg cir_lock_prev;
|
||||
|
||||
assign df_cir_lock = (cir_lock_prev && !deassert_cir_lock) || assert_cir_lock;
|
||||
wire cir_lock = (cir_lock_prev && !deassert_cir_lock) || assert_cir_lock;
|
||||
assign df_cir_flush_behind = assert_cir_lock && !cir_lock_prev;
|
||||
|
||||
always @ (posedge clk or negedge rst_n)
|
||||
if (!rst_n)
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
cir_lock_prev <= 1'b0;
|
||||
else
|
||||
cir_lock_prev <= df_cir_lock;
|
||||
end else begin
|
||||
cir_lock_prev <= cir_lock;
|
||||
end
|
||||
end
|
||||
|
||||
reg [W_ADDR-1:0] pc;
|
||||
wire [W_ADDR-1:0] pc_next = pc + (d_instr_is_32bit ? 32'h4 : 32'h2);
|
||||
|
@ -143,7 +146,7 @@ always @ (posedge clk or negedge rst_n) begin
|
|||
// if (cir_lock_prev && deassert_cir_lock)
|
||||
// assert(f_jump_target == d_jump_target);
|
||||
`endif
|
||||
end else if (!d_stall && !df_cir_lock) begin
|
||||
end else if (!d_stall && !cir_lock) begin
|
||||
pc <= pc_next;
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
`default_nettype none
|
||||
|
||||
module hazard3_frontend #(
|
||||
parameter FIFO_DEPTH = 2, // power of 2, >= 1
|
||||
`include "hazard3_config.vh"
|
||||
) (
|
||||
input wire clk,
|
||||
|
@ -41,17 +40,17 @@ module hazard3_frontend #(
|
|||
// Note reg/wire distinction
|
||||
// => decode is providing live feedback on the CIR it is decoding,
|
||||
// which we fetched previously
|
||||
// This works OK because size is decoded from 2 LSBs of instruction, so cheap.
|
||||
output reg [31:0] cir,
|
||||
output reg [1:0] cir_vld, // number of valid halfwords in CIR
|
||||
input wire [1:0] cir_use, // number of halfwords D intends to consume
|
||||
// *may* be a function of hready
|
||||
output wire [1:0] cir_err, // Bus error on upper/lower halfword of CIR.
|
||||
input wire cir_lock,// Lock-in current contents and level of CIR.
|
||||
// Assert simultaneously with a jump request,
|
||||
// if decode is going to stall. This stops the CIR
|
||||
// from being trashed by incoming fetch data;
|
||||
// jump instructions have other side effects besides jumping!
|
||||
|
||||
// "flush_behind": do not flush the oldest instruction when accepting a
|
||||
// jump request (but still flush younger instructions). Sometimes a
|
||||
// stalled instruction may assert a jump request, because e.g. the stall
|
||||
// is dependent on a bus stall signal so can't gate the request.
|
||||
input wire cir_flush_behind,
|
||||
|
||||
// Provide the rs1/rs2 register numbers which will be in CIR next cycle.
|
||||
// Coarse: valid if this instruction has a nonzero register operand.
|
||||
|
@ -76,67 +75,74 @@ module hazard3_frontend #(
|
|||
`include "rv_opcodes.vh"
|
||||
|
||||
localparam W_BUNDLE = W_DATA / 2;
|
||||
parameter W_FIFO_LEVEL = $clog2(FIFO_DEPTH + 1);
|
||||
// This is the minimum for full throughput (enough to avoid dropping data when
|
||||
// decode stalls) and there is no significant advantage to going larger.
|
||||
localparam FIFO_DEPTH = 2;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Fetch Queue (FIFO)
|
||||
//
|
||||
// This is a little different from either a normal sync fifo or sync fwft fifo
|
||||
// so it's worth implementing from scratch
|
||||
|
||||
wire jump_now = jump_target_vld && jump_target_rdy;
|
||||
reg [1:0] mem_data_hwvld;
|
||||
|
||||
// mem has an extra entry which is equal to next-but-last entry, and valid has
|
||||
// an extra entry which is constant-0. These are just there to handle loop
|
||||
// boundary conditions.
|
||||
// Bus errors travel alongside data. They cause an exception if the core tries
|
||||
// to decode the instruction, but until then can be flushed harmlessly.
|
||||
|
||||
// err has an error (HRESP) bit associated with each FIFO entry, so that we
|
||||
// can correctly speculate and flush fetch errors. The error bit moves
|
||||
// through the prefetch queue alongside the corresponding bus data. We sample
|
||||
// bus errors like an extra data bit -- fetch continues to speculate forward
|
||||
// past an error, and we eventually flush and redirect the frontend if an
|
||||
// errored fetch makes it to the execute stage.
|
||||
reg [W_DATA-1:0] fifo_mem [0:FIFO_DEPTH];
|
||||
reg [FIFO_DEPTH:0] fifo_err;
|
||||
reg [1:0] fifo_valid_hw [0:FIFO_DEPTH];
|
||||
reg [FIFO_DEPTH:-1] fifo_valid;
|
||||
|
||||
reg [W_DATA-1:0] fifo_mem [0:FIFO_DEPTH];
|
||||
reg [FIFO_DEPTH:0] fifo_err;
|
||||
reg [FIFO_DEPTH:0] fifo_valid;
|
||||
wire [W_DATA-1:0] fifo_rdata = fifo_mem[0];
|
||||
wire fifo_full = fifo_valid[FIFO_DEPTH - 1];
|
||||
wire fifo_empty = !fifo_valid[0];
|
||||
wire fifo_almost_full = fifo_valid[FIFO_DEPTH - 2];
|
||||
|
||||
wire [W_DATA-1:0] fifo_wdata = mem_data;
|
||||
wire [W_DATA-1:0] fifo_rdata = fifo_mem[0];
|
||||
always @ (*) fifo_mem[FIFO_DEPTH] = fifo_wdata;
|
||||
wire fifo_push;
|
||||
wire fifo_pop;
|
||||
wire fifo_dbg_inject = DEBUG_SUPPORT && dbg_instr_data_vld && dbg_instr_data_rdy;
|
||||
|
||||
wire fifo_full = fifo_valid[FIFO_DEPTH - 1];
|
||||
wire fifo_empty = !fifo_valid[0];
|
||||
wire fifo_almost_full = FIFO_DEPTH == 1 || (!fifo_valid[FIFO_DEPTH - 1] && fifo_valid[FIFO_DEPTH - 2]);
|
||||
|
||||
wire fifo_push;
|
||||
wire fifo_pop;
|
||||
wire fifo_dbg_inject = DEBUG_SUPPORT && dbg_instr_data_vld && dbg_instr_data_rdy;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
fifo_valid <= {FIFO_DEPTH+1{1'b0}};
|
||||
end else if (jump_now) begin
|
||||
fifo_valid <= {FIFO_DEPTH+1{1'b0}};
|
||||
end else if (fifo_push || fifo_pop || fifo_dbg_inject) begin
|
||||
fifo_valid <= {1'b0, ~(~fifo_valid << (fifo_push || fifo_dbg_inject)) >> fifo_pop};
|
||||
always @ (*) begin: boundary_conditions
|
||||
integer i;
|
||||
fifo_mem[FIFO_DEPTH] = mem_data;
|
||||
fifo_valid_hw[FIFO_DEPTH] = 2'b00;
|
||||
fifo_valid[FIFO_DEPTH] = 1'b0;
|
||||
fifo_valid[-1] = 1'b1;
|
||||
for (i = 0; i < FIFO_DEPTH; i = i + 1) begin
|
||||
fifo_valid[i] = |EXTENSION_C ? |fifo_valid_hw[i] : fifo_valid_hw[i][0];
|
||||
end
|
||||
end
|
||||
|
||||
always @ (posedge clk) begin: fifo_data_shift
|
||||
always @ (posedge clk or negedge rst_n) begin: fifo_update
|
||||
integer i;
|
||||
for (i = 0; i < FIFO_DEPTH; i = i + 1) begin
|
||||
if (fifo_pop || (fifo_push && !fifo_valid[i])) begin
|
||||
fifo_mem[i] <= fifo_valid[i + 1] ? fifo_mem[i + 1] : fifo_wdata;
|
||||
fifo_err[i] <= fifo_err[i + 1] ? fifo_err[i + 1] : mem_data_err;
|
||||
if (!rst_n) begin
|
||||
for (i = 0; i < FIFO_DEPTH; i = i + 1) begin
|
||||
fifo_valid_hw[i] <= 2'b00;
|
||||
fifo_mem[i] <= 32'h0;
|
||||
fifo_err[i] <= 1'b0;
|
||||
end
|
||||
end else begin
|
||||
for (i = 0; i < FIFO_DEPTH; i = i + 1) begin
|
||||
if (fifo_pop || (fifo_push && !fifo_valid[i])) begin
|
||||
fifo_mem[i] <= fifo_valid[i + 1] ? fifo_mem[i + 1] : mem_data;
|
||||
fifo_err[i] <= fifo_valid[i + 1] ? fifo_err[i + 1] : mem_data_err;
|
||||
end
|
||||
fifo_valid_hw[i] <=
|
||||
jump_now ? 2'h0 :
|
||||
fifo_valid[i + 1] && fifo_pop ? fifo_valid_hw[i + 1] :
|
||||
fifo_valid[i] && fifo_pop && !fifo_push ? 2'h0 :
|
||||
fifo_valid[i] && fifo_pop && fifo_push ? mem_data_hwvld :
|
||||
!fifo_valid[i] && fifo_valid[i - 1] && fifo_push && !fifo_pop ? mem_data_hwvld : fifo_valid_hw[i];
|
||||
end
|
||||
// Allow DM to inject instructions directly into the lowest-numbered queue
|
||||
// entry. This mux should not extend critical path since it is balanced
|
||||
// with the instruction-assembly muxes on the queue bypass path.
|
||||
if (fifo_dbg_inject) begin
|
||||
fifo_mem[0] <= dbg_instr_data;
|
||||
fifo_err[0] <= 1'b0;
|
||||
fifo_valid_hw[0] <= 2'b11;
|
||||
end
|
||||
end
|
||||
// Allow DM to inject instructions directly into the lowest-numbered queue
|
||||
// entry. This mux should not extend critical path since it is balanced
|
||||
// with the instruction-assembly muxes on the queue bypass path.
|
||||
if (fifo_dbg_inject) begin
|
||||
fifo_mem[0] <= dbg_instr_data;
|
||||
fifo_err[0] <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -199,44 +205,26 @@ always @ (posedge clk or negedge rst_n) begin
|
|||
end
|
||||
end
|
||||
|
||||
wire unaligned_jump_now = EXTENSION_C && jump_now && jump_target[1];
|
||||
reg unaligned_jump_dph;
|
||||
reg [1:0] mem_aph_hwvld;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
unaligned_jump_dph <= 1'b0;
|
||||
mem_data_hwvld <= 2'b11;
|
||||
mem_aph_hwvld <= 2'b11;
|
||||
end else if (EXTENSION_C) begin
|
||||
if ((mem_data_vld && ~|ctr_flush_pending && !cir_lock)
|
||||
|| (jump_now && !unaligned_jump_now)) begin
|
||||
unaligned_jump_dph <= 1'b0;
|
||||
end
|
||||
if (fifo_pop) begin
|
||||
// Following a lock/unlock of the CIR, we may have an unaligned fetch in
|
||||
// the FIFO, rather than consuming straight from the bus.
|
||||
unaligned_jump_dph <= 1'b0;
|
||||
end
|
||||
if (unaligned_jump_now) begin
|
||||
unaligned_jump_dph <= 1'b1;
|
||||
if (jump_now) begin
|
||||
if (mem_addr_rdy) begin
|
||||
mem_data_hwvld <= {1'b1, !jump_target[1]};
|
||||
end else begin
|
||||
mem_aph_hwvld <= {1'b1, !jump_target[1]};
|
||||
end
|
||||
end else if (mem_addr_vld && mem_addr_rdy) begin
|
||||
mem_data_hwvld <= mem_aph_hwvld;
|
||||
mem_aph_hwvld <= 2'b11;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef FORMAL
|
||||
reg property_after_aligned_jump;
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
property_after_aligned_jump <= 1'b0;
|
||||
end else begin
|
||||
property_after_aligned_jump <= jump_now && !jump_target[1];
|
||||
if (property_after_aligned_jump) begin
|
||||
// Make sure this clears properly (have been subtle historic bugs here)
|
||||
assert(!unaligned_jump_dph);
|
||||
end
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
|
||||
// Combinatorially generate the address-phase request
|
||||
|
||||
reg reset_holdoff;
|
||||
|
@ -296,19 +284,16 @@ assign jump_target_rdy = !mem_addr_hold;
|
|||
reg [1:0] buf_level;
|
||||
reg [W_BUNDLE-1:0] hwbuf;
|
||||
|
||||
// You might wonder why we have a 48-bit instruction shifter {hwbuf, cir}.
|
||||
// What if we had a 32-bit shifter, and tracked halfword-valid status of the
|
||||
// FIFO entries? This would fail in the following case:
|
||||
//
|
||||
// - Initially CIR and FIFO are full
|
||||
// - Consume a 16-bit instruction from CIR
|
||||
// - CIR is refilled and last FIFO entry becomes half-valid.
|
||||
// - Now consume a 32-bit instruction from CIR
|
||||
// - There is not enough data in the last FIFO entry to refill it
|
||||
|
||||
wire [W_DATA-1:0] fetch_data = fifo_empty ? mem_data : fifo_rdata;
|
||||
wire [1:0] fetch_data_hwvld = fifo_empty ? mem_data_hwvld : fifo_valid_hw[0];
|
||||
wire fetch_data_vld = !fifo_empty || (mem_data_vld && ~|ctr_flush_pending && !debug_mode);
|
||||
|
||||
wire [2*W_BUNDLE-1:0] fetch_data_aligned = {
|
||||
fetch_data[W_BUNDLE +: W_BUNDLE],
|
||||
fetch_data_hwvld[0] || ~|EXTENSION_C ?
|
||||
fetch_data[0 +: W_BUNDLE] : fetch_data[W_BUNDLE +: W_BUNDLE]
|
||||
};
|
||||
|
||||
// Shift any recycled instruction data down to backfill D's consumption
|
||||
// We don't care about anything which is invalid or will be overlaid with fresh data,
|
||||
// so choose these values in a way that minimises muxes
|
||||
|
@ -317,52 +302,68 @@ wire [3*W_BUNDLE-1:0] instr_data_shifted =
|
|||
cir_use[0] && EXTENSION_C ? {hwbuf, hwbuf, cir[W_BUNDLE +: W_BUNDLE]} :
|
||||
{hwbuf, cir};
|
||||
|
||||
// Saturating subtraction: on cir_lock deassertion,
|
||||
// buf_level will be 0 but cir_use will be positive!
|
||||
wire [1:0] cir_use_clipped = |buf_level ? cir_use : 2'h0;
|
||||
|
||||
wire [1:0] level_next_no_fetch = buf_level - cir_use_clipped;
|
||||
wire [1:0] level_next_no_fetch = buf_level - cir_use;
|
||||
|
||||
// Overlay fresh fetch data onto the shifted/recycled instruction data
|
||||
// Again, if something won't be looked at, generate cheapest possible garbage.
|
||||
// Don't care if fetch data is valid or not, as will just retry next cycle (as long as flags set correctly)
|
||||
wire instr_fetch_overlay_blocked = cir_lock || (level_next_no_fetch[1] && !unaligned_jump_dph);
|
||||
wire instr_fetch_overlay_blocked = level_next_no_fetch[1] && (~|EXTENSION_C || &fetch_data_hwvld);
|
||||
|
||||
|
||||
wire [3*W_BUNDLE-1:0] instr_data_plus_fetch =
|
||||
instr_fetch_overlay_blocked ? instr_data_shifted :
|
||||
unaligned_jump_dph && EXTENSION_C ? {instr_data_shifted[W_BUNDLE +: 2*W_BUNDLE], fetch_data[W_BUNDLE +: W_BUNDLE]} :
|
||||
level_next_no_fetch[0] && EXTENSION_C ? {fetch_data, instr_data_shifted[0 +: W_BUNDLE]} :
|
||||
{instr_data_shifted[2*W_BUNDLE +: W_BUNDLE], fetch_data};
|
||||
instr_fetch_overlay_blocked ? instr_data_shifted :
|
||||
level_next_no_fetch[1] && |EXTENSION_C ? {fetch_data_aligned[0 +: W_BUNDLE], instr_data_shifted} :
|
||||
level_next_no_fetch[0] && |EXTENSION_C ? {fetch_data_aligned, instr_data_shifted[0 +: W_BUNDLE]} :
|
||||
{instr_data_shifted[2 * W_BUNDLE +: W_BUNDLE], fetch_data_aligned};
|
||||
|
||||
assign cir_must_refill = !cir_lock && !level_next_no_fetch[1];
|
||||
// Also keep track of bus errors associated with CIR contents, shifted in the
|
||||
// same way as instruction data. Errors may come straight from the bus, or
|
||||
// may be buffered in the prefetch queue.
|
||||
|
||||
wire fetch_bus_err = fifo_empty ? mem_data_err : fifo_err[0];
|
||||
|
||||
reg [2:0] cir_bus_err;
|
||||
wire [2:0] cir_bus_err_shifted =
|
||||
cir_use[1] ? cir_bus_err >> 2 :
|
||||
cir_use[0] && EXTENSION_C ? cir_bus_err >> 1 : cir_bus_err;
|
||||
|
||||
wire [2:0] cir_bus_err_plus_fetch =
|
||||
instr_fetch_overlay_blocked ? cir_bus_err_shifted :
|
||||
level_next_no_fetch[1] && |EXTENSION_C ? {fetch_bus_err, cir_bus_err_shifted[1:0]} :
|
||||
level_next_no_fetch[0] && |EXTENSION_C ? {{2{fetch_bus_err}}, cir_bus_err_shifted[0]} :
|
||||
{cir_bus_err_shifted[2], {2{fetch_bus_err}}};
|
||||
|
||||
assign cir_must_refill = !level_next_no_fetch[1];
|
||||
assign fifo_pop = cir_must_refill && !fifo_empty;
|
||||
|
||||
wire [1:0] fetch_fill_amount = cir_must_refill && fetch_data_vld ? (
|
||||
&fetch_data_hwvld ? 2'h2 : 2'h1
|
||||
) : 2'h0;
|
||||
|
||||
wire [1:0] buf_level_next =
|
||||
jump_now || |ctr_flush_pending || cir_lock ? 2'h0 :
|
||||
fetch_data_vld && unaligned_jump_dph ? 2'h1 :
|
||||
buf_level + {cir_must_refill && fetch_data_vld, 1'b0} - cir_use_clipped;
|
||||
jump_now && cir_flush_behind ? (cir[1:0] == 2'b11 || ~|EXTENSION_C ? 2'h2 : 2'h1) :
|
||||
jump_now ? 2'h0 : level_next_no_fetch + fetch_fill_amount;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
buf_level <= 2'h0;
|
||||
cir_vld <= 2'h0;
|
||||
hwbuf <= 16'h0;
|
||||
cir <= 16'h0;
|
||||
cir_bus_err <= 3'h0;
|
||||
end else begin
|
||||
`ifdef FORMAL
|
||||
assert(cir_vld <= 2);
|
||||
assert(cir_use <= cir_vld);
|
||||
if (!jump_now)
|
||||
assert(buf_level_next >= level_next_no_fetch);
|
||||
`endif
|
||||
// Update CIR flags
|
||||
buf_level <= buf_level_next;
|
||||
if (!cir_lock)
|
||||
cir_vld <= buf_level_next & ~(buf_level_next >> 1'b1);
|
||||
// Update CIR contents
|
||||
cir_vld <= buf_level_next & ~(buf_level_next >> 1'b1);
|
||||
cir_bus_err <= cir_bus_err_plus_fetch;
|
||||
{hwbuf, cir} <= instr_data_plus_fetch;
|
||||
end
|
||||
end
|
||||
|
||||
// No need to reset these as they will be written before first use
|
||||
always @ (posedge clk)
|
||||
{hwbuf, cir} <= instr_data_plus_fetch;
|
||||
|
||||
`ifdef FORMAL
|
||||
reg [1:0] property_past_buf_level; // Workaround for weird non-constant $past reset issue
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
|
@ -377,31 +378,6 @@ always @ (posedge clk or negedge rst_n) begin
|
|||
end
|
||||
`endif
|
||||
|
||||
// Also keep track of bus errors associated with CIR contents, shifted in the
|
||||
// same way as instruction data. Errors may come straight from the bus, or
|
||||
// may be buffered in the prefetch queue.
|
||||
|
||||
wire fetch_bus_err = fifo_empty ? mem_data_err : fifo_err[0];
|
||||
|
||||
reg [2:0] cir_bus_err;
|
||||
wire [2:0] cir_bus_err_shifted =
|
||||
cir_use[1] ? cir_bus_err >> 2 :
|
||||
cir_use[0] && EXTENSION_C ? cir_bus_err >> 1 : cir_bus_err;
|
||||
|
||||
wire [2:0] cir_bus_err_plus_fetch =
|
||||
instr_fetch_overlay_blocked ? cir_bus_err_shifted :
|
||||
unaligned_jump_dph && EXTENSION_C ? {cir_bus_err_shifted[2:1], fetch_bus_err} :
|
||||
level_next_no_fetch && EXTENSION_C ? {{2{fetch_bus_err}}, cir_bus_err_shifted[0]} :
|
||||
{cir_bus_err_shifted[2], {2{fetch_bus_err}}};
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
cir_bus_err <= 3'h0;
|
||||
end else if (CSR_M_TRAP) begin
|
||||
cir_bus_err <= cir_bus_err_plus_fetch;
|
||||
end
|
||||
end
|
||||
|
||||
assign cir_err = cir_bus_err[1:0];
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue