diff --git a/hdl/hazard3.f b/hdl/hazard3.f index 762b93b..ecd08b3 100644 --- a/hdl/hazard3.f +++ b/hdl/hazard3.f @@ -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 . diff --git a/hdl/hazard3_core.v b/hdl/hazard3_core.v index 6547a85..f4d3e95 100644 --- a/hdl/hazard3_core.v +++ b/hdl/hazard3_core.v @@ -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; diff --git a/hdl/hazard3_csr.v b/hdl/hazard3_csr.v index a57d1f8..94b3581 100644 --- a/hdl/hazard3_csr.v +++ b/hdl/hazard3_csr.v @@ -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}; // ---------------------------------------------------------------------------- diff --git a/hdl/hazard3_decode.v b/hdl/hazard3_decode.v index 65c04bc..f23955c 100644 --- a/hdl/hazard3_decode.v +++ b/hdl/hazard3_decode.v @@ -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; diff --git a/hdl/hazard3_frontend.v b/hdl/hazard3_frontend.v index 95b88de..6e1dc43 100644 --- a/hdl/hazard3_frontend.v +++ b/hdl/hazard3_frontend.v @@ -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; diff --git a/hdl/hazard3_rvfi_monitor.vh b/hdl/hazard3_rvfi_monitor.vh index 235fb71..16df2f7 100644 --- a/hdl/hazard3_rvfi_monitor.vh +++ b/hdl/hazard3_rvfi_monitor.vh @@ -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 diff --git a/hdl/hazard3_rvfi_wrapper.v b/hdl/hazard3_rvfi_wrapper.v index ecec6e5..25be6c5 100644 --- a/hdl/hazard3_rvfi_wrapper.v +++ b/hdl/hazard3_rvfi_wrapper.v @@ -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;