[RTL] Fix ebreak behaviour in U-mode

Fixes #370

Whether EBREAK enters debug mode is controlled by the
ebreaku and ebreakm dcsr fields. Which is relevant depends upon the
privilege level.
This commit is contained in:
Greg Chadwick 2019-10-15 13:23:48 +01:00
parent 7aa87156d3
commit b94961402c
5 changed files with 19 additions and 4 deletions

View file

@ -57,9 +57,9 @@ lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 16
// Signal unoptimizable: Feedback to clock or circular logic:
// ibex_core.id_stage_i.controller_i.ctrl_fsm_cs
// Issue lowrisc/ibex#211
lint_off -msg UNOPTFLAT -file "*/rtl/ibex_controller.sv" -lines 100
lint_off -msg UNOPTFLAT -file "*/rtl/ibex_controller.sv" -lines 101
// Signal unoptimizable: Feedback to clock or circular logic:
// ibex_core.cs_registers_i.mie_q
// Issue lowrisc/ibex#212
lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 162
lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 163

View file

@ -68,6 +68,7 @@ module ibex_controller (
output logic debug_mode_o,
input logic debug_single_step_i,
input logic debug_ebreakm_i,
input logic debug_ebreaku_i,
output logic csr_save_if_o,
output logic csr_save_id_o,
@ -114,6 +115,7 @@ module ibex_controller (
logic exc_req_lsu;
logic special_req;
logic enter_debug_mode;
logic ebreak_into_debug;
logic handle_irq;
logic [3:0] mfip_id;
@ -197,6 +199,12 @@ module ibex_controller (
// memory) before it has had anything to single step.
assign enter_debug_mode = (debug_req_i | (debug_single_step_i & instr_valid_i)) & ~debug_mode_q;
// Set when an ebreak should enter debug mode rather than jump to exception
// handler
assign ebreak_into_debug = priv_mode_i == PRIV_LVL_M ? debug_ebreakm_i :
priv_mode_i == PRIV_LVL_U ? debug_ebreaku_i :
1'b0;
// interrupts including NMI are ignored while in debug mode [Debug Spec v0.13.2, p.39]
assign handle_irq = ~debug_mode_q &
((irq_nm_i & ~nmi_mode_q) | (irq_pending_i & csr_mstatus_mie_i));
@ -449,7 +457,7 @@ module ibex_controller (
exc_pc_mux_o = EXC_PC_DBD;
// update dcsr and dpc
if (debug_ebreakm_i && !debug_mode_q) begin // ebreak with forced entry
if (ebreak_into_debug && !debug_mode_q) begin // ebreak with forced entry
// dpc (set to the address of the EBREAK, i.e. set to PC in ID stage)
csr_save_cause_o = 1'b1;
@ -496,7 +504,7 @@ module ibex_controller (
EXC_CAUSE_ECALL_UMODE;
end else if (ebrk_insn) begin
if (debug_mode_q | debug_ebreakm_i) begin
if (debug_mode_q | ebreak_into_debug) begin
/*
* EBREAK in debug mode re-enters debug mode
*

View file

@ -207,6 +207,7 @@ module ibex_core #(
logic debug_csr_save;
logic debug_single_step;
logic debug_ebreakm;
logic debug_ebreaku;
// performance counter related signals
logic instr_ret;
@ -448,6 +449,7 @@ module ibex_core #(
.debug_req_i ( debug_req_i ),
.debug_single_step_i ( debug_single_step ),
.debug_ebreakm_i ( debug_ebreakm ),
.debug_ebreaku_i ( debug_ebreaku ),
// write data to commit in the register file
.regfile_wdata_lsu_i ( regfile_wdata_lsu ),
@ -618,6 +620,7 @@ module ibex_core #(
.debug_csr_save_i ( debug_csr_save ),
.debug_single_step_o ( debug_single_step ),
.debug_ebreakm_o ( debug_ebreakm ),
.debug_ebreaku_o ( debug_ebreaku ),
.pc_if_i ( pc_if ),
.pc_id_i ( pc_id ),

View file

@ -67,6 +67,7 @@ module ibex_cs_registers #(
output logic [31:0] csr_depc_o,
output logic debug_single_step_o,
output logic debug_ebreakm_o,
output logic debug_ebreaku_o,
input logic [31:0] pc_if_i,
input logic [31:0] pc_id_i,
@ -570,6 +571,7 @@ module ibex_cs_registers #(
assign csr_mstatus_tw_o = mstatus_q.tw;
assign debug_single_step_o = dcsr_q.step;
assign debug_ebreakm_o = dcsr_q.ebreakm;
assign debug_ebreaku_o = dcsr_q.ebreaku;
assign irq_pending_o = csr_msip_o | csr_mtip_o | csr_meip_o | (|csr_mfip_o);

View file

@ -108,6 +108,7 @@ module ibex_id_stage #(
input logic debug_req_i,
input logic debug_single_step_i,
input logic debug_ebreakm_i,
input logic debug_ebreaku_i,
// Write back signal
input logic [31:0] regfile_wdata_lsu_i,
@ -450,6 +451,7 @@ module ibex_id_stage #(
.debug_req_i ( debug_req_i ),
.debug_single_step_i ( debug_single_step_i ),
.debug_ebreakm_i ( debug_ebreakm_i ),
.debug_ebreaku_i ( debug_ebreaku_i ),
// stall signals
.stall_lsu_i ( stall_lsu ),