1//
2// Copyright 2019 Ettus Research, a National Instruments Company
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5//
6// Module:  ctrlport_clk_cross
7//
8// Description:
9//
10//   Crosses a CTRL Port request and response between two clock domains.
11//
12
13
14module ctrlport_clk_cross (
15  input wire rst, // Can be either clock domain, but must be glitch-free
16
17  //---------------------------------------------------------------------------
18  // Input Clock Domain (Slave Interface)
19  //---------------------------------------------------------------------------
20
21  input  wire        s_ctrlport_clk,
22  input  wire        s_ctrlport_req_wr,
23  input  wire        s_ctrlport_req_rd,
24  input  wire [19:0] s_ctrlport_req_addr,
25  input  wire [ 9:0] s_ctrlport_req_portid,
26  input  wire [15:0] s_ctrlport_req_rem_epid,
27  input  wire [ 9:0] s_ctrlport_req_rem_portid,
28  input  wire [31:0] s_ctrlport_req_data,
29  input  wire [ 3:0] s_ctrlport_req_byte_en,
30  input  wire        s_ctrlport_req_has_time,
31  input  wire [63:0] s_ctrlport_req_time,
32  output wire        s_ctrlport_resp_ack,
33  output wire [ 1:0] s_ctrlport_resp_status,
34  output wire [31:0] s_ctrlport_resp_data,
35
36  //---------------------------------------------------------------------------
37  // Output Clock Domain (Master Interface)
38  //---------------------------------------------------------------------------
39
40  input  wire        m_ctrlport_clk,
41  output wire        m_ctrlport_req_wr,
42  output wire        m_ctrlport_req_rd,
43  output wire [19:0] m_ctrlport_req_addr,
44  output wire [ 9:0] m_ctrlport_req_portid,
45  output wire [15:0] m_ctrlport_req_rem_epid,
46  output wire [ 9:0] m_ctrlport_req_rem_portid,
47  output wire [31:0] m_ctrlport_req_data,
48  output wire [ 3:0] m_ctrlport_req_byte_en,
49  output wire        m_ctrlport_req_has_time,
50  output wire [63:0] m_ctrlport_req_time,
51  input  wire        m_ctrlport_resp_ack,
52  input  wire [ 1:0] m_ctrlport_resp_status,
53  input  wire [31:0] m_ctrlport_resp_data
54);
55  //---------------------------------------------------------------------------
56  // Reset sync to both clock domains
57  //---------------------------------------------------------------------------
58  wire m_rst, s_rst;
59  reset_sync master_reset_sync_inst (
60    .clk(m_ctrlport_clk), .reset_in(rst), .reset_out(m_rst)
61  );
62  reset_sync slave_reset_sync_inst (
63    .clk(s_ctrlport_clk), .reset_in(rst), .reset_out(s_rst)
64  );
65
66  //---------------------------------------------------------------------------
67  // Slave to Master Clock Crossing (Request)
68  //---------------------------------------------------------------------------
69
70  localparam REQ_W =
71    1  + // ctrlport_req_wr
72    1  + // ctrlport_req_rd
73    20 + // ctrlport_req_addr
74    10 + // ctrlport_req_portid
75    16 + // ctrlport_req_rem_epid
76    10 + // ctrlport_req_rem_portid
77    32 + // ctrlport_req_data
78    4  + // ctrlport_req_byte_en
79    1  + // ctrlport_req_has_time
80    64;  // ctrlport_req_time
81
82  wire [ REQ_W-1:0] s_req_flat;
83  wire [ REQ_W-1:0] m_req_flat;
84  wire              m_req_flat_valid;
85  wire              m_ctrlport_req_wr_tmp;
86  wire              m_ctrlport_req_rd_tmp;
87
88  assign s_req_flat = {
89    s_ctrlport_req_wr,
90    s_ctrlport_req_rd,
91    s_ctrlport_req_addr,
92    s_ctrlport_req_portid,
93    s_ctrlport_req_rem_epid,
94    s_ctrlport_req_rem_portid,
95    s_ctrlport_req_data,
96    s_ctrlport_req_byte_en,
97    s_ctrlport_req_has_time,
98    s_ctrlport_req_time
99  };
100
101  // Busy flag can be ignored as the response handshake takes at least the same
102  // amount of cycles to transfer the response as this handshake instance needs
103  // to release the busy flag as they are configured with the same amount of
104  // synchronization stages. Furthermore the ctrlport protocol just allows for
105  // one transaction to be active at the same time. A request can only be issued
106  // once the response is provided.
107  handshake #(
108    .WIDTH(REQ_W)
109  ) req_handshake_inst (
110    .clk_a(s_ctrlport_clk),
111    .rst_a(s_rst),
112    .valid_a((s_ctrlport_req_wr | s_ctrlport_req_rd) & ~s_rst),
113    .data_a(s_req_flat),
114    .busy_a(),
115    .clk_b(m_ctrlport_clk),
116    .valid_b(m_req_flat_valid),
117    .data_b(m_req_flat)
118  );
119
120  assign {
121    m_ctrlport_req_wr_tmp,
122    m_ctrlport_req_rd_tmp,
123    m_ctrlport_req_addr,
124    m_ctrlport_req_portid,
125    m_ctrlport_req_rem_epid,
126    m_ctrlport_req_rem_portid,
127    m_ctrlport_req_data,
128    m_ctrlport_req_byte_en,
129    m_ctrlport_req_has_time,
130    m_ctrlport_req_time
131  } = m_req_flat;
132
133  assign m_ctrlport_req_wr = m_ctrlport_req_wr_tmp & m_req_flat_valid & ~m_rst;
134  assign m_ctrlport_req_rd = m_ctrlport_req_rd_tmp & m_req_flat_valid & ~m_rst;
135
136
137  //---------------------------------------------------------------------------
138  // Master to Slave Clock Crossing (Response)
139  //---------------------------------------------------------------------------
140
141  localparam RESP_W =
142    1  + // ctrlport_resp_ack,
143    2  + // ctrlport_resp_status,
144    32;  // ctrlport_resp_data
145
146  wire [RESP_W-1:0] m_resp_flat;
147  wire [RESP_W-1:0] s_resp_flat;
148  wire              s_resp_flat_valid;
149  wire              s_ctrlport_resp_ack_tmp;
150
151  assign m_resp_flat = {
152    m_ctrlport_resp_ack,
153    m_ctrlport_resp_status,
154    m_ctrlport_resp_data
155  };
156
157  // Busy flag can be ignored as the request handshake takes at least the same
158  // amount of cycles to transfer the request as this handshake instance needs
159  // to release the busy flag as they are configured with the same amount of
160  // synchronization stages. Furthermore the ctrlport protocol just allows for
161  // one transaction to be active at the same time. A response can only be
162  // issued once the request is available.
163  handshake #(
164    .WIDTH(RESP_W)
165  ) resp_handshake_inst (
166    .clk_a(m_ctrlport_clk),
167    .rst_a(m_rst),
168    .valid_a(m_ctrlport_resp_ack & ~m_rst),
169    .data_a(m_resp_flat),
170    .busy_a(),
171    .clk_b(s_ctrlport_clk),
172    .valid_b(s_resp_flat_valid),
173    .data_b(s_resp_flat)
174  );
175
176  assign {
177    s_ctrlport_resp_ack_tmp,
178    s_ctrlport_resp_status,
179    s_ctrlport_resp_data
180  } = s_resp_flat;
181
182  assign s_ctrlport_resp_ack = s_ctrlport_resp_ack_tmp & s_resp_flat_valid & ~s_rst;
183
184endmodule
185