|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // REQ/ACK synchronizer with associated data. | 
|  | // | 
|  | // This module synchronizes a REQ/ACK handshake with associated data across a clock domain | 
|  | // crossing (CDC). Both domains will see a handshake with the duration of one clock cycle. By | 
|  | // default, the data itself is not registered. The main purpose of feeding the data through this | 
|  | // module to have an anchor point for waiving CDC violations. If the data is configured to flow | 
|  | // from the destination (DST) to the source (SRC) domain, an additional register stage can be | 
|  | // inserted for data buffering. | 
|  | // | 
|  | // Under the hood, this module uses a prim_sync_reqack primitive for synchronizing the | 
|  | // REQ/ACK handshake. See prim_sync_reqack.sv for more details. | 
|  |  | 
|  | `include "prim_assert.sv" | 
|  |  | 
|  | module prim_sync_reqack_data #( | 
|  | parameter int unsigned Width       = 1, | 
|  | parameter bit          EnRstChks   = 1'b0, // Enable reset-related assertion checks, disabled by | 
|  | // default. | 
|  | parameter bit          DataSrc2Dst = 1'b1, // Direction of data flow: 1'b1 = SRC to DST, | 
|  | //                         1'b0 = DST to SRC | 
|  | parameter bit          DataReg     = 1'b0, // Enable optional register stage for data, | 
|  | // only usable with DataSrc2Dst == 1'b0. | 
|  | parameter bit          EnRzHs      = 1'b0  // By Default, we the faster NRZ handshake protocol | 
|  | // (EnRzHs = 0) is used. Enable the RZ handshake | 
|  | // protocol if the FSMs need to be partial-reset-safe. | 
|  | ) ( | 
|  | input  clk_src_i,       // REQ side, SRC domain | 
|  | input  rst_src_ni,      // REQ side, SRC domain | 
|  | input  clk_dst_i,       // ACK side, DST domain | 
|  | input  rst_dst_ni,      // ACK side, DST domain | 
|  |  | 
|  | input  logic req_chk_i, // Used for gating assertions. Drive to 1 during normal operation. | 
|  |  | 
|  | input  logic src_req_i, // REQ side, SRC domain | 
|  | output logic src_ack_o, // REQ side, SRC domain | 
|  | output logic dst_req_o, // ACK side, DST domain | 
|  | input  logic dst_ack_i, // ACK side, DST domain | 
|  |  | 
|  | input  logic [Width-1:0] data_i, | 
|  | output logic [Width-1:0] data_o | 
|  | ); | 
|  |  | 
|  | //////////////////////////////////// | 
|  | // REQ/ACK synchronizer primitive // | 
|  | //////////////////////////////////// | 
|  | prim_sync_reqack #( | 
|  | .EnRstChks(EnRstChks), | 
|  | .EnRzHs(EnRzHs) | 
|  | ) u_prim_sync_reqack ( | 
|  | .clk_src_i, | 
|  | .rst_src_ni, | 
|  | .clk_dst_i, | 
|  | .rst_dst_ni, | 
|  |  | 
|  | .req_chk_i, | 
|  |  | 
|  | .src_req_i, | 
|  | .src_ack_o, | 
|  | .dst_req_o, | 
|  | .dst_ack_i | 
|  | ); | 
|  |  | 
|  | ///////////////////////// | 
|  | // Data register stage // | 
|  | ///////////////////////// | 
|  | // Optional - Only relevant if the data flows from DST to SRC. In this case, it must be ensured | 
|  | // that the data remains stable until the ACK becomes visible in the SRC domain. | 
|  | // | 
|  | // Note that for larger data widths, it is recommended to adjust the data sender to hold the data | 
|  | // stable until the next REQ in order to save the cost of this register stage. | 
|  | if (DataSrc2Dst == 1'b0 && DataReg == 1'b1) begin : gen_data_reg | 
|  | logic             data_we; | 
|  | logic [Width-1:0] data_d, data_q; | 
|  |  | 
|  | // Sample the data when seing the REQ/ACK handshake in the DST domain. | 
|  | assign data_we = dst_req_o & dst_ack_i; | 
|  | assign data_d  = data_i; | 
|  | always_ff @(posedge clk_dst_i or negedge rst_dst_ni) begin | 
|  | if (!rst_dst_ni) begin | 
|  | data_q <= '0; | 
|  | end else if (data_we) begin | 
|  | data_q <= data_d; | 
|  | end | 
|  | end | 
|  | assign data_o = data_q; | 
|  |  | 
|  | end else begin : gen_no_data_reg | 
|  | // Just feed through the data. | 
|  | assign data_o = data_i; | 
|  | end | 
|  |  | 
|  | //////////////// | 
|  | // Assertions // | 
|  | //////////////// | 
|  | if (DataSrc2Dst == 1'b1) begin : gen_assert_data_src2dst | 
|  | `ifdef INC_ASSERT | 
|  | //VCS coverage off | 
|  | // pragma coverage off | 
|  | logic effective_rst_n; | 
|  | assign effective_rst_n = rst_src_ni && rst_dst_ni; | 
|  |  | 
|  | logic chk_flag_d, chk_flag_q; | 
|  | assign chk_flag_d = src_req_i && !chk_flag_q ? 1'b1 : chk_flag_q; | 
|  |  | 
|  | always_ff @(posedge clk_src_i or negedge effective_rst_n) begin | 
|  | if (!effective_rst_n) begin | 
|  | chk_flag_q <= '0; | 
|  | end else begin | 
|  | chk_flag_q <= chk_flag_d; | 
|  | end | 
|  | end | 
|  | //VCS coverage on | 
|  | // pragma coverage on | 
|  |  | 
|  | // SRC domain cannot change data while waiting for ACK. | 
|  | `ASSERT(SyncReqAckDataHoldSrc2Dst, !$stable(data_i) && chk_flag_q |-> | 
|  | (!src_req_i || (src_req_i && src_ack_o)), | 
|  | clk_src_i, !rst_src_ni || !rst_dst_ni || !chk_flag_q) | 
|  |  | 
|  | // Register stage cannot be used. | 
|  | `ASSERT_INIT(SyncReqAckDataReg, DataSrc2Dst && !DataReg) | 
|  | `endif | 
|  | end else if (DataSrc2Dst == 1'b0 && DataReg == 1'b0) begin : gen_assert_data_dst2src | 
|  | // DST domain shall not change data while waiting for SRC domain to latch it (together with | 
|  | // receiving ACK). It takes 2 SRC cycles for ACK to cross over from DST to SRC, and 1 SRC cycle | 
|  | // for the next REQ to cross over from SRC to DST. | 
|  | // | 
|  | // Denote the src clock where REQ & ACK as time zero. The data flowing through the CDC could be | 
|  | // corrupted if data_o was not stable over the previous 2 clock cycles (so we want to check time | 
|  | // points -2, -1 and 0). Moreover, the DST domain cannot know that it is allowed to change value | 
|  | // until at least one more SRC cycle (the time taken for REQ to cross back from SRC to DST). | 
|  | // | 
|  | // To make this assertion, we will sample at each of 4 time points (-2, -1, 0 and +1), asserting | 
|  | // that data_o is equal at each of these times. Note this won't detect glitches at intermediate | 
|  | // timepoints. | 
|  | // | 
|  | // The SVAs below are designed not to consume time, which means that they can be disabled with | 
|  | // an $assertoff(..) and won't linger to fail later. This wouldn't work properly if we used | 
|  | // something like |=> instead of the $past(...) function. That means that we have to trigger at | 
|  | // the "end" of the window. To make sure we don't miss a situation where the value changed at | 
|  | // time -1 (causing corruption), but reset was asserted between time 0 and 1, we split the | 
|  | // assertion into two pieces. The first (SyncReqAckDataHoldDst2SrcA) checks that data doesn't | 
|  | // change in a way that could cause data corruption. The second (SyncReqAckDataHoldDst2SrcB) | 
|  | // checks that the DST side doesn't do anything that it shouldn't know is safe. | 
|  | `ifdef INC_ASSERT | 
|  | //VCS coverage off | 
|  | // pragma coverage off | 
|  | logic effective_rst_n; | 
|  | assign effective_rst_n = rst_src_ni && rst_dst_ni; | 
|  |  | 
|  | logic chk_flag_d, chk_flag_q; | 
|  | assign chk_flag_d = src_req_i && !chk_flag_q ? 1'b1 : chk_flag_q; | 
|  |  | 
|  | always_ff @(posedge clk_src_i or negedge effective_rst_n) begin | 
|  | if (!effective_rst_n) begin | 
|  | chk_flag_q <= '0; | 
|  | end else begin | 
|  | chk_flag_q <= chk_flag_d; | 
|  | end | 
|  | end | 
|  | //VCS coverage on | 
|  | // pragma coverage on | 
|  |  | 
|  | `ASSERT(SyncReqAckDataHoldDst2SrcA, | 
|  | chk_flag_q && src_req_i && src_ack_o |-> | 
|  | $past(data_o, 2) == data_o && $past(data_o) == data_o, | 
|  | clk_src_i, !rst_src_ni || !rst_dst_ni || !chk_flag_q) | 
|  | `ASSERT(SyncReqAckDataHoldDst2SrcB, | 
|  | chk_flag_q && $past(src_req_i && src_ack_o) |-> $past(data_o) == data_o, | 
|  | clk_src_i, !rst_src_ni || !rst_dst_ni || !chk_flag_q) | 
|  | `endif | 
|  | end | 
|  |  | 
|  | endmodule |