Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright 2018 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A two-phase clock domain crossing.
///
/// # Reset Behavior!!
///
/// This module must not be used if warm reset capabily is a requirement. The
/// only execption is if you consistently use a reset controller that sequences
/// the resets while gating both clock domains (be very careful if you follow
/// this strategy!). If you need warm reset/clear/flush capabilities, use (AND
/// CAREFULLY READ THE DESCRIPTION) the cc_cdc_2phase_clearable module.
///
/// After this disclaimer, here is how you connect the src_rst_ni and the
/// dst_rst_ni of this module for power-on-reset (POR). The src_rst_ni and
/// dst_rst_ni signal must be asserted SIMULTANEOUSLY (i.e. asynchronous
/// assertion). Othwerwise, spurious transactions could occur in the domain
/// where the reset arrives later than the other. The de-assertion of both reset
/// must be synchronized to their respective clock domain (i.e. src_rst_ni must
/// be deasserted synchronously to the src_clk_i and dst_rst_ni must be
/// deasserted synchronously to dst_clk_i.) You can use the cc_rstgen cell in the
/// common_cells library to achieve this (synchronization of only the
/// de-assertion). However, be careful about reset domain crossings; If you
/// reset both domain asynchronously in their entirety (i.e. POR) you are fine.
/// However, if you use this strategy for warm resets (some parts of the circuit
/// are not reset) you might introduce metastability in this separate
/// reset-domain when you assert the reset (the deassertion synchronizer doen't
/// help here).
///
/// CONSTRAINT: Requires max_delay of min_period(src_clk_i, dst_clk_i) through
/// the paths async_req, async_ack, async_data.
`include "common_cells/registers.svh"
module cc_cdc_2phase #(
parameter type data_t = logic,
parameter int unsigned SyncStages = 2
)(
input logic src_rst_ni,
input logic src_clk_i,
input data_t src_data_i,
input logic src_valid_i,
output logic src_ready_o,
input logic dst_rst_ni,
input logic dst_clk_i,
output data_t dst_data_o,
output logic dst_valid_o,
input logic dst_ready_i
);
// Asynchronous handshake signals.
(* dont_touch = "true" *) logic async_req;
(* dont_touch = "true" *) logic async_ack;
(* dont_touch = "true" *) data_t async_data;
if (SyncStages < 2) begin : gen_sync_stage_assertion
$error("A minimum of 2 synchronizer stages is required for proper functionality.");
end
// The sender in the source domain.
cc_cdc_2phase_src #(
.data_t ( data_t ),
.SyncStages ( SyncStages )
) i_src (
.rst_ni ( src_rst_ni ),
.clk_i ( src_clk_i ),
.data_i ( src_data_i ),
.valid_i ( src_valid_i ),
.ready_o ( src_ready_o ),
.async_req_o ( async_req ),
.async_ack_i ( async_ack ),
.async_data_o ( async_data )
);
// The receiver in the destination domain.
cc_cdc_2phase_dst #(
.data_t ( data_t ),
.SyncStages ( SyncStages )
) i_dst (
.rst_ni ( dst_rst_ni ),
.clk_i ( dst_clk_i ),
.data_o ( dst_data_o ),
.valid_o ( dst_valid_o ),
.ready_i ( dst_ready_i ),
.async_req_i ( async_req ),
.async_ack_o ( async_ack ),
.async_data_i ( async_data )
);
endmodule
/// Half of the two-phase clock domain crossing located in the source domain.
module cc_cdc_2phase_src #(
parameter type data_t = logic,
parameter int unsigned SyncStages = 2
)(
input logic rst_ni,
input logic clk_i,
input data_t data_i,
input logic valid_i,
output logic ready_o,
output logic async_req_o,
input logic async_ack_i,
output data_t async_data_o
);
(* dont_touch = "true" *)
logic req_src_q, ack_synced;
(* dont_touch = "true" *)
data_t data_src_q;
logic src_accept;
assign src_accept = valid_i && ready_o;
if (SyncStages < 2) begin : gen_sync_stage_assertion
$error("A minimum of 2 synchronizer stages is required for proper functionality.");
end
// Synchronize the async ACK.
tc_sync #(
.Stages ( SyncStages )
) i_sync (
.clk_i,
.rst_ni,
.serial_i ( async_ack_i ),
.serial_o ( ack_synced )
);
// The req_src and data_src registers change when a new data item is accepted.
`FFL(req_src_q, ~req_src_q, src_accept, 1'b0, clk_i, rst_ni)
`FFL(data_src_q, data_i, src_accept, data_t'('0), clk_i, rst_ni)
// Output assignments.
assign ready_o = (req_src_q == ack_synced);
assign async_req_o = req_src_q;
assign async_data_o = data_src_q;
endmodule
/// Half of the two-phase clock domain crossing located in the destination
/// domain.
module cc_cdc_2phase_dst #(
parameter type data_t = logic,
parameter int unsigned SyncStages = 2
)(
input logic rst_ni,
input logic clk_i,
output data_t data_o,
output logic valid_o,
input logic ready_i,
input logic async_req_i,
output logic async_ack_o,
input data_t async_data_i
);
(* dont_touch = "true" *)
logic req_synced, req_synced_q1, ack_dst_q;
(* dont_touch = "true" *)
data_t data_dst_q;
logic dst_accept, dst_data_load;
assign dst_accept = valid_o && ready_i;
assign dst_data_load = req_synced != req_synced_q1 && !valid_o;
if (SyncStages < 2) begin : gen_sync_stage_assertion
$error("A minimum of 2 synchronizer stages is required for proper functionality.");
end
// Synchronize the async request.
tc_sync #(
.Stages ( SyncStages )
) i_sync (
.clk_i,
.rst_ni,
.serial_i ( async_req_i ),
.serial_o ( req_synced )
);
// The ack_dst register changes when a new data item is accepted.
`FFL(ack_dst_q, ~ack_dst_q, dst_accept, 1'b0, clk_i, rst_ni)
// The data_dst register changes when a new data item is presented. This is
// indicated by the async_req line changing levels.
`FFL(data_dst_q, async_data_i, dst_data_load, data_t'('0), clk_i, rst_ni)
// Delayed version of the synchronized request for transition detection.
`FF(req_synced_q1, req_synced, 1'b0, clk_i, rst_ni)
// Output assignments.
assign valid_o = (ack_dst_q != req_synced_q1);
assign data_o = data_dst_q;
assign async_ack_o = ack_dst_q;
endmodule
4f62c83c0This file is pinned to the selected release. Download the original to open it in your design tool.