1//
2// Copyright 2018-2019 Ettus Research, A National Instruments Company
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5//
6// Module: ctrlport_endpoint
7// Description:
8//   A bidirectional AXIS-Control to Control-Port converter.
9//   Use this module in noc_shell to interface between the user
10//   logic (using ctrlport) and the rfnoc infrastructure (axis_ctrl)
11//
12// Parameters:
13//   - THIS_PORTID: The 10-bit ID of the control XB port that is
14//                  connected to this converter.
15//   - SYNC_CLKS: Is rfnoc_ctrl_clk and ctrlport_clk the same clock?
16//   - AXIS_CTRL_MST_EN: Enable an AXIS-Ctrl master
17//   - AXIS_CTRL_SLV_EN: Enable an AXIS-Ctrl slave
18//   - SLAVE_FIFO_SIZE: FIFO depth for the slave port
19//
20// Signals:
21//   - *_rfnoc_ctrl_* : Input/output AXIS-Control stream (AXI-Stream)
22//   - *_ctrlport_*   : Input/output control-port bus
23
24module ctrlport_endpoint #(
25  parameter [9:0] THIS_PORTID       = 10'd0,
26  parameter       SYNC_CLKS         = 0,
27  parameter [0:0] AXIS_CTRL_MST_EN  = 1,
28  parameter [0:0] AXIS_CTRL_SLV_EN  = 1,
29  parameter       SLAVE_FIFO_SIZE   = 5
30)(
31  // Clocks, Resets, Misc
32  input  wire         rfnoc_ctrl_clk,
33  input  wire         rfnoc_ctrl_rst,
34  input  wire         ctrlport_clk,
35  input  wire         ctrlport_rst,
36  // AXIS-Control Bus
37  input  wire [31:0]  s_rfnoc_ctrl_tdata,
38  input  wire         s_rfnoc_ctrl_tlast,
39  input  wire         s_rfnoc_ctrl_tvalid,
40  output wire         s_rfnoc_ctrl_tready,
41  output wire [31:0]  m_rfnoc_ctrl_tdata,
42  output wire         m_rfnoc_ctrl_tlast,
43  output wire         m_rfnoc_ctrl_tvalid,
44  input  wire         m_rfnoc_ctrl_tready,
45  // Control Port Master (Request)
46  output wire         m_ctrlport_req_wr,
47  output wire         m_ctrlport_req_rd,
48  output wire [19:0]  m_ctrlport_req_addr,
49  output wire [31:0]  m_ctrlport_req_data,
50  output wire [3:0]   m_ctrlport_req_byte_en,
51  output wire         m_ctrlport_req_has_time,
52  output wire [63:0]  m_ctrlport_req_time,
53  // Control Port Master (Response)
54  input  wire         m_ctrlport_resp_ack,
55  input  wire [1:0]   m_ctrlport_resp_status,
56  input  wire [31:0]  m_ctrlport_resp_data,
57  // Control Port Slave (Request)
58  input  wire         s_ctrlport_req_wr,
59  input  wire         s_ctrlport_req_rd,
60  input  wire [19:0]  s_ctrlport_req_addr,
61  input  wire [9:0]   s_ctrlport_req_portid,
62  input  wire [15:0]  s_ctrlport_req_rem_epid,
63  input  wire [9:0]   s_ctrlport_req_rem_portid,
64  input  wire [31:0]  s_ctrlport_req_data,
65  input  wire [3:0]   s_ctrlport_req_byte_en,
66  input  wire         s_ctrlport_req_has_time,
67  input  wire [63:0]  s_ctrlport_req_time,
68  // Control Port Slave (Response)
69  output wire         s_ctrlport_resp_ack,
70  output wire [1:0]   s_ctrlport_resp_status,
71  output wire [31:0]  s_ctrlport_resp_data
72);
73
74  // ---------------------------------------------------
75  //  RFNoC Includes
76  // ---------------------------------------------------
77  `include "rfnoc_chdr_utils.vh"
78  `include "rfnoc_axis_ctrl_utils.vh"
79
80  // ---------------------------------------------------
81  //  Clock Crossing
82  // ---------------------------------------------------
83
84  wire [31:0] i_ctrl_tdata,  o_ctrl_tdata;
85  wire        i_ctrl_tlast,  o_ctrl_tlast;
86  wire        i_ctrl_tvalid, o_ctrl_tvalid;
87  wire        i_ctrl_tready, o_ctrl_tready;
88
89  generate
90    if (SYNC_CLKS) begin : gen_sync_fifos
91      axi_fifo #(.WIDTH(32+1), .SIZE(1)) in_fifo_i (
92        .clk(ctrlport_clk), .reset(ctrlport_rst), .clear(1'b0),
93        .i_tdata({s_rfnoc_ctrl_tlast, s_rfnoc_ctrl_tdata}),
94        .i_tvalid(s_rfnoc_ctrl_tvalid), .i_tready(s_rfnoc_ctrl_tready),
95        .o_tdata({i_ctrl_tlast, i_ctrl_tdata}),
96        .o_tvalid(i_ctrl_tvalid), .o_tready(i_ctrl_tready),
97        .space(), .occupied()
98      );
99
100      axi_fifo #(.WIDTH(32+1), .SIZE(1)) out_fifo_i (
101        .clk(ctrlport_clk), .reset(ctrlport_rst), .clear(1'b0),
102        .i_tdata({o_ctrl_tlast, o_ctrl_tdata}),
103        .i_tvalid(o_ctrl_tvalid), .i_tready(o_ctrl_tready),
104        .o_tdata({m_rfnoc_ctrl_tlast, m_rfnoc_ctrl_tdata}),
105        .o_tvalid(m_rfnoc_ctrl_tvalid), .o_tready(m_rfnoc_ctrl_tready),
106        .space(), .occupied()
107      );
108    end else begin : gen_async_fifos
109      axi_fifo_2clk #(.WIDTH(32+1), .SIZE(1), .PIPELINE("IN")) in_fifo_i (
110        .reset(rfnoc_ctrl_rst),
111        .i_aclk(rfnoc_ctrl_clk),
112        .i_tdata({s_rfnoc_ctrl_tlast, s_rfnoc_ctrl_tdata}),
113        .i_tvalid(s_rfnoc_ctrl_tvalid), .i_tready(s_rfnoc_ctrl_tready),
114        .o_aclk(ctrlport_clk),
115        .o_tdata({i_ctrl_tlast, i_ctrl_tdata}),
116        .o_tvalid(i_ctrl_tvalid), .o_tready(i_ctrl_tready)
117      );
118
119      axi_fifo_2clk #(.WIDTH(32+1), .SIZE(1), .PIPELINE("OUT")) out_fifo_i (
120        .reset(ctrlport_rst),
121        .i_aclk(ctrlport_clk),
122        .i_tdata({o_ctrl_tlast, o_ctrl_tdata}),
123        .i_tvalid(o_ctrl_tvalid), .i_tready(o_ctrl_tready),
124        .o_aclk(rfnoc_ctrl_clk),
125        .o_tdata({m_rfnoc_ctrl_tlast, m_rfnoc_ctrl_tdata}),
126        .o_tvalid(m_rfnoc_ctrl_tvalid), .o_tready(m_rfnoc_ctrl_tready)
127      );
128
129    end
130  endgenerate
131
132  // ---------------------------------------------------
133  //  MUXING
134  // ---------------------------------------------------
135  wire [31:0] mst_req_tdata,  mst_resp_tdata ;
136  wire        mst_req_tlast,  mst_resp_tlast ;
137  wire        mst_req_tvalid, mst_resp_tvalid;
138  wire        mst_req_tready, mst_resp_tready;
139
140  wire [31:0] slv_req_tdata,  slv_req_fifo_tdata,  slv_resp_tdata ;
141  wire        slv_req_tlast,  slv_req_fifo_tlast,  slv_resp_tlast ;
142  wire        slv_req_tvalid, slv_req_fifo_tvalid, slv_resp_tvalid;
143  wire        slv_req_tready, slv_req_fifo_tready, slv_resp_tready;
144
145  generate
146    if (AXIS_CTRL_MST_EN == 1'b1 && AXIS_CTRL_SLV_EN == 1'b1) begin : gen_mst_slv_muxing
147      wire [31:0] in_hdr;
148      axi_demux #(
149        .WIDTH(32), .SIZE(2), .PRE_FIFO_SIZE(0), .POST_FIFO_SIZE(0)
150      ) demux_i (
151        .clk(ctrlport_clk), .reset(ctrlport_rst), .clear(1'b0),
152        .header(in_hdr), .dest(axis_ctrl_get_is_ack(in_hdr)),
153        .i_tdata (i_ctrl_tdata ),
154        .i_tlast (i_ctrl_tlast ),
155        .i_tvalid(i_ctrl_tvalid),
156        .i_tready(i_ctrl_tready),
157        .o_tdata ({mst_resp_tdata,  slv_req_tdata }),
158        .o_tlast ({mst_resp_tlast,  slv_req_tlast }),
159        .o_tvalid({mst_resp_tvalid, slv_req_tvalid}),
160        .o_tready({mst_resp_tready, slv_req_tready})
161      );
162
163      axi_mux #(
164        .WIDTH(32), .SIZE(2), .PRIO(0), .PRE_FIFO_SIZE(0), .POST_FIFO_SIZE(0)
165      ) mux_i (
166        .clk(ctrlport_clk), .reset(ctrlport_rst), .clear(1'b0),
167        .i_tdata ({mst_req_tdata,  slv_resp_tdata }),
168        .i_tlast ({mst_req_tlast,  slv_resp_tlast }),
169        .i_tvalid({mst_req_tvalid, slv_resp_tvalid}),
170        .i_tready({mst_req_tready, slv_resp_tready}),
171        .o_tdata (o_ctrl_tdata ),
172        .o_tlast (o_ctrl_tlast ),
173        .o_tvalid(o_ctrl_tvalid),
174        .o_tready(o_ctrl_tready)
175      );
176
177    end else if (AXIS_CTRL_MST_EN == 1'b1) begin : gen_mst_muxing
178
179      assign mst_resp_tdata  = i_ctrl_tdata;
180      assign mst_resp_tlast  = i_ctrl_tlast;
181      assign mst_resp_tvalid = i_ctrl_tvalid;
182      assign i_ctrl_tready   = mst_resp_tready;
183
184      assign o_ctrl_tdata    = mst_req_tdata;
185      assign o_ctrl_tlast    = mst_req_tlast;
186      assign o_ctrl_tvalid   = mst_req_tvalid;
187      assign mst_req_tready  = o_ctrl_tready;
188
189    end else begin : gen_no_mst_muxing
190
191      assign slv_req_tdata   = i_ctrl_tdata;
192      assign slv_req_tlast   = i_ctrl_tlast;
193      assign slv_req_tvalid  = i_ctrl_tvalid;
194      assign i_ctrl_tready   = slv_req_tready;
195
196      assign o_ctrl_tdata    = slv_resp_tdata;
197      assign o_ctrl_tlast    = slv_resp_tlast;
198      assign o_ctrl_tvalid   = slv_resp_tvalid;
199      assign slv_resp_tready = o_ctrl_tready;
200
201    end
202  endgenerate
203
204  // ---------------------------------------------------
205  //  AXIS Control Master and Slave
206  // ---------------------------------------------------
207
208  generate
209    if (AXIS_CTRL_MST_EN == 1'b1) begin : gen_ctrl_master
210      axis_ctrl_master #( .THIS_PORTID(THIS_PORTID) ) axis_ctrl_mst_i (
211        .clk                    (ctrlport_clk),
212        .rst                    (ctrlport_rst),
213        .s_axis_ctrl_tdata      (mst_resp_tdata),
214        .s_axis_ctrl_tlast      (mst_resp_tlast),
215        .s_axis_ctrl_tvalid     (mst_resp_tvalid),
216        .s_axis_ctrl_tready     (mst_resp_tready),
217        .m_axis_ctrl_tdata      (mst_req_tdata),
218        .m_axis_ctrl_tlast      (mst_req_tlast),
219        .m_axis_ctrl_tvalid     (mst_req_tvalid),
220        .m_axis_ctrl_tready     (mst_req_tready),
221        .ctrlport_req_wr        (s_ctrlport_req_wr),
222        .ctrlport_req_rd        (s_ctrlport_req_rd),
223        .ctrlport_req_addr      (s_ctrlport_req_addr),
224        .ctrlport_req_portid    (s_ctrlport_req_portid),
225        .ctrlport_req_rem_epid  (s_ctrlport_req_rem_epid),
226        .ctrlport_req_rem_portid(s_ctrlport_req_rem_portid),
227        .ctrlport_req_data      (s_ctrlport_req_data),
228        .ctrlport_req_byte_en   (s_ctrlport_req_byte_en),
229        .ctrlport_req_has_time  (s_ctrlport_req_has_time),
230        .ctrlport_req_time      (s_ctrlport_req_time),
231        .ctrlport_resp_ack      (s_ctrlport_resp_ack),
232        .ctrlport_resp_status   (s_ctrlport_resp_status),
233        .ctrlport_resp_data     (s_ctrlport_resp_data)
234      );
235    end else begin : gen_no_ctrl_master
236      assign mst_resp_tready = 1'b1;
237      assign mst_req_tlast = 1'b0;
238      assign mst_req_tvalid = 1'b0;
239      assign s_ctrlport_resp_ack = 1'b0;
240    end
241
242    if (AXIS_CTRL_SLV_EN == 1'b1) begin : gen_ctrl_slave
243      axi_fifo #(.WIDTH(32+1), .SIZE(SLAVE_FIFO_SIZE)) slv_fifo_i (
244        .clk(ctrlport_clk), .reset(ctrlport_rst), .clear(1'b0),
245        .i_tdata({slv_req_tlast, slv_req_tdata}),
246        .i_tvalid(slv_req_tvalid), .i_tready(slv_req_tready),
247        .o_tdata({slv_req_fifo_tlast, slv_req_fifo_tdata}),
248        .o_tvalid(slv_req_fifo_tvalid), .o_tready(slv_req_fifo_tready),
249        .space(), .occupied()
250      );
251
252      axis_ctrl_slave axis_ctrl_slv_i (
253        .clk                  (ctrlport_clk),
254        .rst                  (ctrlport_rst),
255        .s_axis_ctrl_tdata    (slv_req_fifo_tdata),
256        .s_axis_ctrl_tlast    (slv_req_fifo_tlast),
257        .s_axis_ctrl_tvalid   (slv_req_fifo_tvalid),
258        .s_axis_ctrl_tready   (slv_req_fifo_tready),
259        .m_axis_ctrl_tdata    (slv_resp_tdata),
260        .m_axis_ctrl_tlast    (slv_resp_tlast),
261        .m_axis_ctrl_tvalid   (slv_resp_tvalid),
262        .m_axis_ctrl_tready   (slv_resp_tready),
263        .ctrlport_req_wr      (m_ctrlport_req_wr),
264        .ctrlport_req_rd      (m_ctrlport_req_rd),
265        .ctrlport_req_addr    (m_ctrlport_req_addr),
266        .ctrlport_req_data    (m_ctrlport_req_data),
267        .ctrlport_req_byte_en (m_ctrlport_req_byte_en),
268        .ctrlport_req_has_time(m_ctrlport_req_has_time),
269        .ctrlport_req_time    (m_ctrlport_req_time),
270        .ctrlport_resp_ack    (m_ctrlport_resp_ack),
271        .ctrlport_resp_status (m_ctrlport_resp_status),
272        .ctrlport_resp_data   (m_ctrlport_resp_data)
273      );
274    end else begin : gen_no_ctrl_slave
275      assign slv_req_fifo_tready = 1'b1;
276      assign slv_resp_tlast = 1'b0;
277      assign slv_resp_tvalid = 1'b0;
278      assign m_ctrlport_req_wr = 1'b0;
279      assign m_ctrlport_req_rd = 1'b0;
280    end
281  endgenerate
282
283endmodule // ctrlport_endpoint
284
285