[prim_alert_receiver] Fix ping during init sequence bug Fix #9803 Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/prim/rtl/prim_alert_receiver.sv b/hw/ip/prim/rtl/prim_alert_receiver.sv index 5c1330b..347d424 100644 --- a/hw/ip/prim/rtl/prim_alert_receiver.sv +++ b/hw/ip/prim/rtl/prim_alert_receiver.sv
@@ -98,13 +98,14 @@ logic ping_req_d, ping_req_q; logic ping_pending_d, ping_pending_q; logic send_init; + logic send_ping; // signal ping request upon positive transition on ping_req_i // signalling is performed by a level change event on the diff output - assign ping_req_d = ping_req_i && !(state_q inside {InitReq, InitAckWait}); - assign ping_rise = ping_req_i && !ping_req_q; + assign ping_req_d = ping_req_i; + assign ping_rise = ping_req_d && !ping_req_q; assign ping_tog_pd = (send_init) ? 1'b0 : - (ping_rise) ? ~ping_tog_pq : ping_tog_pq; + (send_ping) ? ~ping_tog_pq : ping_tog_pq; // in-band reset is performed by sending out an integrity error on purpose. assign ack_dn = (send_init) ? ack_pd : ~ack_pd; @@ -135,7 +136,7 @@ ping_tog_pq}) ); - // the ping pending signal is used to in the FSM to distinguish whether the + // the ping pending signal is used in the FSM to distinguish whether the // incoming handshake shall be treated as an alert or a ping response. // it is important that this is only set on a rising ping_en level change, since // otherwise the ping enable signal could be abused to "mask" all native alerts @@ -161,6 +162,8 @@ integ_fail_o = 1'b0; alert_o = 1'b0; send_init = 1'b0; + // by default, a ping request leads to a toogle on the differential ping pair + send_ping = ping_rise; unique case (state_q) Idle: begin @@ -192,6 +195,8 @@ InitReq: begin // we deliberately place a sigint error on the ack and ping lines in this case. send_init = 1'b1; + // suppress any toggles on the ping line while we are in the init phase. + send_ping = 1'b0; // As long as init req is asserted, we remain in this state and acknowledge all incoming // ping requests. As soon as the init request is dropped however, ping requests are not // acked anymore such that the ping mechanism can also flag alert channels that got stuck @@ -208,8 +213,14 @@ // has been deasserted. At this point, we need to wait for the alert_sigint to drop again // before resuming normal operation. InitAckWait: begin + // suppress any toggles on the ping line while we are in the init phase. + send_ping = 1'b0; if (!alert_sigint) begin state_d = Pause0; + // If we get a ping request in this cycle, or if we realize that there is an unhandled + // ping request that came in during initialization (but after init_trig_i has been + // deasserted), we signal this to the alert sender by toggling the request line. + send_ping = ping_rise || ping_pending_q; end end default: state_d = Idle; @@ -276,7 +287,8 @@ !(state_q inside {InitReq, InitAckWait}) |=> send_init) // ping request at input -> need to see encoded ping request - `ASSERT(PingRequest0_A, ##1 $rose(ping_req_i) && !send_init |=> $changed(alert_rx_o.ping_p)) + `ASSERT(PingRequest0_A, ##1 $rose(ping_req_i) && !state_q inside {InitReq, InitAckWait} + |=> $changed(alert_rx_o.ping_p)) // ping response implies it has been requested `ASSERT(PingResponse0_A, ping_ok_o |-> ping_pending_q) // correctly latch ping request