File: rx_control_gen3.v

package info (click to toggle)
uhd 3.13.1.0-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 207,120 kB
  • sloc: cpp: 167,245; ansic: 86,841; vhdl: 53,420; python: 40,839; xml: 13,167; tcl: 5,688; makefile: 2,167; sh: 1,719; pascal: 230; csh: 94; asm: 20; perl: 11
file content (289 lines) | stat: -rw-r--r-- 11,147 bytes parent folder | download | duplicates (2)
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
//
// Copyright 2016 Ettus Research
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Converts strobed sample data from radio frontend to the AXI-Stream bus
// Outputs an error packet if an overrun, late timed command, or empty command fifo error occurs.

// HALT brings RX to an idle state as quickly as possible if RX is running
// without running the risk of leaving a packet fragment in downstream FIFO's.
// HALT also flushes all remaining pending commands in the commmand FIFO.

module rx_control_gen3 #(
  parameter SR_RX_CTRL_COMMAND = 0,     // Command FIFO
  parameter SR_RX_CTRL_TIME_HI = 1,     // Command execute time (high word)
  parameter SR_RX_CTRL_TIME_LO = 2,     // Command execute time (low word)
  parameter SR_RX_CTRL_HALT = 3,        // Halt command -> return to idle state
  parameter SR_RX_CTRL_MAXLEN = 4,      // Packet length
  parameter SR_RX_CTRL_CLEAR_CMDS = 5,   // Clear command FIFO
  parameter SR_RX_CTRL_OUTPUT_FORMAT = 6,  // Output format (use timestamps)
  parameter WIDTH = 32            // Can be 32 or 64
)(
  input clk, input reset,
  input clear, // Resets state machine and clear output FIFO.
  input [63:0] vita_time, input [31:0] sid, input [31:0] resp_sid,
  input set_stb, input [7:0] set_addr, input [31:0] set_data,
  // Data packets
  output [WIDTH-1:0] rx_tdata, output rx_tlast, output rx_tvalid, input rx_tready, output [127:0] rx_tuser,
  // Error packets, Note: Currently unused as error packets must come inline with data.
  output reg [63:0] resp_tdata, output reg [127:0] resp_tuser, output reg resp_tlast, output reg resp_tvalid, input resp_tready,
  // From radio frontend
  output run, input [WIDTH-1:0] sample, input strobe
);

  reg [31:0] error;
  reg [WIDTH-1:0] rx_reg_tdata;
  reg rx_reg_tlast, rx_reg_tvalid;
  wire rx_reg_tready;
  reg [127:0] rx_reg_tuser, error_tuser;

  wire overflow = rx_reg_tvalid & ~rx_reg_tready;
  reg [63:0] overflow_time;

  wire [31:0] command_i;
  wire [63:0] time_i;
  wire store_command;

  wire send_imm, chain, reload, stop;
  wire [27:0] numlines;
  wire [63:0] rcvtime;
  wire use_timestamps;

  wire now, early, late;
  wire command_valid;
  reg command_ready;

  reg chain_sav, reload_sav;
  reg clear_halt;
  reg halt;
  wire set_halt;
  wire [15:0] maxlen;
  wire eob;
  reg [63:0] start_time;
  wire clear_cmds;

  setting_reg #(.my_addr(SR_RX_CTRL_COMMAND)) sr_cmd (
    .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
    .in(set_data),.out(command_i),.changed());

  setting_reg #(.my_addr(SR_RX_CTRL_TIME_HI)) sr_time_h (
    .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
    .in(set_data),.out(time_i[63:32]),.changed());

  setting_reg #(.my_addr(SR_RX_CTRL_TIME_LO)) sr_time_l (
    .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
    .in(set_data),.out(time_i[31:0]),.changed(store_command));

  setting_reg #(.my_addr(SR_RX_CTRL_HALT)) sr_rx_halt (
    .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
    .in(set_data),.out(),.changed(set_halt));

  // use (maxlen >> 1) for 2 samples per cycle
  setting_reg #(.my_addr(SR_RX_CTRL_MAXLEN), .width(16)) sr_maxlen (
    .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
    .in(set_data),.out(maxlen),.changed());

  setting_reg #(.my_addr(SR_RX_CTRL_CLEAR_CMDS)) sr_clear_cmds (
    .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
    .in(set_data),.out(),.changed(clear_cmds));

  setting_reg #(.my_addr(SR_RX_CTRL_OUTPUT_FORMAT), .width(1), .at_reset(1'b1)) sr_output_format (
    .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
    .in(set_data),.out(use_timestamps),.changed());

  always @(posedge clk)
    if (reset | clear | clear_halt | clear_cmds)
      halt <= 1'b0;
    else
      halt <= set_halt;

  axi_fifo_short #(.WIDTH(96)) commandfifo (
    .clk(clk),.reset(reset),.clear(clear | clear_halt | clear_cmds),
    .i_tdata({command_i,time_i}), .i_tvalid(store_command), .i_tready(),
    .o_tdata({send_imm,chain,reload,stop,numlines,rcvtime}),
    .o_tvalid(command_valid), .o_tready(command_ready),
    .occupied(), .space() );

  time_compare time_compare (
    .clk(clk), .reset(reset),
    .time_now(vita_time), .trigger_time(rcvtime), .now(now), .early(early), .late(late), .too_early());

  // State machine states
  localparam IBS_IDLE                = 0;
  localparam IBS_RUNNING             = 1;
  localparam IBS_ERR_WAIT_FOR_READY  = 2;
  localparam IBS_ERR_SEND_PKT        = 3;

  // Error codes
  localparam ERR_OVERRUN      = 32'd8;
  localparam ERR_BROKENCHAIN  = 32'd4;
  localparam ERR_LATECMD      = 32'd2;

  reg [2:0] ibs_state;
  reg [27:0] lines_left, repeat_lines;
  reg [15:0] lines_left_pkt;

  reg [11:0] seqnum_cnt;
  wire [11:0] next_seqnum = (rx_reg_tlast & rx_reg_tready & rx_reg_tvalid & (rx_reg_tuser[127:126] != 2'b11)) ? seqnum_cnt + 1'b1 : seqnum_cnt;
  always @(posedge clk) begin
    if (reset | clear | clear_halt) begin
      seqnum_cnt <= 'd0;
    end else begin
      seqnum_cnt <= next_seqnum;
    end
  end

  wire [127:0] error_header = {2'b11,           1'b1, 1'b1, next_seqnum,                  16'h24, resp_sid, overflow_time};
  wire [127:0] rx_header    = {2'b00, use_timestamps,  eob, next_seqnum, 16'h0 /* len ignored */,      sid, start_time};

  always @(posedge clk) begin
    if (reset | clear) begin
      ibs_state      <= IBS_IDLE;
      lines_left     <= 'd0;
      lines_left_pkt <= 'd0;
      repeat_lines   <= 'd0;
      start_time     <= 'd0;
      chain_sav      <= 1'b0;
      reload_sav     <= 1'b0;
      clear_halt     <= 1'b0;
      rx_reg_tdata   <= 'd0;
      rx_reg_tlast   <= 1'b0;
      rx_reg_tvalid  <= 1'b0;
      rx_reg_tuser   <= 'd0;
      resp_tdata     <= 'd0;
      resp_tlast     <= 1'b0;
      resp_tvalid    <= 1'b0;
      resp_tuser     <= 'd0;
      command_ready  <= 1'b0;
    end else begin
      case (ibs_state)
        IBS_IDLE : begin
          rx_reg_tlast   <= 1'b0;
          rx_reg_tvalid  <= 1'b0;
          command_ready  <= 1'b0;
          clear_halt     <= 1'b0; // Incase we got here through a HALT.
          if (command_valid & rx_reg_tready) begin
            // There is a valid command to pop from FIFO
            if (stop) begin
              // Stop bit set in this command, go idle.
              command_ready <= 1'b1;
              ibs_state     <= IBS_IDLE;
            end else if (late & ~send_imm) begin
              // Got this command later than its execution time.
              command_ready <= 1'b1;
              error         <= ERR_LATECMD;
              ibs_state     <= IBS_ERR_WAIT_FOR_READY;
            end else if (now | send_imm) begin
              // Either its time to run this command or it should run immediately without a time.
              command_ready  <= 1'b1;
              lines_left     <= numlines;
              repeat_lines   <= numlines;
              chain_sav      <= chain;
              reload_sav     <= reload;
              lines_left_pkt <= WIDTH == 64 ? (maxlen >> 1) : maxlen;
              ibs_state      <= IBS_RUNNING;
            end
          end
        end

        IBS_RUNNING : begin
          command_ready <= 1'b0;
          if (strobe) begin
            rx_reg_tvalid <= 1'b1;
            rx_reg_tlast  <= eob | (lines_left_pkt == 1);
            rx_reg_tuser  <= rx_header;
            rx_reg_tdata  <= sample;
            if (lines_left_pkt == 1) begin
              lines_left_pkt <= WIDTH == 64 ? (maxlen >> 1) : maxlen;
            end else begin
              lines_left_pkt <= lines_left_pkt - 1;
            end
            if (lines_left_pkt == (WIDTH == 64 ? (maxlen >> 1) : maxlen)) begin
              start_time <= vita_time;
            end
            if (lines_left == 1) begin
              if (halt) begin // Provide Halt mechanism used to bring RX into known IDLE state at re-initialization.
                ibs_state <= IBS_IDLE;
                clear_halt <= 1'b1;
              end else if (chain_sav) begin // If chain_sav is true then execute the next command now this one finished.
                if (command_valid) begin
                  command_ready <= 1'b1;
                  lines_left    <= numlines;
                  repeat_lines  <= numlines;
                  chain_sav     <= chain;
                  reload_sav    <= reload;
                  if (stop) begin // If the new command includes stop then go idle.
                    ibs_state <= IBS_IDLE;
                  end
                end else if (reload_sav) begin // There is no new command to pop from FIFO so re-run previous command.
                  lines_left <= repeat_lines;
                end else begin // Chain has been broken, no commands left in FIFO and reload not set.
                  error         <= ERR_BROKENCHAIN;
                  ibs_state     <= IBS_ERR_WAIT_FOR_READY;
                end
              end else begin // Chain is not true, so don't look for new command, instead go idle.
                ibs_state <= IBS_IDLE;
              end
            end else begin // Still counting down lines in current command.
              lines_left <= lines_left - 28'd1;
            end
          end else begin
            rx_reg_tvalid <= 1'b0;  // Sample consumed, drop tvalid
          end
          // Overflow condition -- can occur regardless of strobe state
          if (overflow) begin
            rx_reg_tvalid  <= 1'b1;      // Send final sample
            rx_reg_tlast   <= 1'b1;      // ... and end packet
            rx_reg_tuser   <= rx_header; // Update tuser with EOB set
            error          <= ERR_OVERRUN;
            ibs_state      <= IBS_ERR_WAIT_FOR_READY;
            overflow_time  <= vita_time;
          end
        end

        // Wait for output to be ready
        IBS_ERR_WAIT_FOR_READY : begin
          command_ready  <= 1'b0;
          if (rx_reg_tready) begin
            rx_reg_tvalid <= 1'b1;
            rx_reg_tlast  <= 1'b0;
            rx_reg_tdata  <= {WIDTH/32{error}};
            rx_reg_tuser  <= error_header;
            ibs_state     <= IBS_ERR_SEND_PKT;
          end
        end

        IBS_ERR_SEND_PKT : begin
          command_ready <= 1'b0;
          if (rx_reg_tready) begin
            rx_reg_tvalid <= 1'b1;
            rx_reg_tlast  <= 1'b1;
            rx_reg_tdata  <= 'd0;
            if (rx_reg_tlast) begin
              rx_reg_tvalid <= 1'b0;
              rx_reg_tlast  <= 1'b0;
              ibs_state     <= IBS_IDLE;
            end
          end
        end

        default : ibs_state <= IBS_IDLE;
      endcase
    end
  end

  assign run = (ibs_state == IBS_RUNNING);

  assign eob = ((lines_left == 1) & ( !chain_sav | (command_valid & stop) | (!command_valid & !reload_sav) | halt)) | overflow;

  // Register output
  axi_fifo_flop2 #(.WIDTH(129+WIDTH))
  axi_fifo_flop2 (
    .clk(clk), .reset(reset), .clear(clear),
    .i_tdata({rx_reg_tlast, rx_reg_tdata, rx_reg_tuser}), .i_tvalid(rx_reg_tvalid), .i_tready(rx_reg_tready),
    .o_tdata({rx_tlast, rx_tdata, rx_tuser}), .o_tvalid(rx_tvalid), .o_tready(rx_tready),
    .space(), .occupied());

endmodule