From 82e1da1b789a969e70f7283ee49208de4c509b0e Mon Sep 17 00:00:00 2001 From: Wade Fife Date: Wed, 14 Aug 2024 16:09:11 -0500 Subject: [PATCH] fpga: lib: Cleanup axi_demux module - Add documentation - Add generate block labels - Remove tabs and fix indentation - Separate the code into three logical sections Original-commit: 76074ecb319bf770805374b81c966b94cba898c5 --- lib/fifo/axi_demux.v | 213 +++++++++++++++++++++++++++++-------------- 1 file changed, 146 insertions(+), 67 deletions(-) diff --git a/lib/fifo/axi_demux.v b/lib/fifo/axi_demux.v index 965fb95..43008d9 100644 --- a/lib/fifo/axi_demux.v +++ b/lib/fifo/axi_demux.v @@ -1,75 +1,154 @@ - -// Copyright 2012 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company +// +// Copyright 2024 Ettus Research, a National Instruments Brand // // 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 +// +// Description: +// +// Implements a 1-to-SIZE demultiplexer for AXI-Stream. Switching output +// paths happens only between packets. A bubble cycle is added between each +// packet to allow the switching. The output to use for the next packet is +// selected using the dest input. +// +// The header output contains a copy of i_tdata and can be used when the +// first word of the packet contains information that should be used to +// determine the destination using combinational logic. +// -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); +`default_nettype none - 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; +module axi_demux #( + parameter WIDTH = 64, + parameter SIZE = 4, + parameter PRE_FIFO_SIZE = 0, + parameter POST_FIFO_SIZE = 0 +) ( + input wire clk, + input wire reset, + input wire clear, - assign header = i_tdata_int; + output wire [ WIDTH-1:0] header, + input wire [$clog2(SIZE)-1:0] dest, - 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 + input wire [ WIDTH-1:0] i_tdata, + input wire i_tlast, + input wire i_tvalid, + output wire i_tready, -endmodule // axi_demux + output wire [(WIDTH*SIZE)-1:0] o_tdata, + output wire [ SIZE-1:0] o_tlast, + output wire [ SIZE-1:0] o_tvalid, + input wire [ SIZE-1:0] o_tready +); + + //--------------------------------------------------------------------------- + // Optional Input FIFO + //--------------------------------------------------------------------------- + + wire i_tlast_int; + wire i_tready_int; + wire i_tvalid_int; + wire [WIDTH-1:0] i_tdata_int; + + generate + if (PRE_FIFO_SIZE == 0) begin : gen_no_pre_fifo + 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 : gen_pre_fifo + axi_fifo #( + .WIDTH(WIDTH+1), + .SIZE(PRE_FIFO_SIZE) + ) axi_fifo_i ( + .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 + + //--------------------------------------------------------------------------- + // Demultiplexer Logic + //--------------------------------------------------------------------------- + + assign header = i_tdata_int; + + // The state vector indicates which output is selected + reg [SIZE-1:0] st = {SIZE{1'b0}}; + + always @(posedge clk) begin + if(reset | clear) begin + st <= {SIZE{1'b0}}; + end else begin + // If state is 0, that means no output path is selected and we are free + // to select the next destination. + if(st == 0) begin + if(i_tvalid_int) begin + st[dest] <= 1'b1; + end + end else begin + // At the end of the packet, clear the state + if(i_tready_int & i_tvalid_int & i_tlast_int) begin + st <= {SIZE{1'b0}}; + end + end + end + end + + //--------------------------------------------------------------------------- + // Optional Output FIFO(s) + //--------------------------------------------------------------------------- + + genvar n; + generate + if (POST_FIFO_SIZE == 0) begin : gen_no_post_fifo + 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 : gen_post_fifo + wire [SIZE-1:0] i_tready_fifo; + wire [SIZE-1:0] i_tvalid_fifo; + + // Only read tready from and drive tvalid to the currently selected + // output. + assign i_tready_int = |(i_tready_fifo & st); + assign i_tvalid_fifo = {SIZE{i_tvalid_int}} & st; + + for (n = 0; n < SIZE; n = n + 1) begin : gen_post_axi_fifo + axi_fifo #( + .WIDTH(WIDTH+1), + .SIZE (POST_FIFO_SIZE) + ) axi_fifo_i ( + .clk (clk), + .reset (reset), + .clear (clear), + .i_tdata ({i_tlast_int, i_tdata_int}), + .i_tvalid(i_tvalid_fifo[n]), + .i_tready(i_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 + + +`default_nettype wire