blob: ee9c51593489773d54e6d7cea78f8886dfb4c2af [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Debounces the input signal and detects level changes.
module sysrst_ctrl_detect #(
parameter int unsigned TimerWidth = 16,
// If this parameter is set to 1, an edge is required for detection.
// Otherwise the correct level (e.g. low for h2l) is sufficient.
parameter bit EdgeDetect = 0,
// If this parameter is set to 1, the l2h_detected_o and h2l_detected_o conditions can only be
// reset by disabling the corresponding detector (cfg_l2h_en_i or cfg_h2l_en_i).
parameter bit Sticky = 0
) (
input clk_i,
input rst_ni,
input trigger_i,
input [TimerWidth-1:0] cfg_timer_i,
input cfg_l2h_en_i,
input cfg_h2l_en_i,
output logic l2h_detected_o,
output logic h2l_detected_o,
output logic l2h_detected_pulse_o,
output logic h2l_detected_pulse_o
);
logic trigger_debounced_d;
prim_filter_ctr #(
.AsyncOn(0), // input signal has already been synced to the AON clock
.CntWidth(TimerWidth)
) u_prim_filter_ctr (
.clk_i,
.rst_ni,
.enable_i(1'b1),
.filter_i(trigger_i),
.thresh_i(cfg_timer_i),
.filter_o(trigger_debounced_d)
);
logic h2l_event, l2h_event;
if (EdgeDetect) begin : gen_edge_detect
logic trigger_debounced_q;
assign l2h_event = trigger_debounced_d & ~trigger_debounced_q;
assign h2l_event = ~trigger_debounced_d & trigger_debounced_q;
always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg
if (!rst_ni) begin
trigger_debounced_q <= 1'b0;
end else begin
trigger_debounced_q <= trigger_debounced_d;
end
end
end else begin : gen_level_only
// In this case we just look at the signal level.
assign l2h_event = trigger_debounced_d;
assign h2l_event = ~trigger_debounced_d;
end
logic h2l_detected_d, h2l_detected_q;
logic l2h_detected_d, l2h_detected_q;
if (Sticky) begin : gen_sticky
// Keep detected event until detector is disabled.
assign l2h_detected_d = (cfg_l2h_en_i) ? (l2h_event | l2h_detected_q) : 1'b0;
assign h2l_detected_d = (cfg_h2l_en_i) ? (h2l_event | h2l_detected_q) : 1'b0;
end else begin : gen_not_sticky
// Deassert automatically if the level does not remain stable after event.
assign l2h_detected_d = (~trigger_debounced_d) ? 1'b0 :
(cfg_l2h_en_i) ? (l2h_event | l2h_detected_q) :
1'b0;
assign h2l_detected_d = (trigger_debounced_d) ? 1'b0 :
(cfg_h2l_en_i) ? (h2l_event | h2l_detected_q) :
1'b0;
end
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
l2h_detected_q <= 1'b0;
h2l_detected_q <= 1'b0;
end else begin
l2h_detected_q <= l2h_detected_d;
h2l_detected_q <= h2l_detected_d;
end
end
assign l2h_detected_o = l2h_detected_d;
assign h2l_detected_o = h2l_detected_d;
assign l2h_detected_pulse_o = l2h_detected_d & ~l2h_detected_q;
assign h2l_detected_pulse_o = h2l_detected_d & ~h2l_detected_q;
endmodule