First attempt at hacking in triggers, at least seems to have not broken other exception logic. Not yet tested.

This commit is contained in:
Luke Wren 2022-08-22 08:45:06 +01:00
parent 5d6b5a80b0
commit 6e3799eed0
11 changed files with 391 additions and 77 deletions

View File

@ -16,4 +16,5 @@ file hazard3_decode.v
file hazard3_csr.v
file hazard3_regfile_1w2r.v
file hazard3_pmp.v
file hazard3_triggers.v
include .

View File

@ -120,6 +120,10 @@ parameter PMP_HARDWIRED_CFG = PMP_REGIONS > 0 ? {PMP_REGIONS{8'h00}} : 1'b0,
// Requires: CSR_M_MANDATORY, CSR_M_TRAP.
parameter DEBUG_SUPPORT = 0,
// BREAKPOINT_TRIGGERS: Number of triggers which support type=2 execute=1
// (but not store/load=1, i.e. not a watchpoint). Requires: DEBUG_SUPPORT
parameter BREAKPOINT_TRIGGERS = 0,
// ----------------------------------------------------------------------------
// External interrupt support

View File

@ -12,47 +12,48 @@
// except for MHARTID_VAL. It must be defined once before each include of
// this file.
.RESET_VECTOR (RESET_VECTOR),
.MTVEC_INIT (MTVEC_INIT),
.EXTENSION_A (EXTENSION_A),
.EXTENSION_C (EXTENSION_C),
.EXTENSION_M (EXTENSION_M),
.EXTENSION_ZBA (EXTENSION_ZBA),
.EXTENSION_ZBB (EXTENSION_ZBB),
.EXTENSION_ZBC (EXTENSION_ZBC),
.EXTENSION_ZBS (EXTENSION_ZBS),
.EXTENSION_ZBKB (EXTENSION_ZBKB),
.EXTENSION_XH3B (EXTENSION_XH3B),
.EXTENSION_ZIFENCEI (EXTENSION_ZIFENCEI),
.CSR_M_MANDATORY (CSR_M_MANDATORY),
.CSR_M_TRAP (CSR_M_TRAP),
.CSR_COUNTER (CSR_COUNTER),
.U_MODE (U_MODE),
.PMP_REGIONS (PMP_REGIONS),
.PMP_GRAIN (PMP_GRAIN),
.PMP_HARDWIRED (PMP_HARDWIRED),
.PMP_HARDWIRED_ADDR (PMP_HARDWIRED_ADDR),
.PMP_HARDWIRED_CFG (PMP_HARDWIRED_CFG),
.DEBUG_SUPPORT (DEBUG_SUPPORT),
.NUM_IRQS (NUM_IRQS),
.IRQ_PRIORITY_BITS (IRQ_PRIORITY_BITS),
.MVENDORID_VAL (MVENDORID_VAL),
.MIMPID_VAL (MIMPID_VAL),
.RESET_VECTOR (RESET_VECTOR),
.MTVEC_INIT (MTVEC_INIT),
.EXTENSION_A (EXTENSION_A),
.EXTENSION_C (EXTENSION_C),
.EXTENSION_M (EXTENSION_M),
.EXTENSION_ZBA (EXTENSION_ZBA),
.EXTENSION_ZBB (EXTENSION_ZBB),
.EXTENSION_ZBC (EXTENSION_ZBC),
.EXTENSION_ZBS (EXTENSION_ZBS),
.EXTENSION_ZBKB (EXTENSION_ZBKB),
.EXTENSION_XH3B (EXTENSION_XH3B),
.EXTENSION_ZIFENCEI (EXTENSION_ZIFENCEI),
.CSR_M_MANDATORY (CSR_M_MANDATORY),
.CSR_M_TRAP (CSR_M_TRAP),
.CSR_COUNTER (CSR_COUNTER),
.U_MODE (U_MODE),
.PMP_REGIONS (PMP_REGIONS),
.PMP_GRAIN (PMP_GRAIN),
.PMP_HARDWIRED (PMP_HARDWIRED),
.PMP_HARDWIRED_ADDR (PMP_HARDWIRED_ADDR),
.PMP_HARDWIRED_CFG (PMP_HARDWIRED_CFG),
.DEBUG_SUPPORT (DEBUG_SUPPORT),
.BREAKPOINT_TRIGGERS (BREAKPOINT_TRIGGERS),
.NUM_IRQS (NUM_IRQS),
.IRQ_PRIORITY_BITS (IRQ_PRIORITY_BITS),
.MVENDORID_VAL (MVENDORID_VAL),
.MIMPID_VAL (MIMPID_VAL),
`ifndef HAZARD3_CONFIG_INST_NO_MHARTID
.MHARTID_VAL (MHARTID_VAL),
.MHARTID_VAL (MHARTID_VAL),
`endif
.MCONFIGPTR_VAL (MCONFIGPTR_VAL),
.REDUCED_BYPASS (REDUCED_BYPASS),
.MULDIV_UNROLL (MULDIV_UNROLL),
.MUL_FAST (MUL_FAST),
.MUL_FASTER (MUL_FASTER),
.MULH_FAST (MULH_FAST),
.FAST_BRANCHCMP (FAST_BRANCHCMP),
.BRANCH_PREDICTOR (BRANCH_PREDICTOR),
.MTVEC_WMASK (MTVEC_WMASK),
.RESET_REGFILE (RESET_REGFILE),
.W_ADDR (W_ADDR),
.W_DATA (W_DATA)
.MCONFIGPTR_VAL (MCONFIGPTR_VAL),
.REDUCED_BYPASS (REDUCED_BYPASS),
.MULDIV_UNROLL (MULDIV_UNROLL),
.MUL_FAST (MUL_FAST),
.MUL_FASTER (MUL_FASTER),
.MULH_FAST (MULH_FAST),
.FAST_BRANCHCMP (FAST_BRANCHCMP),
.BRANCH_PREDICTOR (BRANCH_PREDICTOR),
.MTVEC_WMASK (MTVEC_WMASK),
.RESET_REGFILE (RESET_REGFILE),
.W_ADDR (W_ADDR),
.W_DATA (W_DATA)
`ifdef HAZARD3_CONFIG_INST_NO_MHARTID
`undef HAZARD3_CONFIG_INST_NO_MHARTID

View File

@ -296,6 +296,7 @@ reg [W_DATA-1:0] xm_result;
reg [1:0] xm_addr_align;
reg [W_MEMOP-1:0] xm_memop;
reg [W_EXCEPT-1:0] xm_except;
reg xm_except_to_d_mode;
reg xm_wfi;
reg xm_delay_irq_entry;
@ -377,6 +378,11 @@ assign x_stall =
wire m_wfi_stall_clear;
wire x_loadstore_pmp_fail;
wire x_exec_pmp_fail;
wire x_trig_break;
wire x_trig_break_d_mode;
// ----------------------------------------------------------------------------
// Execution logic
@ -465,9 +471,6 @@ hazard3_alu #(
// Load/store bus request
wire x_loadstore_pmp_fail;
wire x_exec_pmp_fail;
wire x_unaligned_addr = d_memop != MEMOP_NONE && (
bus_hsize_d == HSIZE_WORD && |bus_haddr_d[1:0] ||
bus_hsize_d == HSIZE_HWORD && bus_haddr_d[0]
@ -608,6 +611,7 @@ always @ (*) begin
x_stall_on_exclusive_overlap ||
x_loadstore_pmp_fail ||
x_exec_pmp_fail ||
x_trig_break ||
x_unaligned_addr ||
m_trap_enter_soon ||
(xm_wfi && !m_wfi_stall_clear) // FIXME will cause a timing issue, better to stall til *after* clear
@ -750,7 +754,7 @@ wire x_jump_req_unchecked = !x_stall_on_raw && (
d_branchcond == BCOND_NZERO && x_branch_cmp
);
assign x_jump_req = x_jump_req_unchecked && !x_jump_misaligned && !x_exec_pmp_fail;
assign x_jump_req = x_jump_req_unchecked && !x_jump_misaligned && !x_exec_pmp_fail || x_trig_break;
assign x_btb_set = |BRANCH_PREDICTOR && (
x_jump_req_unchecked && d_addr_offs[W_ADDR - 1] && !x_branch_was_predicted &&
@ -809,6 +813,46 @@ end else begin: no_pmp
end
endgenerate
// Triggers
wire [11:0] x_trig_cfg_addr;
wire x_trig_cfg_wen;
wire [W_DATA-1:0] x_trig_cfg_wdata;
wire [W_DATA-1:0] x_trig_cfg_rdata;
wire x_trig_m_en;
generate
if (BREAKPOINT_TRIGGERS > 0) begin: have_triggers
hazard3_triggers #(
`include "hazard3_config_inst.vh"
) triggers (
.clk (clk),
.rst_n (rst_n),
.cfg_addr (x_trig_cfg_addr),
.cfg_wen (x_trig_cfg_wen),
.cfg_wdata (x_trig_cfg_wdata),
.cfg_rdata (x_trig_cfg_rdata),
.trig_m_en (x_trig_m_en),
.pc (d_pc),
.m_mode (x_mmode_execution),
.d_mode (debug_mode),
.break (x_trig_break),
.break_d_mode (x_trig_break_d_mode)
);
end else begin: no_triggers
assign x_trig_cfg_rdata = {W_DATA{1'b0}};
assign x_trig_break = 1'b0;
assign x_trig_break_d_mode = 1'b0;
end
endgenerate
// CSRs and Trap Handling
wire [W_DATA-1:0] x_csr_wdata = d_csr_w_imm ?
@ -850,6 +894,7 @@ end
wire [W_ADDR-1:0] m_exception_return_addr;
wire [W_EXCEPT-1:0] x_except =
x_trig_break ? EXCEPT_EBREAK :
x_exec_pmp_fail ? EXCEPT_INSTR_FAULT :
x_jump_req_unchecked && x_jump_misaligned ? EXCEPT_INSTR_MISALIGN :
x_csr_illegal_access ? EXCEPT_INSTR_ILLEGAL :
@ -925,12 +970,19 @@ hazard3_csr #(
.irq_software (soft_irq),
.irq_timer (timer_irq),
.except (xm_except),
.except_to_d_mode (xm_except_to_d_mode),
.pmp_cfg_addr (x_pmp_cfg_addr),
.pmp_cfg_wen (x_pmp_cfg_wen),
.pmp_cfg_wdata (x_pmp_cfg_wdata),
.pmp_cfg_rdata (x_pmp_cfg_rdata),
.trig_cfg_addr (x_trig_cfg_addr),
.trig_cfg_wen (x_trig_cfg_wen),
.trig_cfg_wdata (x_trig_cfg_wdata),
.trig_cfg_rdata (x_trig_cfg_rdata),
.trig_m_en (x_trig_m_en),
// Other CSR-specific signalling
.permit_wfi (x_permit_wfi),
.instr_ret (x_instr_ret)
@ -942,6 +994,7 @@ always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
xm_memop <= MEMOP_NONE;
xm_except <= EXCEPT_NONE;
xm_except_to_d_mode <= 1'b0;
xm_wfi <= 1'b0;
{xm_rs1, xm_rs2, xm_rd} <= {3 * W_REGADDR{1'b0}};
end else begin
@ -950,6 +1003,7 @@ always @ (posedge clk or negedge rst_n) begin
// If some X-sourced exception has squashed the address phase, need to squash the data phase too.
xm_memop <= x_unaligned_addr || x_exec_pmp_fail || x_loadstore_pmp_fail ? MEMOP_NONE : d_memop;
xm_except <= x_except;
xm_except_to_d_mode <= x_trig_break_d_mode;
xm_wfi <= d_wfi && !x_exec_pmp_fail;
// Note the d_starved term is required because it is possible
// (e.g. PMP X permission fail) to except when the frontend is
@ -959,6 +1013,7 @@ always @ (posedge clk or negedge rst_n) begin
xm_rd <= {W_REGADDR{1'b0}};
xm_memop <= MEMOP_NONE;
xm_except <= EXCEPT_NONE;
xm_except_to_d_mode <= 1'b0;
xm_wfi <= 1'b0;
end
end else if (bus_dph_err_d) begin

View File

@ -89,6 +89,7 @@ module hazard3_csr #(
// Exceptions must *not* be a function of bus stall.
input wire [W_EXCEPT-1:0] except,
input wire except_to_d_mode,
// Level-sensitive interrupt sources
input wire delay_irq_entry,
@ -102,6 +103,13 @@ module hazard3_csr #(
output wire [W_DATA-1:0] pmp_cfg_wdata,
input wire [W_DATA-1:0] pmp_cfg_rdata,
// Trigger config interface
output wire [11:0] trig_cfg_addr,
output reg trig_cfg_wen,
output wire [W_DATA-1:0] trig_cfg_wdata,
input wire [W_DATA-1:0] trig_cfg_rdata,
output wire trig_m_en,
// Other CSR-specific signalling
output wire permit_wfi,
input wire instr_ret
@ -619,6 +627,25 @@ end
assign dbg_data0_wdata = wdata;
assign dbg_data0_wen = debug_mode && wen && addr == DMDATA0;
reg tcontrol_mte;
reg tcontrol_mpte;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
tcontrol_mpte <= 1'b0;
tcontrol_mte <= 1'b0;
end else if (wen_m_mode && addr == TCONTROL) begin
tcontrol_mpte <= wdata_update[7] && DEBUG_SUPPORT;
tcontrol_mte <= wdata_update[3] && DEBUG_SUPPORT;
end else if (DEBUG_SUPPORT && trapreg_update_enter) begin
tcontrol_mte <= 1'b0;
tcontrol_mpte <= tcontrol_mte;
end else if (DEBUG_SUPPORT && trapreg_update_exit) begin
tcontrol_mte <= tcontrol_mpte;
tcontrol_mpte <= 1'b1;
end
end
// ----------------------------------------------------------------------------
// Read port + detect addressing of unmapped CSRs
// ----------------------------------------------------------------------------
@ -637,6 +664,7 @@ always @ (*) begin
decode_match = 1'b0;
rdata = {XLEN{1'b0}};
pmp_cfg_wen = 1'b0;
trig_cfg_wen = 1'b0;
case (addr)
// ------------------------------------------------------------------------
@ -1047,12 +1075,61 @@ always @ (*) begin
// ------------------------------------------------------------------------
// Trigger Module CSRs
// If triggers aren't supported, OpenOCD expects the following:
// - tselect must be present
// - tselect must raise an exception when written to
// Otherwise it returns an error instead of 0 count when enumerating triggers
// If triggers aren't supported, we implement tselect as hardwired 0,
// tinfo as hardwired 1 (meaning type=0 always) and tdata as hardwired 0
// (meaning type=0). The debugger will see the first trigger as
// unimplemented, and immediately halt discovery.
TSELECT: if (DEBUG_SUPPORT) begin
decode_match = match_mro;
decode_match = match_mrw;
if (BREAKPOINT_TRIGGERS > 0) begin
trig_cfg_wen = match_mrw && wen;
rdata = trig_cfg_rdata;
end else begin
rdata = 32'h00000000;
end
end
TDATA1: if (DEBUG_SUPPORT) begin
decode_match = match_mrw;
if (BREAKPOINT_TRIGGERS > 0) begin
trig_cfg_wen = match_mrw && wen;
rdata = trig_cfg_rdata;
end else begin
rdata = 32'h00000000;
end
end
TDATA2: if (DEBUG_SUPPORT) begin
decode_match = match_mrw;
if (BREAKPOINT_TRIGGERS > 0) begin
trig_cfg_wen = match_mrw && wen;
rdata = trig_cfg_rdata;
end else begin
rdata = 32'h00000000;
end
end
TINFO: if (DEBUG_SUPPORT) begin
// Note tinfo is a read-write CSR (writes don't trap) even though it
// is entirely read-only.
decode_match = match_mrw;
if (BREAKPOINT_TRIGGERS > 0) begin
trig_cfg_wen = match_mrw && wen;
rdata = trig_cfg_rdata;
end else begin
rdata = 32'h00000001;
end
end
TCONTROL: if (DEBUG_SUPPORT && BREAKPOINT_TRIGGERS > 0) begin
decode_match = match_mrw;
rdata = {
24'h0,
tcontrol_mpte,
3'h0,
tcontrol_mte,
3'h0
};
end
// ------------------------------------------------------------------------
@ -1218,10 +1295,10 @@ end
wire exception_req_any;
wire halt_delayed_by_exception = exception_req_any || loadstore_dphase_pending;
// This would also include triggers, if/when those are implemented:
wire want_halt_except = DEBUG_SUPPORT && !debug_mode && (
dcsr_ebreakm && m_mode && except == EXCEPT_EBREAK ||
dcsr_ebreaku && !m_mode && except == EXCEPT_EBREAK
dcsr_ebreaku && !m_mode && except == EXCEPT_EBREAK ||
except_to_d_mode && except == EXCEPT_EBREAK
);
// Note exception-like causes (trigger, ebreak) are higher priority than
@ -1243,7 +1320,7 @@ wire want_halt_irq_if_no_exception = DEBUG_SUPPORT && !debug_mode && !want_halt_
wire want_halt_irq = want_halt_irq_if_no_exception && !halt_delayed_by_exception;
assign dcause_next =
// Trigger would be highest priority if implemented
except == EXCEPT_EBREAK && except_to_d_mode ? 3'h2 : // trigger (priority 4)
except == EXCEPT_EBREAK ? 3'h1 : // ebreak (priority 3)
dbg_req_halt_prev || (dbg_req_halt_on_reset && have_just_reset) ? 3'h3 : // halt or reset-halt (priority 1, 2)
3'h4; // single-step (priority 0)
@ -1346,6 +1423,10 @@ assign mcause_code_next = exception_req_any ? except : mcause_irq_num;
assign pmp_cfg_addr = addr;
assign pmp_cfg_wdata = wdata_update;
assign trig_cfg_addr = addr;
assign trig_cfg_wdata = wdata_update;
assign trig_m_en = tcontrol_mte;
// Effective privilege for execution. Used for:
// - Privilege level of branch target fetches (frontend keeps fetch privilege
// constant during sequential fetch)
@ -1441,6 +1522,11 @@ always @ (posedge clk) begin
assert(!trap_is_irq);
end
// This must be a breakpoint exception (presumably from the trigger unit).
if (except_to_d_mode) begin
assert(except == EXCEPT_EBREAK);
end
end
`endif

View File

@ -188,6 +188,11 @@ localparam SLEEP = 12'h8f0; // U-mode subset of M-mode sleep control
// Trigger Module
localparam TSELECT = 12'h7a0;
localparam TDATA1 = 12'h7a1;
localparam TDATA2 = 12'h7a2;
localparam TINFO = 12'h7a4;
localparam TCONTROL = 12'h7a5;
localparam MCONTEXT = 12'h7a8;
// ----------------------------------------------------------------------------
// D-mode CSRs

158
hdl/hazard3_triggers.v Normal file
View File

@ -0,0 +1,158 @@
/*****************************************************************************\
| Copyright (C) 2022 Luke Wren |
| SPDX-License-Identifier: Apache-2.0 |
\*****************************************************************************/
`default_nettype none
// Trigger unit. Currently only breakpoint (type=2 execute=1 select=0)
// triggers are supported. Only exact address matches are supported, and the
// timing is always "early".
module hazard3_triggers #(
`include "hazard3_config.vh"
) (
input wire clk,
input wire rst_n,
// Config interface passed through CSR block
input wire [11:0] cfg_addr,
input wire cfg_wen,
input wire [W_DATA-1:0] cfg_wdata,
output reg [W_DATA-1:0] cfg_rdata,
// Global trigger-to-M-mode enable (e.g. from tcontrol or mstatus.mie)
input wire trig_m_en,
// PC query
input wire [W_ADDR-1:0] pc,
input wire m_mode,
input wire d_mode,
// Break request
output wire break,
output wire break_d_mode
);
`include "hazard3_csr_addr.vh"
// ----------------------------------------------------------------------------
// Configuration state
parameter W_TSELECT = $clog2(BREAKPOINT_TRIGGERS);
reg [W_TSELECT-1:0] tselect;
// Note tdata1 and mcontrol are the same CSR. tdata1 refers to the universal
// fields (type/dmode) and mcontrol refers to those fields specific to
// type=2 (address/data match), the only trigger type we implement.
reg tdata1_dmode [0:BREAKPOINT_TRIGGERS-1];
reg mcontrol_action [0:BREAKPOINT_TRIGGERS-1];
reg mcontrol_m [0:BREAKPOINT_TRIGGERS-1];
reg mcontrol_u [0:BREAKPOINT_TRIGGERS-1];
reg [W_DATA-1:0] tdata2 [0:BREAKPOINT_TRIGGERS-1];
// ----------------------------------------------------------------------------
// Configuration write port
always @ (posedge clk or negedge rst_n) begin: cfg_update
integer i;
if (!rst_n) begin
tselect <= {W_TSELECT{1'b0}};
for (i = 0; i < BREAKPOINT_TRIGGERS; i = i + 1) begin
tdata1_dmode[i] <= 1'b0;
mcontrol_action[i] <= 1'b0;
mcontrol_m[i] <= 1'b0;
mcontrol_u[i] <= 1'b0;
tdata2[i] <= {W_DATA{1'b0}};
end
end else if (cfg_wen && cfg_addr == TSELECT) begin
tselect <= cfg_wdata[W_TSELECT-1:0];
end else if (cfg_wen && tselect < BREAKPOINT_TRIGGERS && !(tdata1_dmode[i] && !d_mode)) begin
// Handle writes to tselect-indexed registers (note writes to D-mode
// triggers in non-D-mode are ignored rather than raising an exception)
if (cfg_addr == TDATA1) begin
tdata1_dmode[tselect] <= cfg_wdata[27];
mcontrol_action[tselect] <= cfg_wdata[12];
mcontrol_m[tselect] <= cfg_wdata[6];
mcontrol_u[tselect] <= cfg_wdata[3];
end else if (cfg_addr == TDATA2) begin
tdata2[tselect] <= cfg_wdata;
end
end
end
// ----------------------------------------------------------------------------
// Configuration read port
always @ (*) begin
cfg_rdata = {W_DATA{1'b0}};
if (cfg_addr == TSELECT) begin
cfg_rdata = {{W_DATA-W_TSELECT{1'b0}}, tselect};
end else if (cfg_addr == TDATA1) begin
if (tselect >= BREAKPOINT_TRIGGERS) begin
// Nonexistent -> type=0
cfg_rdata = {W_DATA{1'b0}};
end else begin
cfg_rdata = {
4'h2, // type = address/data match
tdata1_dmode[tselect],
6'h00, // maskmax = 0, exact match only
1'b0, // hit = 0, not implemented
1'b0, // select = 0, address match only
1'b0, // timing = 0, trigger before execution
2'h0, // sizelo = 0, unsized
{3'h0, mcontrol_action[tselect]}, // action = 0/1, break to M-mode/D-mode
1'b0, // chain = 0, chaining is useless for exact matches
3'h0, // match = 0, exact match only
mcontrol_m[tselect],
1'b0,
1'b0, // s = 0, no S-mode
mcontrol_u[tselect],
1'b1, // execute = 1, this is a breakpoint
1'b0, // store = 0, this is not a watchpoint
1'b0 // load = 0, this is not a watchpoint
};
end
end else if (cfg_rdata == TDATA2) begin
if (tselect >= BREAKPOINT_TRIGGERS) begin
cfg_rdata = {W_DATA{1'b0}};
end else begin
cfg_rdata = tdata2[tselect];
end
end else if (cfg_rdata == TINFO) begin
if (tselect >= BREAKPOINT_TRIGGERS) begin
cfg_rdata = 32'h00000001; // type = 0, no trigger
end else begin
cfg_rdata = 32'h00000004; // type = 2, address/data match
end
end
end
// ----------------------------------------------------------------------------
// Trigger match logic
reg [BREAKPOINT_TRIGGERS-1:0] want_d_mode_break;
reg [BREAKPOINT_TRIGGERS-1:0] want_m_mode_break;
always @ (*) begin: match_pc
integer i;
want_m_mode_break = {BREAKPOINT_TRIGGERS{1'b0}};
want_d_mode_break = {BREAKPOINT_TRIGGERS{1'b0}};
for (i = 0; i < BREAKPOINT_TRIGGERS; i = i + 1) begin
if (tdata2[i] == pc && !d_mode && (m_mode ? mcontrol_m[tselect] : mcontrol_u[tselect])) begin
want_d_mode_break[i] = mcontrol_action[i] && tdata1_dmode[i];
want_m_mode_break[i] = !mcontrol_action[i] && trig_m_en;
end
end
end
assign break = |want_m_mode_break || |want_d_mode_break;
assign break_d_mode = |want_d_mode_break;
endmodule
`ifndef YOSYS
`default_nettype wire
`endif

View File

@ -24,8 +24,6 @@ CSR was 302
-> exception, mcause = 2
CSR was 303
-> exception, mcause = 2
CSR was 7a1
-> exception, mcause = 2
CSR was 7b0
-> exception, mcause = 2
CSR was 7b1
@ -132,6 +130,9 @@ int main() {
(void)read_csr(mhpmevent3);
(void)read_csr(tselect);
(void)read_csr(tdata1);
(void)read_csr(tdata2);
(void)read_csr(tinfo);
(void)read_csr(tcontrol);
(void)read_csr(dcsr);
(void)read_csr(dpc);
(void)read_csr(dscratch0);

View File

@ -12,6 +12,7 @@ int main() {
tb_assert(NUM_IRQS <= 32, "Test invalid for >32 IRQs");
global_irq_enable(true);
external_irq_enable(true);
// Dry run: Check that IRQ force array can be written/read and that it
// sets the pending array appropriately
for (int i = 0; i < NUM_IRQS; ++i) {

View File

@ -6,7 +6,7 @@
// the next descending priority
// - Each bottom half hander re-pends the top half handler (which immediately
// preempts it) to set the next lower-numbered bottom handler
// - When top returns to bottom, and that bottom returns to the *next* bottom,
// - Then top returns to bottom, and that bottom returns to the *next* bottom,
// which re-pends the top
// - So on until all handlers have fired
// - This should stack within two exception frames and enter the EIRQ vector

View File

@ -1,32 +1,33 @@
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
BREAKPOINT_TRIGGERS := 4
U_MODE := 1
PMP_REGIONS := 4
NUM_IRQS := 32
IRQ_PRIORITY_BITS := 4
NUM_IRQS := 32
IRQ_PRIORITY_BITS := 4
MULDIV_UNROLL := 2
MUL_FAST := 1
MUL_FASTER := 1
MULH_FAST := 1
FAST_BRANCHCMP := 1
REDUCED_BYPASS := 0
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
MVENDORID_VAL := 32'hdeadbeef
MIMPID_VAL := 32'h12345678
MCONFIGPTR_VAL := 32'h9abcdef0
.PHONY: clean all
@ -40,6 +41,7 @@ SYNTH_CMD += chparam -set EXTENSION_ZBB $(EXTENSION_ZBB) $(TOP);
SYNTH_CMD += chparam -set EXTENSION_ZBC $(EXTENSION_ZBC) $(TOP);
SYNTH_CMD += chparam -set EXTENSION_ZBS $(EXTENSION_ZBS) $(TOP);
SYNTH_CMD += chparam -set DEBUG_SUPPORT $(DEBUG_SUPPORT) $(TOP);
SYNTH_CMD += chparam -set BREAKPOINT_TRIGGERS $(BREAKPOINT_TRIGGERS) $(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);