First pass at implementing the new IRQ controls. Works well enough that the old tests pass :)

This commit is contained in:
Luke Wren 2022-08-07 20:51:12 +01:00
parent 69917ccbbe
commit 15cb21ae43
25 changed files with 1035 additions and 638 deletions

View File

@ -245,7 +245,7 @@ hazard3_cpu_1port #(
.CSR_M_MANDATORY (1),
.CSR_M_TRAP (1),
.DEBUG_SUPPORT (1),
.NUM_IRQ (1),
.NUM_IRQS (1),
.RESET_REGFILE (0),
// Can be overridden from the defaults in hazard3_config.vh during
// instantiation of example_soc():

View File

@ -94,7 +94,8 @@ wire [W_DATA-1:0] ctz_search_mask = aluop == ALUOP_CLZ ? op_a_rev : op_a;
wire [W_SHAMT:0] ctz_clz;
hazard3_priority_encode #(
.W_REQ (W_DATA)
.W_REQ (W_DATA),
.HIGHEST_WINS (0)
) ctz_priority_encode (
.req (ctz_search_mask),
.gnt (ctz_clz[W_SHAMT-1:0])

View File

@ -0,0 +1,33 @@
/*****************************************************************************\
| Copyright (C) 2022 Luke Wren |
| SPDX-License-Identifier: Apache-2.0 |
\*****************************************************************************/
// req: one-hot bitmap
// idx: index of the sole set bit in req
`default_nettype none
module hazard3_onehot_encode #(
parameter W_REQ = 16,
parameter W_GNT = $clog2(W_REQ) // do not modify
) (
input wire [W_REQ-1:0] req,
output reg [W_GNT-1:0] gnt
);
reg [W_GNT-1:0] gnt;
always @ (*) begin: encode
reg [W_GNT:0] i;
gnt = {W_GNT{1'b0}};
for (i = 0; i < W_REQ; i = i + 1) begin
gnt = gnt | ({W_GNT{req[i]}} & i[W_GNT-1:0]);
end
end
endmodule
`ifndef YOSYS
`default_nettype wire
`endif

View File

@ -0,0 +1,33 @@
/*****************************************************************************\
| Copyright (C) 2022 Luke Wren |
| SPDX-License-Identifier: Apache-2.0 |
\*****************************************************************************/
// req: bitmap
// idx: bitmap with all bits clear except the least- (HIGHEST_WINS=0) or
// most- (HIGHEST_WINS=1) significant set bit in req.
`default_nettype none
module hazard3_onehot_priority #(
parameter W_REQ = 16,
parameter HIGHEST_WINS = 0
) (
input wire [W_REQ-1:0] req,
output reg [W_REQ-1:0] gnt
);
always @ (*) begin: select
integer i;
for (i = 0; i < W_REQ; i = i + 1) begin
gnt[i] = req[i] && ~|(req & (
HIGHEST_WINS ? ~({W_REQ{1'b1}} >> i) : ~({W_REQ{1'b1}} << i)
));
end
end
endmodule
`ifndef YOSYS
`default_nettype wire
`endif

View File

@ -0,0 +1,76 @@
/*****************************************************************************\
| Copyright (C) 2022 Luke Wren |
| SPDX-License-Identifier: Apache-2.0 |
\*****************************************************************************/
// req: bitmap of requests
// priority: packed array of dynamic priority level of each request
// gnt: one-hot bitmap with the highest-priority request.
`default_nettype none
module hazard3_onehot_priority_dynamic #(
parameter W_REQ = 8,
parameter N_PRIORITIES = 2,
parameter PRIORITY_HIGHEST_WINS = 1, // If 1, numerically highest level has greatest priority.
// Otherwise, numerically lowest wins.
parameter TIEBREAK_HIGHEST_WINS = 0, // If 1, highest-numbered request at the highest priority
// level wins the tiebreak. Otherwise, lowest-numbered.
// Do not modify:
parameter W_PRIORITY = $clog2(N_PRIORITIES)
) (
input wire [W_REQ*W_PRIORITY-1:0] priority,
input wire [W_REQ-1:0] req,
output wire [W_REQ-1:0] gnt
);
// 1. Stratify requests according to their level
reg [W_REQ-1:0] req_stratified [0:N_PRIORITIES-1];
reg [N_PRIORITIES-1:0] level_has_req;
always @ (*) begin: stratify
integer i, j;
for (i = 0; i < N_PRIORITIES; i = i + 1) begin
for (j = 0; j < W_REQ; j = j + 1) begin
req_stratified[i][j] = req[j] && priority[W_PRIORITY * j +: W_PRIORITY] == i;
end
level_has_req[i] = |req_stratified[i];
end
end
// 2. Select the highest level with active requests
wire [N_PRIORITIES-1:0] active_layer_sel;
hazard3_onehot_priority #(
.W_REQ (N_PRIORITIES),
.HIGHEST_WINS (PRIORITY_HIGHEST_WINS)
) prisel_layer (
.req (level_has_req),
.gnt (active_layer_sel)
);
// 3. Mask only those requests at this level
reg [W_REQ-1:0] reqs_from_highest_layer;
always @ (*) begin: mux_reqs_by_layer
integer i;
reqs_from_highest_layer = {W_REQ{1'b0}};
for (i = 0; i < N_PRIORITIES; i = i + 1)
reqs_from_highest_layer = reqs_from_highest_layer |
(req_stratified[i] & {W_REQ{active_layer_sel[i]}});
end
// 4. Do a standard priority select on those requests as a tie break
hazard3_onehot_priority #(
.W_REQ (W_REQ),
.HIGHEST_WINS (TIEBREAK_HIGHEST_WINS)
) prisel_tiebreak (
.req (reqs_from_highest_layer),
.gnt (gnt)
);
endmodule
`ifndef YOSYS
`default_nettype wire
`endif

View File

@ -3,44 +3,39 @@
| SPDX-License-Identifier: Apache-2.0 |
\*****************************************************************************/
// Really something like this should be in a utility library (or the language!),
// but Hazard3 is supposed to be self-contained
// req: bitmap
// gnt: index of least set bit (HIGHEST_WINS=0) or most set bit (HIGHEST_WINS=1)
`default_nettype none
module hazard3_priority_encode #(
parameter W_REQ = 16,
parameter W_GNT = $clog2(W_REQ) // do not modify
parameter W_REQ = 16,
parameter HIGHEST_WINS = 0,
parameter W_GNT = $clog2(W_REQ) // do not modify
) (
input wire [W_REQ-1:0] req,
output wire [W_GNT-1:0] gnt
);
// First do a priority-select of the input bitmap.
wire [W_REQ-1:0] gnt_onehot;
reg [W_REQ-1:0] gnt_onehot;
hazard3_onehot_priority #(
.W_REQ (W_REQ),
.HIGHEST_WINS (HIGHEST_WINS)
) priority_u (
.req (req),
.gnt (gnt_onehot)
);
always @ (*) begin: smear
integer i;
for (i = 0; i < W_REQ; i = i + 1)
gnt_onehot[i] = req[i] && ~|(req & ~({W_REQ{1'b1}} << i));
end
// As the result is onehot, we can now just OR in the representation of each
// encoded integer.
reg [W_GNT-1:0] gnt_accum;
always @ (*) begin: encode
reg [W_GNT:0] i;
gnt_accum = {W_GNT{1'b0}};
for (i = 0; i < W_REQ; i = i + 1) begin
gnt_accum = gnt_accum | ({W_GNT{gnt_onehot[i]}} & i[W_GNT-1:0]);
end
end
assign gnt = gnt_accum;
hazard3_onehot_encode #(
.W_REQ (W_REQ)
) encode_u (
.req (gnt_onehot),
.gnt (gnt)
);
endmodule
`ifndef YOSYS
`default_nettype wire
`endif

View File

@ -3,8 +3,11 @@ file hazard3_cpu_1port.v
file hazard3_cpu_2port.v
file arith/hazard3_alu.v
file arith/hazard3_branchcmp.v
file arith/hazard3_muldiv_seq.v
file arith/hazard3_mul_fast.v
file arith/hazard3_muldiv_seq.v
file arith/hazard3_onehot_encode.v
file arith/hazard3_onehot_priority.v
file arith/hazard3_onehot_priority_dynamic.v
file arith/hazard3_priority_encode.v
file arith/hazard3_shift_barrel.v
file hazard3_frontend.v

View File

@ -120,9 +120,18 @@ parameter PMP_HARDWIRED_CFG = PMP_REGIONS > 0 ? {PMP_REGIONS{8'h00}} : 1'b0,
// Requires: CSR_M_MANDATORY, CSR_M_TRAP.
parameter DEBUG_SUPPORT = 0,
// NUM_IRQ: Number of external IRQs implemented in meie0 and meip0.
// Minimum 1 (if CSR_M_TRAP = 1), maximum 128.
parameter NUM_IRQ = 32,
// ----------------------------------------------------------------------------
// External interrupt support
// NUM_IRQS: Number of external IRQs implemented in meiea, meipa, meifa and
// meipra, if CSR_M_TRAP is enabled. Minimum 1, maximum 512.
parameter NUM_IRQS = 32,
// Number of priority bits implemented for each interrupt in meipra. The
// number of distinct levels is (1 << IRQ_PRIORITY_BITS). Minimum 0, max 4.
// Note that having more than 1 priority level with a large number of IRQs
// will have a severe effect on timing.
parameter IRQ_PRIORITY_BITS = 0,
// ----------------------------------------------------------------------------
// ID registers

View File

@ -34,7 +34,8 @@
.PMP_HARDWIRED_ADDR (PMP_HARDWIRED_ADDR),
.PMP_HARDWIRED_CFG (PMP_HARDWIRED_CFG),
.DEBUG_SUPPORT (DEBUG_SUPPORT),
.NUM_IRQ (NUM_IRQ),
.NUM_IRQS (NUM_IRQS),
.IRQ_PRIORITY_BITS (IRQ_PRIORITY_BITS),
.MVENDORID_VAL (MVENDORID_VAL),
.MIMPID_VAL (MIMPID_VAL),
`ifndef HAZARD3_CONFIG_INST_NO_MHARTID

View File

@ -11,61 +11,61 @@ module hazard3_core #(
`include "hazard3_width_const.vh"
) (
// Global signals
input wire clk,
input wire rst_n,
input wire clk,
input wire rst_n,
`ifdef RISCV_FORMAL
`RVFI_OUTPUTS ,
`endif
// Instruction fetch port
output wire bus_aph_req_i,
output wire bus_aph_panic_i, // e.g. branch mispredict + flush
input wire bus_aph_ready_i,
input wire bus_dph_ready_i,
input wire bus_dph_err_i,
output wire bus_aph_req_i,
output wire bus_aph_panic_i, // e.g. branch mispredict + flush
input wire bus_aph_ready_i,
input wire bus_dph_ready_i,
input wire bus_dph_err_i,
output wire [W_ADDR-1:0] bus_haddr_i,
output wire [2:0] bus_hsize_i,
output wire bus_priv_i,
input wire [W_DATA-1:0] bus_rdata_i,
output wire [W_ADDR-1:0] bus_haddr_i,
output wire [2:0] bus_hsize_i,
output wire bus_priv_i,
input wire [W_DATA-1:0] bus_rdata_i,
// Load/store port
output reg bus_aph_req_d,
output wire bus_aph_excl_d,
input wire bus_aph_ready_d,
input wire bus_dph_ready_d,
input wire bus_dph_err_d,
input wire bus_dph_exokay_d,
output reg bus_aph_req_d,
output wire bus_aph_excl_d,
input wire bus_aph_ready_d,
input wire bus_dph_ready_d,
input wire bus_dph_err_d,
input wire bus_dph_exokay_d,
output reg [W_ADDR-1:0] bus_haddr_d,
output reg [2:0] bus_hsize_d,
output reg bus_priv_d,
output reg bus_hwrite_d,
output reg [W_DATA-1:0] bus_wdata_d,
input wire [W_DATA-1:0] bus_rdata_d,
output reg [W_ADDR-1:0] bus_haddr_d,
output reg [2:0] bus_hsize_d,
output reg bus_priv_d,
output reg bus_hwrite_d,
output reg [W_DATA-1:0] bus_wdata_d,
input wire [W_DATA-1:0] bus_rdata_d,
// Debugger run/halt control
input wire dbg_req_halt,
input wire dbg_req_halt_on_reset,
input wire dbg_req_resume,
output wire dbg_halted,
output wire dbg_running,
input wire dbg_req_halt,
input wire dbg_req_halt_on_reset,
input wire dbg_req_resume,
output wire dbg_halted,
output wire dbg_running,
// Debugger access to data0 CSR
input wire [W_DATA-1:0] dbg_data0_rdata,
output wire [W_DATA-1:0] dbg_data0_wdata,
output wire dbg_data0_wen,
input wire [W_DATA-1:0] dbg_data0_rdata,
output wire [W_DATA-1:0] dbg_data0_wdata,
output wire dbg_data0_wen,
// Debugger instruction injection
input wire [W_DATA-1:0] dbg_instr_data,
input wire dbg_instr_data_vld,
output wire dbg_instr_data_rdy,
output wire dbg_instr_caught_exception,
output wire dbg_instr_caught_ebreak,
input wire [W_DATA-1:0] dbg_instr_data,
input wire dbg_instr_data_vld,
output wire dbg_instr_data_rdy,
output wire dbg_instr_caught_exception,
output wire dbg_instr_caught_ebreak,
// Level-sensitive interrupt sources
input wire [NUM_IRQ-1:0] irq, // -> mip.meip
input wire soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
input wire [NUM_IRQS-1:0] irq, // -> mip.meip
input wire soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
);
`include "hazard3_ops.vh"

View File

@ -13,60 +13,60 @@ module hazard3_cpu_1port #(
`include "hazard3_config.vh"
) (
// Global signals
input wire clk,
input wire rst_n,
input wire clk,
input wire rst_n,
`ifdef RISCV_FORMAL
`RVFI_OUTPUTS ,
`endif
// AHB-lite Master port
output reg [W_ADDR-1:0] ahblm_haddr,
output reg ahblm_hwrite,
output reg [1:0] ahblm_htrans,
output reg [2:0] ahblm_hsize,
output wire [2:0] ahblm_hburst,
output reg [3:0] ahblm_hprot,
output wire ahblm_hmastlock,
output reg [7:0] ahblm_hmaster,
output reg ahblm_hexcl,
input wire ahblm_hready,
input wire ahblm_hresp,
input wire ahblm_hexokay,
output wire [W_DATA-1:0] ahblm_hwdata,
input wire [W_DATA-1:0] ahblm_hrdata,
output reg [W_ADDR-1:0] ahblm_haddr,
output reg ahblm_hwrite,
output reg [1:0] ahblm_htrans,
output reg [2:0] ahblm_hsize,
output wire [2:0] ahblm_hburst,
output reg [3:0] ahblm_hprot,
output wire ahblm_hmastlock,
output reg [7:0] ahblm_hmaster,
output reg ahblm_hexcl,
input wire ahblm_hready,
input wire ahblm_hresp,
input wire ahblm_hexokay,
output wire [W_DATA-1:0] ahblm_hwdata,
input wire [W_DATA-1:0] ahblm_hrdata,
// Debugger run/halt control
input wire dbg_req_halt,
input wire dbg_req_halt_on_reset,
input wire dbg_req_resume,
output wire dbg_halted,
output wire dbg_running,
input wire dbg_req_halt,
input wire dbg_req_halt_on_reset,
input wire dbg_req_resume,
output wire dbg_halted,
output wire dbg_running,
// Debugger access to data0 CSR
input wire [W_DATA-1:0] dbg_data0_rdata,
output wire [W_DATA-1:0] dbg_data0_wdata,
output wire dbg_data0_wen,
input wire [W_DATA-1:0] dbg_data0_rdata,
output wire [W_DATA-1:0] dbg_data0_wdata,
output wire dbg_data0_wen,
// Debugger instruction injection
input wire [W_DATA-1:0] dbg_instr_data,
input wire dbg_instr_data_vld,
output wire dbg_instr_data_rdy,
output wire dbg_instr_caught_exception,
output wire dbg_instr_caught_ebreak,
input wire [W_DATA-1:0] dbg_instr_data,
input wire dbg_instr_data_vld,
output wire dbg_instr_data_rdy,
output wire dbg_instr_caught_exception,
output wire dbg_instr_caught_ebreak,
// Optional debug system bus access patch-through
input wire [W_ADDR-1:0] dbg_sbus_addr,
input wire dbg_sbus_write,
input wire [1:0] dbg_sbus_size,
input wire dbg_sbus_vld,
output wire dbg_sbus_rdy,
output wire dbg_sbus_err,
input wire [W_DATA-1:0] dbg_sbus_wdata,
output wire [W_DATA-1:0] dbg_sbus_rdata,
input wire [W_ADDR-1:0] dbg_sbus_addr,
input wire dbg_sbus_write,
input wire [1:0] dbg_sbus_size,
input wire dbg_sbus_vld,
output wire dbg_sbus_rdy,
output wire dbg_sbus_err,
input wire [W_DATA-1:0] dbg_sbus_wdata,
output wire [W_DATA-1:0] dbg_sbus_rdata,
// Level-sensitive interrupt sources
input wire [NUM_IRQ-1:0] irq, // -> mip.meip
input wire soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
input wire [NUM_IRQS-1:0] irq, // -> mip.meip
input wire soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
);
// ----------------------------------------------------------------------------

View File

@ -13,73 +13,73 @@ module hazard3_cpu_2port #(
`include "hazard3_config.vh"
) (
// Global signals
input wire clk,
input wire rst_n,
input wire clk,
input wire rst_n,
`ifdef RISCV_FORMAL
`RVFI_OUTPUTS ,
`endif
// Instruction fetch port
output wire [W_ADDR-1:0] i_haddr,
output wire i_hwrite,
output wire [1:0] i_htrans,
output wire [2:0] i_hsize,
output wire [2:0] i_hburst,
output wire [3:0] i_hprot,
output wire i_hmastlock,
output wire [7:0] i_hmaster,
input wire i_hready,
input wire i_hresp,
output wire [W_DATA-1:0] i_hwdata,
input wire [W_DATA-1:0] i_hrdata,
output wire [W_ADDR-1:0] i_haddr,
output wire i_hwrite,
output wire [1:0] i_htrans,
output wire [2:0] i_hsize,
output wire [2:0] i_hburst,
output wire [3:0] i_hprot,
output wire i_hmastlock,
output wire [7:0] i_hmaster,
input wire i_hready,
input wire i_hresp,
output wire [W_DATA-1:0] i_hwdata,
input wire [W_DATA-1:0] i_hrdata,
// Load/store port
output wire [W_ADDR-1:0] d_haddr,
output wire d_hwrite,
output wire [1:0] d_htrans,
output wire [2:0] d_hsize,
output wire [2:0] d_hburst,
output wire [3:0] d_hprot,
output wire d_hmastlock,
output wire [7:0] d_hmaster,
output wire d_hexcl,
input wire d_hready,
input wire d_hresp,
input wire d_hexokay,
output wire [W_DATA-1:0] d_hwdata,
input wire [W_DATA-1:0] d_hrdata,
output wire [W_ADDR-1:0] d_haddr,
output wire d_hwrite,
output wire [1:0] d_htrans,
output wire [2:0] d_hsize,
output wire [2:0] d_hburst,
output wire [3:0] d_hprot,
output wire d_hmastlock,
output wire [7:0] d_hmaster,
output wire d_hexcl,
input wire d_hready,
input wire d_hresp,
input wire d_hexokay,
output wire [W_DATA-1:0] d_hwdata,
input wire [W_DATA-1:0] d_hrdata,
// Debugger run/halt control
input wire dbg_req_halt,
input wire dbg_req_halt_on_reset,
input wire dbg_req_resume,
output wire dbg_halted,
output wire dbg_running,
input wire dbg_req_halt,
input wire dbg_req_halt_on_reset,
input wire dbg_req_resume,
output wire dbg_halted,
output wire dbg_running,
// Debugger access to data0 CSR
input wire [W_DATA-1:0] dbg_data0_rdata,
output wire [W_DATA-1:0] dbg_data0_wdata,
output wire dbg_data0_wen,
input wire [W_DATA-1:0] dbg_data0_rdata,
output wire [W_DATA-1:0] dbg_data0_wdata,
output wire dbg_data0_wen,
// Debugger instruction injection
input wire [W_DATA-1:0] dbg_instr_data,
input wire dbg_instr_data_vld,
output wire dbg_instr_data_rdy,
output wire dbg_instr_caught_exception,
output wire dbg_instr_caught_ebreak,
input wire [W_DATA-1:0] dbg_instr_data,
input wire dbg_instr_data_vld,
output wire dbg_instr_data_rdy,
output wire dbg_instr_caught_exception,
output wire dbg_instr_caught_ebreak,
// Optional debug system bus access patch-through
input wire [W_ADDR-1:0] dbg_sbus_addr,
input wire dbg_sbus_write,
input wire [1:0] dbg_sbus_size,
input wire dbg_sbus_vld,
output wire dbg_sbus_rdy,
output wire dbg_sbus_err,
input wire [W_DATA-1:0] dbg_sbus_wdata,
output wire [W_DATA-1:0] dbg_sbus_rdata,
input wire [W_ADDR-1:0] dbg_sbus_addr,
input wire dbg_sbus_write,
input wire [1:0] dbg_sbus_size,
input wire dbg_sbus_vld,
output wire dbg_sbus_rdy,
output wire dbg_sbus_err,
input wire [W_DATA-1:0] dbg_sbus_wdata,
output wire [W_DATA-1:0] dbg_sbus_rdata,
// Level-sensitive interrupt sources
input wire [NUM_IRQ-1:0] irq, // -> mip.meip
input wire soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
input wire [NUM_IRQS-1:0] irq, // -> mip.meip
input wire soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
);
// ----------------------------------------------------------------------------

View File

@ -92,7 +92,7 @@ module hazard3_csr #(
// Level-sensitive interrupt sources
input wire delay_irq_entry,
input wire [NUM_IRQ-1:0] irq,
input wire [NUM_IRQS-1:0] irq,
input wire irq_software,
input wire irq_timer,
@ -112,7 +112,6 @@ module hazard3_csr #(
localparam X0 = {XLEN{1'b0}};
// ----------------------------------------------------------------------------
// CSR state + update logic
// ----------------------------------------------------------------------------
@ -142,14 +141,19 @@ always @ (posedge clk or negedge rst_n) begin
end
end
// Core execution state, 1 -> M-mode, 0 -> U-mode (if implemented)
reg m_mode;
wire wen_m_mode = wen && (m_mode || debug_mode);
wire ren_m_mode = ren && (m_mode || debug_mode);
// ----------------------------------------------------------------------------
// Trap-handling CSRs
// Standard trap-handling CSRs
wire debug_suppresses_trap_update = DEBUG_SUPPORT && (debug_mode || enter_debug_mode);
// Core execution state, 1 -> M-mode, 0 -> U-mode (if implemented)
reg m_mode;
wire trapreg_update = trap_enter_vld && trap_enter_rdy && !debug_suppresses_trap_update;
wire trapreg_update_enter = trapreg_update && except != EXCEPT_MRET;
wire trapreg_update_exit = trapreg_update && except == EXCEPT_MRET;
reg mstatus_mpie;
reg mstatus_mie;
@ -157,8 +161,6 @@ reg mstatus_mpp; // only MSB is implemented
reg mstatus_mprv;
reg mstatus_tw;
wire wen_m_mode = wen && (m_mode || debug_mode);
// Spec text from priv-1.12:
// "An MRET or SRET instruction is used to return from a trap in M-mode or
// S-mode respectively. When executing an xRET instruction, supposing xPP
@ -176,25 +178,23 @@ always @ (posedge clk or negedge rst_n) begin
mstatus_mprv <= 1'b0;
mstatus_tw <= 1'b0;
end else if (CSR_M_TRAP) begin
if (trap_enter_vld && trap_enter_rdy && !debug_suppresses_trap_update) begin
if (except == EXCEPT_MRET) begin
mstatus_mpie <= 1'b1;
mstatus_mie <= mstatus_mpie;
if (U_MODE) begin
m_mode <= mstatus_mpp;
mstatus_mpp <= 1'b0;
if (!mstatus_mpp) begin
mstatus_mprv <= 1'b0;
end
end
end else begin
mstatus_mpie <= mstatus_mie;
mstatus_mie <= 1'b0;
if (U_MODE) begin
m_mode <= 1'b1;
mstatus_mpp <= m_mode;
if (trapreg_update_exit) begin
mstatus_mpie <= 1'b1;
mstatus_mie <= mstatus_mpie;
if (U_MODE) begin
m_mode <= mstatus_mpp;
mstatus_mpp <= 1'b0;
if (!mstatus_mpp) begin
mstatus_mprv <= 1'b0;
end
end
end else if (trapreg_update_enter) begin
mstatus_mpie <= mstatus_mie;
mstatus_mie <= 1'b0;
if (U_MODE) begin
m_mode <= 1'b1;
mstatus_mpp <= m_mode;
end
end else if (wen_m_mode && addr == MSTATUS) begin
mstatus_mpie <= wdata_update[7];
mstatus_mie <= wdata_update[3];
@ -249,7 +249,7 @@ always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
mepc <= X0;
end else if (CSR_M_TRAP) begin
if (trap_enter_vld && trap_enter_rdy && except != EXCEPT_MRET && !debug_suppresses_trap_update) begin
if (trapreg_update_enter) begin
mepc <= mepc_in & MEPC_MASK;
end else if (wen_m_mode && addr == MEPC) begin
mepc <= wdata_update & MEPC_MASK;
@ -265,81 +265,234 @@ always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
mie <= X0;
end else if (CSR_M_TRAP) begin
if (wen_m_mode && addr == MIE)
if (wen_m_mode && addr == MIE) begin
mie <= update_nonconst(mie, MIE_WMASK);
end else if (wen_m_mode && addr == MEICONTEXT) begin
// meicontext.clearts/mtiesave/msiesave can be used to clear and
// save standard timer and soft IRQ enables, simultaneously with
// saving external interrupt context.
mie[7] <= (mie[7] || wdata_update[3]) && !wdata_update[1];
mie[3] <= (mie[3] || wdata_update[2]) && !wdata_update[1];
end
end
end
wire mie_meie = mie[11];
// Interrupt status ("pending") register, handled later
// Interrupt pending register (assigned later). In our implementation this
// register is entirely read-only.
wire [XLEN-1:0] mip;
// None of the bits we implement are directly writeable.
// MSIP is only writeable by a "platform-defined" mechanism, and we don't implement
// one!
// Trap cause registers. The non-constant bits can be written by software,
// and update automatically on trap entry. (bits 30:0 are WLRL, so we tie most off)
// Trap cause registers. The non-constant bits can be written by software, and
// update automatically on trap entry. The `code` field need only be large
// enough to support causes that will be set by hardware, in our case 4 bits.
// (Note this is different to scause which always has a hard minimum of 5
// bits.)
reg mcause_irq;
reg [5:0] mcause_code;
reg [3:0] mcause_code;
wire mcause_irq_next;
wire [5:0] mcause_code_next;
wire [3:0] mcause_code_next;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
mcause_irq <= 1'b0;
mcause_code <= 6'h0;
mcause_code <= 4'h0;
end else if (CSR_M_TRAP) begin
if (trap_enter_vld && trap_enter_rdy && except != EXCEPT_MRET && !debug_suppresses_trap_update) begin
if (trapreg_update_enter) begin
mcause_irq <= mcause_irq_next;
mcause_code <= mcause_code_next;
end else if (wen_m_mode && addr == MCAUSE) begin
{mcause_irq, mcause_code} <= {wdata_update[31], wdata_update[5:0]};
{mcause_irq, mcause_code} <= {wdata_update[31], wdata_update[3:0]};
end
end
end
// Custom external interrupt enable registers (would be at top of mie, but that
// only leaves room for 16 external interrupts)
// ----------------------------------------------------------------------------
// Custom external IRQ handling CSRs
localparam N_IRQ_REG0 = NUM_IRQ >= 32 ? 32 : NUM_IRQ ;
localparam N_IRQ_REG1 = NUM_IRQ >= 64 ? 32 : NUM_IRQ <= 32 ? 0 : NUM_IRQ - 32;
localparam N_IRQ_REG2 = NUM_IRQ >= 96 ? 32 : NUM_IRQ <= 64 ? 0 : NUM_IRQ - 64;
localparam N_IRQ_REG3 = NUM_IRQ >= 128 ? 32 : NUM_IRQ <= 96 ? 0 : NUM_IRQ - 96;
localparam MAX_IRQS = 512;
localparam [MAX_IRQS-1:0] IRQ_IMPL_MASK = ~({MAX_IRQS{1'b1}} << NUM_IRQS);
localparam MEIE0_WMASK = ~({XLEN{1'b1}} << N_IRQ_REG0);
localparam MEIE1_WMASK = ~({XLEN{1'b1}} << N_IRQ_REG1);
localparam MEIE2_WMASK = ~({XLEN{1'b1}} << N_IRQ_REG2);
localparam MEIE3_WMASK = ~({XLEN{1'b1}} << N_IRQ_REG3);
localparam IRQ_PRIORITY_MASK = ~(4'hf >> IRQ_PRIORITY_BITS);
reg [XLEN-1:0] meie0;
reg [XLEN-1:0] meie1;
reg [XLEN-1:0] meie2;
reg [XLEN-1:0] meie3;
// Assigned later:
wire [MAX_IRQS-1:0] meipa;
wire [8:0] meinext_irq;
wire meinext_noirq;
reg [3:0] eirq_highest_priority;
reg [MAX_IRQS-1:0] meiea;
reg [MAX_IRQS-1:0] meifa;
reg [4*MAX_IRQS-1:0] meipra;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
meie0 <= X0;
meie1 <= X0;
meie2 <= X0;
meie3 <= X0;
end else if (wen_m_mode && addr == MEIE0) begin
meie0 <= update_nonconst(meie0, MEIE0_WMASK);
end else if (wen_m_mode && addr == MEIE1) begin
meie1 <= update_nonconst(meie1, MEIE1_WMASK);
end else if (wen_m_mode && addr == MEIE2) begin
meie2 <= update_nonconst(meie2, MEIE2_WMASK);
end else if (wen_m_mode && addr == MEIE3) begin
meie3 <= update_nonconst(meie3, MEIE3_WMASK);
meiea <= {MAX_IRQS{1'b0}};
meifa <= {MAX_IRQS{1'b0}};
meipra <= {4*MAX_IRQS{1'b0}};
end else begin
// Tie off unimplemented fields with a constant mask, then rely on
// further constant folding. Otherwise subsequent RTL will get a bit
// out of hand.
if (wen_m_mode && addr == MEIEA) begin
meiea[16 * wdata[4:0] +: 16] <= IRQ_IMPL_MASK[16 * wdata[4:0] +: 16] & wdata_update[31:16];
end else if (wen_m_mode && addr == MEIFA) begin
meifa[16 * wdata[4:0] +: 16] <= IRQ_IMPL_MASK[16 * wdata[4:0] +: 16] & wdata_update[31:16];
end else if (wen_m_mode && addr == MEIPRA) begin
meipra[16 * wdata[6:0] +: 16] <= {
{4{IRQ_IMPL_MASK[4 * wdata[6:0] + 0]}},
{4{IRQ_IMPL_MASK[4 * wdata[6:0] + 1]}},
{4{IRQ_IMPL_MASK[4 * wdata[6:0] + 2]}},
{4{IRQ_IMPL_MASK[4 * wdata[6:0] + 3]}}
} & {4{~(4'hf >> IRQ_PRIORITY_BITS)}} & wdata_update[31:16];
end
// Clear IRQ force when the corresponding IRQ is sample from meinext
// (so that an IRQ can be posted *once* without modifying the ISR source)
if (ren_m_mode && addr == MEINEXT && !meinext_noirq) begin
meifa[meinext_irq] <= 1'b0;
end
end
end
// Assigned later:
wire [XLEN-1:0] meip0;
wire [XLEN-1:0] meip1;
wire [XLEN-1:0] meip2;
wire [XLEN-1:0] meip3;
wire [6:0] mlei;
reg [3:0] meicontext_pppreempt;
reg [3:0] meicontext_ppreempt;
reg [4:0] meicontext_preempt;
reg meicontext_noirq;
reg [8:0] meicontext_irq;
reg meicontext_mreteirq;
wire [4:0] preempt_level_next = meinext_noirq ? 5'h10 : (
(5'd1 << (4 - IRQ_PRIORITY_BITS)) + {1'b0, eirq_highest_priority}
);
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
meicontext_pppreempt <= 4'h0;
meicontext_ppreempt <= 4'h0;
meicontext_preempt <= 5'h0;
meicontext_noirq <= 1'b1;
meicontext_irq <= 9'h0;
meicontext_mreteirq <= 1'b0;
end else if (trapreg_update_enter) begin
if (mcause_irq_next && mcause_code_next == 4'hb) begin
// Priority save. Note the MSB of preempt needn't be saved since,
// when it is set, preemption is impossible, so we won't be here.
meicontext_pppreempt <= meicontext_ppreempt & IRQ_PRIORITY_MASK;
meicontext_ppreempt <= meicontext_preempt[3:0] & IRQ_PRIORITY_MASK;
// Setting preempt isn't strictly necessary, since an updating read
// of meinext ought to be performed before re-enabling IRQs via
// mstatus.mie, but it seems the least surprising thing to do:
meicontext_preempt <= preempt_level_next & {1'b1, IRQ_PRIORITY_MASK};
meicontext_mreteirq <= 1'b1;
end else begin
meicontext_mreteirq <= 1'b0;
end
end else if (trapreg_update_exit) begin
meicontext_mreteirq <= 1'b0;
if (meicontext_mreteirq) begin
// Priority restore
meicontext_pppreempt <= 4'h0;
meicontext_ppreempt <= meicontext_pppreempt & IRQ_PRIORITY_MASK;
meicontext_preempt <= {1'b0, meicontext_ppreempt & IRQ_PRIORITY_MASK};
end
end else if (wen_m_mode && addr == MEICONTEXT) begin
meicontext_pppreempt <= wdata_update[31:28] & IRQ_PRIORITY_MASK;
meicontext_ppreempt <= wdata_update[27:24] & IRQ_PRIORITY_MASK;
meicontext_preempt <= wdata_update[20:16] & {1'b1, IRQ_PRIORITY_MASK};
meicontext_noirq <= wdata_update[15];
meicontext_irq <= wdata_update[12:4];
meicontext_mreteirq <= wdata_update[0];
end else if (wen_m_mode && addr == MEINEXT && wdata_update[0]) begin
// Interrupt has been sampled, with the update request set, so update
// the context (including preemption level) appropriately.
meicontext_preempt <= preempt_level_next & IRQ_PRIORITY_MASK;
meicontext_noirq <= meinext_noirq;
meicontext_irq <= meinext_irq;
end
end
// ----------------------------------------------------------------------------
// External interrupt logic
// Signal to standard IRQ logic (mip etc) that at least one of the external IRQ
// signals should cause a trap to the mip.meip vector:
wire external_irq_pending;
// Register external IRQ signals (mainly to avoid a through-path from IRQs to
// bus request signals)
reg [NUM_IRQS-1:0] irq_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
irq_r <= {NUM_IRQS{1'b0}};
end else begin
irq_r <= irq;
end
end
// Trap request is asserted when there is an interrupt at or above our current
// preemption level. meinext displays interrupts at or above our *previous*
// preemption level: this masking helps avoid re-taking IRQs in frames that you
// have preempted.
assign meipa = {{MAX_IRQS{1'b0}}, irq_r} | meifa;
reg [NUM_IRQS-1:0] eirq_active_above_preempt;
reg [NUM_IRQS-1:0] eirq_active_above_ppreempt;
always @ (*) begin: eirq_compare
integer i;
for (i = 0; i < NUM_IRQS; i = i + 1) begin
eirq_active_above_preempt[i] = meipa[i] && meiea[i] && meipra[i * 4 +: 4] >= meicontext_preempt;
eirq_active_above_ppreempt[i] = meipa[i] && meiea[i] && meipra[i * 4 +: 4] >= meicontext_ppreempt;
end
end
assign external_irq_pending = |eirq_active_above_preempt;
assign meinext_noirq = ~|eirq_active_above_ppreempt;
// Two things remaining to calculate:
//
// - What is the IRQ number of the highest-priority pending IRQ that is above
// meicontext.ppreempt
// - What is the priority of that IRQ
//
// In the second case we can relax the calculation to ignore ppreempt, since it
// only needs to be valid if such an IRQ exists. Currently we choose to reuse
// the same priority selector (possibly longer critpath while saving area), but
// we could use a second priority selector that ignores ppreempt masking.
wire [NUM_IRQS-1:0] highest_eirq_onehot;
wire [8:0] meinext_irq_unmasked;
hazard3_onehot_priority_dynamic #(
.W_REQ (NUM_IRQS),
.N_PRIORITIES (16),
.PRIORITY_HIGHEST_WINS (1),
.TIEBREAK_HIGHEST_WINS (0)
) eirq_priority_u (
.priority (meipra[NUM_IRQS-1:0] & {NUM_IRQS{IRQ_PRIORITY_MASK}}),
.req (eirq_active_above_ppreempt),
.gnt (highest_eirq_onehot)
);
always @ (*) begin: get_highest_eirq_priority
integer i;
eirq_highest_priority = 4'h0;
for (i = 0; i < NUM_IRQS; i = i + 1) begin
eirq_highest_priority = meipra[4 * i +: 4] & {4{highest_eirq_onehot[i]}};
end
end
hazard3_onehot_encode #(
.W_REQ (NUM_IRQS),
.W_GNT (9)
) eirq_encode_u (
.req (highest_eirq_onehot),
.gnt (meinext_irq_unmasked)
);
assign meinext_irq = meinext_irq_unmasked & {9{!meinext_noirq}};
// ----------------------------------------------------------------------------
// Counters
@ -597,8 +750,8 @@ always @ (*) begin
decode_match = match_mrw;
rdata = {
mcause_irq, // Sign bit is 1 for IRQ, 0 for exception
{26{1'b0}}, // Padding
mcause_code[4:0] // Enough for 16 external IRQs, which is all we have room for in mip/mie
{27{1'b0}}, // Padding
mcause_code[3:0] // Enough for 16 external IRQs, which is all we have room for in mip/mie
};
end
@ -938,49 +1091,63 @@ always @ (*) begin
// ------------------------------------------------------------------------
// Custom CSRs
MEIE0: if (CSR_M_TRAP && N_IRQ_REG0 > 0) begin
MEIEA: if (CSR_M_TRAP) begin
decode_match = match_mrw;
rdata = meie0;
rdata = {
meiea[wdata[4:0] * 16 +: 16],
16'h0
};
end
MEIE1: if (CSR_M_TRAP && N_IRQ_REG1 > 0) begin
MEIPA: if (CSR_M_TRAP) begin
decode_match = match_mrw;
rdata = meie1;
rdata = {
meipa[wdata[4:0] * 16 +: 16],
16'h0
};
end
MEIE2: if (CSR_M_TRAP && N_IRQ_REG2 > 0) begin
MEIFA: if (CSR_M_TRAP) begin
decode_match = match_mrw;
rdata = meie2;
rdata = {
meifa[wdata[4:0] * 16 +: 16],
16'h0
};
end
MEIE3: if (CSR_M_TRAP && N_IRQ_REG3 > 0) begin
MEIPRA: if (CSR_M_TRAP) begin
decode_match = match_mrw;
rdata = meie3;
rdata = {
meipra[wdata[6:0] * 16 +: 16],
16'h0
};
end
MEIP0: if (CSR_M_TRAP && N_IRQ_REG0 > 0) begin
decode_match = match_mro;
rdata = meip0;
MEINEXT: if (CSR_M_TRAP) begin
decode_match = match_mrw;
rdata = {
meinext_noirq,
20'h0,
meinext_irq,
2'h0
};
end
MEIP1: if (CSR_M_TRAP && N_IRQ_REG1 > 0) begin
decode_match = match_mro;
rdata = meip1;
end
MEIP2: if (CSR_M_TRAP && N_IRQ_REG2 > 0) begin
decode_match = match_mro;
rdata = meip2;
end
MEIP3: if (CSR_M_TRAP && N_IRQ_REG3 > 0) begin
decode_match = match_mro;
rdata = meip3;
end
MLEI: if (CSR_M_TRAP) begin
decode_match = match_mro;
rdata = {{XLEN-9{1'b0}}, mlei, 2'b00};
MEICONTEXT: if (CSR_M_TRAP) begin
decode_match = match_mrw;
rdata = {
meicontext_pppreempt,
meicontext_ppreempt,
3'h0,
meicontext_preempt,
meicontext_noirq,
2'h0,
meicontext_irq,
mie[7] && wdata_update[1],
mie[3] && wdata_update[1],
1'b0,
meicontext_mreteirq
};
end
default: begin end
@ -1097,30 +1264,19 @@ assign dbg_instr_caught_exception = debug_mode && except != EXCEPT_NONE && excep
// ----------------------------------------------------------------------------
// Trap request generation
reg [NUM_IRQ-1:0] irq_r;
reg irq_software_r;
reg irq_timer_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
irq_r <= {NUM_IRQ{1'b0}};
irq_software_r <= 1'b0;
irq_timer_r <= 1'b0;
end else begin
irq_r <= irq;
irq_software_r <= irq_software;
irq_timer_r <= irq_timer;
end
end
localparam MAX_IRQ = 128;
wire [MAX_IRQ-1:0] meip = {{MAX_IRQ-NUM_IRQ{1'b0}}, irq_r};
wire [MAX_IRQ-1:0] meie = {meie3, meie2, meie1, meie0};
assign {meip3, meip2, meip1, meip0} = meip;
wire external_irq_pending = |(meie & meip);
assign mip = {
20'h0, // Reserved
external_irq_pending, // meip, Global pending bit for external IRQs
@ -1137,16 +1293,6 @@ wire irq_active = |(mip & mie) && mstatus_mie && !dcsr_step;
// Additionally, wfi is treated as a nop during single-stepping and D-mode.
assign wfi_stall_clear = |(mip & mie) || dcsr_step || debug_mode || want_halt_irq_if_no_exception;
wire [6:0] external_irq_num;
assign mlei = external_irq_num;
hazard3_priority_encode #(
.W_REQ (MAX_IRQ)
) mlei_priority_encode (
.req (meie & meip),
.gnt (external_irq_num)
);
// Priority order from priv spec: external > software > timer
wire [3:0] standard_irq_num =
mip[11] && mie[11] ? 4'd11 :
@ -1159,13 +1305,13 @@ assign exception_req_any = except != EXCEPT_NONE && !(
except == EXCEPT_EBREAK && (m_mode ? dcsr_ebreakm : dcsr_ebreaku)
);
wire [5:0] mcause_irq_num = irq_active ? {2'h0, standard_irq_num} : 6'd0;
wire [3:0] mcause_irq_num = irq_active ? standard_irq_num : 4'd0;
wire [5:0] vector_sel = !exception_req_any && irq_vector_enable ? mcause_irq_num : 6'd0;
wire [3:0] vector_sel = !exception_req_any && irq_vector_enable ? mcause_irq_num : 4'd0;
assign trap_addr =
except == EXCEPT_MRET ? mepc :
pending_dbg_resume ? dpc : mtvec | {24'h0, vector_sel, 2'h0};
pending_dbg_resume ? dpc : mtvec | {26'h0, vector_sel, 2'h0};
// Check for exception-like or IRQ-like trap entry; any debug mode entry takes
// priority over any regular trap.
@ -1192,7 +1338,7 @@ assign trap_enter_soon = trap_enter_vld || (
);
assign mcause_irq_next = !exception_req_any;
assign mcause_code_next = exception_req_any ? {2'h0, except} : mcause_irq_num;
assign mcause_code_next = exception_req_any ? except : mcause_irq_num;
// ----------------------------------------------------------------------------
// Privilege state outputs

View File

@ -158,15 +158,14 @@ localparam MENVCFG = 12'h30a;
localparam MENVCFGH = 12'h31a;
// Custom M-mode CSRs:
localparam MEIE0 = 12'hbe0; // External interrupt enable register 0
localparam MEIE1 = 12'hbe1; // External interrupt enable register 1
localparam MEIE2 = 12'hbe2; // External interrupt enable register 2
localparam MEIE3 = 12'hbe3; // External interrupt enable register 3
localparam MEIP0 = 12'hfe0; // External interrupt pending register 0
localparam MEIP1 = 12'hfe1; // External interrupt pending register 1
localparam MEIP2 = 12'hfe2; // External interrupt pending register 2
localparam MEIP3 = 12'hfe3; // External interrupt pending register 3
localparam MLEI = 12'hfe4; // Lowest external interrupt number
localparam MEIEA = 12'hbe0; // External interrupt pending array
localparam MEIPA = 12'hbe1; // External interrupt enable array
localparam MEIFA = 12'hbe2; // External interrupt force array
localparam MEIPRA = 12'hbe3; // External interrupt priority array
localparam MEINEXT = 12'hbe4; // Next external interrupt
localparam MEICONTEXT = 12'hbe5; // External interrupt context register
localparam MSLEEP = 12'hbf0; // M-mode sleep control register
// ----------------------------------------------------------------------------
// U-mode CSRs
@ -179,6 +178,9 @@ localparam CYCLEH = 12'hc80;
localparam TIMEH = 12'hc81;
localparam INSTRETH = 12'hc82;
// Custom U-mode CSRs
localparam SLEEP = 12'h8f0; // U-mode subset of M-mode sleep control
// ----------------------------------------------------------------------------
// Trigger Module

View File

@ -5,10 +5,16 @@
#include "stdint.h"
#endif
#define hazard3_csr_dmdata0 0xbff // Debug-mode shadow CSR for DM data transfer
#define hazard3_csr_meie0 0xbe0 // External interrupt enable IRQ0 -> 31
#define hazard3_csr_meip0 0xfe0 // External interrupt pending IRQ0 -> 31
#define hazard3_csr_mlei 0xfe4 // Lowest external interrupt (pending & enabled)
#define hazard3_csr_dmdata0 0xbff // Debug-mode shadow CSR for DM data transfer
#define hazard3_csr_meiea 0xbe0 // External interrupt pending array
#define hazard3_csr_meipa 0xbe1 // External interrupt enable array
#define hazard3_csr_meifa 0xbe2 // External interrupt force array
#define hazard3_csr_meipr 0xbe3 // External interrupt priority array
#define hazard3_csr_meinext 0xbe4 // Next external interrupt
#define hazard3_csr_meicontext 0xbe5 // External interrupt context register
#define hazard3_csr_msleep 0xbf0 // M-mode sleep control register
#define _read_csr(csrname) ({ \
uint32_t __csr_tmp_u32; \
@ -28,10 +34,31 @@
asm volatile ("csrc " #csrname ", %0" : : "r" (data)); \
})
#define _read_write_csr(csrname, data) ({ \
uint32_t __csr_tmp_u32; \
asm volatile ("csrrw %0, " #csrname ", %1" : "=r" (__csr_tmp_u32) : "r" (data)); \
__csr_tmp_u32; \
})
#define _read_set_csr(csrname, data) ({ \
uint32_t __csr_tmp_u32; \
asm volatile ("csrrs %0, " #csrname ", %1" : "=r" (__csr_tmp_u32) : "r" (data)); \
__csr_tmp_u32; \
})
#define _read_clear_csr(csrname, data) ({ \
uint32_t __csr_tmp_u32; \
asm volatile ("csrrc %0, " #csrname ", %1" : "=r" (__csr_tmp_u32) : "r" (data)); \
__csr_tmp_u32; \
})
// Argument macro expansion layer
#define read_csr(csrname) _read_csr(csrname)
#define write_csr(csrname, data) _write_csr(csrname, data)
#define set_csr(csrname, data) _set_csr(csrname, data)
#define clear_csr(csrname, data) _clear_csr(csrname, data)
#define read_csr(csrname) _read_csr(csrname)
#define write_csr(csrname, data) _write_csr(csrname, data)
#define set_csr(csrname, data) _set_csr(csrname, data)
#define clear_csr(csrname, data) _clear_csr(csrname, data)
#define read_write_csr(csrname, data) _read_write_csr(csrname, data)
#define read_set_csr(csrname, data) _read_set_csr(csrname, data)
#define read_clear_csr(csrname, data) _read_clear_csr(csrname, data)
#endif

View File

@ -0,0 +1,31 @@
#ifndef _HAZARD3_IRQ_H
#define _HAZARD3_IRQ_H
#include "hazard3_csr.h"
#include "stdint.h"
#include "stdbool.h"
#define h3irq_array_read(csr, index) (read_set_csr(csr, (index)) >> 16)
#define h3irq_array_write(csr, index, data) (write_csr(csr, (index) | ((uint32_t)(data) << 16)))
#define h3irq_array_set(csr, index, data) (set_csr(csr, (index) | ((uint32_t)(data) << 16)))
#define h3irq_array_clear(csr, index, data) (clear_csr(csr, (index) | ((uint32_t)(data) << 16)))
static inline void h3irq_enable(unsigned int irq, bool enable) {
if (enable) {
h3irq_array_set(hazard3_csr_meiea, irq >> 4, 1u << (irq & 0xfu));
}
else {
h3irq_array_clear(hazard3_csr_meiea, irq >> 4, 1u << (irq & 0xfu));
}
}
static inline bool h3irq_pending(unsigned int irq) {
return h3irq_array_read(hazard3_csr_meipa, irq >> 4) & (1u << (irq & 0xfu));
}
static inline bool h3irq_force_pending(unsigned int irq) {
h3irq_array_set(hazard3_csr_meifa, irq >> 4, 1u << (irq & 0xfu));
}
#endif

View File

@ -137,9 +137,12 @@ int main() {
(void)read_csr(dscratch0);
(void)read_csr(dscratch1);
(void)read_csr(hazard3_csr_dmdata0);
(void)read_csr(hazard3_csr_meie0);
(void)read_csr(hazard3_csr_meip0);
(void)read_csr(hazard3_csr_mlei);
(void)read_csr(hazard3_csr_meiea);
(void)read_csr(hazard3_csr_meipa);
(void)read_csr(hazard3_csr_meifa);
(void)read_csr(hazard3_csr_meipr);
(void)read_csr(hazard3_csr_meinext);
(void)read_csr(hazard3_csr_meicontext);
return 0;
}

View File

@ -184,14 +184,20 @@ CSR was 7b1
CSR was 7b2
-> exception, mcause = 2, mpp = 0 // dscratch1
CSR was 7b3
-> exception, mcause = 2, mpp = 0 // hazard3 dmdata0
-> exception, mcause = 2, mpp = 0 // hazard3_csr_dmdata0
CSR was bff
-> exception, mcause = 2, mpp = 0 // hazard3 meie0
-> exception, mcause = 2, mpp = 0 // hazard3_csr_meiea
CSR was be0
-> exception, mcause = 2, mpp = 0 // hazard3 meip0
CSR was fe0
-> exception, mcause = 2, mpp = 0 // hazard3 mlei
CSR was fe4
-> exception, mcause = 2, mpp = 0 // hazard3_csr_meipa
CSR was be1
-> exception, mcause = 2, mpp = 0 // hazard3_csr_meifa
CSR was be2
-> exception, mcause = 2, mpp = 0 // hazard3_csr_meipr
CSR was be3
-> exception, mcause = 2, mpp = 0 // hazard3_csr_meinext
CSR was be4
-> exception, mcause = 2, mpp = 0 // hazard3_csr_meicontext
CSR was be5
-> exception, mcause = 3, mpp = 0 // This is the ebreak that ends the test
*******************************************************************************/
@ -295,9 +301,12 @@ void read_all_csrs() {
(void)read_csr(dscratch0);
(void)read_csr(dscratch1);
(void)read_csr(hazard3_csr_dmdata0);
(void)read_csr(hazard3_csr_meie0);
(void)read_csr(hazard3_csr_meip0);
(void)read_csr(hazard3_csr_mlei);
(void)read_csr(hazard3_csr_meiea);
(void)read_csr(hazard3_csr_meipa);
(void)read_csr(hazard3_csr_meifa);
(void)read_csr(hazard3_csr_meipr);
(void)read_csr(hazard3_csr_meinext);
(void)read_csr(hazard3_csr_meicontext);
}
void __attribute__((naked)) ebreak_trampoline() {

View File

@ -64,10 +64,6 @@ CSR was 7b3
CSR was bff
-> exception, mcause = 2 // write to dmdata0, D-mode
CSR was bff
-> exception, mcause = 2 // write to meip0, read-only
CSR was fe0
-> exception, mcause = 2 // write to mlei, read-only
CSR was fe4
*******************************************************************************/
@ -170,9 +166,13 @@ int main() {
write_csr(dscratch0, read_csr(dscratch0 ));
write_csr(dscratch1, read_csr(dscratch1 ));
write_csr(hazard3_csr_dmdata0, read_csr(hazard3_csr_dmdata0));
write_csr(hazard3_csr_meie0, read_csr(hazard3_csr_meie0 ));
write_csr(hazard3_csr_meip0, read_csr(hazard3_csr_meip0 ));
write_csr(hazard3_csr_mlei, read_csr(hazard3_csr_mlei ));
write_csr(hazard3_csr_meiea, read_csr(hazard3_csr_meiea ));
write_csr(hazard3_csr_meipa, read_csr(hazard3_csr_meipa ));
write_csr(hazard3_csr_meifa, read_csr(hazard3_csr_meifa ));
write_csr(hazard3_csr_meipr, read_csr(hazard3_csr_meipr ));
write_csr(hazard3_csr_meinext, read_csr(hazard3_csr_meinext ));
write_csr(hazard3_csr_meicontext, read_csr(hazard3_csr_meicontext));
return 0;
}

View File

@ -1,5 +1,6 @@
#include "tb_cxxrtl_io.h"
#include "hazard3_csr.h"
#include "hazard3_irq.h"
// Pend all IRQs, enable them one-by-one and log their firing.
@ -7,14 +8,13 @@
int main() {
asm volatile ("csrsi mstatus, 0x8");
write_csr(hazard3_csr_meie0, 0u);
write_csr(mie, mie_meie);
tb_set_irq_masked(-1u);
for (int i = 31; i >= 0; --i) {
tb_printf("Enabling IRQ %d\n", i);
write_csr(hazard3_csr_meie0, 1u << i);
h3irq_enable(i, true);
}
return 0;
@ -23,148 +23,154 @@ int main() {
void __attribute__((interrupt)) isr_external_irq() {
tb_puts("-> external irq handler\n");
tb_assert(read_csr(mcause) == 0x8000000bu, "mcause should indicate external IRQ\n");
tb_assert(read_csr(mip) == 0x880u, "mip should indicate external + timer IRQ\n");
// The external IRQ pending bit should immediately clear due to the
// premption priority being boosted above the IRQ we took.
tb_assert(read_csr(mip) == 0x080u, "mip should indicate timer IRQ only\n");
// mlei updates dynamically, should be read exactly once at the start of an
// meinext updates dynamically, should be read exactly once at the start of an
// IRQ handler.
uint32_t mlei = read_csr(hazard3_csr_mlei);
tb_printf("mlei = %u\n", mlei);
tb_printf("meip0 = %08x\n", read_csr(hazard3_csr_meip0));
uint32_t meinext = read_csr(hazard3_csr_meinext);
tb_printf("meinext = %u\n", meinext);
tb_printf(
"meipa = %08x\n",
h3irq_array_read(hazard3_csr_meipa, 0) |
((uint32_t)h3irq_array_read(hazard3_csr_meipa, 1) << 16)
);
// mlei is scaled by 4 to make it cheaper to index a software vector table.
tb_assert(read_csr(hazard3_csr_meip0) & (1u << (mlei >> 2)), "IRQ indicated by mlei is not pending\n");
tb_clr_irq_masked(1u << (mlei >> 2));
// meinext is scaled by 4 to make it cheaper to index a software vector table.
tb_assert(h3irq_pending(meinext >> 2), "IRQ indicated by meinext is not pending\n");
tb_clr_irq_masked(1u << (meinext >> 2));
}
/*EXPECTED-OUTPUT***************************************************************
Enabling IRQ 31
-> external irq handler
mlei = 124
meip0 = ffffffff
meinext = 124
meipa = ffffffff
Enabling IRQ 30
-> external irq handler
mlei = 120
meip0 = 7fffffff
meinext = 120
meipa = 7fffffff
Enabling IRQ 29
-> external irq handler
mlei = 116
meip0 = 3fffffff
meinext = 116
meipa = 3fffffff
Enabling IRQ 28
-> external irq handler
mlei = 112
meip0 = 1fffffff
meinext = 112
meipa = 1fffffff
Enabling IRQ 27
-> external irq handler
mlei = 108
meip0 = 0fffffff
meinext = 108
meipa = 0fffffff
Enabling IRQ 26
-> external irq handler
mlei = 104
meip0 = 07ffffff
meinext = 104
meipa = 07ffffff
Enabling IRQ 25
-> external irq handler
mlei = 100
meip0 = 03ffffff
meinext = 100
meipa = 03ffffff
Enabling IRQ 24
-> external irq handler
mlei = 96
meip0 = 01ffffff
meinext = 96
meipa = 01ffffff
Enabling IRQ 23
-> external irq handler
mlei = 92
meip0 = 00ffffff
meinext = 92
meipa = 00ffffff
Enabling IRQ 22
-> external irq handler
mlei = 88
meip0 = 007fffff
meinext = 88
meipa = 007fffff
Enabling IRQ 21
-> external irq handler
mlei = 84
meip0 = 003fffff
meinext = 84
meipa = 003fffff
Enabling IRQ 20
-> external irq handler
mlei = 80
meip0 = 001fffff
meinext = 80
meipa = 001fffff
Enabling IRQ 19
-> external irq handler
mlei = 76
meip0 = 000fffff
meinext = 76
meipa = 000fffff
Enabling IRQ 18
-> external irq handler
mlei = 72
meip0 = 0007ffff
meinext = 72
meipa = 0007ffff
Enabling IRQ 17
-> external irq handler
mlei = 68
meip0 = 0003ffff
meinext = 68
meipa = 0003ffff
Enabling IRQ 16
-> external irq handler
mlei = 64
meip0 = 0001ffff
meinext = 64
meipa = 0001ffff
Enabling IRQ 15
-> external irq handler
mlei = 60
meip0 = 0000ffff
meinext = 60
meipa = 0000ffff
Enabling IRQ 14
-> external irq handler
mlei = 56
meip0 = 00007fff
meinext = 56
meipa = 00007fff
Enabling IRQ 13
-> external irq handler
mlei = 52
meip0 = 00003fff
meinext = 52
meipa = 00003fff
Enabling IRQ 12
-> external irq handler
mlei = 48
meip0 = 00001fff
meinext = 48
meipa = 00001fff
Enabling IRQ 11
-> external irq handler
mlei = 44
meip0 = 00000fff
meinext = 44
meipa = 00000fff
Enabling IRQ 10
-> external irq handler
mlei = 40
meip0 = 000007ff
meinext = 40
meipa = 000007ff
Enabling IRQ 9
-> external irq handler
mlei = 36
meip0 = 000003ff
meinext = 36
meipa = 000003ff
Enabling IRQ 8
-> external irq handler
mlei = 32
meip0 = 000001ff
meinext = 32
meipa = 000001ff
Enabling IRQ 7
-> external irq handler
mlei = 28
meip0 = 000000ff
meinext = 28
meipa = 000000ff
Enabling IRQ 6
-> external irq handler
mlei = 24
meip0 = 0000007f
meinext = 24
meipa = 0000007f
Enabling IRQ 5
-> external irq handler
mlei = 20
meip0 = 0000003f
meinext = 20
meipa = 0000003f
Enabling IRQ 4
-> external irq handler
mlei = 16
meip0 = 0000001f
meinext = 16
meipa = 0000001f
Enabling IRQ 3
-> external irq handler
mlei = 12
meip0 = 0000000f
meinext = 12
meipa = 0000000f
Enabling IRQ 2
-> external irq handler
mlei = 8
meip0 = 00000007
meinext = 8
meipa = 00000007
Enabling IRQ 1
-> external irq handler
mlei = 4
meip0 = 00000003
meinext = 4
meipa = 00000003
Enabling IRQ 0
-> external irq handler
mlei = 0
meip0 = 00000001
meinext = 0
meipa = 00000001
*******************************************************************************/

View File

@ -1,5 +1,6 @@
#include "tb_cxxrtl_io.h"
#include "hazard3_csr.h"
#include "hazard3_irq.h"
// Set IRQ mask (meie0) wide-open, then pend the IRQs one by one and log their
// firing.
@ -8,7 +9,9 @@
int main() {
asm volatile ("csrsi mstatus, 0x8");
write_csr(hazard3_csr_meie0, -1u);
h3irq_array_write(hazard3_csr_meiea, 0, 0xffffu);
h3irq_array_write(hazard3_csr_meiea, 1, 0xffffu);
write_csr(mie, mie_meie);
for (int i = 0; i < 32; ++i) {
@ -22,148 +25,154 @@ int main() {
void __attribute__((interrupt)) isr_external_irq() {
tb_puts("-> external irq handler\n");
tb_assert(read_csr(mcause) == 0x8000000bu, "mcause should indicate external IRQ\n");
tb_assert(read_csr(mip) == 0x880u, "mip should indicate external + timer IRQ\n");
// External IRQ does not appear pending because, after taking the
// interrupt, it no longer has sufficient priority to preempt.
tb_assert(read_csr(mip) == 0x080u, "mip should indicate timer IRQ only\n");
// mlei updates dynamically, should be read exactly once at the start of an
// meinext updates dynamically, should be read exactly once at the start of an
// IRQ handler.
uint32_t mlei = read_csr(hazard3_csr_mlei);
tb_printf("mlei = %u\n", mlei);
tb_printf("meip0 = %08x\n", read_csr(hazard3_csr_meip0));
uint32_t meinext = read_csr(hazard3_csr_meinext);
tb_printf("meinext = %u\n", meinext);
tb_printf(
"meipa = %08x\n",
h3irq_array_read(hazard3_csr_meipa, 0) |
((uint32_t)h3irq_array_read(hazard3_csr_meipa, 1) << 16)
);
// mlei is scaled by 4 to make it cheaper to index a software vector table.
tb_assert(read_csr(hazard3_csr_meip0) & (1u << (mlei >> 2)), "IRQ indicated by mlei is not pending\n");
tb_clr_irq_masked(1u << (mlei >> 2));
// meinext is scaled by 4 to make it cheaper to index a software vector table.
tb_assert(h3irq_pending(meinext >> 2), "IRQ indicated by meinext is not pending\n");
tb_clr_irq_masked(1u << (meinext >> 2));
}
/*EXPECTED-OUTPUT***************************************************************
Setting IRQ 0
-> external irq handler
mlei = 0
meip0 = 00000001
meinext = 0
meipa = 00000001
Setting IRQ 1
-> external irq handler
mlei = 4
meip0 = 00000002
meinext = 4
meipa = 00000002
Setting IRQ 2
-> external irq handler
mlei = 8
meip0 = 00000004
meinext = 8
meipa = 00000004
Setting IRQ 3
-> external irq handler
mlei = 12
meip0 = 00000008
meinext = 12
meipa = 00000008
Setting IRQ 4
-> external irq handler
mlei = 16
meip0 = 00000010
meinext = 16
meipa = 00000010
Setting IRQ 5
-> external irq handler
mlei = 20
meip0 = 00000020
meinext = 20
meipa = 00000020
Setting IRQ 6
-> external irq handler
mlei = 24
meip0 = 00000040
meinext = 24
meipa = 00000040
Setting IRQ 7
-> external irq handler
mlei = 28
meip0 = 00000080
meinext = 28
meipa = 00000080
Setting IRQ 8
-> external irq handler
mlei = 32
meip0 = 00000100
meinext = 32
meipa = 00000100
Setting IRQ 9
-> external irq handler
mlei = 36
meip0 = 00000200
meinext = 36
meipa = 00000200
Setting IRQ 10
-> external irq handler
mlei = 40
meip0 = 00000400
meinext = 40
meipa = 00000400
Setting IRQ 11
-> external irq handler
mlei = 44
meip0 = 00000800
meinext = 44
meipa = 00000800
Setting IRQ 12
-> external irq handler
mlei = 48
meip0 = 00001000
meinext = 48
meipa = 00001000
Setting IRQ 13
-> external irq handler
mlei = 52
meip0 = 00002000
meinext = 52
meipa = 00002000
Setting IRQ 14
-> external irq handler
mlei = 56
meip0 = 00004000
meinext = 56
meipa = 00004000
Setting IRQ 15
-> external irq handler
mlei = 60
meip0 = 00008000
meinext = 60
meipa = 00008000
Setting IRQ 16
-> external irq handler
mlei = 64
meip0 = 00010000
meinext = 64
meipa = 00010000
Setting IRQ 17
-> external irq handler
mlei = 68
meip0 = 00020000
meinext = 68
meipa = 00020000
Setting IRQ 18
-> external irq handler
mlei = 72
meip0 = 00040000
meinext = 72
meipa = 00040000
Setting IRQ 19
-> external irq handler
mlei = 76
meip0 = 00080000
meinext = 76
meipa = 00080000
Setting IRQ 20
-> external irq handler
mlei = 80
meip0 = 00100000
meinext = 80
meipa = 00100000
Setting IRQ 21
-> external irq handler
mlei = 84
meip0 = 00200000
meinext = 84
meipa = 00200000
Setting IRQ 22
-> external irq handler
mlei = 88
meip0 = 00400000
meinext = 88
meipa = 00400000
Setting IRQ 23
-> external irq handler
mlei = 92
meip0 = 00800000
meinext = 92
meipa = 00800000
Setting IRQ 24
-> external irq handler
mlei = 96
meip0 = 01000000
meinext = 96
meipa = 01000000
Setting IRQ 25
-> external irq handler
mlei = 100
meip0 = 02000000
meinext = 100
meipa = 02000000
Setting IRQ 26
-> external irq handler
mlei = 104
meip0 = 04000000
meinext = 104
meipa = 04000000
Setting IRQ 27
-> external irq handler
mlei = 108
meip0 = 08000000
meinext = 108
meipa = 08000000
Setting IRQ 28
-> external irq handler
mlei = 112
meip0 = 10000000
meinext = 112
meipa = 10000000
Setting IRQ 29
-> external irq handler
mlei = 116
meip0 = 20000000
meinext = 116
meipa = 20000000
Setting IRQ 30
-> external irq handler
mlei = 120
meip0 = 40000000
meinext = 120
meipa = 40000000
Setting IRQ 31
-> external irq handler
mlei = 124
meip0 = 80000000
meinext = 124
meipa = 80000000
*******************************************************************************/

View File

@ -1,5 +1,6 @@
#include "tb_cxxrtl_io.h"
#include "hazard3_csr.h"
#include "hazard3_irq.h"
// Fire all IRQs simultaneously, and log the resulting handler calls
@ -8,7 +9,8 @@
int main() {
asm volatile ("csrsi mstatus, 0x8");
write_csr(mie, mie_meie);
write_csr(hazard3_csr_meie0, -1u);
h3irq_array_write(hazard3_csr_meiea, 0, 0xffffu);
h3irq_array_write(hazard3_csr_meiea, 1, 0xffffu);
tb_puts("Firing all IRQs\n");
tb_set_irq_masked(-1u);
@ -20,118 +22,124 @@ int main() {
void __attribute__((interrupt)) isr_external_irq() {
tb_puts("-> external irq handler\n");
tb_assert(read_csr(mcause) == 0x8000000bu, "mcause should indicate external IRQ\n");
tb_assert(read_csr(mip) == 0x880u, "mip should indicate external + timer IRQ\n");
// Once an interrupt has fired, it does not appear pending in mip since it
// can't preempt itself unless its priority is raised.
tb_assert(read_csr(mip) == 0x080u, "mip should indicate timer IRQ only\n");
// mlei updates dynamically, should be read exactly once at the start of an
// meinext updates dynamically, should be read exactly once at the start of an
// IRQ handler.
uint32_t mlei = read_csr(hazard3_csr_mlei);
tb_printf("mlei = %u\n", mlei);
tb_printf("meip0 = %08x\n", read_csr(hazard3_csr_meip0));
uint32_t meinext = read_csr(hazard3_csr_meinext);
tb_printf("meinext = %u\n", meinext);
tb_printf(
"meipa = %08x\n",
h3irq_array_read(hazard3_csr_meipa, 0) |
((uint32_t)h3irq_array_read(hazard3_csr_meipa, 1) << 16)
);
// mlei is scaled by 4 to make it cheaper to index a software vector table.
tb_assert(read_csr(hazard3_csr_meip0) & (1u << (mlei >> 2)), "IRQ indicated by mlei is not pending\n");
tb_clr_irq_masked(1u << (mlei >> 2));
// meinext is scaled by 4 to make it cheaper to index a software vector table.
tb_assert(h3irq_pending(meinext >> 2), "IRQ indicated by meinext is not pending\n");
tb_clr_irq_masked(1u << (meinext >> 2));
}
/*EXPECTED-OUTPUT***************************************************************
Firing all IRQs
-> external irq handler
mlei = 0
meip0 = ffffffff
meinext = 0
meipa = ffffffff
-> external irq handler
mlei = 4
meip0 = fffffffe
meinext = 4
meipa = fffffffe
-> external irq handler
mlei = 8
meip0 = fffffffc
meinext = 8
meipa = fffffffc
-> external irq handler
mlei = 12
meip0 = fffffff8
meinext = 12
meipa = fffffff8
-> external irq handler
mlei = 16
meip0 = fffffff0
meinext = 16
meipa = fffffff0
-> external irq handler
mlei = 20
meip0 = ffffffe0
meinext = 20
meipa = ffffffe0
-> external irq handler
mlei = 24
meip0 = ffffffc0
meinext = 24
meipa = ffffffc0
-> external irq handler
mlei = 28
meip0 = ffffff80
meinext = 28
meipa = ffffff80
-> external irq handler
mlei = 32
meip0 = ffffff00
meinext = 32
meipa = ffffff00
-> external irq handler
mlei = 36
meip0 = fffffe00
meinext = 36
meipa = fffffe00
-> external irq handler
mlei = 40
meip0 = fffffc00
meinext = 40
meipa = fffffc00
-> external irq handler
mlei = 44
meip0 = fffff800
meinext = 44
meipa = fffff800
-> external irq handler
mlei = 48
meip0 = fffff000
meinext = 48
meipa = fffff000
-> external irq handler
mlei = 52
meip0 = ffffe000
meinext = 52
meipa = ffffe000
-> external irq handler
mlei = 56
meip0 = ffffc000
meinext = 56
meipa = ffffc000
-> external irq handler
mlei = 60
meip0 = ffff8000
meinext = 60
meipa = ffff8000
-> external irq handler
mlei = 64
meip0 = ffff0000
meinext = 64
meipa = ffff0000
-> external irq handler
mlei = 68
meip0 = fffe0000
meinext = 68
meipa = fffe0000
-> external irq handler
mlei = 72
meip0 = fffc0000
meinext = 72
meipa = fffc0000
-> external irq handler
mlei = 76
meip0 = fff80000
meinext = 76
meipa = fff80000
-> external irq handler
mlei = 80
meip0 = fff00000
meinext = 80
meipa = fff00000
-> external irq handler
mlei = 84
meip0 = ffe00000
meinext = 84
meipa = ffe00000
-> external irq handler
mlei = 88
meip0 = ffc00000
meinext = 88
meipa = ffc00000
-> external irq handler
mlei = 92
meip0 = ff800000
meinext = 92
meipa = ff800000
-> external irq handler
mlei = 96
meip0 = ff000000
meinext = 96
meipa = ff000000
-> external irq handler
mlei = 100
meip0 = fe000000
meinext = 100
meipa = fe000000
-> external irq handler
mlei = 104
meip0 = fc000000
meinext = 104
meipa = fc000000
-> external irq handler
mlei = 108
meip0 = f8000000
meinext = 108
meipa = f8000000
-> external irq handler
mlei = 112
meip0 = f0000000
meinext = 112
meipa = f0000000
-> external irq handler
mlei = 116
meip0 = e0000000
meinext = 116
meipa = e0000000
-> external irq handler
mlei = 120
meip0 = c0000000
meinext = 120
meipa = c0000000
-> external irq handler
mlei = 124
meip0 = 80000000
meinext = 124
meipa = 80000000
Returned OK

View File

@ -1,29 +1,32 @@
TOP := tb
DOTF := tb.f
TOP := tb
DOTF := tb.f
CPU_RESET_VECTOR := 32'h40
CPU_RESET_VECTOR := 32'h40
EXTENSION_C := 1
EXTENSION_M := 1
EXTENSION_ZBA := 1
EXTENSION_ZBB := 1
EXTENSION_ZBC := 1
EXTENSION_ZBS := 1
EXTENSION_C := 1
EXTENSION_M := 1
EXTENSION_ZBA := 1
EXTENSION_ZBB := 1
EXTENSION_ZBC := 1
EXTENSION_ZBS := 1
DEBUG_SUPPORT := 1
U_MODE := 1
PMP_REGIONS := 4
DEBUG_SUPPORT := 1
U_MODE := 1
PMP_REGIONS := 4
MULDIV_UNROLL := 2
MUL_FAST := 1
MUL_FASTER := 1
MULH_FAST := 1
FAST_BRANCHCMP := 1
REDUCED_BYPASS := 0
NUM_IRQS := 32
IRQ_PRIORITY_BITS := 4
MVENDORID_VAL := 32'hdeadbeef
MIMPID_VAL := 32'h12345678
MCONFIGPTR_VAL := 32'h9abcdef0
MULDIV_UNROLL := 2
MUL_FAST := 1
MUL_FASTER := 1
MULH_FAST := 1
FAST_BRANCHCMP := 1
REDUCED_BYPASS := 0
MVENDORID_VAL := 32'hdeadbeef
MIMPID_VAL := 32'h12345678
MCONFIGPTR_VAL := 32'h9abcdef0
.PHONY: clean all
@ -39,6 +42,8 @@ SYNTH_CMD += chparam -set EXTENSION_ZBS $(EXTENSION_ZBS) $(TOP);
SYNTH_CMD += chparam -set DEBUG_SUPPORT $(DEBUG_SUPPORT) $(TOP);
SYNTH_CMD += chparam -set U_MODE $(U_MODE) $(TOP);
SYNTH_CMD += chparam -set PMP_REGIONS $(PMP_REGIONS) $(TOP);
SYNTH_CMD += chparam -set NUM_IRQS $(NUM_IRQS) $(TOP);
SYNTH_CMD += chparam -set IRQ_PRIORITY_BITS $(IRQ_PRIORITY_BITS) $(TOP);
SYNTH_CMD += chparam -set CSR_COUNTER 1 $(TOP);
SYNTH_CMD += chparam -set RESET_VECTOR $(CPU_RESET_VECTOR) $(TOP);
SYNTH_CMD += chparam -set REDUCED_BYPASS $(REDUCED_BYPASS) $(TOP);

View File

@ -7,50 +7,50 @@ module tb #(
`include "hazard3_config.vh"
) (
// Global signals
input wire clk,
input wire rst_n,
input wire clk,
input wire rst_n,
// JTAG port
input wire tck,
input wire trst_n,
input wire tms,
input wire tdi,
output wire tdo,
input wire tck,
input wire trst_n,
input wire tms,
input wire tdi,
output wire tdo,
// Instruction fetch port
output wire [W_ADDR-1:0] i_haddr,
output wire i_hwrite,
output wire [1:0] i_htrans,
output wire i_hexcl,
output wire [2:0] i_hsize,
output wire [2:0] i_hburst,
output wire [3:0] i_hprot,
output wire i_hmastlock,
input wire i_hready,
input wire i_hresp,
input wire i_hexokay,
output wire [W_DATA-1:0] i_hwdata,
input wire [W_DATA-1:0] i_hrdata,
output wire [W_ADDR-1:0] i_haddr,
output wire i_hwrite,
output wire [1:0] i_htrans,
output wire i_hexcl,
output wire [2:0] i_hsize,
output wire [2:0] i_hburst,
output wire [3:0] i_hprot,
output wire i_hmastlock,
input wire i_hready,
input wire i_hresp,
input wire i_hexokay,
output wire [W_DATA-1:0] i_hwdata,
input wire [W_DATA-1:0] i_hrdata,
// Load/store port
output wire [W_ADDR-1:0] d_haddr,
output wire d_hwrite,
output wire [1:0] d_htrans,
output wire d_hexcl,
output wire [2:0] d_hsize,
output wire [2:0] d_hburst,
output wire [3:0] d_hprot,
output wire d_hmastlock,
input wire d_hready,
input wire d_hresp,
input wire d_hexokay,
output wire [W_DATA-1:0] d_hwdata,
input wire [W_DATA-1:0] d_hrdata,
output wire [W_ADDR-1:0] d_haddr,
output wire d_hwrite,
output wire [1:0] d_htrans,
output wire d_hexcl,
output wire [2:0] d_hsize,
output wire [2:0] d_hburst,
output wire [3:0] d_hprot,
output wire d_hmastlock,
input wire d_hready,
input wire d_hresp,
input wire d_hexokay,
output wire [W_DATA-1:0] d_hwdata,
input wire [W_DATA-1:0] d_hrdata,
// Level-sensitive interrupt sources
input wire [NUM_IRQ-1:0] irq, // -> mip.meip
input wire [1:0] soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
input wire [NUM_IRQS-1:0] irq, // -> mip.meip
input wire [1:0] soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
);
// JTAG-DTM IDCODE, selected after TAP reset, would normally be a

View File

@ -7,50 +7,50 @@ module tb #(
`include "hazard3_config.vh"
) (
// Global signals
input wire clk,
input wire rst_n,
input wire clk,
input wire rst_n,
// JTAG port
input wire tck,
input wire trst_n,
input wire tms,
input wire tdi,
output wire tdo,
input wire tck,
input wire trst_n,
input wire tms,
input wire tdi,
output wire tdo,
// Core 0 bus (named I for consistency with 1-core 2-port tb)
output wire [W_ADDR-1:0] i_haddr,
output wire i_hwrite,
output wire [1:0] i_htrans,
output wire i_hexcl,
output wire [2:0] i_hsize,
output wire [2:0] i_hburst,
output wire [3:0] i_hprot,
output wire i_hmastlock,
input wire i_hready,
input wire i_hresp,
input wire i_hexokay,
output wire [W_DATA-1:0] i_hwdata,
input wire [W_DATA-1:0] i_hrdata,
output wire [W_ADDR-1:0] i_haddr,
output wire i_hwrite,
output wire [1:0] i_htrans,
output wire i_hexcl,
output wire [2:0] i_hsize,
output wire [2:0] i_hburst,
output wire [3:0] i_hprot,
output wire i_hmastlock,
input wire i_hready,
input wire i_hresp,
input wire i_hexokay,
output wire [W_DATA-1:0] i_hwdata,
input wire [W_DATA-1:0] i_hrdata,
// Core 1 bus (named D for consistency with 1-core 2-port tb)
output wire [W_ADDR-1:0] d_haddr,
output wire d_hwrite,
output wire [1:0] d_htrans,
output wire d_hexcl,
output wire [2:0] d_hsize,
output wire [2:0] d_hburst,
output wire [3:0] d_hprot,
output wire d_hmastlock,
input wire d_hready,
input wire d_hresp,
input wire d_hexokay,
output wire [W_DATA-1:0] d_hwdata,
input wire [W_DATA-1:0] d_hrdata,
output wire [W_ADDR-1:0] d_haddr,
output wire d_hwrite,
output wire [1:0] d_htrans,
output wire d_hexcl,
output wire [2:0] d_hsize,
output wire [2:0] d_hburst,
output wire [3:0] d_hprot,
output wire d_hmastlock,
input wire d_hready,
input wire d_hresp,
input wire d_hexokay,
output wire [W_DATA-1:0] d_hwdata,
input wire [W_DATA-1:0] d_hrdata,
// Level-sensitive interrupt sources
input wire [NUM_IRQ-1:0] irq, // -> mip.meip
input wire [1:0] soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
input wire [NUM_IRQS-1:0] irq, // -> mip.meip
input wire [1:0] soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
);
// JTAG-DTM IDCODE, selected after TAP reset, would normally be a