diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-01-23 16:10:22 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2020-01-28 09:35:36 -0800 |
commit | bafa9d95453387814ef25e6b6256ba8db2df612f (patch) | |
tree | 39ba24b5b67072d354775272e687796bb511848d /fpga/usrp3/lib/rfnoc/axi_rate_change.v | |
parent | 3075b981503002df3115d5f1d0b97d2619ba30f2 (diff) | |
download | uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.gz uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.bz2 uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.zip |
Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce
the size of the repository. However, over the last half-decade, the
split between the repositories has proven more burdensome than it has
been helpful. By merging the FPGA code back, it will be possible to
create atomic commits that touch both FPGA and UHD codebases. Continuous
integration testing is also simplified by merging the repositories,
because it was previously difficult to automatically derive the correct
UHD branch when testing a feature branch on the FPGA repository.
This commit also updates the license files and paths therein.
We are therefore merging the repositories again. Future development for
FPGA code will happen in the same repository as the UHD host code and
MPM code.
== Original Codebase and Rebasing ==
The original FPGA repository will be hosted for the foreseeable future
at its original local location: https://github.com/EttusResearch/fpga/
It can be used for bisecting, reference, and a more detailed history.
The final commit from said repository to be merged here is
05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as
v4.0.0.0-pre-uhd-merge.
If you have changes in the FPGA repository that you want to rebase onto
the UHD repository, simply run the following commands:
- Create a directory to store patches (this should be an empty
directory):
mkdir ~/patches
- Now make sure that your FPGA codebase is based on the same state as
the code that was merged:
cd src/fpga # Or wherever your FPGA code is stored
git rebase v4.0.0.0-pre-uhd-merge
Note: The rebase command may look slightly different depending on what
exactly you're trying to rebase.
- Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge:
git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches
Note: Make sure that only patches are stored in your output directory.
It should otherwise be empty. Make sure that you picked the correct
range of commits, and only commits you wanted to rebase were exported
as patch files.
- Go to the UHD repository and apply the patches:
cd src/uhd # Or wherever your UHD repository is stored
git am --directory fpga ~/patches/*
rm -rf ~/patches # This is for cleanup
== Contributors ==
The following people have contributed mainly to these files (this list
is not complete):
Co-authored-by: Alex Williams <alex.williams@ni.com>
Co-authored-by: Andrej Rode <andrej.rode@ettus.com>
Co-authored-by: Ashish Chaudhari <ashish@ettus.com>
Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Derek Kozel <derek.kozel@ettus.com>
Co-authored-by: EJ Kreinar <ej@he360.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Ian Buckley <ian.buckley@gmail.com>
Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Jon Kiser <jon.kiser@ni.com>
Co-authored-by: Josh Blum <josh@joshknows.com>
Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Matt Ettus <matt@ettus.com>
Co-authored-by: Michael West <michael.west@ettus.com>
Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com>
Co-authored-by: Nick Foster <nick@ettus.com>
Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Paul David <paul.david@ettus.com>
Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com>
Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com>
Co-authored-by: Sylvain Munaut <tnt@246tNt.com>
Co-authored-by: Trung Tran <trung.tran@ettus.com>
Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/axi_rate_change.v')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/axi_rate_change.v | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/axi_rate_change.v b/fpga/usrp3/lib/rfnoc/axi_rate_change.v new file mode 100644 index 000000000..166e03c46 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/axi_rate_change.v @@ -0,0 +1,491 @@ +// +// Copyright 2016 Ettus Research +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// - Implements rate change of N:M (a.k.a. M/N), handles headers automatically +// - Note: N should always be written before M in software to prevent false rate changes +// while the block is active +// - User code is responsible for generating correct number of outputs per input +// > Example: When set 1/N, after N input samples block should output 1 sample. If +// user code's pipelining requires additional samples to "push" the 1 +// sample out, it is the user's responsibility to make the mechanism +// (such as injecting extra samples) to do so. +// - Will always send an integer multiple of N samples to user logic. This ensures +// the user will not need to manually clear a "partial output sample" stuck in their +// pipeline due to an uneven (in respect to decimation rate) number of input samples. +// - Can optionally strobe clear_user after receiving packet with EOB +// > enable_clear_user must be enabled via CONFIG settings register +// > Warning: Input will be throttled until last packet has completely passed through +// user code to prevent clearing valid data. In certain conditions, this throttling +// can have a significant impact on throughput. +// - Output packet size will be identical to input packet size. The only exception is +// the final output packet, which may be shorter due to a partial input packet. +// Limitations: +// - Rate changes are ignored while active. Block must be cleared or packet with EOB +// (and enable_clear_user is set) will cause new rates to be loaded. +// - Can potentially use large amounts of block RAM when using large decimation rates +// (greater than 2K). This occurs due to the feature that the block always sends a multiple +// of N samples to the user. Implementing this feature requires N samples to be buffered. +// - User code with long pipelines may need to increase HEADER_FIFOSIZE. The debug signal +// warning_header_fifo_full is useful in determining this case. +// +// Settings Registers: +// sr_n: Number of input samples per M output samples (Always write N before M) +// sr_m: Number of output samples per N input samples +// sr_config: 0: Enable clear_user signal. + +module axi_rate_change #( + parameter WIDTH = 32, // Input bit width, must be a power of 2 and greater than or equal to 8. + parameter MAX_N = 2**16, + parameter MAX_M = 2**16, + parameter MAXIMIZE_OUTPUT_PKT_LEN = 1, + // Settings registers + parameter SR_N_ADDR = 0, + parameter SR_M_ADDR = 1, + parameter SR_CONFIG_ADDR = 2 +)( + input clk, input reset, input clear, + output clear_user, // Strobed after end of burst. Throttles input. Useful for resetting user code between bursts. + input [15:0] src_sid, input [15:0] dst_sid, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready, input [127:0] i_tuser, + output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready, output [127:0] o_tuser, + output [WIDTH-1:0] m_axis_data_tdata, output m_axis_data_tlast, output m_axis_data_tvalid, input m_axis_data_tready, + input [WIDTH-1:0] s_axis_data_tdata, input s_axis_data_tlast, input s_axis_data_tvalid, output s_axis_data_tready, + // Debugging signals: + // - Warnings indicate there may be an issue with user code. + // - Errors mean the user code has violated a rule. + // - Signals latch once set and block must be reset to clear. + output reg warning_long_throttle, // In the throttle state for a "long" time. + output reg error_extra_outputs, // User code generated extra outputs, i.e. received more than the expected M outputs. + output reg error_drop_pkt_lockup // Drop partial packet module is not accepting data even though user code is ready. +); + + reg [$clog2(MAX_N+1)-1:0] n = 1; + reg [$clog2(MAX_M+1)-1:0] m = 1; + + wire [WIDTH-1:0] i_reg_tdata; + wire i_reg_tvalid, i_reg_tready, i_reg_tlast; + wire i_reg_tvalid_int, i_reg_tready_int, i_reg_tlast_int; + + reg throttle = 1'b1, first_header, partial_first_word; + reg [15:0] word_cnt_div_n; + reg [$clog2(MAX_N+1)-1:0] word_cnt_div_n_frac = 1; + reg [$clog2(MAX_N+1)-1:0] in_pkt_cnt = 1; + + reg send_done; + reg rate_changed; + + /******************************************************** + ** Settings Registers + ********************************************************/ + wire [$clog2(MAX_N+1)-1:0] sr_n; + wire n_changed; + setting_reg #(.my_addr(SR_N_ADDR), .width($clog2(MAX_N+1)), .at_reset(1)) set_n ( + .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data), + .out(sr_n), .changed(n_changed)); + + wire [$clog2(MAX_M+1)-1:0] sr_m; + wire m_changed; + setting_reg #(.my_addr(SR_M_ADDR), .width($clog2(MAX_M+1)), .at_reset(1)) set_m ( + .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data), + .out(sr_m), .changed(m_changed)); + + wire sr_config; + wire enable_clear_user; // Enable strobing clear_user between bursts. + setting_reg #(.my_addr(SR_CONFIG_ADDR), .width(1), .at_reset(1'b1)) set_config ( + .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data), + .out(sr_config), .changed()); + assign enable_clear_user = sr_config; + + /******************************************************** + ** Header, word count FIFOs + ** - Header provides VITA Time and payload length for + ** output packets + ** - Word count provides a normalized count for the + ** output state machine to know when it has consumed + ** the final input sample in a burst. + ********************************************************/ + // Decode input header + wire [127:0] i_reg_tuser; + wire has_time_in, eob_in, eob_in_header; + wire [15:0] payload_length_in; + reg [15:0] payload_length_out; + wire [63:0] vita_time_in; + cvita_hdr_decoder cvita_hdr_decoder_in_header ( + .header(i_reg_tuser), .pkt_type(), .eob(eob_in_header), + .has_time(has_time_in), .seqnum(), .length(), .payload_length(payload_length_in), + .src_sid(), .dst_sid(), .vita_time(vita_time_in)); + + assign eob_in = eob_in_header | rate_changed; + + reg [15:0] word_cnt_div_n_tdata; + wire [15:0] word_cnt_div_n_fifo_tdata; + reg word_cnt_div_n_tvalid; + wire word_cnt_div_n_tready, word_cnt_div_n_fifo_tvalid, word_cnt_div_n_fifo_tready; + axi_fifo #(.WIDTH(16), .SIZE(0)) axi_fifo_word_cnt ( + .clk(clk), .reset(reset), .clear(clear), + .i_tdata(word_cnt_div_n_tdata), .i_tvalid(word_cnt_div_n_tvalid), .i_tready(word_cnt_div_n_tready), + .o_tdata(word_cnt_div_n_fifo_tdata), .o_tvalid(word_cnt_div_n_fifo_tvalid), .o_tready(word_cnt_div_n_fifo_tready), + .space(), .occupied()); + + /******************************************************** + ** Register input stream + ** - Upsteam will be throttled when clearing user logic + ********************************************************/ + // Input register with header + axi_fifo_flop #(.WIDTH(WIDTH+1+128)) axi_fifo_flop_input ( + .clk(clk), .reset(reset), .clear(clear), + .i_tdata({i_tlast,i_tdata,i_tuser}), .i_tvalid(i_tvalid), .i_tready(i_tready), + .o_tdata({i_reg_tlast,i_reg_tdata,i_reg_tuser}), .o_tvalid(i_reg_tvalid_int), .o_tready(i_reg_tready), + .space(), .occupied()); + + assign i_reg_tready = i_reg_tready_int & word_cnt_div_n_tready & ~throttle; + assign i_reg_tvalid = i_reg_tvalid_int & word_cnt_div_n_tready & ~throttle; + // Assert AXI Drop Partial Packet's i_tlast every N samples, which is used to detect and drop + // partial output samples. + assign i_reg_tlast_int = (word_cnt_div_n_frac == n) | (eob_in & i_reg_tlast); + + /******************************************************** + ** Input state machine + ********************************************************/ + reg [1:0] input_state; + localparam RECV_INIT = 0; + localparam RECV = 1; + localparam RECV_WAIT_FOR_SEND_DONE = 2; + + always @(posedge clk) begin + if (reset | clear) begin + n <= 1; + m <= 1; + rate_changed <= 1'b0; + first_header <= 1'b1; + partial_first_word <= 1'b1; + payload_length_out <= 'd0; + word_cnt_div_n <= 0; + word_cnt_div_n_frac <= 1; + throttle <= 1'b1; + word_cnt_div_n_tvalid <= 1'b0; + word_cnt_div_n_tdata <= 'd0; + input_state <= RECV_INIT; + end else begin + if (word_cnt_div_n_tvalid & word_cnt_div_n_tready) begin + word_cnt_div_n_tvalid <= 1'b0; + end + // Input state machine + case (input_state) + RECV_INIT : begin + n <= sr_n; + m <= sr_m; + rate_changed <= 1'b0; + first_header <= 1'b1; + partial_first_word <= 1'b1; + payload_length_out <= 'd0; + word_cnt_div_n <= 0; + word_cnt_div_n_frac <= 1; + if (i_reg_tvalid_int & word_cnt_div_n_tready) begin + throttle <= 1'b0; + input_state <= RECV; + end + end + // Logic used by the RECV state to track several variables: + // word_cnt_div_n: Number of words received divided by n. + // Needed for tracking final sample in a burst. + // word_cnt_div_n_frac: Used to increment word_cnt_div_n. Can be + // thought of as the fractional part of + // word_cnt_div_n. + // in_pkt_cnt: Similar to in_word_cnt, but for packets. Used + // to determine when a group of N packets has been + // received to store the next header. + // first_header: We only use the header from the first packet in + // a group of N packets (this greatly reduces + // the header FIFO size). + RECV : begin + // If rate changed, force a EOB. + if (m_changed) begin + rate_changed <= 1'b1; + end + if (i_reg_tvalid & i_reg_tready) begin + // Track the number of words sent to the user divided by N. + // At the end of a burst, this value is forwarded to the output + // state machine and used to determine when the final sample has + // arrived from the user code. + if (word_cnt_div_n_frac == n) begin + word_cnt_div_n <= word_cnt_div_n + 1; + word_cnt_div_n_frac <= 1; + end else begin + word_cnt_div_n_frac <= word_cnt_div_n_frac + 1; + end + // Use payload length from first packet + first_header <= 1'b0; + if (first_header) begin + payload_length_out <= payload_length_in; + end else if (MAXIMIZE_OUTPUT_PKT_LEN) begin + if (payload_length_out < payload_length_in) begin + payload_length_out <= payload_length_in; + end + end + // Track when at least N input samples have been received in this burst + if (partial_first_word & (word_cnt_div_n_frac == n)) begin + partial_first_word <= 1'b0; + end + // Burst ended before we received enough samples to form + // at least one full output sample. + // Note: axi_drop_partial_packet automatically handles + // dropping the partial sample. + if (i_reg_tlast & eob_in & partial_first_word) begin + input_state <= RECV_INIT; + end else begin + if (i_reg_tlast) begin + // At the end of a burst, forward the number of words divided by N to + // the output state machine via a FIFO. This allows the output state + // machine to know when it has received the final output word. + // We use a FIFO in case the bursts are very small and we + // need to store several of these values. + if (eob_in) begin + word_cnt_div_n_tdata <= word_cnt_div_n + (word_cnt_div_n_frac == n); + word_cnt_div_n_tvalid <= 1'b1; + throttle <= 1'b1; + if (enable_clear_user) begin + input_state <= RECV_WAIT_FOR_SEND_DONE; + end else begin + input_state <= RECV_INIT; + end + end + end + end + end + end + // Wait until last sample has been output and user logic is cleared + // WARNING: This can be a huge bubble state! However, since it only happens with + // EOBs, it should be infrequent. + RECV_WAIT_FOR_SEND_DONE : begin + if (send_done) begin + input_state <= RECV_INIT; + end + end + default : begin + input_state <= RECV_INIT; + end + endcase + end + end + + assign clear_user = send_done & enable_clear_user; + + /******************************************************** + ** AXI Drop Partial Packet (to user) + ** - Enforces sending integer multiple of N samples + ** to user + ********************************************************/ + axi_drop_partial_packet #( + .WIDTH(WIDTH+1), + .HOLD_LAST_WORD(1), + .MAX_PKT_SIZE(MAX_N), + .SR_PKT_SIZE_ADDR(SR_N_ADDR)) + axi_drop_partial_packet ( + .clk(clk), .reset(reset), .clear(clear | send_done), + .flush(word_cnt_div_n_tvalid & word_cnt_div_n_tready), // Flush on EOB + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .i_tdata({i_reg_tlast,i_reg_tdata}), .i_tvalid(i_reg_tvalid), .i_tlast(i_reg_tlast_int), .i_tready(i_reg_tready_int), + .o_tdata({m_axis_data_tlast,m_axis_data_tdata}), .o_tvalid(m_axis_data_tvalid), .o_tlast(/* Unused */), .o_tready(m_axis_data_tready)); + + /******************************************************** + ** Output state machine + ********************************************************/ + reg [1:0] output_state; + localparam SEND_INIT = 0; + localparam SEND = 1; + + wire [WIDTH-1:0] o_reg_tdata; + wire [127:0] o_reg_tuser; + wire o_reg_tvalid, o_reg_tready, o_reg_tlast, o_reg_tlast_int; + + reg [15:0] out_payload_cnt = (WIDTH/8); + reg [15:0] word_cnt_div_m; + reg [$clog2(MAX_M+1)-1:0] word_cnt_div_m_frac = 1; + reg [$clog2(MAX_M+1)-1:0] out_pkt_cnt = 1; + + // End of burst tracking. Compare the number of words sent to the user divided by N + // to the number of words received from the user divided by M. When they equal each other + // then we have received the last word from the user in this burst. + // Note: Using word_cnt_div_n_fifo_tdata to make sure the last word is identified before + // it has been consumed. + wire last_word_in_burst = word_cnt_div_n_fifo_tvalid & + (word_cnt_div_m == word_cnt_div_n_fifo_tdata) & + (word_cnt_div_m_frac == m); + + always @(posedge clk) begin + if (reset | clear) begin + word_cnt_div_m <= 1; + word_cnt_div_m_frac <= 1; + out_payload_cnt <= (WIDTH/8); + send_done <= 1'b0; + output_state <= SEND_INIT; + end else begin + // Track + case (output_state) + SEND_INIT : begin + word_cnt_div_m <= 1; + word_cnt_div_m_frac <= 1; + out_payload_cnt <= (WIDTH/8); + send_done <= 1'b0; + output_state <= SEND; + end + SEND : begin + if (o_reg_tvalid & o_reg_tready) begin + if (o_reg_tlast) begin + // Track number of samples from user to set tlast + out_payload_cnt <= (WIDTH/8); + end else begin + out_payload_cnt <= out_payload_cnt + (WIDTH/8); + end + // Track number of words consumed divided by M. This is used + // in conjunction with word_cnt_div_n to determine when we have received + // the last word in a burst from the user. + if (word_cnt_div_m_frac == m) begin + word_cnt_div_m <= word_cnt_div_m + 1; + word_cnt_div_m_frac <= 1; + end else begin + word_cnt_div_m_frac <= word_cnt_div_m_frac + 1; + end + if (last_word_in_burst) begin + send_done <= 1'b1; + output_state <= SEND_INIT; + end + end + end + default : begin + output_state <= SEND_INIT; + end + endcase + end + end + + // Only pop this FIFO at EOB. + assign word_cnt_div_n_fifo_tready = o_reg_tvalid & o_reg_tready & last_word_in_burst; + + /******************************************************** + ** Adjust VITA time + ********************************************************/ + localparam VT_INIT = 0; + localparam VT_INCREMENT = 1; + reg vt_state; + + reg has_time_out, has_time_clear; + reg [63:0] vita_time_out, vita_time_accum; + + always @(posedge clk) begin + if (reset | clear) begin + vt_state <= VT_INIT; + end else begin + case (vt_state) + VT_INIT : begin + has_time_clear <= 1'b0; + if (i_reg_tvalid & i_reg_tready & first_header) begin + vita_time_out <= vita_time_in; + vita_time_accum <= vita_time_in; + has_time_out <= has_time_in; + vt_state <= VT_INCREMENT; + end + end + VT_INCREMENT : begin + // Stop sending vita time if user does not send vita time + if (i_reg_tvalid & ~has_time_in) begin + has_time_clear <= 1'b1; + end + if (o_reg_tvalid & o_reg_tready) begin + if (o_reg_tlast) begin + if (has_time_clear) begin + has_time_out <= 1'b0; + end + vita_time_out <= vita_time_accum + n; + end + vita_time_accum <= vita_time_accum + n; + if (last_word_in_burst) begin + vt_state <= VT_INIT; + end + end + end + default : begin + vt_state <= VT_INIT; + end + endcase + end + end + + // Create output header + cvita_hdr_encoder cvita_hdr_encoder ( + .pkt_type(2'd0), .eob(last_word_in_burst), .has_time(has_time_out), + .seqnum(12'd0), .payload_length(16'd0), // Not needed, handled by AXI Wrapper + .src_sid(src_sid), .dst_sid(dst_sid), + .vita_time(vita_time_out), + .header(o_reg_tuser)); + + /******************************************************** + ** Register input stream from user and output stream + ********************************************************/ + assign o_reg_tlast = o_reg_tlast_int | + // End of packet + (out_payload_cnt == payload_length_out) | + // EOB, could be a partial packet + last_word_in_burst; + + axi_fifo_flop #(.WIDTH(WIDTH+1)) axi_fifo_flop_from_user_0 ( + .clk(clk), .reset(reset), .clear(clear), + // FIXME: If user asserts tlast at the wrong time, it likely causes a deadlock. For now ignore tlast. + //.i_tdata({s_axis_data_tlast,s_axis_data_tdata}), .i_tvalid(s_axis_data_tvalid), .i_tready(s_axis_data_tready), + .i_tdata({1'b0,s_axis_data_tdata}), .i_tvalid(s_axis_data_tvalid), .i_tready(s_axis_data_tready), + .o_tdata({o_reg_tlast_int,o_reg_tdata}), .o_tvalid(o_reg_tvalid), .o_tready(o_reg_tready), + .space(), .occupied()); + + // Output register with header + axi_fifo_flop #(.WIDTH(WIDTH+1+128)) axi_fifo_flop_output ( + .clk(clk), .reset(reset), .clear(clear), + .i_tdata({o_reg_tlast,o_reg_tdata,o_reg_tuser}), .i_tvalid(o_reg_tvalid), .i_tready(o_reg_tready), + .o_tdata({o_tlast,o_tdata,o_tuser}), .o_tvalid(o_tvalid), .o_tready(o_tready), + .space(), .occupied()); + + /******************************************************** + ** Error / warning signals + ********************************************************/ + reg [23:0] counter_header_fifo_full, counter_throttle, counter_drop_pkt_lockup; + reg [2:0] counter_header_fifo_empty; + always @(posedge clk) begin + if (reset) begin + warning_long_throttle <= 1'b0; + error_extra_outputs <= 1'b0; + error_drop_pkt_lockup <= 1'b0; + counter_throttle <= 0; + counter_header_fifo_full <= 0; + counter_drop_pkt_lockup <= 0; + counter_header_fifo_empty <= 0; + end else begin + // In throttle state for a "long" time + if (throttle) begin + counter_throttle <= counter_throttle + 1; + if (counter_throttle == 2**24-1) begin + warning_long_throttle <= 1'b1; + end + end else begin + counter_throttle <= 0; + end + // More than M outputs per N inputs + if (word_cnt_div_n_fifo_tvalid & (word_cnt_div_m > word_cnt_div_n_fifo_tdata)) begin + error_extra_outputs <= 1'b1; + end + // Bad internal state. AXI drop partial packet is in a lockup condition. + if (~i_reg_tready_int & m_axis_data_tready) begin + counter_drop_pkt_lockup <= counter_drop_pkt_lockup + 1; + if (counter_drop_pkt_lockup == 2**24-1) begin + error_drop_pkt_lockup <= 1'b1; + end + end else begin + counter_drop_pkt_lockup <= 0; + end + end + end + +endmodule |