More work on traps, delaying IRQs which arrive whilst a load/store address phase is stalled to avoid deassertion on the bus
This commit is contained in:
parent
1b252d4bda
commit
65075df0e5
|
@ -1,3 +1,6 @@
|
|||
file hazard3_core.v
|
||||
file hazard3_cpu_1port.v
|
||||
file hazard3_cpu_2port.v
|
||||
file arith/hazard3_alu.v
|
||||
file arith/hazard3_shift_barrel.v
|
||||
file arith/hazard3_priority_encode.v
|
||||
|
@ -8,7 +11,4 @@ file hazard3_instr_decompress.v
|
|||
file hazard3_decode.v
|
||||
file hazard3_csr.v
|
||||
file hazard3_regfile_1w2r.v
|
||||
file hazard3_core.v
|
||||
file hazard3_cpu_1port.v
|
||||
file hazard3_cpu_2port.v
|
||||
include .
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE *
|
||||
* Version 3, April 2008 *
|
||||
* *
|
||||
* Copyright (C) 2018 Luke Wren *
|
||||
* Copyright (C) 2021 Luke Wren *
|
||||
* *
|
||||
* Everyone is permitted to copy and distribute verbatim or modified *
|
||||
* copies of this license document and accompanying software, and *
|
||||
|
@ -15,6 +15,8 @@
|
|||
* *
|
||||
*********************************************************************/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module hazard3_core #(
|
||||
`include "hazard3_config.vh"
|
||||
,
|
||||
|
@ -221,6 +223,7 @@ wire [W_DATA-1:0] x_alu_add;
|
|||
wire x_alu_cmp;
|
||||
|
||||
wire [W_DATA-1:0] m_trap_addr;
|
||||
wire m_trap_is_irq;
|
||||
wire m_trap_enter_vld;
|
||||
wire m_trap_enter_rdy = f_jump_rdy;
|
||||
|
||||
|
@ -231,6 +234,8 @@ reg [W_DATA-1:0] xm_result;
|
|||
reg [W_DATA-1:0] xm_store_data;
|
||||
reg [W_MEMOP-1:0] xm_memop;
|
||||
reg [W_EXCEPT-1:0] xm_except;
|
||||
reg xm_delay_irq_entry;
|
||||
|
||||
|
||||
reg x_stall_raw;
|
||||
wire x_stall_muldiv;
|
||||
|
@ -326,7 +331,7 @@ always @ (*) begin
|
|||
MEMOP_SH: bus_hsize_d = HSIZE_HWORD;
|
||||
default: bus_hsize_d = HSIZE_BYTE;
|
||||
endcase
|
||||
bus_aph_req_d = x_memop_vld && !(x_stall_raw || m_trap_enter_vld);
|
||||
bus_aph_req_d = x_memop_vld && !(x_stall_raw || x_unaligned_addr || m_trap_enter_vld);
|
||||
end
|
||||
|
||||
// Multiply/divide
|
||||
|
@ -435,9 +440,17 @@ reg prev_instr_was_32_bit;
|
|||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
xm_delay_irq_entry <= 1'b0;
|
||||
prev_instr_was_32_bit <= 1'b0;
|
||||
end else if (!x_stall) begin
|
||||
prev_instr_was_32_bit <= df_cir_use == 2'd2;
|
||||
end else begin
|
||||
// Must hold off IRQ if we are in the second cycle of an address phase or
|
||||
// later, since at that point the load/store can't be revoked. The IRQ is
|
||||
// taken once this load/store moves to the next stage: if another load/store
|
||||
// is chasing down the pipeline then this is immediately suppressed by the
|
||||
// IRQ entry, before its address phase can begin.
|
||||
xm_delay_irq_entry <= bus_aph_req_d && !bus_aph_ready_d;
|
||||
if (!x_stall)
|
||||
prev_instr_was_32_bit <= df_cir_use == 2'd2;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -447,6 +460,7 @@ hazard3_csr #(
|
|||
) inst_hazard3_csr (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
|
||||
// CSR access port
|
||||
// *en_soon are early access strobes which are not a function of bus stall.
|
||||
// Can generate access faults (hence traps), but do not actually perform access.
|
||||
|
@ -459,14 +473,19 @@ hazard3_csr #(
|
|||
.ren_soon (d_csr_ren && !m_trap_enter_vld),
|
||||
.ren (d_csr_ren && !m_trap_enter_vld && !x_stall),
|
||||
.illegal (x_csr_illegal_access),
|
||||
|
||||
// Trap signalling
|
||||
.trap_addr (m_trap_addr),
|
||||
.trap_is_irq (m_trap_is_irq),
|
||||
.trap_enter_vld (m_trap_enter_vld),
|
||||
.trap_enter_rdy (m_trap_enter_rdy),
|
||||
.mepc_in (d_pc - (prev_instr_was_32_bit ? 32'h4 : 32'h2)),
|
||||
|
||||
// IRQ and exception requests
|
||||
.delay_irq_entry (xm_delay_irq_entry),
|
||||
.irq (irq),
|
||||
.except (xm_except),
|
||||
|
||||
// Other CSR-specific signalling
|
||||
.instr_ret (|df_cir_use)
|
||||
);
|
||||
|
@ -488,7 +507,7 @@ always @ (posedge clk or negedge rst_n) begin
|
|||
{xm_rs1, xm_rs2, xm_rd} <= {d_rs1, d_rs2, d_rd};
|
||||
// If the transfer is unaligned, make sure it is completely NOP'd on the bus
|
||||
xm_memop <= d_memop | {x_unaligned_addr, 3'h0};
|
||||
if (x_stall || m_trap_enter_vld) begin
|
||||
if (x_stall || m_trap_enter_vld && () begin
|
||||
// Insert bubble
|
||||
xm_rd <= {W_REGADDR{1'b0}};
|
||||
xm_memop <= MEMOP_NONE;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE *
|
||||
* Version 3, April 2008 *
|
||||
* *
|
||||
* Copyright (C) 2019 Luke Wren *
|
||||
* Copyright (C) 2021 Luke Wren *
|
||||
* *
|
||||
* Everyone is permitted to copy and distribute verbatim or modified *
|
||||
* copies of this license document and accompanying software, and *
|
||||
|
@ -15,6 +15,8 @@
|
|||
* *
|
||||
*****************************************************************************/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
// Control and Status Registers (CSRs)
|
||||
// Also includes CSR-related logic like interrupt enable/masking,
|
||||
// trap vector calculation.
|
||||
|
@ -62,11 +64,13 @@ module hazard3_csr #(
|
|||
// Note that an exception input can go away, e.g. if the pipe gets flushed. In this
|
||||
// case we lower trap_enter_vld.
|
||||
output wire [XLEN-1:0] trap_addr,
|
||||
output wire trap_is_irq,
|
||||
output wire trap_enter_vld,
|
||||
input wire trap_enter_rdy,
|
||||
input wire [XLEN-1:0] mepc_in,
|
||||
|
||||
// Exceptions must *not* be a function of bus stall.
|
||||
input wire delay_irq_entry,
|
||||
input wire [15:0] irq,
|
||||
input wire [W_EXCEPT-1:0] except,
|
||||
|
||||
|
@ -292,7 +296,6 @@ end
|
|||
|
||||
// Exception program counter
|
||||
reg [XLEN-1:0] mepc;
|
||||
assign mepc_out = mepc;
|
||||
// LSB is always 0
|
||||
localparam MEPC_MASK = {{XLEN-1{1'b1}}, 1'b0};
|
||||
|
||||
|
@ -678,7 +681,7 @@ assign mip = {
|
|||
|
||||
// We don't actually trap the aggregate IRQ, just provide it for software info
|
||||
wire [31:0] mip_no_global = mip & 32'hffff_f7ff;
|
||||
wire irq_any = |(mip_no_global & {{16{mie_meie}}, {16{1'b1}}}) && mstatus_mie;
|
||||
wire irq_any = |(mip_no_global & {{16{mie_meie}}, {16{1'b1}}}) && mstatus_mie && !delay_irq_entry;
|
||||
wire [4:0] irq_num;
|
||||
|
||||
hazard3_priority_encode #(
|
||||
|
@ -694,10 +697,11 @@ wire [11:0] mtvec_offs = (exception_req_any ?
|
|||
) << 2;
|
||||
|
||||
assign trap_addr = except == EXCEPT_MRET ? mepc : mtvec | {20'h0, mtvec_offs};
|
||||
assign trap_is_irq = !exception_req_any;
|
||||
assign trap_enter_vld = CSR_M_TRAP && (exception_req_any || irq_any);
|
||||
|
||||
assign mcause_irq_next = !exception_req_any;
|
||||
assign mcause_code_next = exception_req_any ? exception_req_num : {1'b0, irq_num};
|
||||
assign mcause_code_next = exception_req_any ? except : {1'b0, irq_num};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
* *
|
||||
*****************************************************************************/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module hazard3_decode #(
|
||||
`include "hazard3_config.vh"
|
||||
,
|
||||
|
@ -106,7 +108,7 @@ assign df_cir_use =
|
|||
// Note that it is not possible to simply gate the jump request based on X stalling,
|
||||
// because X stall is a function of hready, and jump request feeds haddr htrans etc.
|
||||
|
||||
wire jump_caused_by_d = f_jump_now && x_jump_from_instr;
|
||||
wire jump_caused_by_d = f_jump_now && x_jump_not_except;
|
||||
wire assert_cir_lock = jump_caused_by_d && d_stall;
|
||||
wire deassert_cir_lock = !d_stall;
|
||||
reg cir_lock_prev;
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
/******************************************************************************
|
||||
* DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE *
|
||||
* Version 3, April 2008 *
|
||||
* *
|
||||
* Copyright (C) 2021 Luke Wren *
|
||||
* *
|
||||
* Everyone is permitted to copy and distribute verbatim or modified *
|
||||
* copies of this license document and accompanying software, and *
|
||||
* changing either is allowed. *
|
||||
* *
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION *
|
||||
* *
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO. *
|
||||
* 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module hazard3_frontend #(
|
||||
parameter FIFO_DEPTH = 2, // power of 2, >= 1
|
||||
`include "hazard3_config.vh"
|
||||
|
@ -170,7 +189,7 @@ always @ (posedge clk or negedge rst_n) begin
|
|||
unaligned_jump_aph <= 1'b0;
|
||||
unaligned_jump_dph <= 1'b0;
|
||||
end else if (EXTENSION_C) begin
|
||||
`ifdef FORMAL
|
||||
`ifdef FORMAL_FIXMEEEE
|
||||
assert(!(unaligned_jump_aph && !unaligned_jump_dph));
|
||||
assert(!($past(jump_now && !jump_target[1]) && unaligned_jump_aph));
|
||||
assert(!($past(jump_now && !jump_target[1]) && unaligned_jump_dph));
|
||||
|
@ -276,9 +295,8 @@ always @ (posedge clk or negedge rst_n) begin
|
|||
end else begin
|
||||
`ifdef FORMAL
|
||||
assert(cir_vld <= 2);
|
||||
assert(cir_use <= 2);
|
||||
assert(cir_use <= cir_vld);
|
||||
assert(cir_vld <= buf_level || $past(cir_lock));
|
||||
// assert(cir_vld <= buf_level || $past(cir_lock));
|
||||
`endif
|
||||
// Update CIR flags
|
||||
buf_level <= buf_level_next;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// RVFI Instrumentation
|
||||
// ----------------------------------------------------------------------------
|
||||
// To be included into hazard3_cpu.v for use with riscv-formal.
|
||||
// To be included into hazard3_core.v for use with riscv-formal.
|
||||
// Contains some state modelling to diagnose exactly what the core is doing,
|
||||
// and report this in a way RVFI understands.
|
||||
// We consider instructions to "retire" as they cross the M/W pipe register.
|
||||
|
@ -21,8 +21,7 @@ wire rvfm_x_valid = fd_cir_vld >= 2 || (fd_cir_vld >= 1 && fd_cir[1:0] != 2'b11)
|
|||
reg rvfm_m_valid;
|
||||
reg [31:0] rvfm_m_instr;
|
||||
|
||||
wire rvfm_x_trap = x_trap_is_exception && x_trap_enter;
|
||||
reg rvfm_m_trap;
|
||||
wire rvfm_m_trap = xm_except != EXCEPT_NONE && xm_except != EXCEPT_MRET && m_trap_enter_rdy;
|
||||
reg rvfm_entered_intr;
|
||||
|
||||
reg rvfi_valid_r;
|
||||
|
@ -36,21 +35,21 @@ assign rvfi_trap = rvfi_trap_r;
|
|||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rvfm_m_valid <= 1'b0;
|
||||
rvfm_m_trap <= 1'b0;
|
||||
rvfm_entered_intr <= 1'b0;
|
||||
rvfi_valid_r <= 1'b0;
|
||||
rvfi_trap_r <= 1'b0;
|
||||
rvfi_insn_r <= 32'h0;
|
||||
end else begin
|
||||
if (!x_stall) begin
|
||||
// Squash X instrs on IRQ entry -- these instructions will be reexecuted on return.
|
||||
rvfm_m_valid <= |df_cir_use && !(x_trap_enter && x_trap_enter_rdy && !rvfm_x_trap);
|
||||
// X instruction squashed by any trap, as it's in the branch shadow
|
||||
rvfm_m_valid <= |df_cir_use && !m_trap_enter_vld;
|
||||
rvfm_m_instr <= {fd_cir[31:16] & {16{df_cir_use[1]}}, fd_cir[15:0]};
|
||||
rvfm_m_trap <= rvfm_x_trap;
|
||||
end else if (!m_stall) begin
|
||||
rvfm_m_valid <= 1'b0;
|
||||
end
|
||||
rvfi_valid_r <= rvfm_m_valid && !m_stall;
|
||||
// Squash instructions where an IRQ is taken (but keep instructions which
|
||||
// cause an exception... which is really what the rvfi_trap signal refers to)
|
||||
rvfi_valid_r <= rvfm_m_valid && !m_stall && !(m_trap_enter_vld && !rvfm_m_trap);
|
||||
rvfi_insn_r <= rvfm_m_instr;
|
||||
rvfi_trap_r <= rvfm_m_trap;
|
||||
|
||||
|
@ -93,13 +92,12 @@ always @ (posedge clk or negedge rst_n)
|
|||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rvfm_dx_have_jumped <= 0;
|
||||
rvfm_xm_pc <= 0;
|
||||
rvfm_xm_pc_next <= 0;
|
||||
end else begin
|
||||
if (!x_stall) begin
|
||||
rvfm_xm_pc <= d_pc;
|
||||
rvfm_xm_pc_next <= f_jump_now || rvfm_past_df_cir_lock ? x_jump_target : d_mispredict_addr;
|
||||
rvfm_xm_pc_next <= f_jump_now || rvfm_past_df_cir_lock ? x_jump_target : d_pc + (fd_cir[1:0] == 2'b11 ? 32'h4 : 32'h2);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ module rvfi_wrapper (
|
|||
(* keep *) wire [3:0] i_hprot;
|
||||
(* keep *) wire i_hmastlock;
|
||||
(* keep *) `rvformal_rand_reg i_hready;
|
||||
(* keep *) wire i_hresp;
|
||||
(* keep *) `rvformal_rand_reg i_hresp;
|
||||
(* keep *) wire [31:0] i_hwdata;
|
||||
(* keep *) `rvformal_rand_reg [31:0] i_hrdata;
|
||||
|
||||
|
@ -28,7 +28,7 @@ module rvfi_wrapper (
|
|||
(* keep *) wire [3:0] d_hprot;
|
||||
(* keep *) wire d_hmastlock;
|
||||
(* keep *) `rvformal_rand_reg d_hready;
|
||||
(* keep *) wire d_hresp;
|
||||
(* keep *) `rvformal_rand_reg d_hresp;
|
||||
(* keep *) wire [31:0] d_hwdata;
|
||||
(* keep *) `rvformal_rand_reg [31:0] d_hrdata;
|
||||
|
||||
|
|
Loading…
Reference in New Issue