Skip to content

Commit

Permalink
[rv_dm] Implement NDM reset tracking
Browse files Browse the repository at this point in the history
This adds tracking logic for NDM reset requests and issues an
acknowledgement to the DM_CSRs so that dmstatus.allhavereset /
dmstatus.anyhavereset can be asserted at the correct time.

Fixes lowRISC#15123

Signed-off-by: Michael Schaffner <msf@opentitan.org>
  • Loading branch information
msfschaffner committed Mar 14, 2024
1 parent eea567e commit d4f08e1
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 10 deletions.
5 changes: 4 additions & 1 deletion hw/ip/rv_dm/data/rv_dm.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
design_stage: "D2S",
verification_stage: "V1",
clocking: [
{clock: "clk_i", reset: "rst_ni"}
{clock: "clk_i", reset: "rst_ni", primary: true},
// Ideally, this is the processor clock and reset.
// Note that only the reset input is used here for NDM reset request tracking.
{clock: "clk_lc_i", reset: "rst_lc_ni"}
]
bus_interfaces: [
{ protocol: "tlul", direction: "host", name: "sba" }
Expand Down
6 changes: 5 additions & 1 deletion hw/ip/rv_dm/dv/tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ module tb;
) dut (
.clk_i (clk ),
.rst_ni (rst_n),

// TODO: this should be attached to another reset that can be driven low separately from rst_n.
// It is used for tracking NDM reset requests internally (the clock input is unused, but
// required so that the topgen tooling works correctly).
.clk_lc_i (clk ),
.rst_lc_ni (rst_n),
// the differing behavior of lc_hw_debug_en_i and pinmux_hw_debug_en_i
// will be tested at the top-level. for the purposes of this TB we connect
// both signals to the same life cycle signal.
Expand Down
78 changes: 73 additions & 5 deletions hw/ip/rv_dm/rtl/rv_dm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ module rv_dm
parameter logic [31:0] IdcodeValue = 32'h 0000_0001
) (
input logic clk_i, // clock
input logic clk_lc_i, // only declared here so that the topgen
// tooling connects the correct clk/rst domains.
input logic rst_ni, // asynchronous reset active low, connect PoR
// here, not the system reset
input logic rst_lc_ni, // asynchronous reset active low, connect the lc
// reset here. this is only used for NDM reset tracking.
input logic [31:0] next_dm_addr_i, // static word address of the next debug module.
// SEC_CM: LC_HW_DEBUG_EN.INTERSIG.MUBI
// HW Debug lifecycle enable signal (live version from the life cycle controller)
Expand Down Expand Up @@ -269,16 +273,80 @@ module rv_dm
logic dmi_rsp_valid, dmi_rsp_ready;
logic dmi_rst_n;

logic dmi_en;
// SEC_CM: DM_EN.CTRL.LC_GATED
assign dmi_en = lc_tx_test_true_strict(pinmux_hw_debug_en[PmEnDmiReq]);

////////////////////////
// NDM Reset Tracking //
////////////////////////

logic reset_req_en;
logic ndmreset_req;
logic ndmreset_req, ndmreset_ack;
logic ndmreset_req_qual;
// SEC_CM: DM_EN.CTRL.LC_GATED
assign reset_req_en = lc_tx_test_true_strict(lc_hw_debug_en_gated[LcEnResetReq]);
assign ndmreset_req_o = ndmreset_req_qual & reset_req_en;

logic dmi_en;
// SEC_CM: DM_EN.CTRL.LC_GATED
assign dmi_en = lc_tx_test_true_strict(pinmux_hw_debug_en[PmEnDmiReq]);
// Sample the processor reset to detect lc reset assertion.
logic lc_rst_asserted_async;
prim_flop_2sync #(
.Width(1),
.ResetValue(1) // Resets to 1 to indicate assertion.
) u_prim_flop_2sync_lc_rst_assert (
.clk_i, // Use RV_DM clock
.rst_ni(rst_lc_ni), // Use LC reset here that resets the entire system except the RV_DM.
.d_i(1'b0), // Set to 0 to indicate deassertion.
.q_o(lc_rst_asserted_async)
);

// Note that the output of the above flops can be metastable at reset assertion, since the reset
// signal is coming from a different clock domain and has not been synchronized with clk_i.
logic lc_rst_asserted;
prim_flop_2sync #(
.Width(1)
) u_prim_flop_2sync_lc_rst_sync (
.clk_i,
.rst_ni,
.d_i(lc_rst_asserted_async),
.q_o(lc_rst_asserted)
);

// The acknowledgement pulse sets the dmstatus.allhavereset / dmstatus.anyhavereset registers in
// RV_DM. It should only be asserted once an NDM reset request has been fully completed.
logic ndmreset_pending_q;
logic lc_rst_pending_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : p_ndm_reset
if (!rst_ni) begin
ndmreset_pending_q <= 1'b0;
lc_rst_pending_q <= 1'b0;
end else begin
// Only set this if there was no previous pending NDM request.
if (ndmreset_req && !ndmreset_pending_q) begin
ndmreset_pending_q <= 1'b1;
end else if (ndmreset_ack && ndmreset_pending_q) begin
ndmreset_pending_q <= 1'b0;
end
// We only track lc resets that are asserted during an active ndm reset request..
if (ndmreset_pending_q && lc_rst_asserted) begin
lc_rst_pending_q <= 1'b1;
end else if (ndmreset_ack && lc_rst_pending_q) begin
lc_rst_pending_q <= 1'b0;
end
end
end

// In order to ACK the following conditions must be met
// 1) an NDM reset request was asserted and is pending
// 2) a lc reset was asserted after the NDM reset request
// 3) the NDM reset request was deasserted
// 4) the NDM lc request was deasserted
// 5) the debug module has been ungated for operation (depending on LC state, OTP config and CSR)
assign ndmreset_ack = ndmreset_pending_q &&
lc_rst_pending_q &&
!ndmreset_req &&
!lc_rst_asserted &&
reset_req_en;

/////////////////////////////////////////
// System Bus Access Port (TL-UL Host) //
Expand Down Expand Up @@ -502,7 +570,7 @@ module rv_dm
.next_dm_addr_i,
.testmode_i (testmode ),
.ndmreset_o (ndmreset_req ),
.ndmreset_ack_i (ndmreset_req ),
.ndmreset_ack_i (ndmreset_ack ),
.dmactive_o,
.debug_req_o (debug_req ),
.unavailable_i,
Expand Down
7 changes: 7 additions & 0 deletions hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -5166,6 +5166,7 @@
clock_srcs:
{
clk_i: main
clk_lc_i: main
}
clock_group: infra
reset_connections:
Expand All @@ -5175,6 +5176,11 @@
name: sys
domain: "0"
}
rst_lc_ni:
{
name: lc
domain: "0"
}
}
param_decl:
{
Expand All @@ -5188,6 +5194,7 @@
clock_connections:
{
clk_i: clkmgr_aon_clocks.clk_main_infra
clk_lc_i: clkmgr_aon_clocks.clk_main_infra
}
domain:
[
Expand Down
4 changes: 2 additions & 2 deletions hw/top_earlgrey/data/top_earlgrey.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -620,9 +620,9 @@
},
{ name: "rv_dm",
type: "rv_dm",
clock_srcs: {clk_i: "main"},
clock_srcs: {clk_i: "main", clk_lc_i: "main"},
clock_group: "infra",
reset_connections: {rst_ni: "sys"},
reset_connections: {rst_ni: "sys", rst_lc_ni: "lc"},
param_decl: {
IdcodeValue: "jtag_id_pkg::RV_DM_JTAG_IDCODE",
},
Expand Down
4 changes: 3 additions & 1 deletion hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
Original file line number Diff line number Diff line change
Expand Up @@ -2175,7 +2175,9 @@ module top_earlgrey #(

// Clock and reset connections
.clk_i (clkmgr_aon_clocks.clk_main_infra),
.rst_ni (rstmgr_aon_resets.rst_sys_n[rstmgr_pkg::Domain0Sel])
.clk_lc_i (clkmgr_aon_clocks.clk_main_infra),
.rst_ni (rstmgr_aon_resets.rst_sys_n[rstmgr_pkg::Domain0Sel]),
.rst_lc_ni (rstmgr_aon_resets.rst_lc_n[rstmgr_pkg::Domain0Sel])
);
rv_plic #(
.AlertAsyncOn(alert_handler_reg_pkg::AsyncOn[41:41])
Expand Down

0 comments on commit d4f08e1

Please sign in to comment.