First pass at implementing the new IRQ controls. Works well enough that the old tests pass :)
This commit is contained in:
parent
69917ccbbe
commit
15cb21ae43
|
@ -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():
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
*******************************************************************************/
|
||||
|
|
|
@ -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
|
||||
|
||||
*******************************************************************************/
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue