diff --git a/doc/cs_registers.rst b/doc/cs_registers.rst index 6b1f3b4d..fdeb6107 100644 --- a/doc/cs_registers.rst +++ b/doc/cs_registers.rst @@ -46,6 +46,18 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow +---------+--------------------+--------+-----------------------------------------------+ | 0x3BF | ``pmpaddr15`` | WARL | PMP Address Register | +---------+--------------------+--------+-----------------------------------------------+ +| 0x7A0 | ``tselect`` | WARL | Trigger Select Register | ++---------+--------------------+--------+-----------------------------------------------+ +| 0x7A1 | ``tdata1`` | WARL | Trigger Data Register 1 | ++---------+--------------------+--------+-----------------------------------------------+ +| 0x7A2 | ``tdata2`` | WARL | Trigger Data Register 2 | ++---------+--------------------+--------+-----------------------------------------------+ +| 0x7A3 | ``tdata3`` | WARL | Trigger Data Register 3 | ++---------+--------------------+--------+-----------------------------------------------+ +| 0x7A8 | ``mcontext`` | WARL | Machine Context Register | ++---------+--------------------+--------+-----------------------------------------------+ +| 0x7AA | ``scontext`` | WARL | Supervisor Context Register | ++---------+--------------------+--------+-----------------------------------------------+ | 0x7B0 | ``dcsr`` | WARL | Debug Control and Status Register | +---------+--------------------+--------+-----------------------------------------------+ | 0x7B1 | ``dpc`` | RW | Debug PC | @@ -282,6 +294,122 @@ Reset Value: ``0x0000_0000`` | address[33:2] | +----------------+ +.. _csr-tselect: + +Trigger Select Register (tselect) +--------------------------------- + +CSR Address: ``0x7A0`` + +Reset Value: ``0x0000_0000`` + +Accessible in Debug Mode or M-Mode when trigger support is enabled (using the DbgTriggerEn parameter). + +Ibex implements a single trigger, therefore this register will always read as zero. + +.. _csr-tdata1: + +Trigger Data Register 1 (tdata1) +-------------------------------- + +CSR Address: ``0x7A1`` + +Reset Value: ``0x2800_1000`` + +Accessible in Debug Mode or M-Mode when trigger support is enabled (using the DbgTriggerEn parameter). +Since native triggers are not supported, writes to this register from M-Mode will be ignored. + +Ibex only implements one type of trigger, instruction address match. +Most fields of this register will read as a fixed value to reflect the mode that is supported. + ++-------+------+------------------------------------------------------------------+ +| Bit# | R/W | Description | ++-------+------+------------------------------------------------------------------+ +| 31:28 | R | **type:** 2 = Address/Data match trigger type. | ++-------+------+------------------------------------------------------------------+ +| 27 | R | **dmode:** 1 = Only debug mode can write tdata registers | ++-------+------+------------------------------------------------------------------+ +| 26:21 | R | **maskmax:** 0 = Only exact matching supported. | ++-------+------+------------------------------------------------------------------+ +| 20 | R | **hit:** 0 = Hit indication not supported. | ++-------+------+------------------------------------------------------------------+ +| 19 | R | **select:** 0 = Only address matching is supported. | ++-------+------+------------------------------------------------------------------+ +| 18 | R | **timing:** 0 = Break before the instruction at the specified | +| | | address. | ++-------+------+------------------------------------------------------------------+ +| 17:16 | R | **sizelo:** 0 = Match accesses of any size. | ++-------+------+------------------------------------------------------------------+ +| 15:12 | R | **action:** 1 = Enter debug mode on match. | ++-------+------+------------------------------------------------------------------+ +| 11 | R | **chain:** 0 = Chaining not supported. | ++-------+------+------------------------------------------------------------------+ +| 10:7 | R | **match:** 0 = Match the whole address. | ++-------+------+------------------------------------------------------------------+ +| 6 | R | **m:** 1 = Match in M-Mode. | ++-------+------+------------------------------------------------------------------+ +| 5 | R | zero. | ++-------+------+------------------------------------------------------------------+ +| 4 | R | **s:** 0 = S-Mode not supported. | ++-------+------+------------------------------------------------------------------+ +| 3 | R | **u:** 1 = Match in U-Mode. | ++-------+------+------------------------------------------------------------------+ +| 2 | RW | **execute:** Enable matching on instruction address. | ++-------+------+------------------------------------------------------------------+ +| 1 | R | **store:** 0 = Store address / data matching not supported. | ++-------+------+------------------------------------------------------------------+ +| 0 | R | **load:** 0 = Load address / data matching not supported. | ++-------+------+------------------------------------------------------------------+ + +Details of these configuration bits can be found in the RISC-V Debug Specification, version 0.13.2 (see Trigger Registers, Section 5.2). + +.. _csr-tdata2: + +Trigger Data Register 2 (tdata2) +-------------------------------- + +CSR Address: ``0x7A2`` + +Reset Value: ``0x0000_0000`` + +Accessible in Debug Mode or M-Mode when trigger support is enabled (using the DbgTriggerEn parameter). +Since native triggers are not supported, writes to this register from M-Mode will be ignored. + +This register stores the instruction address to match against for a breakpoint trigger. + +Trigger Data Register 3 (tdata3) +-------------------------------- + +CSR Address: ``0x7A3`` + +Reset Value: ``0x0000_0000`` + +Accessible in Debug Mode or M-Mode when trigger support is enabled (using the DbgTriggerEn parameter). + +Ibex does not support the features requiring this register, so writes are ignored and it will always read as zero. + +Machine Context Register (mcontext) +----------------------------------- + +CSR Address: ``0x7A8`` + +Reset Value: ``0x0000_0000`` + +Accessible in Debug Mode or M-Mode when trigger support is enabled (using the DbgTriggerEn parameter). + +Ibex does not support the features requiring this register, so writes are ignored and it will always read as zero. + +Supervisor Context Register (scontext) +-------------------------------------- + +CSR Address: ``0x7AA`` + +Reset Value: ``0x0000_0000`` + +Accessible in Debug Mode or M-Mode when trigger support is enabled (using the DbgTriggerEn parameter). + +Ibex does not support the features requiring this register, so writes are ignored and it will always read as zero. + .. _csr-dcsr: Debug Control and Status Register (dcsr) diff --git a/doc/debug.rst b/doc/debug.rst index 732ab1f4..5ac976e8 100644 --- a/doc/debug.rst +++ b/doc/debug.rst @@ -26,10 +26,14 @@ Parameters +---------------------+-----------------------------------------------------------------+ | ``DmExceptionAddr`` | Address to jump to when an exception occurs while in Debug Mode | +---------------------+-----------------------------------------------------------------+ +| ``DbgTriggerEn`` | Enable support for debug triggers | ++---------------------+-----------------------------------------------------------------+ Core Debug Registers -------------------- Ibex implements four core debug registers, namely :ref:`csr-dcsr`, :ref:`csr-dpc`, and two debug scratch registers. +If the ``DbgTriggerEn`` parameter is set, debug trigger registers are available. +See :ref:`csr-tselect`, :ref:`csr-tdata1` and :ref:`csr-tdata2` for details. All those registers are accessible from Debug Mode only. If software tries to access them without the core being in Debug Mode, an illegal instruction exception is triggered. diff --git a/doc/integration.rst b/doc/integration.rst index 41f635aa..387298cd 100644 --- a/doc/integration.rst +++ b/doc/integration.rst @@ -20,6 +20,7 @@ Instantiation Template .RV32E ( 0 ), .RV32M ( 1 ), .MultiplierImplementation ( "fast" ), + .DbgTriggerEn ( 0 ), .DmHaltAddr ( 32'h1A110800 ), .DmExceptionAddr ( 32'h1A110808 ) ) u_core ( @@ -88,6 +89,8 @@ Parameters +------------------------------+-------------+------------+-----------------------------------------------------------------+ | ``MultiplierImplementation`` | string | "fast" | Multiplicator type, "slow", or "fast" | +------------------------------+-------------+------------+-----------------------------------------------------------------+ +| ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) | ++------------------------------+-------------+------------+-----------------------------------------------------------------+ | ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode | +------------------------------+-------------+------------+-----------------------------------------------------------------+ | ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode | diff --git a/dv/cs_registers/tb/tb_cs_registers.sv b/dv/cs_registers/tb/tb_cs_registers.sv index a190dfd7..9661b9d7 100644 --- a/dv/cs_registers/tb/tb_cs_registers.sv +++ b/dv/cs_registers/tb/tb_cs_registers.sv @@ -3,13 +3,14 @@ // SPDX-License-Identifier: Apache-2.0 module tb_cs_registers #( + parameter bit DbgTriggerEn = 0, parameter int unsigned MHPMCounterNum = 8, parameter int unsigned MHPMCounterWidth = 40, parameter bit PMPEnable = 0, parameter int unsigned PMPGranularity = 0, parameter int unsigned PMPNumRegions = 4, - parameter bit RV32E = 0, - parameter bit RV32M = 0 + parameter bit RV32E = 0, + parameter bit RV32M = 0 ) ( // Clock and Reset inout wire clk_i, @@ -64,6 +65,7 @@ module tb_cs_registers #( logic debug_single_step_o; logic debug_ebreakm_o; logic debug_ebreaku_o; + logic trigger_match_o; logic [31:0] pc_if_i; logic [31:0] pc_id_i; @@ -116,6 +118,7 @@ module tb_cs_registers #( `endif ibex_cs_registers #( + .DbgTriggerEn (DbgTriggerEn), .MHPMCounterNum (MHPMCounterNum), .MHPMCounterWidth (MHPMCounterWidth), .PMPEnable (PMPEnable), diff --git a/lint/verilator_waiver.vlt b/lint/verilator_waiver.vlt index 0c514cd9..fe4abe70 100644 --- a/lint/verilator_waiver.vlt +++ b/lint/verilator_waiver.vlt @@ -57,4 +57,4 @@ lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 16 // 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 164 +lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 166 diff --git a/rtl/ibex_controller.sv b/rtl/ibex_controller.sv index f0330054..9fd07171 100644 --- a/rtl/ibex_controller.sv +++ b/rtl/ibex_controller.sv @@ -68,6 +68,7 @@ module ibex_controller ( input logic debug_single_step_i, input logic debug_ebreakm_i, input logic debug_ebreaku_i, + input logic trigger_match_i, output logic csr_save_if_o, output logic csr_save_id_o, @@ -197,7 +198,9 @@ module ibex_controller ( // instruction valid otherwise the core will immediately enter debug mode // due to a recently flushed IF (or a delay in an instruction returning from // 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; + // Also enter debug mode on a trigger match (hardware breakpoint) + assign enter_debug_mode = (debug_req_i | (debug_single_step_i & instr_valid_i) | + trigger_match_i) & ~debug_mode_q; // Set when an ebreak should enter debug mode rather than jump to exception // handler @@ -420,7 +423,7 @@ module ibex_controller ( DBG_TAKEN_IF: begin // enter debug mode and save PC in IF to dpc // jump to debug exception handler in debug memory - if (debug_single_step_i || debug_req_i) begin + if (debug_single_step_i || debug_req_i || trigger_match_i) begin flush_id = 1'b1; pc_mux_o = PC_EXC; pc_set_o = 1'b1; @@ -430,7 +433,9 @@ module ibex_controller ( debug_csr_save_o = 1'b1; csr_save_cause_o = 1'b1; - if (debug_single_step_i) begin + if (trigger_match_i) begin + debug_cause_o = DBG_CAUSE_TRIGGER; + end else if (debug_single_step_i) begin debug_cause_o = DBG_CAUSE_STEP; end else begin debug_cause_o = DBG_CAUSE_HALTREQ; diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 83d8253c..f7922efc 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -19,6 +19,7 @@ module ibex_core #( parameter bit RV32E = 1'b0, parameter bit RV32M = 1'b1, parameter MultiplierImplementation = "fast", + parameter bit DbgTriggerEn = 1'b0, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( @@ -209,6 +210,7 @@ module ibex_core #( logic debug_single_step; logic debug_ebreakm; logic debug_ebreaku; + logic trigger_match; // performance counter related signals logic instr_ret; @@ -448,6 +450,7 @@ module ibex_core #( .debug_single_step_i ( debug_single_step ), .debug_ebreakm_i ( debug_ebreakm ), .debug_ebreaku_i ( debug_ebreaku ), + .trigger_match_i ( trigger_match ), // write data to commit in the register file .regfile_wdata_lsu_i ( regfile_wdata_lsu ), @@ -565,6 +568,7 @@ module ibex_core #( assign valid_csr_id = instr_new_id & ~instr_fetch_err; ibex_cs_registers #( + .DbgTriggerEn ( DbgTriggerEn ), .MHPMCounterNum ( MHPMCounterNum ), .MHPMCounterWidth ( MHPMCounterWidth ), .PMPEnable ( PMPEnable ), @@ -620,6 +624,7 @@ module ibex_core #( .debug_single_step_o ( debug_single_step ), .debug_ebreakm_o ( debug_ebreakm ), .debug_ebreaku_o ( debug_ebreaku ), + .trigger_match_o ( trigger_match ), .pc_if_i ( pc_if ), .pc_id_i ( pc_id ), diff --git a/rtl/ibex_core_tracing.sv b/rtl/ibex_core_tracing.sv index 3d4653b9..2eb40cce 100644 --- a/rtl/ibex_core_tracing.sv +++ b/rtl/ibex_core_tracing.sv @@ -15,6 +15,7 @@ module ibex_core_tracing #( parameter bit RV32E = 1'b0, parameter bit RV32M = 1'b1, parameter MultiplierImplementation = "fast", + parameter bit DbgTriggerEn = 1'b0, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( @@ -98,6 +99,7 @@ module ibex_core_tracing #( .MHPMCounterWidth ( MHPMCounterWidth ), .RV32E ( RV32E ), .RV32M ( RV32M ), + .DbgTriggerEn ( DbgTriggerEn ), .MultiplierImplementation ( MultiplierImplementation ), .DmHaltAddr ( DmHaltAddr ), .DmExceptionAddr ( DmExceptionAddr ) diff --git a/rtl/ibex_cs_registers.sv b/rtl/ibex_cs_registers.sv index 9261e7aa..4b4ca9d1 100644 --- a/rtl/ibex_cs_registers.sv +++ b/rtl/ibex_cs_registers.sv @@ -10,13 +10,14 @@ * Specification, draft version 1.11 */ module ibex_cs_registers #( + parameter bit DbgTriggerEn = 0, parameter int unsigned MHPMCounterNum = 8, parameter int unsigned MHPMCounterWidth = 40, parameter bit PMPEnable = 0, parameter int unsigned PMPGranularity = 0, parameter int unsigned PMPNumRegions = 4, - parameter bit RV32E = 0, - parameter bit RV32M = 0 + parameter bit RV32E = 0, + parameter bit RV32M = 0 ) ( // Clock and Reset input logic clk_i, @@ -68,6 +69,7 @@ module ibex_cs_registers #( output logic debug_single_step_o, output logic debug_ebreakm_o, output logic debug_ebreaku_o, + output logic trigger_match_o, input logic [31:0] pc_if_i, input logic [31:0] pc_id_i, @@ -196,6 +198,11 @@ module ibex_cs_registers #( logic [31:0] mhpmevent [32]; logic [4:0] mhpmcounter_idx; + // Debug / trigger registers + logic [31:0] tselect_rdata; + logic [31:0] tmatch_control_rdata; + logic [31:0] tmatch_value_rdata; + // CSR update logic logic [31:0] csr_wdata_int; logic [31:0] csr_rdata_int; @@ -368,6 +375,32 @@ module ibex_cs_registers #( csr_rdata_int = mhpmcounter_q[mhpmcounter_idx][63:32]; end + // Debug triggers + CSR_TSELECT: begin + csr_rdata_int = tselect_rdata; + illegal_csr = ~DbgTriggerEn; + end + CSR_TDATA1: begin + csr_rdata_int = tmatch_control_rdata; + illegal_csr = ~DbgTriggerEn; + end + CSR_TDATA2: begin + csr_rdata_int = tmatch_value_rdata; + illegal_csr = ~DbgTriggerEn; + end + CSR_TDATA3: begin + csr_rdata_int = '0; + illegal_csr = ~DbgTriggerEn; + end + CSR_MCONTEXT: begin + csr_rdata_int = '0; + illegal_csr = ~DbgTriggerEn; + end + CSR_SCONTEXT: begin + csr_rdata_int = '0; + illegal_csr = ~DbgTriggerEn; + end + default: begin illegal_csr = 1'b1; end @@ -899,4 +932,78 @@ module ibex_cs_registers #( end end + ///////////////////////////// + // Debug trigger registers // + ///////////////////////////// + + if (DbgTriggerEn) begin : gen_trigger_regs + // Register values + logic tmatch_control_d, tmatch_control_q; + logic [31:0] tmatch_value_d, tmatch_value_q; + // Write enables + logic tmatch_control_we; + logic tmatch_value_we; + + // Write select + assign tmatch_control_we = csr_we_int & debug_mode_i & (csr_addr_i == CSR_TDATA1); + assign tmatch_value_we = csr_we_int & debug_mode_i & (csr_addr_i == CSR_TDATA2); + + // tmatch_control is enabled when the execute bit is set + assign tmatch_control_d = tmatch_control_we ? csr_wdata_int[2] : + tmatch_control_q; + // tmatch_value has its own clock gate + assign tmatch_value_d = csr_wdata_int[31:0]; + + // Registers + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + tmatch_control_q <= 'b0; + end else begin + tmatch_control_q <= tmatch_control_d; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + tmatch_value_q <= 'b0; + end else if (tmatch_value_we) begin + tmatch_value_q <= tmatch_value_d; + end + end + + // Assign read data + // TSELECT - only one supported + assign tselect_rdata = 'b0; + // TDATA0 - only support simple address matching + assign tmatch_control_rdata = {4'h2, // type : address/data match + 1'b1, // dmode : access from D mode only + 6'h00, // maskmax : exact match only + 1'b0, // hit : not supported + 1'b0, // select : address match only + 1'b0, // timing : match before execution + 2'b00, // sizelo : match any access + 4'h1, // action : enter debug mode + 1'b0, // chain : not supported + 4'h0, // match : simple match + 1'b1, // m : match in m-mode + 1'b0, // 0 : zero + 1'b0, // s : not supported + 1'b1, // u : match in u-mode + tmatch_control_q, // execute : match instruction address + 1'b0, // store : not supported + 1'b0}; // load : not supported + // TDATA1 - address match value only + assign tmatch_value_rdata = tmatch_value_q; + + // Breakpoint matching + // We match against the next address, as the breakpoint must be taken before execution + assign trigger_match_o = tmatch_control_q & (pc_if_i[31:0] == tmatch_value_q[31:0]); + + end else begin : gen_no_trigger_regs + assign tselect_rdata = 'b0; + assign tmatch_control_rdata = 'b0; + assign tmatch_value_rdata = 'b0; + assign trigger_match_o = 'b0; + end + endmodule diff --git a/rtl/ibex_id_stage.sv b/rtl/ibex_id_stage.sv index fdf854ad..71183761 100644 --- a/rtl/ibex_id_stage.sv +++ b/rtl/ibex_id_stage.sv @@ -109,6 +109,7 @@ module ibex_id_stage #( input logic debug_single_step_i, input logic debug_ebreakm_i, input logic debug_ebreaku_i, + input logic trigger_match_i, // Write back signal input logic [31:0] regfile_wdata_lsu_i, @@ -452,6 +453,7 @@ module ibex_id_stage #( .debug_single_step_i ( debug_single_step_i ), .debug_ebreakm_i ( debug_ebreakm_i ), .debug_ebreaku_i ( debug_ebreaku_i ), + .trigger_match_i ( trigger_match_i ), // stall signals .stall_lsu_i ( stall_lsu ), diff --git a/rtl/ibex_pkg.sv b/rtl/ibex_pkg.sv index 8640ee41..f3d1101d 100644 --- a/rtl/ibex_pkg.sv +++ b/rtl/ibex_pkg.sv @@ -257,6 +257,14 @@ typedef enum logic[11:0] { CSR_PMPADDR14 = 12'h3BE, CSR_PMPADDR15 = 12'h3BF, + // Debug trigger + CSR_TSELECT = 12'h7A0, + CSR_TDATA1 = 12'h7A1, + CSR_TDATA2 = 12'h7A2, + CSR_TDATA3 = 12'h7A3, + CSR_MCONTEXT = 12'h7A8, + CSR_SCONTEXT = 12'h7AA, + // Debug/trace CSR_DCSR = 12'h7b0, CSR_DPC = 12'h7b1,