File: axis_ctrl_master.v

package info (click to toggle)
uhd 4.9.0.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 184,180 kB
  • sloc: cpp: 262,887; python: 112,011; ansic: 102,670; vhdl: 57,031; tcl: 19,924; xml: 8,581; makefile: 3,028; sh: 2,812; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (316 lines) | stat: -rw-r--r-- 12,900 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
//
// Copyright 2018-2019 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: axis_ctrl_master
// Description:
//  This module implements an AXIS-Control master (and a Control-Port
//  slave). Requests are accepted on the slave Control-Port, converted
//  to AXIS-Control requests, then sent over the master AXI-Stream port.
//  Responses are received on the AXI-Stream slave port, and converted
//  to Control-Port responses.
//  NOTE: Transactions are not buffered so there is no need for flow 
//        control or throttling.
//
// Parameters:
//   - THIS_PORTID     : The local port-ID of this control port
//
// Signals:
//   - s_axis_ctrl_*   : Input control stream (AXI-Stream) for responses
//   - m_axis_ctrl_*   : Output control stream (AXI-Stream) for requests
//   - ctrlport_req_*  : Control-port master request port
//   - ctrlport_resp_* : Control-port master response port

module axis_ctrl_master #(
  parameter [9:0] THIS_PORTID = 10'd0
)(
  // Clock and reset
  input  wire         clk,
  input  wire         rst,
  // AXIS-Control Bus (Response)
  input  wire [31:0]  s_axis_ctrl_tdata,
  input  wire         s_axis_ctrl_tlast,
  input  wire         s_axis_ctrl_tvalid,
  output wire         s_axis_ctrl_tready,
  // AXIS-Control Bus (Request)
  output reg  [31:0]  m_axis_ctrl_tdata,
  output wire         m_axis_ctrl_tlast,
  output wire         m_axis_ctrl_tvalid,
  input  wire         m_axis_ctrl_tready,
  // Control Port Endpoint (Request)
  input  wire         ctrlport_req_wr,
  input  wire         ctrlport_req_rd,
  input  wire [19:0]  ctrlport_req_addr,
  input  wire [9:0]   ctrlport_req_portid,
  input  wire [15:0]  ctrlport_req_rem_epid,
  input  wire [9:0]   ctrlport_req_rem_portid,
  input  wire [31:0]  ctrlport_req_data,
  input  wire [3:0]   ctrlport_req_byte_en,
  input  wire         ctrlport_req_has_time,
  input  wire [63:0]  ctrlport_req_time,
  // Control Port Endpoint (Response)
  output wire         ctrlport_resp_ack,
  output wire [1:0]   ctrlport_resp_status,
  output wire [31:0]  ctrlport_resp_data
);

  // ---------------------------------------------------
  //  RFNoC Includes
  // ---------------------------------------------------
  `include "rfnoc_chdr_utils.vh"
  `include "rfnoc_axis_ctrl_utils.vh"

  // ---------------------------------------------------
  //  State Machine
  // ---------------------------------------------------
  localparam [3:0] ST_IDLE          = 4'd0;   // Waiting for a request on slave ctrlport
  localparam [3:0] ST_REQ_HDR_LO    = 4'd1;   // Sending AXIS-Control request header (low bits)
  localparam [3:0] ST_REQ_HDR_HI    = 4'd2;   // Sending AXIS-Control request header (high bits)
  localparam [3:0] ST_REQ_TS_LO     = 4'd3;   // Sending AXIS-Control request timestamp (low bits)
  localparam [3:0] ST_REQ_TS_HI     = 4'd4;   // Sending AXIS-Control request timestamp (high bits)
  localparam [3:0] ST_REQ_OP_WORD   = 4'd5;   // Sending AXIS-Control request operation word
  localparam [3:0] ST_REQ_OP_DATA   = 4'd6;   // Sending AXIS-Control request data word
  localparam [3:0] ST_RESP_HDR_LO   = 4'd7;   // Receiving AXIS-Control response header (low bits)
  localparam [3:0] ST_RESP_HDR_HI   = 4'd8;   // Receiving AXIS-Control response header (high bits)
  localparam [3:0] ST_RESP_TS_LO    = 4'd9;   // Receiving AXIS-Control response timestamp (low bits)
  localparam [3:0] ST_RESP_TS_HI    = 4'd10;  // Receiving AXIS-Control response timestamp (high bits)
  localparam [3:0] ST_RESP_OP_WORD  = 4'd11;  // Receiving AXIS-Control response operation word
  localparam [3:0] ST_RESP_OP_DATA  = 4'd12;  // Receiving AXIS-Control response data word     
  localparam [3:0] ST_SHORT_PKT_ERR = 4'd13;  // Response was too short. Send a dummy response on ctrlport
  localparam [3:0] ST_DROP_LONG_PKT = 4'd14;  // Response was too long. Dump the rest of the packet

  // State variables
  reg [3:0]   state = ST_IDLE;    // Current state for FSM
  reg [5:0]   seq_num = 6'd0;     // Expected seqnum for response
  // Request state
  reg [3:0]   req_opcode;         // Cached opcode for transaction request
  reg [19:0]  req_addr;           // Cached address for transaction request
  reg [9:0]   req_portid;         // Cached port ID for transaction request
  reg [15:0]  req_rem_epid;       // Cached remote endpoint ID for transaction request
  reg [9:0]   req_rem_portid;     // Cached remote port ID for transaction request
  reg [31:0]  req_data;           // Cached data word for transaction request
  reg [3:0]   req_byte_en;        // Cached byte enable for transaction request
  reg         req_has_time;       // Cached has_time bit for transaction request
  reg [63:0]  req_time;           // Cached timestamp for transaction request
  // Response state
  reg         resp_has_time;      // Does the response have a timestamp?
  reg [1:0]   resp_status;        // The status in the response
  reg         resp_seq_err, resp_cmd_err; // Error bits for the response

  always @(posedge clk) begin
    if (rst) begin
      state <= ST_IDLE;
      seq_num <= 6'd0;
    end else begin
      case (state)

        // Ready to receive a request on ctrlport
        // ------------------------------------
        ST_IDLE: begin
          if (ctrlport_req_wr | ctrlport_req_rd) begin
            // A transaction was posted on the slave ctrlport...
            // Cache the opcode
            if (ctrlport_req_wr & ctrlport_req_rd)
              req_opcode   <= AXIS_CTRL_OPCODE_WRITE_READ;
            else if (ctrlport_req_rd)
              req_opcode   <= AXIS_CTRL_OPCODE_READ;
            else
              req_opcode   <= AXIS_CTRL_OPCODE_WRITE;
            // Cache transaction info
            req_addr       <= ctrlport_req_addr;
            req_portid     <= ctrlport_req_portid;
            req_rem_epid   <= ctrlport_req_rem_epid;
            req_rem_portid <= ctrlport_req_rem_portid;
            req_data       <= ctrlport_req_data;
            req_byte_en    <= ctrlport_req_byte_en;
            req_has_time   <= ctrlport_req_has_time;
            req_time       <= ctrlport_req_time;
            // Start sending out AXIS-Ctrl packet
            state <= ST_REQ_HDR_LO;
          end
        end

        // Send a request AXIS comand
        // (a state for each stage in the packet)
        // ------------------------------------
        ST_REQ_HDR_LO: begin
          if (m_axis_ctrl_tready)
            state <= ST_REQ_HDR_HI;
        end
        ST_REQ_HDR_HI: begin
          if (m_axis_ctrl_tready)
            state <= req_has_time ? ST_REQ_TS_LO : ST_REQ_OP_WORD;
        end
        ST_REQ_TS_LO: begin
          if (m_axis_ctrl_tready)
            state <= ST_REQ_TS_HI;
        end
        ST_REQ_TS_HI: begin
          if (m_axis_ctrl_tready)
            state <= ST_REQ_OP_WORD;
        end
        ST_REQ_OP_WORD: begin
          if (m_axis_ctrl_tready)
            state <= ST_REQ_OP_DATA;
        end
        ST_REQ_OP_DATA: begin
          if (m_axis_ctrl_tready)
            state <= ST_RESP_HDR_LO;
        end

        // Receive a response AXIS comand
        // (a state for each stage in the packet)
        // ------------------------------------
        ST_RESP_HDR_LO: begin
          if (s_axis_ctrl_tvalid) begin
            // Remeber if the packet is supposed to have a timestamp
            resp_has_time <= axis_ctrl_get_has_time(s_axis_ctrl_tdata);
            // Check for a sequence error
            resp_seq_err <= (axis_ctrl_get_seq_num(s_axis_ctrl_tdata) != seq_num);
            // Assert a command error if:
            // - The port ID does not match
            // - The response was too short (the next check)
            resp_cmd_err <= (axis_ctrl_get_dst_port(s_axis_ctrl_tdata) != THIS_PORTID);
            if (!s_axis_ctrl_tlast) begin
              state <= ST_RESP_HDR_HI;
            end else begin
              // Response was too short
              resp_cmd_err <= 1'b1;
              state <= ST_SHORT_PKT_ERR;
            end
          end
        end
        ST_RESP_HDR_HI: begin
          if (s_axis_ctrl_tvalid) begin
            if (!s_axis_ctrl_tlast) begin
              state <= resp_has_time ? ST_RESP_TS_LO : ST_RESP_OP_WORD;
            end else begin
              // Response was too short
              resp_cmd_err <= 1'b1;
              state <= ST_SHORT_PKT_ERR;
            end
          end
        end
        ST_RESP_TS_LO: begin
          if (s_axis_ctrl_tvalid) begin
            if (!s_axis_ctrl_tlast) begin
              state <= ST_RESP_TS_HI;
            end else begin
              // Response was too short
              resp_cmd_err <= 1'b1;
              state <= ST_SHORT_PKT_ERR;
            end
          end
        end
        ST_RESP_TS_HI: begin
          if (s_axis_ctrl_tvalid) begin
            if (!s_axis_ctrl_tlast) begin
              state <= ST_RESP_OP_WORD;
            end else begin
              // Response was too short
              resp_cmd_err <= 1'b1;
              state <= ST_SHORT_PKT_ERR;
            end
          end
        end
        ST_RESP_OP_WORD: begin
          if (s_axis_ctrl_tvalid) begin
            if (!s_axis_ctrl_tlast) begin
              // Assert a command error if opcode and addr in request does not match response
              resp_cmd_err <= resp_cmd_err ||
                              (axis_ctrl_get_opcode(s_axis_ctrl_tdata) != req_opcode) ||
                              (axis_ctrl_get_address(s_axis_ctrl_tdata) != req_addr);
              resp_status <= axis_ctrl_get_status(s_axis_ctrl_tdata);
              state <= ST_RESP_OP_DATA;
            end else begin
              // Response was too short
              resp_cmd_err <= 1'b1;
              state <= ST_SHORT_PKT_ERR;
            end
          end
        end
        ST_RESP_OP_DATA: begin
          if (s_axis_ctrl_tvalid) begin
            // If the packet was too long then just drop the rest without complaining
            state <= s_axis_ctrl_tlast ? ST_IDLE : ST_DROP_LONG_PKT;
            seq_num <= seq_num + 6'd1;
          end
        end

        // Error handling states
        // ------------------------------------
        ST_SHORT_PKT_ERR: begin
          state <= ST_IDLE;
        end
        ST_DROP_LONG_PKT: begin
          if (s_axis_ctrl_tvalid && s_axis_ctrl_tlast)
            state <= ST_IDLE;
        end

        default: begin
          // We should never get here
          state <= ST_IDLE;
        end
      endcase
    end
  end

  // Logic to drive m_axis_ctrl_*
  // ------------------------------------
  always @(*) begin
    case (state)
      ST_REQ_HDR_LO: begin
        m_axis_ctrl_tdata = axis_ctrl_build_hdr_lo(
          1'b0 /* is_ack*/, req_has_time, seq_num,
          4'd1 /* num_data */, THIS_PORTID, req_portid);
      end
      ST_REQ_HDR_HI: begin
        m_axis_ctrl_tdata = axis_ctrl_build_hdr_hi(
          req_rem_portid, req_rem_epid);
      end
      ST_REQ_TS_LO: begin
        m_axis_ctrl_tdata = req_time[31:0];
      end
      ST_REQ_TS_HI: begin
        m_axis_ctrl_tdata = req_time[63:32];
      end
      ST_REQ_OP_WORD: begin
        m_axis_ctrl_tdata = axis_ctrl_build_op_word(
          AXIS_CTRL_STS_OKAY, req_opcode, req_byte_en, req_addr);
      end
      ST_REQ_OP_DATA: begin
        m_axis_ctrl_tdata = req_data;
      end
      default: begin
        m_axis_ctrl_tdata = 32'h0;
      end
    endcase
  end
  assign m_axis_ctrl_tvalid = (state == ST_REQ_HDR_LO)  ||
                              (state == ST_REQ_HDR_HI)  ||
                              (state == ST_REQ_TS_LO)   ||
                              (state == ST_REQ_TS_HI)   ||
                              (state == ST_REQ_OP_WORD) ||
                              (state == ST_REQ_OP_DATA);
  assign m_axis_ctrl_tlast  = (state == ST_REQ_OP_DATA);

  // Logic to backpressure responses
  // ------------------------------------
  assign s_axis_ctrl_tready = (state == ST_RESP_HDR_LO)  ||
                              (state == ST_RESP_HDR_HI)  ||
                              (state == ST_RESP_TS_LO)   ||
                              (state == ST_RESP_TS_HI)   ||
                              (state == ST_RESP_OP_WORD) ||
                              (state == ST_RESP_OP_DATA) ||
                              (state == ST_DROP_LONG_PKT);

  // Logic to drive Control-port response
  // ------------------------------------
  assign ctrlport_resp_ack    = (state == ST_RESP_OP_DATA && s_axis_ctrl_tvalid) || 
                                (state == ST_SHORT_PKT_ERR); 
  assign ctrlport_resp_status = resp_cmd_err ? AXIS_CTRL_STS_CMDERR : 
                                  (resp_seq_err ? AXIS_CTRL_STS_WARNING : resp_status);
  assign ctrlport_resp_data   = (state == ST_SHORT_PKT_ERR) ? 32'h0 : s_axis_ctrl_tdata;

endmodule // axis_ctrl_master