1//
2// Copyright 2018-2019 Ettus Research, A National Instruments Company
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5//
6// Module: context_handler_sync
7// Description:
8//
9// Parameters:
10//   - CHDR_W: Width of the input CHDR bus in bits
11//
12// Signals:
13//
14
15module context_handler_sync #(
16  parameter CHDR_W = 256,
17  parameter ITEM_W = 32,
18  parameter NIPC   = 2
19)(
20  // Clock and reset
21  input  wire              clk,
22  input  wire              rst,
23  // Context stream in (AXI-Stream)
24  input  wire [CHDR_W-1:0] s_axis_context_tdata,
25  input  wire [3:0]        s_axis_context_tuser,
26  input  wire              s_axis_context_tlast,
27  input  wire              s_axis_context_tvalid,
28  output wire              s_axis_context_tready,
29  // Context stream out (AXI-Stream)
30  output wire [CHDR_W-1:0] m_axis_context_tdata,
31  output wire [3:0]        m_axis_context_tuser,
32  output wire              m_axis_context_tlast,
33  output wire              m_axis_context_tvalid,
34  input  wire              m_axis_context_tready,
35  // Input payload stream monitor
36  input  wire [NIPC-1:0]   in_payload_tkeep,
37  input  wire              in_payload_tlast,
38  input  wire              in_payload_tvalid,
39  input  wire              in_payload_tready,
40  // Output payload stream monitor
41  input  wire [NIPC-1:0]   out_payload_tkeep,
42  input  wire              out_payload_tlast,
43  input  wire              out_payload_tvalid,
44  input  wire              out_payload_tready,
45  // Status
46  output reg               length_err_stb,
47  output reg               seq_err_stb
48);
49
50  `include "../core/rfnoc_chdr_utils.vh"
51
52  // Thermometer to binary decoder
53  // 4'b0000 => 3'd0
54  // 4'b0001 => 3'd1
55  // 4'b0011 => 3'd2
56  // 4'b0111 => 3'd3
57  // 4'b1111 => 3'd4
58  function [$clog2(NIPC):0] thermo2bin(input [NIPC-1:0] thermo);
59    reg [NIPC:0] onehot;
60    integer i;
61  begin
62    onehot = thermo + 1;
63    thermo2bin = 0;
64    for (i = 0; i <= NIPC; i=i+1)
65      if (onehot[i])
66        thermo2bin = thermo2bin | i;
67  end
68  endfunction
69
70  axi_fifo #(.WIDTH(CHDR_W+4+1), .SIZE(1)) ctxt_pipe_i (
71    .clk(clk), .reset(rst), .clear(1'b0),
72    .i_tdata({s_axis_context_tlast, s_axis_context_tuser, s_axis_context_tdata}),
73    .i_tvalid(s_axis_context_tvalid), .i_tready(s_axis_context_tready),
74    .o_tdata({m_axis_context_tlast, m_axis_context_tuser, m_axis_context_tdata}),
75    .o_tvalid(m_axis_context_tvalid), .o_tready(m_axis_context_tready),
76    .space(), .occupied()
77  );
78
79  wire is_ctxt_hdr = s_axis_context_tvalid && s_axis_context_tready &&
80                     (s_axis_context_tuser == CONTEXT_FIELD_HDR ||
81                      s_axis_context_tuser == CONTEXT_FIELD_HDR_TS);
82
83  reg [15:0] exp_pkt_len = 16'd0;
84  reg [15:0] exp_seq_num = 16'd0;
85  reg        check_seq_num = 1'b0;
86  always @(posedge clk) begin
87    if (rst) begin
88      exp_pkt_len <= 16'd0;
89      check_seq_num <= 1'b0;
90    end else if (is_ctxt_hdr) begin
91      check_seq_num <= 1'b1;
92      exp_pkt_len <= chdr_get_length(s_axis_context_tdata[63:0]);
93      exp_seq_num <= chdr_get_seq_num(s_axis_context_tdata[63:0]) + 16'd1;
94    end
95    seq_err_stb <= is_ctxt_hdr && check_seq_num &&
96                   (exp_seq_num != chdr_get_seq_num(s_axis_context_tdata[63:0]));
97  end
98
99  reg [15:0] pyld_pkt_len = 16'd0;
100  always @(posedge clk) begin
101    if (rst) begin
102      pyld_pkt_len <= 16'd0;
103    end else if (in_payload_tvalid && in_payload_tready) begin
104      pyld_pkt_len <= in_payload_tlast ? 16'd0 : (pyld_pkt_len + ((ITEM_W*NIPC)/8));
105    end
106    length_err_stb <= in_payload_tvalid && in_payload_tready && in_payload_tlast &&
107                      (pyld_pkt_len + (thermo2bin(in_payload_tkeep)*(ITEM_W/8)) != exp_pkt_len);
108  end
109
110endmodule // context_handler_sync
111