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>


Original-commit: bafa9d95453387814ef25e6b6256ba8db2df612f
This commit is contained in:
Martin Braun
2020-01-28 09:35:36 -08:00
co-authored by 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
parent 74893643ca
commit 6b67702ad7
2157 changed files with 1282567 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
#
# Copyright 2010-2013 Ettus Research LLC
# Copyright 2016 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
##################################################
# SERDES Sources
##################################################
GPIF2_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/gpif2/, \
gpif2_slave_fifo32.v \
gpif2_to_fifo64.v \
fifo64_to_gpif2.v \
gpif2_error_checker.v \
))
+68
View File
@@ -0,0 +1,68 @@
//
// Copyright 2012-2013 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module fifo64_to_gpif2
#(
parameter FIFO_SIZE = 9,
parameter MTU = 12
)
(
//input fifo interface
input fifo_clk, input fifo_rst,
input [63:0] i_tdata,
input i_tlast,
input i_tvalid,
output i_tready,
//output interface
input gpif_clk, input gpif_rst,
output [31:0] o_tdata,
output o_tlast,
output o_tvalid,
input o_tready
);
wire [31:0] i32_tdata;
wire i32_tlast;
wire i32_tvalid, i32_tready;
axi_fifo64_to_fifo32 fifo64_to_fifo32
(
.clk(fifo_clk), .reset(fifo_rst), .clear(1'b0),
.i_tdata(i_tdata), .i_tuser(3'b0/*done care*/), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(i32_tdata), .o_tuser(/*ignored cuz vita has len*/), .o_tlast(i32_tlast), .o_tvalid(i32_tvalid), .o_tready(i32_tready)
);
wire [31:0] gate_tdata;
wire gate_tlast;
wire gate_tvalid, gate_tready;
axi_fifo_2clk #(.WIDTH(33), .SIZE(FIFO_SIZE)) cross_clock_fifo
(
.reset(fifo_rst | gpif_rst),
.i_aclk(fifo_clk), .i_tdata({i32_tlast, i32_tdata}), .i_tvalid(i32_tvalid), .i_tready(i32_tready),
.o_aclk(gpif_clk), .o_tdata({gate_tlast, gate_tdata}), .o_tvalid(gate_tvalid), .o_tready(gate_tready)
);
wire [31:0] int0_tdata; wire int0_tlast, int0_tvalid, int0_tready;
axi_packet_gate #(.WIDTH(32), .SIZE(MTU), .USE_AS_BUFF(0)) buffer_whole_pkt
(
.clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
.i_tdata(gate_tdata), .i_tlast(gate_tlast), .i_terror(1'b0), .i_tvalid(gate_tvalid), .i_tready(gate_tready),
.o_tdata(int0_tdata), .o_tlast(int0_tlast), .o_tvalid(int0_tvalid), .o_tready(int0_tready)
);
axi_fifo #(.WIDTH(33), .SIZE(1)) outgress_timing_fifo
(
.clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
.i_tdata({int0_tlast, int0_tdata}), .i_tvalid(int0_tvalid), .i_tready(int0_tready), .space(),
.o_tdata({o_tlast, o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready), .occupied()
);
endmodule //fifo_to_gpmc16
+129
View File
@@ -0,0 +1,129 @@
// Copyright 2013 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// inspect the input for invalid conditions
// when bad - drain input, flag error, and insert error msg packet
//
// Packets alignment errors are searched for in two different ways:
// 1) Blatently illegal values in what is assumed to be the PACKET_LENGTH field
// in the CHDR header
// (We could probably improve this by looking at other fields of the header that
// have a limited range of values)
// 2) Packet length indicating an EOF word that doesn't have TLAST set in the FIFO.
// (Upstream can howvever legally insert TLAST in the FIFO for words that are not EOF)
//
// Packet allignment recovery strategy is to wait for TLAST asserted and then decode the
// following data assuming it is the start of new CHDR headers.
//
//TODO - insert bad packet
module gpif2_error_checker
#(parameter SIZE = 9)
(input clk, input reset, input clear,
input [31:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [31:0] o_tdata, output o_tlast, output o_tvalid, input o_tready,
output bus_error, output [63:0] debug);
wire [31:0] gate_tdata;
wire gate_tlast, gate_terror;
wire gate_tvalid, gate_tready;
localparam STATE_HDR = 0;
localparam STATE_FWD = 1;
localparam STATE_EOF = 2;
localparam STATE_WAIT = 3;
reg [1:0] state;
reg [15:0] lines32;
reg [11:0] seq_id_ref;
reg seq_id_bad;
reg seq_id_wayoff;
wire [15:0] hdr_bytes = i_tdata[15:0] + 3; //round up to multiple of 4
wire [15:0] hdr_lines32 = {2'b0, hdr_bytes[15:2]}; //convert to lines32 count
wire [11:0] seq_id_actual = i_tdata[27:16];
wire obviously_bad_hdr = (hdr_lines32 == 16'h0) || (hdr_lines32 > (1 << SIZE));
always @(posedge clk) begin
if (reset | clear) begin
state <= STATE_HDR;
lines32 <= 16'b0;
seq_id_ref <= 12'h0;
seq_id_bad <= 0;
seq_id_wayoff <= 0;
end
else case (state)
STATE_HDR: begin //forward header and grab vita length
if (i_tvalid && i_tready) begin
if (obviously_bad_hdr) state <= STATE_WAIT;
else if (hdr_lines32 == 16'h1) state <= STATE_HDR;
else if (hdr_lines32 == 16'h2) state <= STATE_EOF;
else state <= STATE_FWD;
seq_id_bad <= (seq_id_actual != seq_id_ref);
seq_id_wayoff <= (seq_id_actual != seq_id_ref) |
(seq_id_actual != seq_id_ref+1) |
(seq_id_actual != seq_id_ref+2) |
(seq_id_actual != seq_id_ref+3);
if (seq_id_actual != seq_id_ref)
seq_id_ref <= seq_id_actual + 1;
else
seq_id_ref <= seq_id_ref + 1;
end
lines32 <= hdr_lines32;
end
STATE_FWD: begin //forward the rest of vita packet
if (i_tvalid && i_tready) begin
if (lines32 == 16'h3) state <= STATE_EOF;
lines32 <= lines32 - 1'b1;
end
end
STATE_EOF: begin //do last line of vita frame + eof
if (i_tvalid && i_tready)
if (gate_tlast) state <= STATE_HDR;
else state <= STATE_WAIT; // Try somehow to get synchronized again.
end
STATE_WAIT: begin //drop until idle
if (i_tvalid && i_tready && i_tlast) state <= STATE_HDR;
end
endcase //state
end
assign bus_error = (gate_terror && gate_tvalid && gate_tready) || ((state == STATE_HDR) && i_tvalid && i_tready && obviously_bad_hdr);
assign gate_tlast = (state == STATE_HDR)? (hdr_lines32 == 16'h1) : (state == STATE_EOF);
assign gate_tdata = i_tdata;
assign gate_tvalid = i_tvalid && ((state == STATE_HDR)? !obviously_bad_hdr : (state != STATE_WAIT));
assign i_tready = gate_tready;
axi_packet_gate #(.WIDTH(32), .SIZE(SIZE), .USE_AS_BUFF(0)) gate_xfer
(
.clk(clk), .reset(reset), .clear(clear),
.i_tdata(gate_tdata), .i_tlast(gate_tlast), .i_terror(1'b0), .i_tvalid(gate_tvalid), .i_tready(gate_tready),
.o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
);
assign debug = {13'b0,
seq_id_wayoff, //[50] [114]
gate_terror, // [49] [113]
obviously_bad_hdr, // [48] [112]
seq_id_bad, // [47] [111]
seq_id_ref, // [46:35] [110:99]
i_tlast, // [34] [98]
i_tready, // [33] [97]
i_tvalid, // [32] [96]
i_tdata}; // [31:0] [95:64]
endmodule // gpif2_error_checker
+590
View File
@@ -0,0 +1,590 @@
//
// Copyright 2011-2013 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
//////////////////////////////////////////////////////////////////////////////////
//this is a FIFO master interface for the FX3 in "slave fifo" mode.
module gpif2_slave_fifo32
#(
//sizes for fifo64 2 clock cascade fifos
parameter DATA_RX_FIFO_SIZE = 12, //max vita pkt size
parameter DATA_TX_FIFO_SIZE = 12, //max vita pkt size
parameter CTRL_RX_FIFO_SIZE = 5, //small resp packets
parameter CTRL_TX_FIFO_SIZE = 5, //small ctrl packets
//address constants for the endpoints
parameter ADDR_DATA_TX = 2'b00,
parameter ADDR_DATA_RX = 2'b01,
parameter ADDR_CTRL_TX = 2'b10,
parameter ADDR_CTRL_RX = 2'b11
)
(
// GPIF signals
input gpif_clk,
input gpif_rst,
input gpif_enb,
inout [31:0] gpif_d,
input [3:0] gpif_ctl,
output reg sloe,
output reg slrd,
output reg slwr,
output slcs,
output reg pktend,
output reg [1:0] fifoadr,
// FIFO interfaces
input fifo_clk,
input fifo_rst,
// TX Data interface to DSP
output [63:0] tx_tdata, output tx_tlast, output tx_tvalid, input tx_tready,
// RX Data interface to DSP
input [63:0] rx_tdata, input rx_tlast, input rx_tvalid, output rx_tready,
// Incomming control interface
output [63:0] ctrl_tdata, output ctrl_tlast, output ctrl_tvalid, input ctrl_tready,
// Outgoing control interface
input [63:0] resp_tdata, input resp_tlast, input resp_tvalid, output resp_tready,
// Debug Signals
output [31:0] debug
);
reg fifo_nearly_full;
wire ctrl_tx_fifo_nearly_full, data_tx_fifo_nearly_full;
wire ctrl_tx_fifo_has_space, data_tx_fifo_has_space;
assign slcs = 1'b0;
//
// DMA FIFO ready and watermark flags
// These are double registered not for meta stability protection, but to make timing closure easier
// since the first register is locked in the I/O pad.
//
reg fx3_ready, fx3_ready1, fx3_wmark, fx3_wmark1;
always @(posedge gpif_clk) fx3_ready <= gpif_ctl[0];
always @(posedge gpif_clk) fx3_wmark <= gpif_ctl[1];
always @(posedge gpif_clk) fx3_ready1 <= fx3_ready;
always @(posedge gpif_clk) fx3_wmark1 <= fx3_wmark;
//
// GPIF input and output data lines, tristate
//
reg [31:0] gpif_data_in, gpif_data_out;
always @(posedge gpif_clk)
if (~slrd2)
// Update data register only when something useful is read.
// Hold values until we know if they are end of packets for single beat reads.
gpif_data_in <= gpif_d;
assign gpif_d = sloe ? gpif_data_out[31:0] : 32'bz;
// ////////////////////////////////////////////////////////////////////
// GPIF bus master state machine
wire wr_fifo_xfer, wr_fifo_eop;
wire [31:0] wr_fifo_data;
reg read_ready_go, write_ready_go;
reg [3:0] state; //state machine current state
localparam STATE_IDLE = 0;
localparam STATE_THINK = 1;
localparam STATE_READ = 2;
localparam STATE_WRITE = 3;
localparam STATE_WAIT = 4;
localparam STATE_READ_FLUSH = 5;
localparam STATE_WRITE_FLUSH = 6;
localparam STATE_READ_SINGLE = 7;
// General purpose pseudo-state counter.
reg [2:0] idle_cycles;
// Select next address (endpoint) to be processed
reg [1:0] last_addr, next_addr;
wire local_fifo_ready;
// Track size of a wriet burst to look for FX3 corner cases related to 2^n sized bursts.
reg [15:0] transfer_size;
// Read strobe pipeline.
reg slrd1, slrd2, slrd3, slrd4, slrd5;
always @(posedge gpif_clk)
if (gpif_rst) begin
slrd1 <= 1'b1;
slrd2 <= 1'b1;
slrd3 <= 1'b1;
slrd4 <= 1'b1;
slrd5 <= 1'b1;
end else begin
slrd1 <= slrd;
slrd2 <= slrd1;
slrd3 <= slrd2;
slrd4 <= slrd3;
slrd5 <= slrd4;
end
// End of packet pipeline for reads.
reg rx_eop, rx_eop1, rx_eop2;
// This pipeline tracks the end of a CHDR TX packet seperately from the local FIFO becoming full.
// This is because a true packet end causes a tlast assertion to the FIFO, where as a full local FIFO only requires
// the GPIF transaction to be ended before local FIFO overflow occurs.
always @(posedge gpif_clk)
if (gpif_rst) begin
rx_eop1 <= 1;
rx_eop2 <= 1;
end else begin
rx_eop2 <= rx_eop1;
rx_eop1 <= rx_eop;
end
reg first_read;
reg pad = 0;
// //////////////////////////////////////////////////////////////
// FX2 slave FIFO bus master state machine
//
always @(posedge gpif_clk)
if(gpif_rst) begin
state <= STATE_IDLE;
sloe <= 1;
slrd <= 1;
slwr <= 1;
pktend <= 1;
gpif_data_out <= 32'b0;
idle_cycles <= 3'h0;
fifoadr <= 0;
first_read <= 1'b0;
last_addr <= 2'b0;
rx_eop <= 1'b0;
transfer_size <= 1;
pad <= 0;
end
else if (gpif_enb) begin
case (state)
//
// Increment fifoadr to point at next thread, set all strobes to idle,
//
STATE_IDLE: begin
sloe <= 1;
slrd <= 1;
slwr <= 1;
pktend <= 1;
gpif_data_out <= 32'b0;
fifoadr <= next_addr;
state <= STATE_WAIT;
idle_cycles <= 3'h0;
rx_eop <= 1'b0;
first_read <= 1'b0;
end
//
// If the current thread we are pointing at (fifoadr) can not immediately proceed
// then quickly move to the next thread. Once we are pointing at a thread that can proceed locally
// wait for 8 clock cycles to allow fifoadr to propogate to FX3, and corresponding flag state to
// propogate back to FPGA and through resampling flops. At this point transition to STATE_THINK
// to evaluate remote flag.
//
STATE_WAIT: begin
// Current thread can proceed locally
if (local_fifo_ready) begin
idle_cycles <= idle_cycles + 1'b1;
if (idle_cycles == 3'b111) state <= STATE_THINK; // Could shorten this delay, flags now stable for several clocks.
end
// ....move onto next thread.
else begin
idle_cycles <= 3'b0;
//fifoadr <= fifoadr + 2'b1;
fifoadr <= next_addr;
end
end
//
// Flags from FX3 now stable. Make a decision about what type of transaction to start.
//
STATE_THINK: begin
// This is written like a priority encoder but in reality read_ready_go and
// write_ready_go are mutually exclusive by design.
if (fx3_ready1 && fx3_wmark1 && read_ready_go) begin
state <= STATE_READ;
slrd <= 0;
rx_eop <= 1'b0;
first_read <= 1'b1; // Set unconditional read flag to kick off transaction
sloe <= 0; // FX3 drives the data bus.
end else if (fx3_ready1 && ~fx3_wmark1 && read_ready_go) begin
state <= STATE_READ_SINGLE;
slrd <= 0;
sloe <= 0; // FX3 drives the data bus.
end else if (fx3_ready1 && write_ready_go && wr_fifo_eop && (transfer_size[7:0] == 0)) begin // remember that write_ready_go shows 1 cycle old status.
// If an exact multiple of the native USB packet size (1K USB3, 512B USB2) has been transfered
// and TLAST is asserted (but the transfer is less than a full FX3 DMA buffer - this is
// indicated when the watermark will terminate the transfer in this case) then we will pad the packet
// for one more cycle to ensure it does not get stuck in the FX3.
pktend <= 1'b1; // Active low - De-asserted
slwr <= 1'b0; //Active low - Asserted, write to FX3.
transfer_size <= transfer_size + 1; // Increment transfer_size.
gpif_data_out <= wr_fifo_data; // Always latch data from FIFO's into output register
pad <= 1;
end else if ((fx3_ready1 && write_ready_go && wr_fifo_eop) | pad) begin // remember that write_ready_go shows 1 cycle old status.
// Its the end of a CHDR packet and we are not on a FX3 corner case size.
// Go IDLE with pktend and slwr asserted to write the last data.
pktend <= 1'b0; // Active low - Asserted,
state <= STATE_WRITE_FLUSH;
idle_cycles <= 3'd5; // Stay in flush 3 cycles
slwr <= 1'b0; // Active low - Asserted, write to FX3
transfer_size <= 1; // End of packet will release FX3 DMA buffer, reset transfer size count.
gpif_data_out <= wr_fifo_data; // Always latch data from FIFO's into output register
pad <= 0; // Reset pad
end else if (fx3_ready1 && write_ready_go) begin // remember that write_ready_go shows 1 cycle old status.
// There is (an unknown amount of) data ready to send to FX from local FIFO.
state <= STATE_WRITE;
slwr <= 1'b0; // Active low - Write strobe active
gpif_data_out <= wr_fifo_data; // Always latch data from FIFO's into output register
transfer_size <= transfer_size + 1; // Account for current cycles transfer
end
else begin
state <= STATE_IDLE;
end
idle_cycles <= 3'h0;
last_addr <= fifoadr;
end // case: STATE_THINK
// Got here because READY flag asserted but watermark deaaserted...QED there's less than the watermarks
// worth of data to read from FX remaining in this DMA page. Need to do that with single beat reads
// followed by rechecking the READY flag to see if it deassserted indicating that the page emptied.
// Since we have the read data from FX3 earlier than we have a flag to inspect we keep the data in
// gpif_data_in until we know if we are commiting it to the FIFO with or without an asserted TLAST.
//
STATE_READ_SINGLE: begin
if (idle_cycles == 0) begin
// Deassert read strobe after reading single 32bit word
slrd <= 1'b1;
idle_cycles <= idle_cycles + 1;
end else if (idle_cycles == 5) begin
// READY1 flag now reflect effects of last read.
if (!fx3_ready1) begin
state <= STATE_IDLE;
sloe <= 1'b1;
end else begin
// Initiate another READ beat.
state <= STATE_READ_SINGLE;
slrd <= 1'b0;
end
idle_cycles <= 0;
end else begin
// All other idle_cycles counts.
idle_cycles <= idle_cycles + 1;
end
end // case: STATE_READ_SINGLE
// If flag first_read and ~slrd3 have gone deasserted
// (meaning that the watermark deasserted 5 clock cycles ago or local FIFO full) transition to STATE_IDLE.
// If watermark deasserted 2 cycles ago de-assert slrd ...read data is still traveling in the pipeline.
// Whilst ~slrd3 stays asserted keep the first_read flag armed.
// Trigger TLAST only for transfer ended by watermark (Which indicates a true packet end), not local full FIFO.
STATE_READ: begin
if (~fx3_wmark1 | fifo_nearly_full) begin
// Either end of packet or local FIFO full is imminent, start shutting down this read burst.
slrd <= 1'b1; // Active low - Take read strobe inactive
state <= STATE_READ_FLUSH;
end else begin
slrd <= 1'b0; // Active low - Keep read strobe active.
end
if (~fx3_wmark1)
// Put TLAST into pipeline to mark end of packet
rx_eop <= 1'b1;
if (~slrd3)
// Reset first_read flag as slrd assertion progresses down pipeline
first_read <= 1'b0;
end // case: STATE_READ
// SLRD has been deasserted but data continues to flow from FX3 into FPGA until pipeline empties.
STATE_READ_FLUSH: begin
slrd <= 1'b1; // Active low - Keep read strobe inactive.
rx_eop <= 1'b0; // EOP indication can be reset now - Already traveling in the pipeline if it was active.
if (~slrd3)
// Reset first_read flag as slrd assertion progresses down pipeline
first_read <= 1'b0;
if (!first_read && slrd3) begin // Active low signal
// Last data of burst will be written to FIFO next clock edge so transition to IDLE also.
state <= STATE_IDLE;
sloe <= 1'b1; // Active low - Resume parking bus with FPGA driving.
end
end
// Now in potential write burst. Exit this sate immediately if we are only doing a single beat write.
// Can exit this state in several ways:
// At EOP and on a USB packet boundery (1K for USB3, 512B for USB2) must pad packet for 1 clock cycle in
// addition to simply asserting pktend.
// Otherwise at EOP just send a short packet.
// If local FIFO goes empty then we terminatethe burst without asserting pktend.
STATE_WRITE: begin
if (wr_fifo_eop && wr_fifo_xfer && (transfer_size[7:0] == 0)) begin
// If an exact multiple of the native USB packet size (1K USB3, 512B USB2) has been transfered
// and TLAST is asserted (but the transfer is less than a full FX3 DMA buffer - this is
// indicated when the watermark will terminate the transfer in this case) then we will pad the packet
// for one more cycle to ensure it does not get stuck in the FX3.
pktend <= 1'b1; // Active low - De-asserted,
slwr <= 1'b0; // Active low - Asserted, write to FX3
transfer_size <= transfer_size + 1; // Increment transfer_size.
pad <= 1;
end else if ((wr_fifo_eop && wr_fifo_xfer) | pad) begin
// Its the end of a CHDR packet and we are not on a FX3 corner case size.
// Go IDLE with pktend and slwr asserted to write the last data.
pktend <= 1'b0; // Active low - Asserted,
state <= STATE_WRITE_FLUSH;
idle_cycles <= 3'd5; // Stay in flush 3 cycles
slwr <= 1'b0; // Active low - Asserted, write to FX3
transfer_size <= 1; // End of packet will release FX3 DMA buffer, reset transfer size count.
pad <= 0; //Reset pad
end else if (wr_fifo_xfer) begin
// Regular write beat as part of a burst.
pktend <= 1'b1; // Active low - De-asserted,
slwr <= 1'b0; // Active low - Asserted, write to FX3
transfer_size <= transfer_size + 1; // Account for current cycles transfer
end else begin // Implicit if (~wr_fifo_xfer)
// This was either a single beat write (watermark was never asserted)
// or the water mark just deasserted or we ran out of local data to send.
// slwr will be deasserted and we transition to the flush state.
state <= STATE_WRITE_FLUSH;
idle_cycles <= 3'd6; // Stay in flush 2 cycles.
pktend <= 1'b1; // Active low - De-asserted,
slwr <= 1'b1; // Active low - Deasserted, don't write to FX3
end
gpif_data_out <= wr_fifo_data; // Always latch data from FIFO's into output register
end // case: STATE_WRITE
// Some FX3 timing diagrams seem to imply address should be held stable after transaction
STATE_WRITE_FLUSH: begin
slrd <= 1;
slwr <= 1;
pktend <= 1;
gpif_data_out <= 32'b0;
idle_cycles <= idle_cycles + 1'b1;
if (idle_cycles == 3'b111) begin
state <= STATE_IDLE;
end
end
default: state <= STATE_IDLE;
endcase
end
// ///////////////////////////////////////////////////////////////////
// fifo signal assignments and enables
//output from fifos - ready to xfer
wire data_tx_tready, ctrl_tx_tready;
wire ctrl_rx_tvalid, data_rx_tvalid;
//Priority encoding for the the next address to service:
//The next address to service is based on the readiness
//of the internal fifos and last serviced fairness metric.
/* -----\/----- EXCLUDED -----\/-----
always @(posedge gpif_clk) next_addr <=
((ctrl_rx_tvalid && (last_addr != ADDR_CTRL_RX))? ADDR_CTRL_RX :
((ctrl_tx_fifo_has_space && (last_addr != ADDR_CTRL_TX))? ADDR_CTRL_TX :
((data_rx_tvalid && (last_addr != ADDR_DATA_RX))? ADDR_DATA_RX :
((data_tx_fifo_has_space && (last_addr != ADDR_DATA_TX))? ADDR_DATA_TX :
(fifoadr + 2'b1)
))));
-----/\----- EXCLUDED -----/\----- */
//always @(posedge gpif_clk) next_addr <= (fifoadr + 2'b1);
// Sequence addresses 0->2->1->3->0......
always @(posedge gpif_clk) {next_addr[0],next_addr[1]} <= ({fifoadr[0],fifoadr[1]} + 2'b1);
//Help the FPGA search to only look for addrs that the FPGA is ready for
assign local_fifo_ready =
(ctrl_rx_tvalid && (fifoadr == ADDR_CTRL_RX)) ||
(ctrl_tx_fifo_has_space && (fifoadr == ADDR_CTRL_TX)) ||
(data_rx_tvalid && (fifoadr == ADDR_DATA_RX)) ||
(data_tx_fifo_has_space && (fifoadr == ADDR_DATA_TX));
// Local TX FIFO imminantly about to fill.
always @(posedge gpif_clk) fifo_nearly_full <=
(ctrl_tx_fifo_nearly_full && (fifoadr == ADDR_CTRL_TX)) ||
(data_tx_fifo_nearly_full && (fifoadr == ADDR_DATA_TX));
// There is enough space in local FIFO to RX an entire CHDR packet (sized for channel type)
always @(posedge gpif_clk) read_ready_go <=
(ctrl_tx_fifo_has_space && (fifoadr == ADDR_CTRL_TX)) ||
(data_tx_fifo_has_space && (fifoadr == ADDR_DATA_TX));
// The is data waiting to be sent to FX3 in local FIFO's
always @(posedge gpif_clk) write_ready_go <=
(ctrl_rx_tvalid && (fifoadr == ADDR_CTRL_RX)) ||
(data_rx_tvalid && (fifoadr == ADDR_DATA_RX));
//fifo xfer enable
wire data_rx_tready = (
((state == STATE_WRITE) && fx3_wmark1 && ~pad) || // Sustain burst
((state == STATE_THINK) && fx3_ready1) // First beat
) && (fifoadr == ADDR_DATA_RX) ;
wire ctrl_rx_tready = (
((state == STATE_WRITE) && fx3_wmark1) || // Sustain burst
((state == STATE_THINK) && fx3_ready1) // First beat
) && (fifoadr == ADDR_CTRL_RX) ;
// Burst reads tap the read strobe pipeline at stage3, single beat reads at stage5.
wire data_tx_tvalid = (
(((state == STATE_READ) || (state == STATE_READ_FLUSH)) && ~slrd3) |
((state == STATE_READ_SINGLE) && ~slrd5)
) && (fifoadr == ADDR_DATA_TX);
wire ctrl_tx_tvalid = (
(((state == STATE_READ) || (state == STATE_READ_FLUSH)) && ~slrd3) |
((state == STATE_READ_SINGLE) && ~slrd5)
) && (fifoadr == ADDR_CTRL_TX);
// The position of RX TLAST is known well in advance for bursts by monitoring the watermark. However for
// single beat reads it can only be deduced after a read that causes the ready flag to go inactive.
wire data_ctrl_tx_tlast = ((state == STATE_READ_FLUSH) && rx_eop2) || ((state == STATE_READ_SINGLE) && ~fx3_ready1);
//outputs from rx fifo paths
wire ctrl_rx_tlast, data_rx_tlast;
wire [31:0] ctrl_rx_tdata, data_rx_tdata;
// There will be a RX FIFO transaction this cycle
assign wr_fifo_xfer = (fifoadr == ADDR_CTRL_RX)? (ctrl_rx_tvalid && ctrl_rx_tready) : (data_rx_tvalid && data_rx_tready);
// The RX FIFO transaction this cycle has TLAST set
assign wr_fifo_eop = (fifoadr == ADDR_CTRL_RX)? ctrl_rx_tlast : data_rx_tlast;
// Route data from addressed RX FIFO towards FX3
assign wr_fifo_data = (fifoadr == ADDR_CTRL_RX)? ctrl_rx_tdata : data_rx_tdata;
wire ctrl_bus_error, tx_bus_error;
// ////////////////////////////////////////////////////////////////////
// TX Data Path
wire [31:0] debug_data_fifo;
gpif2_to_fifo64 #(.FIFO_SIZE(DATA_TX_FIFO_SIZE)) gpif2_to_fifo64_tx(
.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
.i_tdata(gpif_data_in), .i_tlast(data_ctrl_tx_tlast), .i_tvalid(data_tx_tvalid), .i_tready(data_tx_tready), // IJB. NOTE data_tx_tready currently unused.
.fifo_clk(fifo_clk), .fifo_rst(fifo_rst),
.fifo_nearly_full(data_tx_fifo_nearly_full), .fifo_has_space(data_tx_fifo_has_space),
.o_tdata(tx_tdata), .o_tlast(tx_tlast), .o_tvalid(tx_tvalid), .o_tready(tx_tready),
.bus_error(tx_bus_error), .debug(debug_data_fifo)
);
// ////////////////////////////////////////////
// RX Data Path
fifo64_to_gpif2 #(.FIFO_SIZE(DATA_RX_FIFO_SIZE)) fifo64_to_gpif2_rx(
.fifo_clk(fifo_clk), .fifo_rst(fifo_rst),
.i_tdata(rx_tdata), .i_tlast(rx_tlast), .i_tvalid(rx_tvalid), .i_tready(rx_tready),
.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
.o_tdata(data_rx_tdata), .o_tlast(data_rx_tlast), .o_tvalid(data_rx_tvalid), .o_tready(data_rx_tready)
);
// ////////////////////////////////////////////////////////////////////
// CTRL path
wire [31:0] debug_ctrl_fifo;
gpif2_to_fifo64 #(.FIFO_SIZE(CTRL_TX_FIFO_SIZE)) gpif2_to_fifo64_ctrl(
.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
.i_tdata(gpif_data_in), .i_tlast(data_ctrl_tx_tlast), .i_tvalid(ctrl_tx_tvalid), .i_tready(ctrl_tx_tready), // IJB. NOTE data_tx_tready currently unused.
.fifo_clk(fifo_clk), .fifo_rst(fifo_rst),
.fifo_nearly_full(ctrl_tx_fifo_nearly_full), .fifo_has_space(ctrl_tx_fifo_has_space),
.o_tdata(ctrl_tdata), .o_tlast(ctrl_tlast), .o_tvalid(ctrl_tvalid), .o_tready(ctrl_tready),
.bus_error(ctrl_bus_error), .debug(debug_ctrl_fifo)
);
// ////////////////////////////////////////////////////////////////////
// RESP path
fifo64_to_gpif2 #(.FIFO_SIZE(CTRL_RX_FIFO_SIZE)) fifo64_to_gpif2_resp(
.fifo_clk(fifo_clk), .fifo_rst(fifo_rst),
.i_tdata(resp_tdata), .i_tlast(resp_tlast), .i_tvalid(resp_tvalid), .i_tready(resp_tready),
.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
.o_tdata(ctrl_rx_tdata), .o_tlast(ctrl_rx_tlast), .o_tvalid(ctrl_rx_tvalid), .o_tready(ctrl_rx_tready)
);
// ////////////////////////////////////////////
// DEBUG
/* -----\/----- EXCLUDED -----\/-----
wire [35:0] CONTROL0;
reg wr_fifo_eop_debug;
reg read_ready_go_debug;
reg fifo_nearly_full_debug;
reg local_fifo_ready_debug;
reg slwr_debug;
reg slrd_debug;
reg sloe_debug;
reg pktend_debug;
reg [1:0] fifoadr_debug;
reg ep_wmark1_debug;
reg ep_ready1_debug;
reg [3:0] state_debug;
reg wr_fifo_xfer_debug;
always @(posedge gpif_clk) begin
wr_fifo_eop_debug <= wr_fifo_eop;
read_ready_go_debug <= read_ready_go;
fifo_nearly_full_debug <= fifo_nearly_full;
local_fifo_ready_debug <= local_fifo_ready;
wr_fifo_xfer_debug <= wr_fifo_xfer;
slwr_debug <= slwr;
slrd_debug <= slrd;
sloe_debug <= sloe;
pktend_debug <= pktend;
fifoadr_debug[1:0] <= fifoadr;
ep_wmark1_debug <= fx3_wmark1;
ep_ready1_debug <= fx3_ready1;
state_debug[3:0] <= state;
end
chipscope_ila_32 chipscope_ila_32_0 (
.CONTROL(CONTROL0), // INOUT BUS [35:0]
.CLK(gpif_clk), // IN
.TRIG0({
debug_data_fifo[5:0],
debug_ctrl_fifo[5:0],
wr_fifo_eop_debug,
read_ready_go_debug,
fifo_nearly_full_debug,
local_fifo_ready_debug,
wr_fifo_xfer_debug,
slwr_debug,
slrd_debug,
sloe_debug,
pktend_debug,
fifoadr_debug[1:0],
ep_wmark1_debug,
ep_ready1_debug,
state_debug[3:0]
}) // IN BUS [31:0]
);
chipscope_icon chipscope_icon_i0
(
.CONTROL0(CONTROL0) // INOUT BUS [35:0]
);
-----/\----- EXCLUDED -----/\----- */
endmodule // gpif2_slave_fifo32
+152
View File
@@ -0,0 +1,152 @@
//
// Copyright 2012-2013 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module gpif2_to_fifo64
#(
parameter FIFO_SIZE = 9,
parameter MTU = 12
)
(
//input interface
input gpif_clk,
input gpif_rst,
input [31:0] i_tdata,
input i_tlast,
input i_tvalid,
output i_tready,
output fifo_has_space,
output fifo_nearly_full,
//output fifo interface
input fifo_clk,
input fifo_rst,
output [63:0] o_tdata,
output o_tlast,
output o_tvalid,
input o_tready,
output bus_error,
output [31:0] debug
);
wire [31:0] int_tdata;
wire int_tlast;
wire int_tvalid, int_tready;
wire [31:0] int0_tdata;
wire int0_tlast, int0_tvalid, int0_tready;
//
// Generate flags that show if initial FIFO's can accept a maximum sized burst from the FX3
// or if the FIFO is about to fill.
//
wire [15:0] space;
assign fifo_has_space = space >= (1 << MTU);
assign fifo_nearly_full = (space < 6); // 5 spaces left.
//
// This FIFO is provdied purely to ease FPGA timing closure as data is coming from I/O pins.
//
axi_fifo #(.WIDTH(33), .SIZE(5)) ingress_timing_fifo
(
.clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
.i_tdata({i_tlast, i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready), .space(),
.o_tdata({int0_tlast, int0_tdata}), .o_tvalid(int0_tvalid), .o_tready(int0_tready), .occupied()
);
//
// This FIFO provides space to accept a single burst from FX3 and it's fullness drives flags to GPIF2 logic
//
axi_fifo_legacy #(.WIDTH(33), .SIZE(MTU)) min_read_buff
(
.clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
.i_tdata({int0_tlast, int0_tdata}), .i_tvalid(int0_tvalid), .i_tready(int0_tready), .space(space),
.o_tdata({int_tlast, int_tdata}), .o_tvalid(int_tvalid), .o_tready(int_tready), .occupied()
);
//
// This logic allows signals to cross from the GPIF2 clock domain to the BUS clock domain.
// It may now be obselete if bus_clk and gpif_clk are merged
//
wire [31:0] chk_tdata;
wire chk_tlast;
wire chk_tvalid, chk_tready;
axi_fifo_2clk #(.WIDTH(33), .SIZE(FIFO_SIZE)) cross_clock_fifo
(
.reset(fifo_rst | gpif_rst),
.i_aclk(gpif_clk), .i_tdata({int_tlast, int_tdata}), .i_tvalid(int_tvalid), .i_tready(int_tready),
.o_aclk(fifo_clk), .o_tdata({chk_tlast, chk_tdata}), .o_tvalid(chk_tvalid), .o_tready(chk_tready)
);
//
// Performs basic tests on incomming packets such as testing if size on the wire patches
// the internal size field. Uses axi_packet_gate internally so can back pressure upstream if
// packet needs to be dropped.
//
wire [31:0] o32_tdata;
wire o32_tlast;
wire o32_tvalid, o32_tready;
gpif2_error_checker #(.SIZE(MTU)) checker
(
.clk(fifo_clk), .reset(fifo_rst), .clear(1'b0),
.i_tdata(chk_tdata), .i_tlast(chk_tlast), .i_tvalid(chk_tvalid), .i_tready(chk_tready),
.o_tdata(o32_tdata), .o_tlast(o32_tlast), .o_tvalid(o32_tvalid), .o_tready(o32_tready),
.bus_error(bus_error), .debug()
);
//assign o32_tdata = chk_tdata;
//assign o32_tlast = chk_tlast;
//assign o32_tvalid = chk_tvalid;
//assign chk_tready = o32_tready;
//
// Convert 32bit AXIS bus to 64bit
//
axi_fifo32_to_fifo64 fifo32_to_fifo64
(
.clk(fifo_clk), .reset(fifo_rst), .clear(1'b0),
.i_tdata(o32_tdata), .i_tuser(2'b0/*always 32 bits*/), .i_tlast(o32_tlast), .i_tvalid(o32_tvalid), .i_tready(o32_tready),
.o_tdata(o_tdata), .o_tuser(/*ignored cuz vita has len*/), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
);
/////////////////////////////////////////////
//
// Debug logic only
//
/////////////////////////////////////////////
reg o_tready_debug;
reg o_tvalid_debug;
reg o_tlast_debug;
reg i_tready_debug;
reg i_tvalid_debug;
reg i_tlast_debug;
always @(posedge gpif_clk) begin
o_tready_debug <= o_tready;
o_tvalid_debug <= o_tvalid;
o_tlast_debug <= o_tlast;
i_tready_debug <= i_tready;
i_tvalid_debug <= i_tvalid;
i_tlast_debug <= i_tlast;
end
assign debug = {26'h0,
o_tready_debug,
o_tvalid_debug,
o_tlast_debug,
i_tready_debug,
i_tvalid_debug,
i_tlast_debug
};
endmodule //fifo_to_gpif2