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
+37
View File
@@ -0,0 +1,37 @@
#
# Copyright 2012-2013 Ettus Research LLC
# Copyright 2016 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
##################################################
# FIFO Sources
##################################################
FIFO_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/fifo/, \
axi_demux4.v \
axi_demux8.v \
axi_demux.v \
axi_fifo_2clk.v \
axi_fifo32_to_fifo64.v \
axi_fifo64_to_fifo32.v \
axi_fifo32_to_fifo16.v \
axi_fifo16_to_fifo32.v \
axi_fifo_bram.v \
axi_fifo_cascade.v \
axi_fifo_flop2.v \
axi_fifo_flop.v \
axi_fifo_short.v \
axi_fifo.v \
axi_filter_mux4.v \
axi_loopback.v \
axi_mux4.v \
axi_mux8.v \
axi_mux_select.v \
axi_mux.v \
axi_packet_gate.v \
fifo64_to_axi4lite.v \
shortfifo.v \
axis_fifo_monitor.v \
axis_strm_monitor.v \
))
+75
View File
@@ -0,0 +1,75 @@
// Copyright 2012 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// axi_demux -- takes 1 AXI stream, demuxes to up to 16 output streams
// One bubble cycle between each packet
module axi_demux
#(parameter WIDTH=64,
parameter SIZE=4,
parameter PRE_FIFO_SIZE=0,
parameter POST_FIFO_SIZE=0)
(input clk, input reset, input clear,
output [WIDTH-1:0] header, input [$clog2(SIZE)-1:0] dest,
input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [(WIDTH*SIZE)-1:0] o_tdata, output [SIZE-1:0] o_tlast, output [SIZE-1:0] o_tvalid, input [SIZE-1:0] o_tready);
wire i_tlast_int, i_tready_int, i_tvalid_int;
wire [WIDTH-1:0] i_tdata_int;
generate
if (PRE_FIFO_SIZE == 0) begin
assign i_tlast_int = i_tlast;
assign i_tdata_int = i_tdata;
assign i_tvalid_int = i_tvalid;
assign i_tready = i_tready_int;
end else begin
axi_fifo #(.WIDTH(WIDTH+1),.SIZE(PRE_FIFO_SIZE)) axi_fifo (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata({i_tlast_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int),
.space(), .occupied());
end
endgenerate
reg [SIZE-1:0] st;
assign header = i_tdata_int;
always @(posedge clk)
if(reset | clear)
st <= {SIZE{1'b0}};
else
if(st == 0)
if(i_tvalid_int)
st[dest] <= 1'b1;
else
;
else
if(i_tready_int & i_tvalid_int & i_tlast_int)
st <= {SIZE{1'b0}};
wire [SIZE-1:0] o_tlast_int, o_tready_int, o_tvalid_int;
wire [WIDTH-1:0] o_tdata_int[0:SIZE-1];
genvar n;
generate
if (POST_FIFO_SIZE == 0) begin
assign o_tdata = {SIZE{i_tdata_int}};
assign o_tlast = {SIZE{i_tlast_int}};
assign o_tvalid = {SIZE{i_tvalid_int}} & st;
assign i_tready_int = |(o_tready & st);
end else begin
wire [SIZE-1:0] o_tready_fifo;
assign i_tready_int = |(o_tready_fifo & st);
for (n = 0; n < SIZE; n = n + 1) begin
axi_fifo #(.WIDTH(WIDTH+1),.SIZE(POST_FIFO_SIZE)) axi_fifo (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({i_tlast_int,i_tdata_int}), .i_tvalid(i_tvalid_int & st[n]), .i_tready(o_tready_fifo[n]),
.o_tdata({o_tlast[n],o_tdata[WIDTH*(n+1)-1:WIDTH*n]}), .o_tvalid(o_tvalid[n]), .o_tready(o_tready[n]),
.space(), .occupied());
end
end
endgenerate
endmodule // axi_demux
+80
View File
@@ -0,0 +1,80 @@
// Copyright 2012 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// axi_demux -- takes one AXI stream, sends to one of 4 output channels
// Choice of output channel is by external logic based on first line of packet ("header" port)
// If compressed vita data, this line contains vita header and streamid.
module axi_demux4
#(parameter ACTIVE_CHAN = 4'b1111, // ACTIVE_CHAN is a map of connected outputs
parameter WIDTH = 64,
parameter BUFFER=0)
(input clk, input reset, input clear,
output [WIDTH-1:0] header, input [1:0] dest,
input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [WIDTH-1:0] o0_tdata, output o0_tlast, output o0_tvalid, input o0_tready,
output [WIDTH-1:0] o1_tdata, output o1_tlast, output o1_tvalid, input o1_tready,
output [WIDTH-1:0] o2_tdata, output o2_tlast, output o2_tvalid, input o2_tready,
output [WIDTH-1:0] o3_tdata, output o3_tlast, output o3_tvalid, input o3_tready);
wire [WIDTH-1:0] i_tdata_int;
wire i_tlast_int, i_tvalid_int, i_tready_int;
generate
if(BUFFER == 0)
begin
assign i_tdata_int = i_tdata;
assign i_tlast_int = i_tlast;
assign i_tvalid_int = i_tvalid;
assign i_tready = i_tready_int;
end
else
axi_fifo_flop2 #(.WIDTH(WIDTH+1)) axi_fifo_flop2
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata({i_tlast_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int),
.space(), .occupied());
endgenerate
reg [3:0] dm_state;
localparam DM_IDLE = 4'b0000;
localparam DM_0 = 4'b0001;
localparam DM_1 = 4'b0010;
localparam DM_2 = 4'b0100;
localparam DM_3 = 4'b1000;
assign header = i_tdata_int;
always @(posedge clk)
if(reset | clear)
dm_state <= DM_IDLE;
else
case (dm_state)
DM_IDLE :
if(i_tvalid_int)
case(dest)
2'b00 : dm_state <= DM_0;
2'b01 : dm_state <= DM_1;
2'b10 : dm_state <= DM_2;
2'b11 : dm_state <= DM_3;
endcase // case (i_tdata[1:0])
DM_0, DM_1, DM_2, DM_3 :
if(i_tvalid_int & i_tready_int & i_tlast_int)
dm_state <= DM_IDLE;
default :
dm_state <= DM_IDLE;
endcase // case (dm_state)
assign {o3_tvalid, o2_tvalid, o1_tvalid, o0_tvalid} = dm_state & {4{i_tvalid_int}};
assign i_tready_int = |(dm_state & ({o3_tready, o2_tready, o1_tready, o0_tready} | ~ACTIVE_CHAN));
assign {o0_tlast, o0_tdata} = {i_tlast_int, i_tdata_int};
assign {o1_tlast, o1_tdata} = {i_tlast_int, i_tdata_int};
assign {o2_tlast, o2_tdata} = {i_tlast_int, i_tdata_int};
assign {o3_tlast, o3_tdata} = {i_tlast_int, i_tdata_int};
endmodule // axi_demux4
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2012 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// axi_demux -- takes one AXI stream, sends to one of 8 output channels
// Choice of output channel is by external logic based on first line of packet ("header" port)
// If compressed vita data, this line contains vita header and streamid.
module axi_demux8 #(
parameter ACTIVE_CHAN = 8'b11111111, // ACTIVE_CHAN is a map of connected outputs
parameter WIDTH = 64,
parameter BUFFER=0
) (
input clk, input reset, input clear,
output [WIDTH-1:0] header, input [2:0] dest,
input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [WIDTH-1:0] o0_tdata, output o0_tlast, output o0_tvalid, input o0_tready,
output [WIDTH-1:0] o1_tdata, output o1_tlast, output o1_tvalid, input o1_tready,
output [WIDTH-1:0] o2_tdata, output o2_tlast, output o2_tvalid, input o2_tready,
output [WIDTH-1:0] o3_tdata, output o3_tlast, output o3_tvalid, input o3_tready,
output [WIDTH-1:0] o4_tdata, output o4_tlast, output o4_tvalid, input o4_tready,
output [WIDTH-1:0] o5_tdata, output o5_tlast, output o5_tvalid, input o5_tready,
output [WIDTH-1:0] o6_tdata, output o6_tlast, output o6_tvalid, input o6_tready,
output [WIDTH-1:0] o7_tdata, output o7_tlast, output o7_tvalid, input o7_tready
);
wire [WIDTH-1:0] i_tdata_int0, i_tdata_int1;
wire i_tlast_int0, i_tlast_int1;
wire i_tvalid_int0, i_tvalid_int1;
wire i_tready_int0, i_tready_int1;
axi_demux4 #(.ACTIVE_CHAN({2'b00, (|(ACTIVE_CHAN[7:4])), (|(ACTIVE_CHAN[3:0]))}), .WIDTH(WIDTH), .BUFFER(BUFFER)) demux2 (
.clk(clk), .reset(reset), .clear(clear),
.header(header), .dest({1'b0, dest[2]}),
.i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o0_tdata(i_tdata_int0), .o0_tlast(i_tlast_int0), .o0_tvalid(i_tvalid_int0), .o0_tready(i_tready_int0),
.o1_tdata(i_tdata_int1), .o1_tlast(i_tlast_int1), .o1_tvalid(i_tvalid_int1), .o1_tready(i_tready_int1),
.o2_tdata(), .o2_tlast(), .o2_tvalid(), .o2_tready(1'b0),
.o3_tdata(), .o3_tlast(), .o3_tvalid(), .o3_tready(1'b0)
);
axi_demux4 #(.ACTIVE_CHAN(ACTIVE_CHAN[3:0]), .WIDTH(WIDTH), .BUFFER(0)) demux4_int0 (
.clk(clk), .reset(reset), .clear(clear),
.header(), .dest(dest[1:0]),
.i_tdata(i_tdata_int0), .i_tlast(i_tlast_int0), .i_tvalid(i_tvalid_int0), .i_tready(i_tready_int0),
.o0_tdata(o0_tdata), .o0_tlast(o0_tlast), .o0_tvalid(o0_tvalid), .o0_tready(o0_tready),
.o1_tdata(o1_tdata), .o1_tlast(o1_tlast), .o1_tvalid(o1_tvalid), .o1_tready(o1_tready),
.o2_tdata(o2_tdata), .o2_tlast(o2_tlast), .o2_tvalid(o2_tvalid), .o2_tready(o2_tready),
.o3_tdata(o3_tdata), .o3_tlast(o3_tlast), .o3_tvalid(o3_tvalid), .o3_tready(o3_tready)
);
axi_demux4 #(.ACTIVE_CHAN(ACTIVE_CHAN[7:4]), .WIDTH(WIDTH), .BUFFER(0)) demux4_int1 (
.clk(clk), .reset(reset), .clear(clear),
.header(), .dest(dest[1:0]),
.i_tdata(i_tdata_int1), .i_tlast(i_tlast_int1), .i_tvalid(i_tvalid_int1), .i_tready(i_tready_int1),
.o0_tdata(o4_tdata), .o0_tlast(o4_tlast), .o0_tvalid(o4_tvalid), .o0_tready(o4_tready),
.o1_tdata(o5_tdata), .o1_tlast(o5_tlast), .o1_tvalid(o5_tvalid), .o1_tready(o5_tready),
.o2_tdata(o6_tdata), .o2_tlast(o6_tlast), .o2_tvalid(o6_tvalid), .o2_tready(o6_tready),
.o3_tdata(o7_tdata), .o3_tlast(o7_tlast), .o3_tvalid(o7_tvalid), .o3_tready(o7_tready)
);
endmodule // axi_demux4
+71
View File
@@ -0,0 +1,71 @@
//
// Copyright 2012-2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// General FIFO block
// Size == 0: Uses a single stage flop (axi_fifo_flop).
// Size == 1: Uses a two stage flop (axi_fifo_flop2). Best choice for single stage pipelining.
// Breaks combinatorial paths on the AXI stream data / control lines at the cost of
// additional registers. Maps to SLICELs (i.e. does not use distributed RAM).
// Size <= 5: Uses SRL32 to efficient maps a 32 deep FIFO to SLICEMs (axi_fifo_short). Not
// recommended for pipelining as most devices have twice as many SLICELs as SLICEMs.
// Size > 5: Uses BRAM fifo (axi_fifo_bram)
module axi_fifo
#(parameter WIDTH=32, SIZE=5)
(input clk, input reset, input clear,
input [WIDTH-1:0] i_tdata,
input i_tvalid,
output i_tready,
output [WIDTH-1:0] o_tdata,
output o_tvalid,
input o_tready,
output [15:0] space,
output [15:0] occupied);
generate
if(SIZE==0)
begin
axi_fifo_flop #(.WIDTH(WIDTH)) fifo_flop
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(space[0]), .occupied(occupied[0]));
assign space[15:1] = 15'd0;
assign occupied[15:1] = 15'd0;
end
else if(SIZE==1)
begin
axi_fifo_flop2 #(.WIDTH(WIDTH)) fifo_flop2
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(space[1:0]), .occupied(occupied[1:0]));
assign space[15:2] = 14'd0;
assign occupied[15:2] = 14'd0;
end
else if(SIZE<=5)
begin
axi_fifo_short #(.WIDTH(WIDTH)) fifo_short
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(space[5:0]), .occupied(occupied[5:0]));
assign space[15:6] = 10'd0;
assign occupied[15:6] = 10'd0;
end
else
begin
axi_fifo_bram #(.WIDTH(WIDTH), .SIZE(SIZE)) fifo_bram
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(space), .occupied(occupied));
end
endgenerate
endmodule // axi_fifo
+43
View File
@@ -0,0 +1,43 @@
//
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module axi_fifo16_to_fifo32
(input clk, input reset, input clear,
input [15:0] i_tdata, input [1:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
output [31:0] o_tdata, output [2:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
);
reg [15:0] holding;
reg state;
always @(posedge clk)
if(reset | clear)
state <= 0;
else
if(i_tvalid & i_tready)
case(state)
0 : if(~i_tlast) state <= 1'b1;
1 : state <= 1'b0;
default : state <= 1'b0;
endcase // case (state)
always @(posedge clk)
if(i_tvalid & i_tready)
holding <= i_tdata;
assign i_tready = (state == 0 && !i_tlast)? 1'b1 : o_tready;
assign o_tvalid = (state == 0 && !i_tlast)? 1'b0 : i_tvalid;
assign o_tdata = (state == 0) ? {i_tdata, 16'h0} : { holding, i_tdata };
assign o_tlast = i_tlast;
wire [2:0] occ_in = (i_tuser == 0) ? 3'd4 : {1'b0, i_tuser};
wire [2:0] occ_out = (state == 0) ? occ_in : (occ_in + 3'd4);
assign o_tuser = ~o_tlast ? 3'd0 : occ_out;
endmodule // axi_fifo32_to_fifo64
+36
View File
@@ -0,0 +1,36 @@
//
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module axi_fifo32_to_fifo16
(input clk, input reset, input clear,
input [31:0] i_tdata, input [2:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
output [15:0] o_tdata, output [1:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
);
wire short_last = i_tlast & ((i_tuser == 3'd1) | (i_tuser == 3'd2) | (i_tuser == 3'd3) | (i_tuser == 3'd4));
reg state;
always @(posedge clk)
if(reset | clear)
state <= 1'b0;
else
if(i_tvalid & o_tready)
case(state)
1'b0 :
if(~short_last)
state <= 1'b1;
1'b1 :
state <= 1'b0;
endcase // case (state)
assign o_tdata = (state == 0) ? i_tdata[31:16] : i_tdata[15:0];
assign o_tuser = o_tlast ? i_tuser[1:0] : 2'd0;
assign o_tlast = i_tlast & ((state == 1'b1) | short_last);
assign o_tvalid = i_tvalid;
assign i_tready = o_tready & ((state == 1'b1) | short_last);
endmodule // axi_fifo64_to_fifo32
+44
View File
@@ -0,0 +1,44 @@
//
// Copyright 2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module axi_fifo32_to_fifo64
(input clk, input reset, input clear,
input [31:0] i_tdata, input [1:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
output [63:0] o_tdata, output [2:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
);
reg [31:0] holding;
reg state;
always @(posedge clk)
if(reset | clear)
state <= 0;
else
if(i_tvalid & i_tready)
case(state)
0 : if(~i_tlast) state <= 1'b1;
1 : state <= 1'b0;
default : state <= 1'b0;
endcase // case (state)
always @(posedge clk)
if(i_tvalid & i_tready)
holding <= i_tdata;
assign i_tready = (state == 0 && !i_tlast)? 1'b1 : o_tready;
assign o_tvalid = (state == 0 && !i_tlast)? 1'b0 : i_tvalid;
assign o_tdata = (state == 0) ? {i_tdata, 32'h0} : { holding, i_tdata };
assign o_tlast = i_tlast;
wire [2:0] occ_in = (i_tuser == 0) ? 3'd4 : {1'b0, i_tuser};
wire [2:0] occ_out = (state == 0) ? occ_in : (occ_in + 3'd4);
assign o_tuser = ~o_tlast ? 3'd0 : occ_out;
endmodule // axi_fifo32_to_fifo64
+37
View File
@@ -0,0 +1,37 @@
//
// Copyright 2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module axi_fifo64_to_fifo32
(input clk, input reset, input clear,
input [63:0] i_tdata, input [2:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
output [31:0] o_tdata, output [1:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
);
wire short_last = i_tlast & ((i_tuser == 3'd1) | (i_tuser == 3'd2) | (i_tuser == 3'd3) | (i_tuser == 3'd4));
reg state;
always @(posedge clk)
if(reset | clear)
state <= 1'b0;
else
if(i_tvalid & o_tready)
case(state)
1'b0 :
if(~short_last)
state <= 1'b1;
1'b1 :
state <= 1'b0;
endcase // case (state)
assign o_tdata = (state == 0) ? i_tdata[63:32] : i_tdata[31:0];
assign o_tuser = o_tlast ? i_tuser[1:0] : 2'd0;
assign o_tlast = i_tlast & ((state == 1'b1) | short_last);
assign o_tvalid = i_tvalid;
assign i_tready = o_tready & ((state == 1'b1) | short_last);
endmodule // axi_fifo64_to_fifo32
+184
View File
@@ -0,0 +1,184 @@
/////////////////////////////////////////////////////////////////////
//
// Copyright 2017 Ettus Research, A National Instruments Company
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: axi_fifo_2clk.v
//
// Purpose:
// An asynchronous clock crossing for AXI-Stream buses
// The width (WIDTH) and depth (SIZE) of the FIFO is configurable
// For depths less than the technology's SRL threshold, an SRL
// will be instantiated. For depths less the minimum RAM block
// depth (that corresponds to the max width), a single BRAM block
// will be instantiated. For other larger depths, a BRAM block
// plus a regular axi_fifo will be instantiated. The depth of the
// combined FIFO in that case will be larger than the user request.
//
// Requirements:
// Implementation for fifo_short_2clk, fifo_4k_2clk that infer SRL
// and BRAM based clock-crossing FIFOs respectively
//
//////////////////////////////////////////////////////////////////////
module axi_fifo_2clk #(
parameter WIDTH = 69, // Width of input/output data word
parameter SIZE = 9, // log2 of the depth of the FIFO
parameter PIPELINE = "NONE", // Which ports to pipeline? {NONE, IN, OUT, INOUT}
parameter DEVICE = "7SERIES" // FPGA technology identifier (for optimal inference)
)(
input wire reset,
input wire i_aclk,
input wire [WIDTH-1:0] i_tdata,
input wire i_tvalid,
output wire i_tready,
input wire o_aclk,
output wire [WIDTH-1:0] o_tdata,
output wire o_tvalid,
input wire o_tready
);
wire i_arst, o_arst;
synchronizer #(.INITIAL_VAL(1'b1)) i_rst_sync_i (
.clk(i_aclk), .rst(1'b0), .in(reset), .out(i_arst)
);
synchronizer #(.INITIAL_VAL(1'b1)) o_rst_sync_i (
.clk(o_aclk), .rst(1'b0), .in(reset), .out(o_arst)
);
//----------------------------------------------
// Pipeline Logic
//----------------------------------------------
wire [WIDTH-1:0] i_pipe_tdata, o_pipe_tdata;
wire i_pipe_tvalid, o_pipe_tvalid;
wire i_pipe_tready, o_pipe_tready;
generate
if (PIPELINE == "IN" || PIPELINE == "INOUT") begin
axi_fifo_flop2 #(.WIDTH(WIDTH)) in_pipe_i (
.clk(i_aclk), .reset(i_arst), .clear(1'b0),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(i_pipe_tdata), .o_tvalid(i_pipe_tvalid), .o_tready(i_pipe_tready),
.space(), .occupied()
);
end else begin
assign {i_pipe_tdata, i_pipe_tvalid} = {i_tdata, i_tvalid};
assign i_tready = i_pipe_tready;
end
if (PIPELINE == "OUT" || PIPELINE == "INOUT") begin
axi_fifo_flop2 #(.WIDTH(WIDTH)) out_pipe_i (
.clk(o_aclk), .reset(o_arst), .clear(1'b0),
.i_tdata(o_pipe_tdata), .i_tvalid(o_pipe_tvalid), .i_tready(o_pipe_tready),
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied()
);
end else begin
assign {o_tdata, o_tvalid} = {o_pipe_tdata, o_pipe_tvalid};
assign o_pipe_tready = o_tready;
end
endgenerate
//----------------------------------------------
// FIFO Logic
//----------------------------------------------
wire [WIDTH-1:0] o_ext_tdata;
wire o_ext_tvalid;
wire o_ext_tready;
// Ideally the following parameters should be technology
// specific. For now these values have been optimized for
// 7Series FPGAs. They also work for Spartan6 but may not
// be optimal. For future generations, make these values
// depend on the DEVICE parameter.
localparam BASE_WIDTH = 72;
localparam SRL_THRESHOLD = 5;
localparam RAM_THRESHOLD = 9;
// How many parallel FIFOs to instantiate to fit WIDTH
localparam NUM_FIFOS = ((WIDTH-1)/BASE_WIDTH)+1;
localparam INT_WIDTH = BASE_WIDTH * NUM_FIFOS;
wire [INT_WIDTH-1:0] wr_data, rd_data;
wire [NUM_FIFOS-1:0] full, empty;
wire wr_en, rd_en;
// Read/write logic for FIFO sections
assign wr_data = {{(INT_WIDTH-WIDTH){1'b0}}, i_pipe_tdata};
assign wr_en = i_pipe_tready & i_pipe_tvalid;
assign i_pipe_tready = &(~full);
assign o_ext_tdata = rd_data[WIDTH-1:0];
assign o_ext_tvalid = &(~empty);
assign rd_en = o_ext_tready & o_ext_tvalid;
// FIFO IP instantiation
genvar i;
generate
for (i = 0; i < NUM_FIFOS; i = i + 1) begin: fifo_section
if (SIZE <= SRL_THRESHOLD) begin
fifo_short_2clk impl_srl_i (
.rst (i_arst),
.wr_clk (i_aclk),
.din (wr_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
.wr_en (wr_en),
.full (full[i]),
.wr_data_count(),
.rd_clk (o_aclk),
.dout (rd_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
.rd_en (rd_en),
.empty (empty[i]),
.rd_data_count()
);
end else begin
fifo_4k_2clk impl_bram_i (
.rst (i_arst),
.wr_clk (i_aclk),
.din (wr_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
.wr_en (wr_en),
.full (full[i]),
.wr_data_count(),
.rd_clk (o_aclk),
.dout (rd_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
.rd_en (rd_en),
.empty (empty[i]),
.rd_data_count()
);
end
end
endgenerate
//----------------------------------------------
// Extension FIFO (for large sizes)
//----------------------------------------------
generate
if (SIZE > RAM_THRESHOLD) begin
wire [WIDTH-1:0] ext_pipe_tdata;
wire ext_pipe_tvalid;
wire ext_pipe_tready;
// Add a register slice between BRAM cascades
axi_fifo_flop2 #(.WIDTH(WIDTH)) ext_fifo_pipe_i (
.clk(o_aclk), .reset(o_arst), .clear(1'b0),
.i_tdata(o_ext_tdata), .i_tvalid(o_ext_tvalid), .i_tready(o_ext_tready),
.o_tdata(ext_pipe_tdata), .o_tvalid(ext_pipe_tvalid), .o_tready(ext_pipe_tready),
.space(), .occupied()
);
// Bolt on an extension FIFO if the requested depth is larger than the BRAM
// 2clk FIFO primitive (IP)
axi_fifo_bram #(.WIDTH(WIDTH), .SIZE(SIZE)) ext_fifo_i (
.clk(o_aclk), .reset(o_arst), .clear(1'b0),
.i_tdata(ext_pipe_tdata), .i_tvalid(ext_pipe_tvalid), .i_tready(ext_pipe_tready),
.o_tdata(o_pipe_tdata), .o_tvalid(o_pipe_tvalid), .o_tready(o_pipe_tready),
.space(), .occupied()
);
end else begin
assign {o_pipe_tdata, o_pipe_tvalid} = {o_ext_tdata, o_ext_tvalid};
assign o_ext_tready = o_pipe_tready;
end
endgenerate
endmodule
+119
View File
@@ -0,0 +1,119 @@
//
// Copyright 2013 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
`timescale 1ns/1ps
module axi_fifo_32_64_tb();
reg clk = 0;
reg reset = 1;
always #10 clk = ~clk;
initial $dumpfile("axi_fifo_32_64_tb.vcd");
initial $dumpvars(0,axi_fifo_32_64_tb);
task send_packet;
input [63:0] data_start;
input [2:0] user;
input [31:0] len;
begin
@(posedge clk);
{i_tuser, i_tlast, i_tdata} <= { 3'd0, 1'b0, data_start };
repeat(len-1)
begin
i_tvalid <= 1;
@(posedge clk);
i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
end
i_tuser <= user;
i_tlast <= 1;
@(posedge clk);
i_tvalid <= 1'b0;
@(posedge clk);
end
endtask // send_packet
initial
begin
#1000 reset = 0;
#200000;
$finish;
end
reg [63:0] i_tdata;
reg [2:0] i_tuser;
reg i_tlast;
reg i_tvalid;
wire i_tready;
wire [63:0] i_tdata_int;
wire [2:0] i_tuser_int;
wire i_tlast_int, i_tvalid_int, i_tready_int;
wire [63:0] o_tdata;
wire [31:0] o_tdata_int, o_tdata_int2;
wire [2:0] o_tuser;
wire [1:0] o_tuser_int, o_tuser_int2;
wire o_tlast, o_tlast_int, o_tvalid, o_tvalid_int, o_tready, o_tready_int;
wire o_tlast_int2, o_tvalid_int2, o_tready_int2;
localparam RPT_COUNT = 16;
initial
begin
i_tvalid <= 0;
while(reset)
@(posedge clk);
@(posedge clk);
send_packet(64'hA0000000_A0000001, 3'd7, 4);
@(posedge clk);
end // initial begin
axi_fifo #(.WIDTH(68), .SIZE(10)) fifo
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({i_tlast,i_tuser,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata({i_tlast_int,i_tuser_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int));
axi_fifo64_to_fifo32 dut
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata(i_tdata_int), .i_tuser(i_tuser_int), .i_tlast(i_tlast_int), .i_tvalid(i_tvalid_int), .i_tready(i_tready_int),
.o_tdata(o_tdata_int), .o_tuser(o_tuser_int), .o_tlast(o_tlast_int), .o_tvalid(o_tvalid_int), .o_tready(o_tready_int));
/*
axi_fifo #(.WIDTH(35), .SIZE(10)) fifo_middle
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({o_tlast_int,o_tuser_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
.o_tdata({o_tlast_int2,o_tuser_int2,o_tdata_int2}), .o_tvalid(o_tvalid_int2), .o_tready(o_tready_int2));
*/
assign o_tdata_int2 = o_tdata_int;
assign o_tlast_int2 = o_tlast_int;
assign o_tuser_int2 = o_tuser_int;
assign o_tvalid_int2 = o_tvalid_int;
assign o_tready_int = o_tready_int2;
axi_fifo32_to_fifo64 dut2
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata(o_tdata_int2), .i_tuser(o_tuser_int2), .i_tlast(o_tlast_int2), .i_tvalid(o_tvalid_int2), .i_tready(o_tready_int2),
.o_tdata(o_tdata), .o_tuser(o_tuser), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready));
assign o_tready = 1'b1;
always @(posedge clk)
if(i_tvalid & i_tready)
$display("IN: TUSER %x\tTLAST %x\tTDATA %x", i_tuser, i_tlast, i_tdata);
always @(posedge clk)
if(o_tvalid_int & o_tready_int)
$display("\t\t\t\t\t\tMIDDLE: TUSER %x\tTLAST %x\tTDATA %x", o_tuser_int, o_tlast_int, o_tdata_int);
always @(posedge clk)
if(o_tvalid & o_tready)
$display("\t\t\t\t\t\t\t\t\t\t\tOUT: TUSER %x\tTLAST %x\tTDATA %x", o_tuser, o_tlast, o_tdata);
endmodule // axi_fifo_32_64_tb
+174
View File
@@ -0,0 +1,174 @@
//
// Copyright 2012-2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Block RAM AXI fifo
module axi_fifo_bram
#(parameter WIDTH=32, SIZE=9)
(input clk, input reset, input clear,
input [WIDTH-1:0] i_tdata,
input i_tvalid,
output i_tready,
output reg [WIDTH-1:0] o_tdata = 'd0,
output reg o_tvalid = 1'b0,
input o_tready,
output reg [15:0] space,
output reg [15:0] occupied);
wire [WIDTH-1:0] int_tdata;
wire int_tready;
wire full, empty;
wire write = i_tvalid & i_tready;
// read_int will assert when either a read occurs or the output register is empty (and there is data in the shift register fifo)
wire read_int = ~empty & int_tready;
// read will only assert when an actual 1read request occurs at the interface
wire read = o_tready & o_tvalid;
assign i_tready = ~full;
// Read side states
localparam ST_EMPTY = 0;
localparam PRE_READ = 1;
localparam READING = 2;
reg [SIZE-1:0] wr_addr, rd_addr;
reg [1:0] read_state;
reg empty_reg = 1'b1, full_reg = 1'b0;
always @(posedge clk)
if(reset)
wr_addr <= 0;
else if(clear)
wr_addr <= 0;
else if(write)
wr_addr <= wr_addr + 1;
ram_2port #(.DWIDTH(WIDTH),.AWIDTH(SIZE))
ram (.clka(clk),
.ena(1'b1),
.wea(write),
.addra(wr_addr),
.dia(i_tdata),
.doa(),
.clkb(clk),
.enb((read_state==PRE_READ)|read_int),
.web(1'b0),
.addrb(rd_addr),
.dib({WIDTH{1'b1}}),
.dob(int_tdata));
always @(posedge clk)
if(reset)
begin
read_state <= ST_EMPTY;
rd_addr <= 0;
empty_reg <= 1;
end
else
if(clear)
begin
read_state <= ST_EMPTY;
rd_addr <= 0;
empty_reg <= 1;
end
else
case(read_state)
ST_EMPTY :
if(write)
begin
//rd_addr <= wr_addr;
read_state <= PRE_READ;
end
PRE_READ :
begin
read_state <= READING;
empty_reg <= 0;
rd_addr <= rd_addr + 1;
end
READING :
if(read_int)
if(rd_addr == wr_addr)
begin
empty_reg <= 1;
if(write)
read_state <= PRE_READ;
else
read_state <= ST_EMPTY;
end
else
rd_addr <= rd_addr + 1;
endcase // case(read_state)
wire [SIZE-1:0] dont_write_past_me = rd_addr - 2;
wire becoming_full = wr_addr == dont_write_past_me;
always @(posedge clk)
if(reset)
full_reg <= 0;
else if(clear)
full_reg <= 0;
else if(read_int & ~write)
full_reg <= 0;
//else if(write & ~read_int & (wr_addr == (rd_addr-3)))
else if(write & ~read_int & becoming_full)
full_reg <= 1;
//assign empty = (read_state != READING);
assign empty = empty_reg;
// assign full = ((rd_addr - 1) == wr_addr);
assign full = full_reg;
// Output registered stage
always @(posedge clk)
begin
// Valid flag
if (reset | clear)
o_tvalid <= 1'b0;
else if (int_tready)
o_tvalid <= ~empty;
// Data
if (int_tready)
o_tdata <= int_tdata;
end
assign int_tready = o_tready | ~o_tvalid;
//////////////////////////////////////////////
// space and occupied are for diagnostics only
// not guaranteed exact
localparam NUMLINES = (1<<SIZE)+1; //Output register increases capacity by 1
always @(posedge clk)
if(reset)
space <= NUMLINES;
else if(clear)
space <= NUMLINES;
else if(read & ~write)
space <= space + 16'b1;
else if(write & ~read)
space <= space - 16'b1;
always @(posedge clk)
if(reset)
occupied <= 16'b0;
else if(clear)
occupied <= 16'b0;
else if(read & ~write)
occupied <= occupied - 16'b1;
else if(write & ~read)
occupied <= occupied + 16'b1;
endmodule // fifo_long
+48
View File
@@ -0,0 +1,48 @@
//
// Copyright 2012-2013 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Cascade FIFO : ShortFIFO -> Block RAM fifo -> ShortFIFO for timing and placement help
// Special case SIZE <= 5 uses a short fifo in the middle, which is not too useful in this case
module axi_fifo_cascade
#(parameter WIDTH=32, SIZE=9)
(input clk, input reset, input clear,
input [WIDTH-1:0] i_tdata,
input i_tvalid,
output i_tready,
output [WIDTH-1:0] o_tdata,
output o_tvalid,
input o_tready,
output [15:0] space,
output [15:0] occupied);
wire [WIDTH-1:0] int1_tdata, int2_tdata;
wire int1_tvalid, int1_tready, int2_tvalid, int2_tready;
axi_fifo_flop2 #(.WIDTH(WIDTH)) pre_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(int1_tdata), .o_tvalid(int1_tvalid), .o_tready(int1_tready),
.space(), .occupied());
axi_fifo #(.WIDTH(WIDTH), .SIZE(SIZE)) main_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata(int1_tdata), .i_tvalid(int1_tvalid), .i_tready(int1_tready),
.o_tdata(int2_tdata), .o_tvalid(int2_tvalid), .o_tready(int2_tready),
.space(space), .occupied(occupied)); // May change unexpectedly, but are always conservative
axi_fifo_flop2 #(.WIDTH(WIDTH)) post_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata(int2_tdata), .i_tvalid(int2_tvalid), .i_tready(int2_tready),
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
endmodule // axi_fifo_cascade
+43
View File
@@ -0,0 +1,43 @@
//
// Copyright 2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
//
// Single FIFO (register) with AXI4-STREAM interface
//
module axi_fifo_flop
#(parameter WIDTH=32)
(input clk,
input reset,
input clear,
input [WIDTH-1:0] i_tdata,
input i_tvalid,
output i_tready,
output reg [WIDTH-1:0] o_tdata = 'd0,
output reg o_tvalid = 1'b0,
input o_tready,
output space,
output occupied);
assign i_tready = ~reset & (~o_tvalid | o_tready);
always @(posedge clk)
if(reset | clear)
o_tvalid <= 1'b0;
else
o_tvalid <= (i_tready & i_tvalid) | (o_tvalid & ~o_tready);
always @(posedge clk)
if(i_tvalid & i_tready)
o_tdata <= i_tdata;
// These aren't terribly useful, but include them for consistency
assign space = i_tready;
assign occupied = o_tvalid;
endmodule // axi_fifo_flop
+59
View File
@@ -0,0 +1,59 @@
//
// Copyright 2015 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Single cycle latency, depth of 2 "Flip flop" with no end to end combinatorial paths on
// AXI control signals (such as i_tready depends on o_tready). Breaking the combinatorial
// paths requires an additional register stage.
//
// Note: Once i_tvalid is asserted, it cannot be deasserted without i_tready having asserted
// indicating i_tdata has been read. This is an AXI stream requirement.
module axi_fifo_flop2 #(
parameter WIDTH = 32
)(
input clk,
input reset,
input clear,
input [WIDTH-1:0] i_tdata,
input i_tvalid,
output i_tready,
output reg [WIDTH-1:0] o_tdata = 'h0,
output reg o_tvalid = 1'b0,
input o_tready,
output [1:0] space,
output [1:0] occupied);
reg [WIDTH-1:0] i_tdata_temp = 'h0;
reg i_tvalid_temp = 1'b0;
assign i_tready = ~i_tvalid_temp;
always @(posedge clk) begin
if (~o_tvalid | o_tready) begin
if (i_tvalid_temp) begin
o_tvalid <= 1'b1;
o_tdata <= i_tdata_temp;
end else begin
o_tvalid <= i_tvalid;
o_tdata <= i_tdata;
end
i_tvalid_temp <= 1'b0;
end else begin
if (~i_tvalid_temp) begin
i_tvalid_temp <= i_tvalid;
i_tdata_temp <= i_tdata;
end
end
if (reset | clear) begin
o_tvalid <= 1'b0;
i_tvalid_temp <= 1'b0;
end
end
assign occupied = i_tvalid_temp + o_tvalid;
assign space = 2 - occupied;
endmodule
+113
View File
@@ -0,0 +1,113 @@
//
// Copyright 2012 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
//
// 32 word FIFO with AXI4-STREAM interface.
//
// NOTE: This module uses the SRLC32E primitive explicitly and as such
// can only be used with Xilinx technology of the VIRTEX-6/SPARTAN-6/SIERIES-7 or newer.
//
module axi_fifo_short
#(parameter WIDTH=32)
(
input clk,
input reset,
input clear,
input [WIDTH-1:0] i_tdata,
input i_tvalid,
output i_tready,
output [WIDTH-1:0] o_tdata,
output o_tvalid,
input o_tready,
output reg [5:0] space,
output reg [5:0] occupied
);
reg full = 1'b0, empty = 1'b1;
wire write = i_tvalid & i_tready;
wire read = o_tready & o_tvalid;
assign i_tready = ~full;
assign o_tvalid = ~empty;
reg [4:0] a;
genvar i;
generate
for (i=0;i<WIDTH;i=i+1)
begin : gen_srlc32e
SRLC32E
srlc32e(.Q(o_tdata[i]), .Q31(),
.A(a), //.A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),.A4(a[4]),
.CE(write),.CLK(clk),.D(i_tdata[i]));
end
endgenerate
always @(posedge clk)
if(reset)
begin
a <= 0;
empty <= 1;
full <= 0;
end
else if(clear)
begin
a <= 0;
empty <= 1;
full<= 0;
end
else if(read & ~write)
begin
full <= 0;
if(a==0)
empty <= 1;
else
a <= a - 1;
end
else if(write & ~read)
begin
empty <= 0;
if(~empty)
a <= a + 1;
if(a == 30)
full <= 1;
end
// NOTE will fail if you write into a full fifo or read from an empty one
//////////////////////////////////////////////////////////////
// space and occupied are used for diagnostics, not
// guaranteed correct
//assign space = full ? 0 : empty ? 16 : 15-a;
//assign occupied = empty ? 0 : full ? 16 : a+1;
always @(posedge clk)
if(reset)
space <= 6'd32;
else if(clear)
space <= 6'd32;
else if(read & ~write)
space <= space + 6'd1;
else if(write & ~read)
space <= space - 6'd1;
always @(posedge clk)
if(reset)
occupied <= 6'd0;
else if(clear)
occupied <= 6'd0;
else if(read & ~write)
occupied <= occupied - 6'd1;
else if(write & ~read)
occupied <= occupied + 6'd1;
endmodule // axi_fifo_short
+328
View File
@@ -0,0 +1,328 @@
//
// Copyright 2015 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module axi_fifo_tb();
/*********************************************
** User variables
*********************************************/
localparam FIFO_SIZE = 1;
localparam TEST_VECTOR_SIZE = 10;
/*********************************************
** Clocks & Reset
*********************************************/
`define CLOCK_FREQ 200e6
`define RESET_TIME 100
reg clk;
initial clk = 1'b0;
localparam CLOCK_PERIOD = 1e9/`CLOCK_FREQ;
always
#(CLOCK_PERIOD) clk = ~clk;
reg reset;
initial begin
reset = 1'b1;
#(`RESET_TIME);
@(posedge clk);
reset = 1'b0;
end
/*********************************************
** DUT
*********************************************/
reg [31:0] i_tdata;
reg i_tvalid, o_tready;
wire i_tready, o_tvalid;
wire [31:0] o_tdata;
reg clear;
axi_fifo #(
.SIZE(FIFO_SIZE),
.WIDTH(32))
dut_axi_fifo (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
/*********************************************
** Testbench
*********************************************/
reg [TEST_VECTOR_SIZE-1:0] i_tvalid_sequence;
reg [TEST_VECTOR_SIZE-1:0] o_tready_sequence;
integer i,k,n,i_tready_timeout;
reg [31:0] o_tdata_check;
initial begin
i_tdata = {32{1'b1}};
i_tvalid = 1'b0;
o_tready = 1'b0;
i_tready_timeout = 0;
clear = 1'b0;
@(negedge reset);
#(10*CLOCK_PERIOD)
@(posedge clk);
$display("*****************************************************");
$display("** Begin Assertion Tests **");
$display("*****************************************************");
$display("Test 1 -- Check filling FIFO");
// Note, if REG_OUTPUT is enabled, the FIFO has space for 1 extra entry
for (i = 0; i < 2**FIFO_SIZE; i = i + 1) begin
if (~i_tready) begin
$display("Test 1 FAILED!");
$error("FIFO size should be %d entries, but detected %d!",2**FIFO_SIZE,i);
$stop;
end
i_tvalid = 1'b1;
i_tdata = i_tdata + 32'd1;
@(posedge clk);
end
i_tvalid = 1'b0;
@(posedge clk);
if (i_tready) begin
$display("Test 1 warning!");
$warning("i_tready still asserted after filling FIFO with %d entries! Might be due to output registering.",i);
//$stop;
end
$display("Test 1 Passed!");
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
$display("Test 2 -- Check emptying FIFO");
for (i = 0; i < 2**FIFO_SIZE; i = i + 1) begin
if (~o_tvalid) begin
$display("Test 2 FAILED!");
$error("FIFO o_tvalid not asserted! Occured at entry %d",2**FIFO_SIZE-i+1);
$stop;
end
o_tready = 1'b1;
@(posedge clk);
end
o_tready = 1'b0;
@(posedge clk);
if (o_tvalid) begin
$display("Test 1 FAILED!");
$error("o_tvalid still asserted after emptying FIFO!");
$stop;
end
$display("Test 2 Passed!");
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
$display("Test 3 -- Check for o_tready / i_tready dropping unexpectantly");
clear = 1'b1;
i_tdata = {32{1'b1}};
i_tvalid = 1'b0;
o_tready = 1'b0;
@(posedge clk);
clear = 1'b0;
@(posedge clk);
for (i = 0; i < 2**FIFO_SIZE-1; i = i + 1) begin
i_tvalid = 1'b1;
i_tdata = i_tdata + 32'd1;
@(posedge clk);
i_tvalid = 1'b0;
// Give some time to propogate
@(posedge clk);
@(posedge clk);
@(posedge clk);
if (~i_tready) begin
$display("Test 3 FAILED!");
$error("i_tready deasserted unexpectantly after writing %d entries!",i+1);
$stop;
end
if (~o_tvalid) begin
$display("Test 3 FAILED!");
$error("o_tvalid deasserted unexpectantly after writing %d entries!",i+1);
$stop;
end
end
// Write final entry
i_tvalid = 1'b1;
i_tdata = i_tdata + 32'd1;
@(posedge clk);
i_tvalid = 1'b0;
@(posedge clk);
if (i_tready) begin
$display("Test 3 warning!");
$warning("i_tready still asserted after writing %d entries! Might be due to output registering.",i+1);
//$stop;
end
@(posedge clk);
for (i = 0; i < 2**FIFO_SIZE-1; i = i + 1) begin
o_tready = 1'b1;
@(posedge clk);
o_tready = 1'b0;
// Give some time to propogate
@(posedge clk);
@(posedge clk);
@(posedge clk);
if (~i_tready) begin
$display("Test 3 FAILED!");
$error("i_tready deasserted unexpectantly after reading %d entries!",i+1);
$stop;
end
if (~o_tvalid) begin
$display("Test 3 FAILED!");
$error("o_tvalid deasserted unexpectantly after reading %d entries!",i+1);
$stop;
end
end
// Read final entry
o_tready = 1'b1;
@(posedge clk);
o_tready = 1'b0;
@(posedge clk);
if (o_tvalid) begin
$display("Test 3 FAILED!");
$error("o_tvalid still asserted after reading %d entries!",i+1);
$stop;
end
@(posedge clk);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
$display("Test 4 -- Check for bubble states");
clear = 1'b1;
i_tdata = {32{1'b1}};
i_tvalid = 1'b0;
o_tready = 1'b0;
@(posedge clk);
clear = 1'b0;
@(posedge clk);
// Fill up half way
for (i = 0; i < (2**FIFO_SIZE + 1)/2; i = i + 1) begin
i_tvalid = 1'b1;
i_tdata = i_tdata + 32'd1;
@(posedge clk);
end
// Start reading
o_tready = 1'b1;
i_tdata = i_tdata + 32'd1;
@(posedge clk);
// Give a clock cycle for latency, but no bubbles should occur after this
i_tdata = i_tdata + 32'd1;
@(posedge clk);
// Continue to write and read at full rate
for (i = 0; i < (2**FIFO_SIZE + 1)/2; i = i + 1) begin
if (~i_tready) begin
$display("Test 4 FAILED!");
$error("FIFO bubble state detected when writing & reading at full rate!");
$stop;
end
i_tvalid = 1'b1;
i_tdata = i_tdata + 32'd1;
@(posedge clk);
end
// Read at full, write at half rate
for (i = 0; i < (2**FIFO_SIZE + 1)/2; i = i + 1) begin
if (~i_tready | ~o_tvalid) begin
$display("Test 4 FAILED!");
$error("FIFO bubble state detected when write at half rate, reading at full rate!");
$stop;
end
i_tvalid = ~i_tvalid;
if (i_tvalid) i_tdata = i_tdata + 32'd1;
@(posedge clk);
end
// Read at half rate, write at full rate
for (i = 0; i < (2**FIFO_SIZE + 1)/2; i = i + 1) begin
if (~i_tready | ~o_tvalid) begin
$display("Test 4 FAILED!");
$error("FIFO bubble state detected when write at half rate, reading at full rate!");
$stop;
end
o_tready = ~o_tready;
i_tvalid = 1'b1;
i_tdata = i_tdata + 32'd1;
@(posedge clk);
end
$display("Test 4 Passed!");
//////////////////////////////////////////////////////////////////////////////
// Tests combinations of i_tvalid / o_tready sequences.
// Test space depends on TEST_VECTOR_SIZE.
// Example: TEST_VECTOR_SIZE = 10 => 1024*1024 number of test sequences,
// which is every possible 10 bit sequence of i_tvalid / o_tready.
$display("Test 5 -- Check combinations of i_tvalid / o_tready");
clear = 1'b1;
i_tdata = {32{1'b1}};
i_tvalid = 1'b0;
o_tready = 1'b0;
i_tready_timeout = 0;
i_tvalid_sequence = {TEST_VECTOR_SIZE{1'd0}};
o_tready_sequence = {TEST_VECTOR_SIZE{1'd0}};
@(posedge clk);
clear = 1'b0;
@(posedge clk);
for (i = 0; i < 2**TEST_VECTOR_SIZE; i = i + 1) begin
i_tvalid_sequence = i_tvalid_sequence + 1;
for (k = 0; k < 2**TEST_VECTOR_SIZE; k = k + 1) begin
o_tready_sequence = o_tready_sequence + 1;
for (n = 0; n < TEST_VECTOR_SIZE; n = n + 1) begin
if (o_tready_sequence[n]) begin
o_tready = 1'b1;
end else begin
o_tready = 1'b0;
end
// Special Case: If i_tready timed out, then i_tvalid is still asserted and we cannot
// deassert i_tvalid until we see a corresponding i_tready. This is a basic
// AXI stream requirement, so we will continue to assert i_tvalid regardless
// of what i_tvalid_sequence would have set i_tvalid for this loop.
if (i_tvalid_sequence[n] | (i_tready_timeout == TEST_VECTOR_SIZE)) begin
i_tvalid = 1'b1;
if (i_tready_timeout < TEST_VECTOR_SIZE) begin
i_tdata = i_tdata + 32'd1;
end
@(posedge clk);
i_tready_timeout = 0;
// Wait for i_tready until timeout. Timeouts may occur when o_tready_sequence
// has o_tready not asserted for several clock cycles.
while(~i_tready & (i_tready_timeout < TEST_VECTOR_SIZE)) begin
@(posedge clk)
i_tready_timeout = i_tready_timeout + 1;
end
end else begin
i_tvalid = 1'b0;
@(posedge clk);
end
end
end
// Reset starting conditions for the test sequences
clear = 1'b1;
i_tdata = {32{1'b1}};
i_tvalid = 1'b0;
o_tready = 1'b0;
i_tready_timeout = 0;
@(posedge clk);
clear = 1'b0;
@(posedge clk);
end
$display("Test 5 Passed!");
$display("All tests PASSED!");
$stop;
end
// Check the input counting sequence independent of
// i_tvalid / o_tready sequences.
always @(posedge clk) begin
if (reset) begin
o_tdata_check <= 32'd0;
end else begin
if (clear) begin
o_tdata_check <= 32'd0;
end
if (o_tready & o_tvalid) begin
o_tdata_check <= o_tdata_check + 32'd1;
if (o_tdata != o_tdata_check) begin
$display("Test FAILED!");
$error("Incorrect output!");
$stop;
end
end
end
end
endmodule
+158
View File
@@ -0,0 +1,158 @@
//
// Copyright 2014 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// axi_filter_mux -- takes 4 64-bit AXI stream of CHDR data, merges them to 1 output channel
// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
// Bubble cycles are inserted after each packet in PRIO mode, or on wraparound in Round Robin mode.
// Filter forces specific destination SID to pass per port, else dump data to /dev/null
module axi_filter_mux4
#(parameter PRIO=0,
parameter WIDTH=64,
parameter BUFFER=0,
parameter FILTER0 =0,
parameter FILTER1 =0,
parameter FILTER2 =0,
parameter FILTER3 =0
)
(input clk, input reset, input clear,
input [WIDTH-1:0] i0_tdata, input i0_tlast, input i0_tvalid, output i0_tready,
input [WIDTH-1:0] i1_tdata, input i1_tlast, input i1_tvalid, output i1_tready,
input [WIDTH-1:0] i2_tdata, input i2_tlast, input i2_tvalid, output i2_tready,
input [WIDTH-1:0] i3_tdata, input i3_tlast, input i3_tvalid, output i3_tready,
output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
wire [WIDTH-1:0] o_tdata_int;
wire o_tlast_int, o_tvalid_int, o_tready_int;
reg [3:0] mx_state;
reg filter_packet;
localparam MX_IDLE = 4'b0000;
localparam MX_0 = 4'b0001;
localparam MX_1 = 4'b0010;
localparam MX_2 = 4'b0100;
localparam MX_3 = 4'b1000;
assign good0 = i0_tdata[15:0]==FILTER0;
assign good1 = i1_tdata[15:0]==FILTER1;
assign good2 = i2_tdata[15:0]==FILTER2;
assign good3 = i3_tdata[15:0]==FILTER3;
always @(posedge clk)
if(reset | clear)
mx_state <= MX_IDLE;
else
case (mx_state)
MX_IDLE :
if(i0_tvalid) begin
mx_state <= MX_0;
filter_packet <= !good0;
end
else if(i1_tvalid) begin
mx_state <= MX_1;
filter_packet <= !good1;
end
else if(i2_tvalid) begin
mx_state <= MX_2;
filter_packet <= !good2;
end
else if(i3_tvalid) begin
mx_state <= MX_3;
filter_packet <= !good3;
end
MX_0 :
if(o_tready_int & o_tvalid_int & o_tlast_int)
if(PRIO)
mx_state <= MX_IDLE;
else if(i1_tvalid) begin
mx_state <= MX_1;
filter_packet <= !good1;
end
else if(i2_tvalid) begin
mx_state <= MX_2;
filter_packet <= !good2;
end
else if(i3_tvalid) begin
mx_state <= MX_3;
filter_packet <= !good3;
end
else begin
mx_state <= MX_IDLE;
filter_packet <= 0;
end
MX_1 :
if(o_tready_int & o_tvalid_int & o_tlast_int)
if(PRIO)
mx_state <= MX_IDLE;
else if(i2_tvalid) begin
mx_state <= MX_2;
filter_packet <= !good2;
end
else if(i3_tvalid) begin
mx_state <= MX_3;
filter_packet <= !good3;
end
else begin
mx_state <= MX_IDLE;
filter_packet <= 0;
end
MX_2 :
if(o_tready_int & o_tvalid_int & o_tlast_int)
if(PRIO)
mx_state <= MX_IDLE;
else if(i3_tvalid) begin
mx_state <= MX_3;
filter_packet <= !good3;
end
else begin
mx_state <= MX_IDLE;
filter_packet <= 0;
end
MX_3 :
if(o_tready_int & o_tvalid_int & o_tlast_int)
begin
mx_state <= MX_IDLE;
filter_packet <= 0;
end
default :
mx_state <= MX_IDLE;
endcase // case (mx_state)
assign {i3_tready, i2_tready, i1_tready, i0_tready} = mx_state & {4{o_tready_int}};
assign o_tvalid_int = |(mx_state & ({i3_tvalid, i2_tvalid, i1_tvalid, i0_tvalid}));
assign {o_tlast_int, o_tdata_int} = mx_state[3] ? {i3_tlast, i3_tdata} :
mx_state[2] ? {i2_tlast, i2_tdata} :
mx_state[1] ? {i1_tlast, i1_tdata} :
{i0_tlast, i0_tdata};
generate
if(BUFFER == 0)
begin
assign o_tdata = o_tdata_int;
assign o_tlast = o_tlast_int;
assign o_tvalid = o_tvalid_int & !filter_packet;
assign o_tready_int = o_tready | filter_packet;
end
else
begin
wire o_tready_int_fifo;
assign o_tready_int = o_tready_int_fifo | filter_packet;
axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int & !filter_packet), .i_tready(o_tready_int_fifo),
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
end
endgenerate
endmodule // axi__mux4
+75
View File
@@ -0,0 +1,75 @@
//
// Copyright 2012 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
//
// axi_loopback.v
//
// Loopback all data assuming it's in CHDR format, and swap SRC/DST in the SID in the process
// thus reflecting it back to it's origin...in theory!
//
module axi_loopback
#(
parameter WIDTH = 64
)
(
input clk,
input reset,
// Input AXIS
input [WIDTH-1:0] i_tdata,
input i_tlast,
input i_tvalid,
output i_tready,
// Output AXIS
output [WIDTH-1:0] o_tdata,
output o_tlast,
output o_tvalid,
input o_tready
);
wire [WIDTH-1:0] fifoin_tdata,fifoout_tdata,dmux_tdata;
wire fifoin_tlast,dmux_tlast;
wire fifoin_tvalid,dmux_tvalid;
wire fifoin_tready,dmux_tready;
// Since most real endpoints go via Demux4 place one in here to look for bugs.
axi_demux4 #(.ACTIVE_CHAN(4'b0001), .WIDTH(WIDTH)) demux
(.clk(clk), .reset(reset), .clear(1'b0),
.header(), .dest(2'b00),
.i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o0_tdata(dmux_tdata), .o0_tlast(dmux_tlast), .o0_tvalid(dmux_tvalid), .o0_tready(dmux_tready),
.o1_tdata(), .o1_tlast(), .o1_tvalid(), .o1_tready(1'b1),
.o2_tdata(), .o2_tlast(), .o2_tvalid(), .o2_tready(1'b1),
.o3_tdata(), .o3_tlast(), .o3_tvalid(), .o3_tready(1'b1));
axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short1
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({dmux_tlast,dmux_tdata}), .i_tvalid(dmux_tvalid), .i_tready(dmux_tready),
.o_tdata({fifoin_tlast,fifoin_tdata}), .o_tvalid(fifoin_tvalid), .o_tready(fifoin_tready),
.space(), .occupied());
reg header;
always @(posedge clk) begin
if(reset) begin
header <= 1'b1;
end else if (header) begin
if(fifoin_tvalid & fifoin_tready & ~fifoin_tlast) header <= 1'b0;
end else begin
if(fifoin_tvalid & fifoin_tready & fifoin_tlast) header <= 1'b1;
end
end
assign fifoout_tdata = header ?
{fifoin_tdata[63:32] ,fifoin_tdata[15:0],fifoin_tdata[31:16]} :
fifoin_tdata;
axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short2
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({fifoin_tlast,fifoout_tdata}), .i_tvalid(fifoin_tvalid), .i_tready(fifoin_tready),
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
endmodule // axi_loopback
+110
View File
@@ -0,0 +1,110 @@
// Copyright 2016 Ettus Research
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// axi_mux -- takes arbitrary number of AXI stream, merges them to 1 output channel
// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
// Bubble cycles are inserted after each packet
module axi_mux
#(parameter PRIO=0,
parameter WIDTH=64,
parameter PRE_FIFO_SIZE=0,
parameter POST_FIFO_SIZE=0,
parameter SIZE=4)
(input clk, input reset, input clear,
input [(WIDTH*SIZE)-1:0] i_tdata, input [SIZE-1:0] i_tlast, input [SIZE-1:0] i_tvalid, output [SIZE-1:0] i_tready,
output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
wire [WIDTH*SIZE-1:0] i_tdata_int;
wire [SIZE-1:0] i_tlast_int, i_tvalid_int, i_tready_int;
wire [WIDTH-1:0] o_tdata_int;
wire o_tlast_int, o_tvalid_int, o_tready_int;
reg [$clog2(SIZE)-1:0] st_port;
reg st_active;
genvar n;
generate
if (PRE_FIFO_SIZE == 0) begin
assign i_tdata_int = i_tdata;
assign i_tlast_int = i_tlast;
assign i_tvalid_int = i_tvalid;
assign i_tready = i_tready_int;
end else begin
for (n = 0; n < SIZE; n = n + 1) begin
axi_fifo #(.WIDTH(WIDTH+1), .SIZE(PRE_FIFO_SIZE)) axi_fifo (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({i_tlast[n],i_tdata[WIDTH*(n+1)-1:WIDTH*n]}), .i_tvalid(i_tvalid[n]), .i_tready(i_tready[n]),
.o_tdata({i_tlast_int[n],i_tdata_int[WIDTH*(n+1)-1:WIDTH*n]}), .o_tvalid(i_tvalid_int[n]), .o_tready(i_tready_int[n]),
.space(), .occupied());
end
end
endgenerate
always @(posedge clk)
if(reset)
begin
st_port <= 0;
st_active <= 1'b0;
end
else
if(st_active)
begin
if(o_tlast_int & o_tvalid_int & o_tready_int)
begin
st_active <= 1'b0;
if((PRIO != 0) | (st_port == (SIZE-1)))
st_port <= 0;
else
st_port <= st_port + 1;
end
end // if (st_active)
else
if(i_tvalid_int[st_port])
st_active <= 1'b1;
else
if(st_port == (SIZE-1))
st_port <= 0;
else
st_port <= st_port + 1;
genvar i;
generate
for(i=0;i<SIZE;i=i+1)
begin : gen1
assign i_tready_int[i] = st_active & o_tready_int & (st_port == i);
end
endgenerate
assign o_tvalid_int = st_active & i_tvalid_int[st_port];
assign o_tlast_int = i_tlast_int[st_port];
genvar j;
generate
for (j=0;j<WIDTH;j=j+1)
begin : gen2
assign o_tdata_int[j] = i_tdata_int[st_port*WIDTH+j];
end
endgenerate
generate
if(POST_FIFO_SIZE == 0)
begin
assign o_tdata = o_tdata_int;
assign o_tlast = o_tlast_int;
assign o_tvalid = o_tvalid_int;
assign o_tready_int = o_tready;
end
else
axi_fifo #(.WIDTH(WIDTH+1),.SIZE(POST_FIFO_SIZE)) axi_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
endgenerate
endmodule // axi__mux
+115
View File
@@ -0,0 +1,115 @@
// Copyright 2012 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// axi_mux -- takes 4 64-bit AXI stream, merges them to 1 output channel
// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
// Bubble cycles are inserted after each packet in PRIO mode, or on wraparound in Round Robin mode
module axi_mux4
#(parameter PRIO=0,
parameter WIDTH=64,
parameter BUFFER=0)
(input clk, input reset, input clear,
input [WIDTH-1:0] i0_tdata, input i0_tlast, input i0_tvalid, output i0_tready,
input [WIDTH-1:0] i1_tdata, input i1_tlast, input i1_tvalid, output i1_tready,
input [WIDTH-1:0] i2_tdata, input i2_tlast, input i2_tvalid, output i2_tready,
input [WIDTH-1:0] i3_tdata, input i3_tlast, input i3_tvalid, output i3_tready,
output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
wire [WIDTH-1:0] o_tdata_int;
wire o_tlast_int, o_tvalid_int, o_tready_int;
reg [3:0] mx_state;
localparam MX_IDLE = 4'b0000;
localparam MX_0 = 4'b0001;
localparam MX_1 = 4'b0010;
localparam MX_2 = 4'b0100;
localparam MX_3 = 4'b1000;
always @(posedge clk)
if(reset | clear)
mx_state <= MX_IDLE;
else
case (mx_state)
MX_IDLE :
if(i0_tvalid)
mx_state <= MX_0;
else if(i1_tvalid)
mx_state <= MX_1;
else if(i2_tvalid)
mx_state <= MX_2;
else if(i3_tvalid)
mx_state <= MX_3;
MX_0 :
if(o_tready_int & o_tvalid_int & o_tlast_int)
if(PRIO)
mx_state <= MX_IDLE;
else if(i1_tvalid)
mx_state <= MX_1;
else if(i2_tvalid)
mx_state <= MX_2;
else if(i3_tvalid)
mx_state <= MX_3;
else
mx_state <= MX_IDLE;
MX_1 :
if(o_tready_int & o_tvalid_int & o_tlast_int)
if(PRIO)
mx_state <= MX_IDLE;
else if(i2_tvalid)
mx_state <= MX_2;
else if(i3_tvalid)
mx_state <= MX_3;
else
mx_state <= MX_IDLE;
MX_2 :
if(o_tready_int & o_tvalid_int & o_tlast_int)
if(PRIO)
mx_state <= MX_IDLE;
else if(i3_tvalid)
mx_state <= MX_3;
else
mx_state <= MX_IDLE;
MX_3 :
if(o_tready_int & o_tvalid_int & o_tlast_int)
if(PRIO)
mx_state <= MX_IDLE;
else
mx_state <= MX_IDLE;
default :
mx_state <= MX_IDLE;
endcase // case (mx_state)
assign {i3_tready, i2_tready, i1_tready, i0_tready} = mx_state & {4{o_tready_int}};
assign o_tvalid_int = |(mx_state & ({i3_tvalid, i2_tvalid, i1_tvalid, i0_tvalid}));
assign {o_tlast_int, o_tdata_int} = mx_state[3] ? {i3_tlast, i3_tdata} :
mx_state[2] ? {i2_tlast, i2_tdata} :
mx_state[1] ? {i1_tlast, i1_tdata} :
{i0_tlast, i0_tdata};
generate
if(BUFFER == 0)
begin
assign o_tdata = o_tdata_int;
assign o_tlast = o_tlast_int;
assign o_tvalid = o_tvalid_int;
assign o_tready_int = o_tready;
end
else
axi_fifo_flop2 #(.WIDTH(WIDTH+1)) axi_fifo_flop2
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
endgenerate
endmodule // axi__mux4
+59
View File
@@ -0,0 +1,59 @@
// Copyright 2012 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// axi_mux -- takes 8 64-bit AXI stream, merges them to 1 output channel
// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
// Bubble cycles are inserted after each packet in PRIO mode, or on wraparound in Round Robin mode
module axi_mux8 #(
parameter PRIO=0,
parameter WIDTH=64,
parameter BUFFER=0
) (
input clk, input reset, input clear,
input [WIDTH-1:0] i0_tdata, input i0_tlast, input i0_tvalid, output i0_tready,
input [WIDTH-1:0] i1_tdata, input i1_tlast, input i1_tvalid, output i1_tready,
input [WIDTH-1:0] i2_tdata, input i2_tlast, input i2_tvalid, output i2_tready,
input [WIDTH-1:0] i3_tdata, input i3_tlast, input i3_tvalid, output i3_tready,
input [WIDTH-1:0] i4_tdata, input i4_tlast, input i4_tvalid, output i4_tready,
input [WIDTH-1:0] i5_tdata, input i5_tlast, input i5_tvalid, output i5_tready,
input [WIDTH-1:0] i6_tdata, input i6_tlast, input i6_tvalid, output i6_tready,
input [WIDTH-1:0] i7_tdata, input i7_tlast, input i7_tvalid, output i7_tready,
output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);
wire [WIDTH-1:0] o_tdata_int0, o_tdata_int1;
wire o_tlast_int0, o_tlast_int1;
wire o_tvalid_int0, o_tvalid_int1;
wire o_tready_int0, o_tready_int1;
axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(0)) mux4_int0 (
.clk(clk), .reset(reset), .clear(clear),
.i0_tdata(i0_tdata), .i0_tlast(i0_tlast), .i0_tvalid(i0_tvalid), .i0_tready(i0_tready),
.i1_tdata(i1_tdata), .i1_tlast(i1_tlast), .i1_tvalid(i1_tvalid), .i1_tready(i1_tready),
.i2_tdata(i2_tdata), .i2_tlast(i2_tlast), .i2_tvalid(i2_tvalid), .i2_tready(i2_tready),
.i3_tdata(i3_tdata), .i3_tlast(i3_tlast), .i3_tvalid(i3_tvalid), .i3_tready(i3_tready),
.o_tdata(o_tdata_int0), .o_tlast(o_tlast_int0), .o_tvalid(o_tvalid_int0), .o_tready(o_tready_int0)
);
axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(0)) mux4_int1 (
.clk(clk), .reset(reset), .clear(clear),
.i0_tdata(i4_tdata), .i0_tlast(i4_tlast), .i0_tvalid(i4_tvalid), .i0_tready(i4_tready),
.i1_tdata(i5_tdata), .i1_tlast(i5_tlast), .i1_tvalid(i5_tvalid), .i1_tready(i5_tready),
.i2_tdata(i6_tdata), .i2_tlast(i6_tlast), .i2_tvalid(i6_tvalid), .i2_tready(i6_tready),
.i3_tdata(i7_tdata), .i3_tlast(i7_tlast), .i3_tvalid(i7_tvalid), .i3_tready(i7_tready),
.o_tdata(o_tdata_int1), .o_tlast(o_tlast_int1), .o_tvalid(o_tvalid_int1), .o_tready(o_tready_int1)
);
axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(BUFFER)) mux2 (
.clk(clk), .reset(reset), .clear(clear),
.i0_tdata(o_tdata_int0), .i0_tlast(o_tlast_int0), .i0_tvalid(o_tvalid_int0), .i0_tready(o_tready_int0),
.i1_tdata(o_tdata_int1), .i1_tlast(o_tlast_int1), .i1_tvalid(o_tvalid_int1), .i1_tready(o_tready_int1),
.i2_tdata(0), .i2_tlast(1'b0), .i2_tvalid(1'b0), .i2_tready(),
.i3_tdata(0), .i3_tlast(1'b0), .i3_tvalid(1'b0), .i3_tready(),
.o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
);
endmodule // axi_mux8
+104
View File
@@ -0,0 +1,104 @@
//
// Copyright 2016 Ettus Research
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// AXI-Stream multipler with select line
//
module axi_mux_select #(
parameter WIDTH = 32,
parameter PRE_FIFO_SIZE = 0,
parameter POST_FIFO_SIZE = 0,
parameter SWITCH_ON_LAST = 0, // Wait until tlast is asserted before updating
parameter SIZE = 4)
(
input clk, input reset, input clear,
input [$clog2(SIZE)-1:0] select,
input [SIZE*WIDTH-1:0] i_tdata, input [SIZE-1:0] i_tlast, input [SIZE-1:0] i_tvalid, output [SIZE-1:0] i_tready,
output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);
wire [WIDTH*SIZE-1:0] i_tdata_int;
wire [WIDTH-1:0] i_tdata_arr[0:SIZE-1];
wire [SIZE-1:0] i_tlast_int, i_tvalid_int, i_tready_int;
wire [WIDTH-1:0] o_tdata_int;
wire o_tlast_int, o_tvalid_int, o_tready_int;
genvar n;
generate
if (PRE_FIFO_SIZE == 0) begin
assign i_tdata_int = i_tdata;
assign i_tlast_int = i_tlast;
assign i_tvalid_int = i_tvalid;
assign i_tready = i_tready_int;
end else begin
for (n = 0; n < SIZE; n = n + 1) begin
axi_fifo #(.WIDTH(WIDTH+1), .SIZE(PRE_FIFO_SIZE)) axi_fifo (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({i_tlast[n],i_tdata[WIDTH*(n+1)-1:WIDTH*n]}), .i_tvalid(i_tvalid[n]), .i_tready(i_tready[n]),
.o_tdata({i_tlast_int[n],i_tdata_int[WIDTH*(n+1)-1:WIDTH*n]}), .o_tvalid(i_tvalid_int[n]), .o_tready(i_tready_int[n]),
.space(), .occupied());
end
end
endgenerate
// Make arrays for easier muxing
genvar i;
generate
for (i = 0; i < SIZE; i = i + 1) begin
assign i_tdata_arr[i] = i_tdata_int[WIDTH*(i+1)-1:WIDTH*i];
end
endgenerate
// Switch select line either immediately or after the last word in a packet
reg [$clog2(SIZE)-1:0] select_hold;
generate
if (SWITCH_ON_LAST) begin
reg init;
always @(posedge clk) begin
if (reset | clear) begin
init <= 1'b0;
select_hold <= 'd0;
end else begin
if (|i_tvalid) begin
init <= 1'b1;
end
// Set select any time after reset and before the first packet OR
// at the end of a packet
if (~init | (o_tlast_int & o_tvalid_int & o_tready_int)) begin
select_hold <= select;
end
end
end
end else begin
always @(*) begin
select_hold <= select;
end
end
endgenerate
// Mux
assign o_tdata_int = i_tdata_arr[select_hold];
assign o_tlast_int = i_tlast_int[select_hold];
assign o_tvalid_int = i_tvalid_int[select_hold];
assign i_tready_int = (1'b1 << select_hold) & {SIZE{o_tready_int}};
generate
if(POST_FIFO_SIZE == 0) begin
assign o_tdata = o_tdata_int;
assign o_tlast = o_tlast_int;
assign o_tvalid = o_tvalid_int;
assign o_tready_int = o_tready;
end else begin
axi_fifo #(.WIDTH(WIDTH+1),.SIZE(POST_FIFO_SIZE)) axi_fifo (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
end
endgenerate
endmodule
+229
View File
@@ -0,0 +1,229 @@
//
// Copyright 2012 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Description:
// Holds packets in a FIFO until they are complete. This allows buffering
// slowly-built packets so they don't clog up downstream logic. If o_tready
// is held high, this module guarantees that o_tvalid will not be deasserted
// until a full packet is transferred. This module can also optionally drop
// a packet if the i_terror bit is asserted along with i_tlast. This allows
// discarding packet, say, if a CRC check fails.
// NOTE:
// - The maximum size of a packet that can pass through this module is
// 2^SIZE lines. If a larger packet is sent, this module will lock up.
// - Assuming that upstream is valid and downstream is ready, the maximum
// in to out latency per packet is (2^SIZE + 2) clock cycles.
// 2^SIZE because this module gates a packet, 1 cycle for the RAM read and
// 1 more cycle for the output register. This is not guaranteed behavior though.
// - The USE_AS_BUFF parameter can be used to treat this packet gate as
// a multi-packet buffer. When USE_AS_BUFF=0, the max number of packets
// (regardless of size) that the module can store is 2. When USE_AS_BUFF=1,
// the entire storage of this module can be used to buffer packets but at
// the cost of some additional RAM. Beware the sequence of (big packet,
// small packet, small packet), as some outside buffering may be needed
// to handle this case if USE_AS_BUFF=0.
module axi_packet_gate #(
parameter WIDTH = 64, // Width of datapath
parameter SIZE = 10, // log2 of the buffer size (must be >= MTU of packet)
parameter USE_AS_BUFF = 0, // Allow the packet gate to be used as a buffer (uses more RAM)
parameter MIN_PKT_SIZE= 0 // log2 of minimum valid packet size (rounded down, used to reduce addr fifo size)
) (
input wire clk,
input wire reset,
input wire clear,
input wire [WIDTH-1:0] i_tdata,
input wire i_tlast,
input wire i_terror,
input wire i_tvalid,
output wire i_tready,
output reg [WIDTH-1:0] o_tdata = {WIDTH{1'b0}},
output reg o_tlast = 1'b0,
output reg o_tvalid = 1'b0,
input wire o_tready
);
localparam [SIZE-1:0] ADDR_ZERO = {SIZE{1'b0}};
localparam [SIZE-1:0] ADDR_ONE = {{(SIZE-1){1'b0}}, 1'b1};
// -------------------------------------------
// RAM block that will hold pkts
// -------------------------------------------
wire wr_en, rd_en;
wire [WIDTH:0] wr_data, rd_data;
reg [SIZE-1:0] wr_addr = ADDR_ZERO, rd_addr = ADDR_ZERO;
// Threshold to explicitly instantiate LUTRAM
localparam LUTRAM_THRESH = 5;
// We need to instantiate a simple dual-port RAM here so
// we use the ram_2port module with one read port and one
// write port and "NO-CHANGE" mode.
ram_2port #(
.DWIDTH (WIDTH+1), .AWIDTH(SIZE),
.RW_MODE("NO-CHANGE"), .OUT_REG(0),
.RAM_TYPE(SIZE <= LUTRAM_THRESH ? "LUTRAM" : "AUTOMATIC")
) ram_i (
.clka (clk), .ena(1'b1), .wea(wr_en),
.addra(wr_addr), .dia(wr_data), .doa(),
.clkb (clk), .enb(rd_en), .web(1'b0),
.addrb(rd_addr), .dib({WIDTH{1'b0}}), .dob(rd_data)
);
// FIFO empty/full logic. The condition for both
// empty and full is when rd_addr == wr_addr. However,
// it matters if we approach that case from the low side
// or the high side. So keep track of the almost empty/full
// state for determine if the next transaction will cause
// the FIFO to be truly empty or full.
reg ram_full = 1'b0, ram_empty = 1'b1;
wire almost_full = (wr_addr == rd_addr - ADDR_ONE);
wire almost_empty = (wr_addr == rd_addr + ADDR_ONE);
always @(posedge clk) begin
if (reset | clear) begin
ram_full <= 1'b0;
end else begin
if (almost_full) begin
if (wr_en & ~rd_en)
ram_full <= 1'b1;
end else begin
if (~wr_en & rd_en)
ram_full <= 1'b0;
end
end
end
always @(posedge clk) begin
if (reset | clear) begin
ram_empty <= 1'b1;
end else begin
if (almost_empty) begin
if (rd_en & ~wr_en)
ram_empty <= 1'b1;
end else begin
if (~rd_en & wr_en)
ram_empty <= 1'b0;
end
end
end
// -------------------------------------------
// Address FIFO
// -------------------------------------------
// The address FIFO will hold the write address
// for the last line in a non-errant packet
wire [SIZE-1:0] afifo_i_tdata, afifo_o_tdata, afifo_p_tdata;
wire afifo_i_tvalid, afifo_i_tready;
wire afifo_o_tvalid, afifo_o_tready;
wire afifo_p_tvalid, afifo_p_tready;
axi_fifo #(.WIDTH(SIZE), .SIZE(USE_AS_BUFF==1 ? SIZE-MIN_PKT_SIZE : 1)) addr_fifo_i (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata(afifo_i_tdata), .i_tvalid(afifo_i_tvalid), .i_tready(afifo_i_tready),
.o_tdata(afifo_p_tdata), .o_tvalid(afifo_p_tvalid), .o_tready(afifo_p_tready),
.space(), .occupied()
);
axi_fifo #(.WIDTH(SIZE), .SIZE(1)) addr_fifo_pipe_i (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata(afifo_p_tdata), .i_tvalid(afifo_p_tvalid), .i_tready(afifo_p_tready),
.o_tdata(afifo_o_tdata), .o_tvalid(afifo_o_tvalid), .o_tready(afifo_o_tready),
.space(), .occupied()
);
// -------------------------------------------
// Write state machine
// -------------------------------------------
reg [SIZE-1:0] wr_head_addr = ADDR_ZERO;
assign i_tready = ~ram_full & afifo_i_tready;
assign wr_en = i_tvalid & i_tready;
assign wr_data = {i_tlast, i_tdata};
always @(posedge clk) begin
if (reset | clear) begin
wr_addr <= ADDR_ZERO;
wr_head_addr <= ADDR_ZERO;
end else begin
if (wr_en) begin
if (i_tlast) begin
if (i_terror) begin
// Incoming packet had an error. Rewind the write
// pointer and pretend that a packet never came in.
wr_addr <= wr_head_addr;
end else begin
// Incoming packet had no error, advance wr_addr and
// wr_head_addr for the next packet.
wr_addr <= wr_addr + ADDR_ONE;
wr_head_addr <= wr_addr + ADDR_ONE;
end
end else begin
// Packet is still in progress, only update wr_addr
wr_addr <= wr_addr + ADDR_ONE;
end
end
end
end
// Push the write address to the address FIFO if
// - It is the last one in the packet
// - The packet has no errors
assign afifo_i_tdata = wr_addr;
assign afifo_i_tvalid = ~ram_full & i_tvalid & i_tlast & ~i_terror;
// -------------------------------------------
// Read state machine
// -------------------------------------------
reg rd_data_valid = 1'b0;
wire update_out_reg;
// Data can be read if there is a valid last address in the
// address FIFO (signifying the end of an input packet) and
// if there is data available in RAM
wire ready_to_read = (~ram_empty) & afifo_o_tvalid;
// Pop from address FIFO once we have see the end of the pkt
assign afifo_o_tready = rd_en & (afifo_o_tdata == rd_addr);
// Read from RAM if
// - A full packet has been written AND
// - Output data is not valid OR is currently being transferred
assign rd_en = ready_to_read & (update_out_reg | ~rd_data_valid);
always @(posedge clk) begin
if (reset | clear) begin
rd_data_valid <= 1'b0;
rd_addr <= ADDR_ZERO;
end else begin
if (update_out_reg | ~rd_data_valid) begin
// Output data is not valid OR is currently being transferred
if (ready_to_read) begin
rd_data_valid <= 1'b1;
rd_addr <= rd_addr + ADDR_ONE;
end else begin
rd_data_valid <= 1'b0; // Don't read
end
end
end
end
// Instantiate an output register to break critical paths starting
// at the RAM module. When ram_2port is inferred as BRAM, the tools
// should absorb this register into the BRAM block without using
// SLICE resources.
always @(posedge clk) begin
if (reset | clear) begin
o_tvalid <= 1'b0;
end else if (update_out_reg) begin
o_tvalid <= rd_data_valid;
{o_tlast, o_tdata} <= rd_data;
end
end
// Update the output reg only *after* the downstream
// block has consumed the current value
assign update_out_reg = o_tready | ~o_tvalid;
endmodule
+66
View File
@@ -0,0 +1,66 @@
//
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Description:
// This module is instantiated in parallel with a FIFO with AXI4-STREAM interfaces.
// It tracks how many complete packets are contained within the FIFO, and also indicates
// when the first word of a packet is presented on the FIFO outputs.
module axis_fifo_monitor #(
parameter COUNT_W = 32
)(
// Clocks and resets
input wire clk,
input wire reset,
// FIFO Input
input wire i_tlast,
input wire i_tvalid,
input wire i_tready,
// FIFO Output
input wire o_tlast,
input wire o_tvalid,
input wire o_tready,
// FIFO Stats
output wire i_sop,
output wire i_eop,
output wire o_sop,
output wire o_eop,
output wire [COUNT_W-1:0] occupied,
output wire [COUNT_W-1:0] occupied_pkts
);
wire [COUNT_W-1:0] i_pkt_count, o_pkt_count;
wire [COUNT_W-1:0] i_xfer_count, o_xfer_count;
axis_strm_monitor #(
.WIDTH(1), .COUNT_W(COUNT_W),
.PKT_LENGTH_EN(0), .PKT_CHKSUM_EN(0),
.PKT_COUNT_EN(1), .XFER_COUNT_EN(1)
) input_monitor (
.clk(clk), .reset(reset),
.axis_tdata(1'b0), .axis_tlast(i_tlast), .axis_tvalid(i_tvalid), .axis_tready(i_tready),
.sop(i_sop), .eop(i_eop),
.pkt_length(), .pkt_chksum(),
.pkt_count(i_pkt_count), .xfer_count(i_xfer_count)
);
axis_strm_monitor #(
.WIDTH(1), .COUNT_W(COUNT_W),
.PKT_LENGTH_EN(0), .PKT_CHKSUM_EN(0),
.PKT_COUNT_EN(1), .XFER_COUNT_EN(1)
) output_monitor (
.clk(clk), .reset(reset),
.axis_tdata(1'b0), .axis_tlast(o_tlast), .axis_tvalid(o_tvalid), .axis_tready(o_tready),
.sop(o_sop), .eop(o_eop),
.pkt_length(), .pkt_chksum(),
.pkt_count(o_pkt_count), .xfer_count(o_xfer_count)
);
// Count packets in FIFO.
// No protection on counter wrap,
assign occupied = (i_xfer_count - o_xfer_count);
assign occupied_pkts = (i_pkt_count - o_pkt_count);
endmodule
+110
View File
@@ -0,0 +1,110 @@
//
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Description:
// A module to monitor a an AXI-Stream link and gather various
// metric about packets and the stream in general
module axis_strm_monitor #(
parameter WIDTH = 64,
parameter COUNT_W = 32,
parameter PKT_LENGTH_EN = 0,
parameter PKT_CHKSUM_EN = 0,
parameter PKT_COUNT_EN = 0,
parameter XFER_COUNT_EN = 0
)(
// Clocks and resets
input wire clk,
input wire reset,
// Stream to monitor
input wire [WIDTH-1:0] axis_tdata,
input wire axis_tlast,
input wire axis_tvalid,
input wire axis_tready,
// Packet Stats
output wire sop,
output wire eop,
output reg [15:0] pkt_length = 16'd0,
output wire [WIDTH-1:0] pkt_chksum,
// Stream Stats
output reg [COUNT_W-1:0] pkt_count = {COUNT_W{1'b0}},
output reg [COUNT_W-1:0] xfer_count = {COUNT_W{1'b0}}
);
//----------------------------
// Packet specific
//----------------------------
reg pkt_head = 1'b1;
wire xfer = axis_tvalid & axis_tready;
assign sop = pkt_head & xfer;
assign eop = xfer & axis_tlast;
always @(posedge clk) begin
if (reset) begin
pkt_head <= 1'b1;
end else begin
if (pkt_head) begin
if (xfer)
pkt_head <= ~eop;
end else begin
if (eop)
pkt_head <= 1'b0;
end
end
end
generate if (PKT_LENGTH_EN == 0) begin
// Count the number of lines (transfers) in a packet
always @(posedge clk) begin
if (reset | eop) begin
pkt_length <= 16'd1;
end else if (xfer) begin
pkt_length <= pkt_length + 1'b1;
end
end
end else begin
// Default packet length is 0
always @(*) pkt_length <= 16'd0;
end endgenerate
generate if (PKT_LENGTH_EN == 0) begin
// Compute the XOR checksum of the lines in a packet
reg [WIDTH-1:0] chksum_prev = {WIDTH{1'b0}};
always @(posedge clk) begin
if (reset) begin
chksum_prev <= {WIDTH{1'b0}};
end else if (xfer) begin
chksum_prev <= pkt_chksum;
end
end
assign pkt_chksum = chksum_prev ^ axis_tdata;
end else begin
// Default checksum is 0
assign pkt_chksum = {WIDTH{1'b0}};
end endgenerate
//----------------------------
// Stream specific
//----------------------------
always @(posedge clk) begin
if (reset | (PKT_COUNT_EN == 0)) begin
pkt_count <= {COUNT_W{1'b0}};
end else if (eop) begin
pkt_count <= pkt_count + 1'b1;
end
end
always @(posedge clk) begin
if (reset | (XFER_COUNT_EN == 0)) begin
xfer_count <= {COUNT_W{1'b0}};
end else if (xfer) begin
xfer_count <= xfer_count + 1'b1;
end
end
endmodule
+140
View File
@@ -0,0 +1,140 @@
/////////////////////////////////////////////////////////////////////
//
// Copyright 2016-2017 Ettus Research
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
//////////////////////////////////////////////////////////////////////
module fifo64_to_axi4lite
(
input s_axi_aclk,
input s_axi_areset,
input [31:0] s_axi_awaddr,
input s_axi_awvalid,
output s_axi_awready,
input [31:0] s_axi_wdata,
input [3:0] s_axi_wstrb,
input s_axi_wvalid,
output s_axi_wready,
output [1:0] s_axi_bresp,
output s_axi_bvalid,
input s_axi_bready,
input [31:0] s_axi_araddr,
input s_axi_arvalid,
output s_axi_arready,
output [31:0] s_axi_rdata,
output [1:0] s_axi_rresp,
output s_axi_rvalid,
input s_axi_rready,
output m_axis_tvalid,
output m_axis_tlast,
output [63:0] m_axis_tdata,
input m_axis_tready,
output [3:0] m_axis_tuser,
input s_axis_tvalid,
input s_axis_tlast,
input [63:0] s_axis_tdata,
output s_axis_tready,
input [3:0] s_axis_tuser,
output irq
);
wire clear_txn;
wire [31:0] tx_tdata;
wire tx_tlast;
wire tx_tvalid;
wire tx_tready;
wire [3:0] tx_tkeep;
wire [1:0] tx_tuser = (tx_tkeep == 4'b1111) ? 2'd0 :
(tx_tkeep == 4'b0001) ? 2'd1 :
(tx_tkeep == 4'b0011) ? 2'd2 :
(tx_tkeep == 4'b0111) ? 2'd3 : 2'd0;
axi_fifo32_to_fifo64 inst_axi_fifo32_to_fifo64
(
.clk(s_axi_aclk),
.reset(s_axi_areset | ~clear_txn),
.i_tdata({tx_tdata[7:0], tx_tdata[15:8], tx_tdata[23:16], tx_tdata[31:24]}), // endian swap
.i_tuser(tx_tuser),
.i_tlast(tx_tlast),
.i_tvalid(tx_tvalid),
.i_tready(tx_tready),
.o_tdata(m_axis_tdata),
.o_tuser(m_axis_tuser),
.o_tlast(m_axis_tlast),
.o_tvalid(m_axis_tvalid),
.o_tready(m_axis_tready)
);
wire clear_rxn;
wire [31:0] rx_tdata;
wire rx_tlast;
wire rx_tvalid;
wire rx_tready;
wire [1:0] rx_tuser;
axi_fifo64_to_fifo32 inst_axi_fifo64_to_fifo32
(
.clk(s_axi_aclk),
.reset(s_axi_areset || ~clear_rxn),
.i_tdata(s_axis_tdata),
.i_tuser(s_axis_tuser[2:0]),
.i_tlast(s_axis_tlast),
.i_tvalid(s_axis_tvalid),
.i_tready(s_axis_tready),
.o_tdata({rx_tdata[7:0], rx_tdata[15:8], rx_tdata[23:16], rx_tdata[31:24]}), // endian swap
.o_tuser(rx_tuser),
.o_tlast(rx_tlast),
.o_tvalid(rx_tvalid),
.o_tready(rx_tready)
);
wire [3:0] rx_tkeep = ~rx_tlast ? 4'b1111 : (rx_tuser == 2'd0) ? 4'b1111 :
(rx_tuser == 2'd1) ? 4'b0001 :
(rx_tuser == 2'd2) ? 4'b0011 :
(rx_tuser == 2'd3) ? 4'b0111 :
4'b1111;
axis_fifo_to_axi4lite inst_axis_fifo_to_axi4lite0
(
.interrupt(irq),
.s_axi_aclk(s_axi_aclk),
.s_axi_aresetn(~s_axi_areset),
.s_axi_awaddr({16'h0000, s_axi_awaddr}),
.s_axi_awvalid(s_axi_awvalid),
.s_axi_awready(s_axi_awready),
.s_axi_wdata(s_axi_wdata),
.s_axi_wstrb(s_axi_wstrb),
.s_axi_wvalid(s_axi_wvalid),
.s_axi_wready(s_axi_wready),
.s_axi_bresp(s_axi_bresp),
.s_axi_bvalid(s_axi_bvalid),
.s_axi_bready(s_axi_bready),
.s_axi_araddr({16'h0000, s_axi_araddr}),
.s_axi_arvalid(s_axi_arvalid),
.s_axi_arready(s_axi_arready),
.s_axi_rdata(s_axi_rdata),
.s_axi_rresp(s_axi_rresp),
.s_axi_rvalid(s_axi_rvalid),
.s_axi_rready(s_axi_rready),
.mm2s_prmry_reset_out_n(clear_txn),
.axi_str_txd_tvalid(tx_tvalid),
.axi_str_txd_tready(tx_tready),
.axi_str_txd_tlast(tx_tlast),
.axi_str_txd_tdata(tx_tdata),
.axi_str_txd_tkeep(tx_tkeep),
.s2mm_prmry_reset_out_n(clear_rxn),
.axi_str_rxd_tvalid(rx_tvalid),
.axi_str_rxd_tready(rx_tready),
.axi_str_rxd_tlast(rx_tlast),
.axi_str_rxd_tdata(rx_tdata),
.axi_str_rxd_tkeep(rx_tkeep)
);
endmodule
+95
View File
@@ -0,0 +1,95 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module shortfifo
#(parameter WIDTH=32)
(input clk, input rst,
input [WIDTH-1:0] datain,
output [WIDTH-1:0] dataout,
input read,
input write,
input clear,
output reg full,
output reg empty,
output reg [4:0] space,
output reg [4:0] occupied);
reg [3:0] a;
genvar i;
generate
for (i=0;i<WIDTH;i=i+1)
begin : gen_srl16
SRL16E
srl16e(.Q(dataout[i]),
.A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),
.CE(write),.CLK(clk),.D(datain[i]));
end
endgenerate
always @(posedge clk)
if(rst)
begin
a <= 0;
empty <= 1;
full <= 0;
end
else if(clear)
begin
a <= 0;
empty <= 1;
full<= 0;
end
else if(read & ~write)
begin
full <= 0;
if(a==0)
empty <= 1;
else
a <= a - 1;
end
else if(write & ~read)
begin
empty <= 0;
if(~empty)
a <= a + 1;
if(a == 14)
full <= 1;
end
// NOTE will fail if you write into a full fifo or read from an empty one
//////////////////////////////////////////////////////////////
// space and occupied are used for diagnostics, not
// guaranteed correct
//assign space = full ? 0 : empty ? 16 : 15-a;
//assign occupied = empty ? 0 : full ? 16 : a+1;
always @(posedge clk)
if(rst)
space <= 16;
else if(clear)
space <= 16;
else if(read & ~write)
space <= space + 1;
else if(write & ~read)
space <= space - 1;
always @(posedge clk)
if(rst)
occupied <= 0;
else if(clear)
occupied <= 0;
else if(read & ~write)
occupied <= occupied - 1;
else if(write & ~read)
occupied <= occupied + 1;
endmodule // shortfifo