aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/periodic_framer.v
blob: 3e83bcf8d6e81b334238dddad6ab4e84e7f34275 (plain)
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
//
// Copyright 2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//

module periodic_framer #(
  parameter SR_FRAME_LEN            = 0,
  parameter SR_GAP_LEN              = 1,
  parameter SR_OFFSET               = 2,
  parameter SR_NUMBER_SYMBOLS_MAX   = 3,
  parameter SR_NUMBER_SYMBOLS_SHORT = 4,
  // Skip a set number of gaps at the beginning. Use 1 to properly frame 802.11 long preamble.
  parameter SKIP_GAPS               = 1,
  parameter WIDTH                   = 32)
(
  input clk, input reset, input clear,
  input set_stb, input [7:0] set_addr, input [31:0] set_data,
  input [WIDTH-1:0] stream_i_tdata, input stream_i_tlast, input stream_i_tvalid, output stream_i_tready,
  output [WIDTH-1:0] stream_o_tdata, output stream_o_tlast, output stream_o_tvalid, input stream_o_tready,
  output reg sof, output reg eof);

  wire [15:0] frame_len;
  wire [15:0] gap_len;
  wire [15:0] offset;

  wire [15:0] numsymbols_max, numsymbols_thisburst, numsymbols_short;
  wire [15:0] burst_len;
  wire        set_numsymbols;
  wire        consume;
  reg  [15:0] counter;
  reg  [$clog2(SKIP_GAPS):0] skip_cnt;
  reg  [15:0] numsymbols;

  setting_reg #(.my_addr(SR_FRAME_LEN), .width(16)) reg_frame_len (
    .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data),
    .out(frame_len), .changed());

  setting_reg #(.my_addr(SR_GAP_LEN), .width(16)) reg_gap_len (
    .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data),
    .out(gap_len), .changed());

  setting_reg #(.my_addr(SR_OFFSET), .width(16)) reg_offset (
    .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data),
    .out(offset), .changed());

  setting_reg #(.my_addr(SR_NUMBER_SYMBOLS_MAX), .width(16)) reg_max_symbols (
    .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data),
    .out(numsymbols_max), .changed());

  setting_reg #(.my_addr(SR_NUMBER_SYMBOLS_SHORT), .width(16)) reg_symbols_short (
    .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data),
    .out(numsymbols_short), .changed(set_numsymbols));

  reg [1:0]  state;
  localparam ST_WAIT_FOR_TRIG = 2'd0;
  localparam ST_DO_OFFSET     = 2'd1;
  localparam ST_FRAME         = 2'd2;
  localparam ST_GAP           = 2'd3;

  reg shorten_burst;
  always @(posedge clk) begin
    if (reset | clear) begin
      shorten_burst <= 1'b0;
    end else if (set_numsymbols) begin
      shorten_burst <= 1'b1;
    end else if(state == ST_WAIT_FOR_TRIG) begin
      shorten_burst <= 1'b0;
    end
  end

  assign numsymbols_thisburst = shorten_burst ? numsymbols_short : numsymbols_max;

  always @(posedge clk) begin
    if (reset | clear) begin
      eof        <= 1'b0;
      sof        <= 1'b0;
      counter    <= 1;
      skip_cnt   <= 0;
      numsymbols <= 16'd1;
      state      <= ST_WAIT_FOR_TRIG;
    end else begin
      if (consume) begin
        case(state)
          ST_WAIT_FOR_TRIG : begin
            eof       <= 1'b0;
            skip_cnt  <= 0;
            if (stream_i_tlast) begin
              counter <= 16'b1;
              if (offset == 0) begin
                state   <= ST_FRAME;
              end else begin
                state   <= ST_DO_OFFSET;
              end
            end
          end

          ST_DO_OFFSET : begin
            if (counter >= offset) begin
              sof        <= 1'b1;
              counter    <= 16'b1;
              numsymbols <= 16'd1;
              state      <= ST_FRAME;
            end else begin
              counter <= counter + 16'd1;
            end
          end

          ST_FRAME : begin
            if (counter >= frame_len) begin
              sof        <= 1'b0;
              counter    <= 1;
              numsymbols <= numsymbols + 1;
              if (numsymbols >= numsymbols_thisburst) begin
                eof      <= 1'b1;
                state    <= ST_WAIT_FOR_TRIG;
              end else begin
                if (skip_cnt < SKIP_GAPS) begin
                  skip_cnt <= skip_cnt + 1;
                  state    <= ST_FRAME;
                end else begin
                  state  <= ST_GAP;
                end
              end
            end else begin
              counter <= counter + 16'd1;
            end
          end

          ST_GAP : begin
            if (counter >= gap_len) begin
              state   <= ST_FRAME;
              counter <= 1;
            end else begin
              counter <= counter + 16'd1;
            end
          end
        endcase
      end
    end
  end

  assign stream_o_tdata = stream_i_tdata;
  assign stream_o_tlast = (state == ST_FRAME) & (counter >= frame_len);
  assign stream_o_tvalid = stream_i_tvalid & (state == ST_FRAME);

  assign stream_i_tready = consume;
  assign consume = stream_i_tvalid & ((state != ST_FRAME) | stream_o_tready);

endmodule // periodic_framer