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:
Luke Wren 2021-05-29 18:00:43 +01:00
parent 1b252d4bda
commit 65075df0e5
7 changed files with 69 additions and 28 deletions

View File

@ -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 .

View File

@ -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;

View File

@ -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};
// ----------------------------------------------------------------------------

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;