+18









Martin Braun
Alex Williams
Andrej Rode
Ashish Chaudhari
Ben Hilburn
Ciro Nishiguchi
Daniel Jepson
Derek Kozel
EJ Kreinar
Humberto Jimenez
Ian Buckley
Jörg Hofrichter
Jon Kiser
Josh Blum
Jonathon Pendlum
Matt Ettus
Michael West
Moritz Fischer
Nick Foster
Nicolas Cuervo
Paul Butler
Paul David
Ryan Marlow
Sugandha Gupta
Sylvain Munaut
Trung Tran
Vidush Vishwanath
Wade Fife
6b67702ad7
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> Original-commit: bafa9d95453387814ef25e6b6256ba8db2df612f
558 lines
20 KiB
Verilog
558 lines
20 KiB
Verilog
//
|
|
// Copyright 2018-2019 Ettus Research, A National Instruments Company
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: chdr_stream_output
|
|
// Description:
|
|
// Implements the CHDR output port for a stream endpoint.
|
|
// The module generates stream command packets to setup
|
|
// a downstream endpoint module (chdr_stream_input). Once
|
|
// a stream is setup, the CHDR data on the axis_data port
|
|
// can be sent downstream with full flow control. Stream
|
|
// status messages are recieved from the downstream node
|
|
// to update flow control state. This module has an external
|
|
// configuration bus to initiate stream creation.
|
|
//
|
|
// Parameters:
|
|
// - CHDR_W: Width of the CHDR bus in bits
|
|
// - MTU: Log2 of the maximum number of lines in a packet
|
|
//
|
|
// Signals:
|
|
// - m_axis_chdr_* : Output CHDR stream (AXI-Stream)
|
|
// - s_axis_data_* : Input CHDR Data stream (AXI-Stream) before flow control
|
|
// - s_axis_strs_* : Input stream status (AXI-Stream)
|
|
|
|
module chdr_stream_output #(
|
|
parameter CHDR_W = 256,
|
|
parameter MTU = 10
|
|
)(
|
|
// Clock, reset and settings
|
|
input wire clk,
|
|
input wire rst,
|
|
// CHDR out (AXI-Stream)
|
|
output wire [CHDR_W-1:0] m_axis_chdr_tdata,
|
|
output wire m_axis_chdr_tlast,
|
|
output wire m_axis_chdr_tvalid,
|
|
input wire m_axis_chdr_tready,
|
|
// Data packets in (AXI-Stream)
|
|
input wire [CHDR_W-1:0] s_axis_data_tdata,
|
|
input wire s_axis_data_tlast,
|
|
input wire s_axis_data_tvalid,
|
|
output wire s_axis_data_tready,
|
|
// Stream status in (AXI-Stream)
|
|
input wire [CHDR_W-1:0] s_axis_strs_tdata,
|
|
input wire s_axis_strs_tlast,
|
|
input wire s_axis_strs_tvalid,
|
|
output wire s_axis_strs_tready,
|
|
// Configuration port
|
|
input wire cfg_start,
|
|
output reg cfg_pending = 1'b0,
|
|
output reg cfg_failed = 1'b0,
|
|
input wire cfg_lossy_xport,
|
|
input wire [15:0] cfg_dst_epid,
|
|
input wire [15:0] cfg_this_epid,
|
|
input wire [39:0] cfg_fc_freq_bytes,
|
|
input wire [23:0] cfg_fc_freq_pkts,
|
|
input wire [15:0] cfg_fc_headroom_bytes,
|
|
input wire [7:0] cfg_fc_headroom_pkts,
|
|
// Flow control status
|
|
output reg fc_enabled = 1'b0,
|
|
output reg [39:0] capacity_bytes = 40'd0,
|
|
output reg [23:0] capacity_pkts = 24'd0,
|
|
// Stream status
|
|
output wire seq_err_stb,
|
|
output reg [31:0] seq_err_cnt = 32'd0,
|
|
output wire data_err_stb,
|
|
output reg [31:0] data_err_cnt = 32'd0,
|
|
output wire route_err_stb,
|
|
output reg [31:0] route_err_cnt = 32'd0
|
|
);
|
|
|
|
// ---------------------------------------------------
|
|
// RFNoC Includes
|
|
// ---------------------------------------------------
|
|
`include "rfnoc_chdr_utils.vh"
|
|
`include "rfnoc_chdr_internal_utils.vh"
|
|
|
|
localparam CHDR_W_LOG2 = $clog2(CHDR_W);
|
|
|
|
// ---------------------------------------------------
|
|
// Output packet gate
|
|
// ---------------------------------------------------
|
|
reg [CHDR_W-1:0] chdr_out_tdata;
|
|
reg chdr_out_tlast, chdr_out_tvalid;
|
|
wire chdr_out_tready;
|
|
|
|
axi_packet_gate #(
|
|
.WIDTH(CHDR_W), .SIZE(MTU), .USE_AS_BUFF(0)
|
|
) chdr_pkt_gate_i (
|
|
.clk(clk), .reset(rst), .clear(1'b0),
|
|
.i_tdata(chdr_out_tdata), .i_tlast(chdr_out_tlast), .i_terror(1'b0),
|
|
.i_tvalid(chdr_out_tvalid), .i_tready(chdr_out_tready),
|
|
.o_tdata(m_axis_chdr_tdata), .o_tlast(m_axis_chdr_tlast),
|
|
.o_tvalid(m_axis_chdr_tvalid), .o_tready(m_axis_chdr_tready)
|
|
);
|
|
|
|
// ---------------------------------------------------
|
|
// Flow Control State
|
|
// ---------------------------------------------------
|
|
|
|
// send_cnt: Total transfer count at the sender (here)
|
|
// recv_cnt: Total transfer count at the receiver
|
|
// accum: Transfer count since last FC resynchronization request
|
|
// headroom: Total headroom to keep in the downstream buffer
|
|
// adj_cap: The adjusted capacity (after headroom) of the downstream buffer
|
|
// strc_cnt: Saved count for the STRC packet (prevents mid-packet updates)
|
|
reg [63:0] send_cnt_bytes = 64'd0;
|
|
reg [39:0] send_cnt_pkts = 40'd0;
|
|
reg [63:0] recv_cnt_bytes = 64'd0;
|
|
reg [39:0] recv_cnt_pkts = 40'd0;
|
|
reg [39:0] accum_bytes = 40'd0;
|
|
reg [23:0] accum_pkts = 24'd0;
|
|
reg [15:0] headroom_bytes = 16'd0;
|
|
reg [ 7:0] headroom_pkts = 8'd0;
|
|
reg [39:0] adj_cap_bytes = 40'd0;
|
|
reg [23:0] adj_cap_pkts = 24'd0;
|
|
reg [63:0] strc_cnt_bytes = 64'd0;
|
|
|
|
// Output transfer count
|
|
always @(posedge clk) begin
|
|
if (rst || !fc_enabled) begin
|
|
send_cnt_bytes <= 64'd0;
|
|
send_cnt_pkts <= 40'd0;
|
|
end else if (chdr_out_tvalid && chdr_out_tready) begin
|
|
send_cnt_bytes <= send_cnt_bytes + (CHDR_W/8);
|
|
if (chdr_out_tlast)
|
|
send_cnt_pkts <= send_cnt_pkts + 40'd1;
|
|
end
|
|
end
|
|
|
|
// Buffer occupied counts
|
|
// TODO: Need better overflow handling
|
|
wire signed [64:0] occupied_bytes =
|
|
$signed({1'b0, send_cnt_bytes}) - $signed({1'b0, recv_cnt_bytes});
|
|
wire signed [40:0] occupied_pkts =
|
|
$signed({1'b0, send_cnt_pkts}) - $signed({1'b0, recv_cnt_pkts});
|
|
|
|
// OK-to-Send shift register
|
|
// - Why a shift-register here?
|
|
// To allow the tools to re-time the wide comparators.
|
|
// - We don't care about the latency here because stream
|
|
// status messages are asynchronous wrt the data
|
|
reg [3:0] ok_shreg = 4'b1111; // OK to send? (shift register)
|
|
always @(posedge clk) begin
|
|
if (rst || !fc_enabled) begin
|
|
ok_shreg <= 4'b1111;
|
|
end else begin
|
|
ok_shreg <= {ok_shreg[2:0], (
|
|
(occupied_bytes[40:0] < $signed({1'b0, adj_cap_bytes})) &&
|
|
(occupied_pkts [24:0] < $signed({1'b0, adj_cap_pkts }))
|
|
)};
|
|
end
|
|
end
|
|
wire ok_to_send = ok_shreg[3];
|
|
|
|
// Accumulated transfer count updater for FC resync
|
|
reg lossy_xport = 1'b0;
|
|
reg [3:0] fc_resync_req_shreg = 4'h0;
|
|
wire fc_resync_req, fc_resync_ack;
|
|
|
|
always @(posedge clk) begin
|
|
if (rst || !fc_enabled || !lossy_xport || fc_resync_ack) begin
|
|
// Reset
|
|
accum_bytes <= 40'd0;
|
|
accum_pkts <= 24'd0;
|
|
fc_resync_req_shreg <= 4'b0000;
|
|
end else begin
|
|
if (chdr_out_tvalid && chdr_out_tready) begin
|
|
// Count
|
|
accum_bytes <= accum_bytes + (CHDR_W/8);
|
|
if (chdr_out_tlast)
|
|
accum_pkts <= accum_pkts + 24'd1;
|
|
end
|
|
// FC resync request
|
|
fc_resync_req_shreg <= {fc_resync_req_shreg[2:0],
|
|
(accum_bytes > capacity_bytes) || (accum_pkts > capacity_pkts)};
|
|
end
|
|
end
|
|
assign fc_resync_req = fc_resync_req_shreg[3];
|
|
|
|
// ---------------------------------------------------
|
|
// Stream Status Parser
|
|
// ---------------------------------------------------
|
|
|
|
wire [3:0] msg_i_tdata, msg_o_tdata;
|
|
wire msg_i_tvalid, msg_o_tvalid;
|
|
wire msg_i_tready, msg_o_tready;
|
|
|
|
axi_fifo #(.WIDTH(4), .SIZE(1)) msg_fifo_i (
|
|
.clk(clk), .reset(rst), .clear(1'b0),
|
|
.i_tdata(msg_i_tdata), .i_tvalid(msg_i_tvalid), .i_tready(msg_i_tready),
|
|
.o_tdata(msg_o_tdata), .o_tvalid(msg_o_tvalid), .o_tready(msg_o_tready),
|
|
.space(), .occupied()
|
|
);
|
|
|
|
localparam [2:0] ST_STRS_HDR = 3'd0; // Receiving the CHDR header of a stream status msg
|
|
localparam [2:0] ST_STRS_W0 = 3'd1; // Receiving the first word of a stream status msg
|
|
localparam [2:0] ST_STRS_W1 = 3'd2; // Receiving the second word of a stream status msg
|
|
localparam [2:0] ST_STRS_W2 = 3'd3; // Receiving the third word of a stream status msg
|
|
localparam [2:0] ST_STRS_W3 = 3'd4; // Receiving the fourth word of a stream status msg
|
|
localparam [2:0] ST_STRS_LATCH = 3'd5; // Atomically updating and posting the status msg
|
|
localparam [2:0] ST_STRS_DROP = 3'd6; // Something went wrong dropping current packet
|
|
|
|
reg [2:0] strs_state = ST_STRS_HDR;
|
|
reg strs_too_long = 1'b0;
|
|
reg [15:0] cached_dst_epid = 16'd0;
|
|
reg [255:0] cached_strs_msg;
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
strs_state <= ST_STRS_HDR;
|
|
strs_too_long <= 1'b0;
|
|
end else begin
|
|
case (strs_state)
|
|
|
|
// ST_STRS_HDR
|
|
// ------------------
|
|
ST_STRS_HDR: begin
|
|
if (s_axis_strs_tvalid) begin
|
|
// Only accept stream status packets. Drop everything else
|
|
if (chdr_get_pkt_type(s_axis_strs_tdata[63:0]) == CHDR_PKT_TYPE_STRS)
|
|
strs_state <= ST_STRS_W0;
|
|
else
|
|
strs_state <= ST_STRS_DROP;
|
|
strs_too_long <= 1'b0;
|
|
end
|
|
end
|
|
|
|
// ST_STRS_W0
|
|
// ------------------
|
|
// - Cache the first word of the stream status
|
|
// - For CHDR_W == 64, this is one of 4 words.
|
|
// - For CHDR_W == 128, this is one of 2 words.
|
|
// - For CHDR_W >= 256, this is the only word.
|
|
ST_STRS_W0: begin
|
|
if (s_axis_strs_tvalid) begin
|
|
if (CHDR_W == 64) begin
|
|
cached_strs_msg[63:0] <= s_axis_strs_tdata[63:0];
|
|
strs_state <= !s_axis_strs_tlast ? ST_STRS_W1 : ST_STRS_HDR;
|
|
end else if (CHDR_W == 128) begin
|
|
cached_strs_msg[127:0] <= s_axis_strs_tdata[127:0];
|
|
strs_state <= !s_axis_strs_tlast ? ST_STRS_W1 : ST_STRS_HDR;
|
|
end else begin //CHDR_W >= 256
|
|
cached_strs_msg[255:0] <= s_axis_strs_tdata[255:0];
|
|
strs_state <= ST_STRS_LATCH;
|
|
strs_too_long <= !s_axis_strs_tlast;
|
|
end
|
|
end
|
|
end
|
|
|
|
// ST_STRS_W1
|
|
// ------------------
|
|
// - Cache the second word of the stream status
|
|
ST_STRS_W1: begin
|
|
if (s_axis_strs_tvalid) begin
|
|
if (CHDR_W == 64) begin
|
|
cached_strs_msg[127:64] <= s_axis_strs_tdata[63:0];
|
|
strs_state <= !s_axis_strs_tlast ? ST_STRS_W2 : ST_STRS_HDR;
|
|
end else begin //CHDR_W >= 128
|
|
cached_strs_msg[255:128] <= s_axis_strs_tdata[127:0];
|
|
strs_state <= ST_STRS_LATCH;
|
|
strs_too_long <= !s_axis_strs_tlast;
|
|
end
|
|
end
|
|
end
|
|
|
|
// ST_STRS_W2
|
|
// ------------------
|
|
// - Cache the third word of the stream status
|
|
ST_STRS_W2: begin
|
|
if (s_axis_strs_tvalid) begin
|
|
cached_strs_msg[191:128] <= s_axis_strs_tdata[63:0];
|
|
strs_state <= !s_axis_strs_tlast ? ST_STRS_W3 : ST_STRS_HDR;
|
|
end
|
|
end
|
|
|
|
// ST_STRS_W3
|
|
// ------------------
|
|
// - Cache the fourth word of the stream status
|
|
ST_STRS_W3: begin
|
|
if (s_axis_strs_tvalid) begin
|
|
cached_strs_msg[255:192] <= s_axis_strs_tdata[63:0];
|
|
strs_state <= ST_STRS_LATCH;
|
|
strs_too_long <= !s_axis_strs_tlast;
|
|
end
|
|
end
|
|
|
|
// ST_STRS_LATCH
|
|
// ------------------
|
|
// - Act on the received stream status
|
|
ST_STRS_LATCH: begin
|
|
capacity_bytes <= chdr256_strs_get_capacity_bytes(cached_strs_msg);
|
|
capacity_pkts <= chdr256_strs_get_capacity_pkts(cached_strs_msg);
|
|
recv_cnt_bytes <= chdr256_strs_get_xfercnt_bytes(cached_strs_msg);
|
|
recv_cnt_pkts <= chdr256_strs_get_xfercnt_pkts(cached_strs_msg);
|
|
adj_cap_bytes <= chdr256_strs_get_capacity_bytes(cached_strs_msg) -
|
|
{24'd0, headroom_bytes[15:(CHDR_W_LOG2-3)], {(CHDR_W_LOG2-3){1'b0}}};
|
|
adj_cap_pkts <= chdr256_strs_get_capacity_pkts(cached_strs_msg) -
|
|
{16'd0, headroom_pkts};
|
|
if (msg_i_tready) begin
|
|
strs_state <= strs_too_long ? ST_STRS_DROP : ST_STRS_HDR;
|
|
end
|
|
end
|
|
|
|
// ST_STRS_DROP
|
|
// ------------------
|
|
ST_STRS_DROP: begin
|
|
if (s_axis_strs_tvalid && s_axis_strs_tlast)
|
|
strs_state <= ST_STRS_HDR;
|
|
end
|
|
default: begin
|
|
// We should never get here
|
|
strs_state <= ST_STRS_HDR;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
assign s_axis_strs_tready = (strs_state != ST_STRS_LATCH);
|
|
|
|
assign msg_i_tvalid = (strs_state == ST_STRS_LATCH);
|
|
assign msg_i_tdata = (chdr256_strs_get_src_epid(cached_strs_msg) != cached_dst_epid) ?
|
|
CHDR_STRS_STATUS_CMDERR : chdr256_strs_get_status(cached_strs_msg);
|
|
|
|
|
|
// ---------------------------------------------------
|
|
// Main State Machine
|
|
// ---------------------------------------------------
|
|
|
|
localparam [2:0] ST_PASS_DATA = 3'd0; // Passing input axis_data out
|
|
localparam [2:0] ST_STRC_HDR = 3'd1; // Sending CHDR header for stream cmd
|
|
localparam [2:0] ST_STRC_W0 = 3'd2; // Sending first word of stream cmd
|
|
localparam [2:0] ST_STRC_W1 = 3'd3; // Sending second word of stream cmd
|
|
localparam [2:0] ST_STRC_WAIT = 3'd4; // Waiting for response (stream status)
|
|
localparam [2:0] ST_INIT_DLY = 3'd5; // Finishing command execution
|
|
|
|
reg [2:0] state = ST_PASS_DATA;
|
|
reg mid_pkt = 1'b0;
|
|
reg [15:0] data_seq_num = 16'd0;
|
|
reg [15:0] strc_seq_num = 16'd0;
|
|
reg [2:0] cfg_delay = 3'd0;
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
state <= ST_PASS_DATA;
|
|
mid_pkt <= 1'b0;
|
|
data_seq_num <= 16'd0;
|
|
strc_seq_num <= 16'd0;
|
|
cfg_pending <= 1'b0;
|
|
cfg_failed <= 1'b0;
|
|
end else begin
|
|
case (state)
|
|
|
|
// ST_PASS_DATA
|
|
// ------------------
|
|
// This is the default state where input data is passed to the
|
|
// output port. Flow control is enforced in this state.
|
|
// This state also serves as the launch state for a configuration
|
|
// operation (using cfg_start)
|
|
ST_PASS_DATA: begin
|
|
// Update the mid_pkt flag and sequence number
|
|
if (chdr_out_tvalid && chdr_out_tready) begin
|
|
mid_pkt <= !chdr_out_tlast;
|
|
if (chdr_out_tlast)
|
|
data_seq_num <= data_seq_num + 16'd1;
|
|
end
|
|
// Launch a configuration operation
|
|
if (cfg_start) begin
|
|
// Latch cfg command
|
|
cfg_pending <= 1'b1;
|
|
cfg_failed <= 1'b0;
|
|
// Disable flow control
|
|
fc_enabled <= 1'b0;
|
|
// Cache relevant data from the cfg cmd
|
|
lossy_xport <= cfg_lossy_xport;
|
|
cached_dst_epid <= cfg_dst_epid;
|
|
headroom_bytes <= cfg_fc_headroom_bytes;
|
|
headroom_pkts <= cfg_fc_headroom_pkts;
|
|
end
|
|
// Wait for current packet to transfer then begin the
|
|
// configuration process or stream command
|
|
if (cfg_start || cfg_pending || fc_resync_req) begin
|
|
if (mid_pkt) begin
|
|
if (chdr_out_tvalid && chdr_out_tready && chdr_out_tlast)
|
|
state <= ST_STRC_HDR;
|
|
end else begin
|
|
if (!(chdr_out_tvalid && chdr_out_tready))
|
|
state <= ST_STRC_HDR;
|
|
end
|
|
end
|
|
end
|
|
|
|
// ST_STRC_HDR
|
|
// ------------------
|
|
// Send the CHDR header for a stream command
|
|
ST_STRC_HDR: begin
|
|
if (chdr_out_tvalid && chdr_out_tready) begin
|
|
state <= ST_STRC_W0;
|
|
// Update seqnum for the next packet
|
|
strc_seq_num <= strc_seq_num + 16'd1;
|
|
end
|
|
// Update byte count for stream command
|
|
strc_cnt_bytes <= send_cnt_bytes;
|
|
end
|
|
|
|
// ST_STRC_W0
|
|
// ------------------
|
|
// Send the first line of a stream command
|
|
ST_STRC_W0: begin
|
|
if (chdr_out_tvalid && chdr_out_tready)
|
|
if (CHDR_W < 128)
|
|
state <= ST_STRC_W1;
|
|
else
|
|
state <= ST_STRC_WAIT;
|
|
end
|
|
|
|
// ST_STRC_W1
|
|
// ------------------
|
|
// Send the second line of a stream command
|
|
ST_STRC_W1: begin
|
|
if (chdr_out_tvalid && chdr_out_tready)
|
|
state <= fc_resync_req ? ST_PASS_DATA : ST_STRC_WAIT;
|
|
end
|
|
|
|
// ST_STRC_WAIT
|
|
// ------------------
|
|
// Done sending stream command. Wait for a response
|
|
ST_STRC_WAIT: begin
|
|
// Wait for a new response to arrive
|
|
if (msg_o_tvalid) begin
|
|
if (msg_o_tdata == CHDR_STRS_STATUS_OKAY) begin
|
|
state <= ST_INIT_DLY;
|
|
cfg_delay <= 3'd4;
|
|
fc_enabled <= 1'b1;
|
|
data_seq_num <= 16'd0;
|
|
strc_seq_num <= 16'd0;
|
|
end else begin
|
|
state <= ST_PASS_DATA;
|
|
cfg_failed <= 1'b1;
|
|
cfg_pending <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
// ST_INIT_DLY
|
|
// ------------------
|
|
// Delay matching state for ok_shreg
|
|
ST_INIT_DLY: begin
|
|
if (cfg_delay == 3'd0) begin
|
|
state <= ST_PASS_DATA;
|
|
cfg_pending <= 1'b0;
|
|
end else begin
|
|
cfg_delay <= cfg_delay - 3'd1;
|
|
end
|
|
end
|
|
|
|
// We should never get here
|
|
default: begin
|
|
state <= ST_PASS_DATA;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// Header for output CHDR data
|
|
wire [CHDR_W-1:0] data_header;
|
|
assign data_header[63:0] = chdr_set_seq_num(
|
|
chdr_set_dst_epid(s_axis_data_tdata[63:0], cached_dst_epid),
|
|
data_seq_num);
|
|
generate if (CHDR_W > 64)
|
|
assign data_header[CHDR_W-1:64] = s_axis_data_tdata[CHDR_W-1:64];
|
|
endgenerate
|
|
|
|
// Header for stream command
|
|
wire [CHDR_W-1:0] strc_header;
|
|
assign strc_header[63:0] = chdr_build_header(
|
|
/*VC*/ 6'd0, /*eob*/ 1'b0, /*eov*/ 1'b0, CHDR_PKT_TYPE_STRC, CHDR_NO_MDATA,
|
|
strc_seq_num, 16'd16+(CHDR_W/8), cached_dst_epid);
|
|
generate if (CHDR_W > 64)
|
|
assign strc_header[CHDR_W-1:64] = {(CHDR_W-64){1'b0}};
|
|
endgenerate
|
|
|
|
// Payload for stream command
|
|
wire [127:0] strc_init_payload = chdr128_strc_build(
|
|
{24'h0, cfg_fc_freq_bytes}, {16'h0, cfg_fc_freq_pkts},
|
|
/*op_data*/ 4'h0, CHDR_STRC_OPCODE_INIT, cfg_this_epid);
|
|
wire [127:0] strc_resync_payload = chdr128_strc_build(
|
|
strc_cnt_bytes, send_cnt_pkts,
|
|
/*op_data*/ 4'h0, CHDR_STRC_OPCODE_RESYNC, cfg_this_epid);
|
|
wire [127:0] strc_payload = fc_resync_req ? strc_resync_payload : strc_init_payload;
|
|
|
|
always @(*) begin
|
|
case (state)
|
|
ST_PASS_DATA: begin
|
|
chdr_out_tdata = mid_pkt ? s_axis_data_tdata : data_header;
|
|
chdr_out_tlast = s_axis_data_tlast;
|
|
chdr_out_tvalid = s_axis_data_tvalid && ok_to_send;
|
|
end
|
|
ST_STRC_HDR: begin
|
|
chdr_out_tdata = strc_header;
|
|
chdr_out_tlast = 1'b0;
|
|
chdr_out_tvalid = ok_to_send;
|
|
end
|
|
ST_STRC_W0: begin
|
|
chdr_out_tdata = strc_payload;
|
|
chdr_out_tlast = (CHDR_W < 128) ? 1'b0 : 1'b1;
|
|
chdr_out_tvalid = ok_to_send;
|
|
end
|
|
ST_STRC_W1: begin
|
|
// We will enter this state only if CHDR_W = 64
|
|
chdr_out_tdata = strc_payload[127:64];
|
|
chdr_out_tlast = 1'b1;
|
|
chdr_out_tvalid = ok_to_send;
|
|
end
|
|
default: begin
|
|
chdr_out_tdata = {CHDR_W{1'b0}};
|
|
chdr_out_tlast = 1'b0;
|
|
chdr_out_tvalid = 1'b0;
|
|
end
|
|
endcase
|
|
end
|
|
assign s_axis_data_tready = (state == ST_PASS_DATA) && chdr_out_tready && ok_to_send;
|
|
|
|
// Consume all messages when passing data forward. The flow control state is automatically
|
|
// updated outside the message FIFO. When a stream command is issued, we wait for the
|
|
// "wait" state to consume responses.
|
|
assign msg_o_tready = msg_o_tvalid && (state == ST_PASS_DATA || state == ST_STRC_WAIT);
|
|
|
|
// Acknowledge a flow control resync command
|
|
assign fc_resync_ack = fc_resync_req && (state == ST_STRC_W1) &&
|
|
chdr_out_tvalid && chdr_out_tready && chdr_out_tlast;
|
|
|
|
// ---------------------------------------------------
|
|
// Stream Status Reporting
|
|
// ---------------------------------------------------
|
|
|
|
wire runtime_err_stb = msg_o_tvalid && msg_o_tready && (state == ST_PASS_DATA);
|
|
assign seq_err_stb = runtime_err_stb && (msg_o_tdata == CHDR_STRS_STATUS_SEQERR);
|
|
assign data_err_stb = runtime_err_stb && (msg_o_tdata == CHDR_STRS_STATUS_DATAERR);
|
|
assign route_err_stb = runtime_err_stb && (msg_o_tdata == CHDR_STRS_STATUS_RTERR);
|
|
|
|
always @(posedge clk) begin
|
|
if (rst || !fc_enabled) begin
|
|
seq_err_cnt <= 32'd0;
|
|
data_err_cnt <= 32'd0;
|
|
route_err_cnt <= 32'd0;
|
|
end else begin
|
|
if (seq_err_stb)
|
|
seq_err_cnt <= seq_err_cnt + 32'd1;
|
|
if (data_err_stb)
|
|
data_err_cnt <= data_err_cnt + 32'd1;
|
|
if (route_err_stb)
|
|
route_err_cnt <= route_err_cnt + 32'd1;
|
|
end
|
|
end
|
|
|
|
endmodule // chdr_stream_output
|