aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi/axis_data_swap.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/axi/axis_data_swap.v')
-rw-r--r--fpga/usrp3/lib/axi/axis_data_swap.v125
1 files changed, 125 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/axi/axis_data_swap.v b/fpga/usrp3/lib/axi/axis_data_swap.v
new file mode 100644
index 000000000..2408ab6c6
--- /dev/null
+++ b/fpga/usrp3/lib/axi/axis_data_swap.v
@@ -0,0 +1,125 @@
+//
+// Copyright 2019 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: axis_data_swap
+// Description:
+// A generic data swapper module for AXI-Stream. The contents of
+// tdata are swapped based on the tswap signal. For each bit 'i'
+// in tswap, adjacent words of width 2^i are swapped if tswap[i]
+// is high. For example, if tswap[3] = 1, then each byte in tdata
+// will be swapped with its adjacent neighbor. It is permissible
+// for tswap to change for each transfer in an AXIS packet.
+// Swapping can also be configured to be static (zero logic) by
+// setting DYNAMIC = 0. To reduce area, certain swap stages can
+// even be disabled. For example, if STAGES_EN[2:0] is set to 0
+// then the lowest granularity for swaps will be a byte.
+//
+// Parameters:
+// - DATA_W: Width of the tdata bus in bits
+// - USER_W: Width of the tuser bus in bits
+// - STAGES_EN: Which swap stages are enabled.
+// - DYNAMIC: Dynamic swapping enabled (use tswap)
+//
+// Signals:
+// - s_axis_*: The input AXI stream
+// - m_axis_*: The output AXI stream
+//
+
+module axis_data_swap #(
+ parameter integer DATA_W = 256,
+ parameter integer USER_W = 1,
+ parameter [$clog2(DATA_W)-1:0] STAGES_EN = 'hFFFFFFFF, //@HACK: Vivado does not allow $clog2 in value of this expr
+ parameter [0:0] DYNAMIC = 1
+)(
+ // Clock and Reset
+ input wire clk,
+ input wire rst,
+ // Input AXIS
+ input wire [DATA_W-1:0] s_axis_tdata,
+ input wire [$clog2(DATA_W)-2:0] s_axis_tswap,
+ input wire [USER_W-1:0] s_axis_tuser,
+ input wire s_axis_tlast,
+ input wire s_axis_tvalid,
+ output wire s_axis_tready,
+ // Output AXIS
+ output wire [DATA_W-1:0] m_axis_tdata,
+ output wire [USER_W-1:0] m_axis_tuser,
+ output wire m_axis_tlast,
+ output wire m_axis_tvalid,
+ input wire m_axis_tready
+);
+
+ parameter SWAP_STAGES = $clog2(DATA_W);
+ parameter SWAP_W = $clog2(DATA_W)-1;
+ genvar s, w;
+
+ wire [DATA_W-1:0] stg_tdata [0:SWAP_STAGES], stg_tdata_swp[0:SWAP_STAGES], stg_tdata_res[0:SWAP_STAGES];
+ wire [SWAP_W-1:0] stg_tswap [0:SWAP_STAGES];
+ wire [USER_W-1:0] stg_tuser [0:SWAP_STAGES];
+ wire stg_tlast [0:SWAP_STAGES];
+ wire stg_tvalid[0:SWAP_STAGES];
+ wire stg_tready[0:SWAP_STAGES];
+
+ // Connect input and output to stage wires
+ generate
+ assign stg_tdata [0] = s_axis_tdata;
+ assign stg_tswap [0] = s_axis_tswap;
+ assign stg_tuser [0] = s_axis_tuser;
+ assign stg_tlast [0] = s_axis_tlast;
+ assign stg_tvalid[0] = s_axis_tvalid;
+ assign s_axis_tready = stg_tready[0];
+
+ assign m_axis_tdata = stg_tdata [SWAP_STAGES];
+ assign m_axis_tuser = stg_tuser [SWAP_STAGES];
+ assign m_axis_tlast = stg_tlast [SWAP_STAGES];
+ assign m_axis_tvalid = stg_tvalid[SWAP_STAGES];
+ assign stg_tready[SWAP_STAGES] = m_axis_tready;
+ endgenerate
+
+ // Instantiate AXIS flip-flops for each stage
+ generate
+ for (s = 0; s < SWAP_STAGES; s=s+1) begin
+ if (STAGES_EN[SWAP_STAGES-s-1]) begin
+ // Swap Logic
+ for (w = 0; w < (1<<s); w=w+1) begin
+ assign stg_tdata_swp[s][(w*(DATA_W/(1<<s)))+:(DATA_W/(1<<s))] =
+ stg_tdata[s][(((1<<s)-w-1)*(DATA_W/(1<<s)))+:(DATA_W/(1<<s))];
+ end
+ if (DYNAMIC) begin
+ // Honor tswap in DYNAMIC mode.
+ // Also add a flip_flop to break the long start-to-end critical path
+ assign stg_tdata_res[s] = (s > 0 && stg_tswap[s][SWAP_W-s]) ?
+ stg_tdata_swp[s] : stg_tdata[s];
+ // Flip-flop
+ axi_fifo_flop #(.WIDTH(DATA_W+SWAP_W+USER_W+1)) reg_i (
+ .clk(clk), .reset(rst), .clear(1'b0),
+ .i_tdata({stg_tlast[s], stg_tuser[s], stg_tswap[s], stg_tdata_res[s]}),
+ .i_tvalid(stg_tvalid[s]), .i_tready(stg_tready[s]),
+ .o_tdata({stg_tlast[s+1], stg_tuser[s+1], stg_tswap[s+1], stg_tdata[s+1]}),
+ .o_tvalid(stg_tvalid[s+1]), .o_tready(stg_tready[s+1]),
+ .occupied(), .space()
+ );
+ end else begin
+ // Static swapping logic
+ assign stg_tdata [s+1] = stg_tdata_swp[s];
+ assign stg_tswap [s+1] = stg_tswap [s];
+ assign stg_tuser [s+1] = stg_tuser [s];
+ assign stg_tlast [s+1] = stg_tlast [s];
+ assign stg_tvalid[s+1] = stg_tvalid [s];
+ assign stg_tready[s] = stg_tready [s+1];
+ end
+ end else begin
+ // Skip this stage
+ assign stg_tdata [s+1] = stg_tdata [s];
+ assign stg_tswap [s+1] = stg_tswap [s];
+ assign stg_tuser [s+1] = stg_tuser [s];
+ assign stg_tlast [s+1] = stg_tlast [s];
+ assign stg_tvalid[s+1] = stg_tvalid[s];
+ assign stg_tready[s] = stg_tready[s+1];
+ end
+ end
+ endgenerate
+
+endmodule // axis_data_swap