1// 2// Copyright 2019 Ettus Research, A National Instruments Company 3// 4// SPDX-License-Identifier: LGPL-3.0-or-later 5// 6// Module: axis_data_swap 7// Description: 8// A generic data swapper module for AXI-Stream. The contents of 9// tdata are swapped based on the tswap signal. For each bit 'i' 10// in tswap, adjacent words of width 2^i are swapped if tswap[i] 11// is high. For example, if tswap[3] = 1, then each byte in tdata 12// will be swapped with its adjacent neighbor. It is permissible 13// for tswap to change for each transfer in an AXIS packet. 14// Swapping can also be configured to be static (zero logic) by 15// setting DYNAMIC = 0. To reduce area, certain swap stages can 16// even be disabled. For example, if STAGES_EN[2:0] is set to 0 17// then the lowest granularity for swaps will be a byte. 18// 19// Parameters: 20// - DATA_W: Width of the tdata bus in bits 21// - USER_W: Width of the tuser bus in bits 22// - STAGES_EN: Which swap stages are enabled. 23// - DYNAMIC: Dynamic swapping enabled (use tswap) 24// 25// Signals: 26// - s_axis_*: The input AXI stream 27// - m_axis_*: The output AXI stream 28// 29 30module axis_data_swap #( 31 parameter integer DATA_W = 256, 32 parameter integer USER_W = 1, 33 parameter [$clog2(DATA_W)-1:0] STAGES_EN = 'hFFFFFFFF, //@HACK: Vivado does not allow $clog2 in value of this expr 34 parameter [0:0] DYNAMIC = 1 35)( 36 // Clock and Reset 37 input wire clk, 38 input wire rst, 39 // Input AXIS 40 input wire [DATA_W-1:0] s_axis_tdata, 41 input wire [$clog2(DATA_W)-2:0] s_axis_tswap, 42 input wire [USER_W-1:0] s_axis_tuser, 43 input wire s_axis_tlast, 44 input wire s_axis_tvalid, 45 output wire s_axis_tready, 46 // Output AXIS 47 output wire [DATA_W-1:0] m_axis_tdata, 48 output wire [USER_W-1:0] m_axis_tuser, 49 output wire m_axis_tlast, 50 output wire m_axis_tvalid, 51 input wire m_axis_tready 52); 53 54 parameter SWAP_STAGES = $clog2(DATA_W); 55 parameter SWAP_W = $clog2(DATA_W)-1; 56 genvar s, w; 57 58 wire [DATA_W-1:0] stg_tdata [0:SWAP_STAGES], stg_tdata_swp[0:SWAP_STAGES], stg_tdata_res[0:SWAP_STAGES]; 59 wire [SWAP_W-1:0] stg_tswap [0:SWAP_STAGES]; 60 wire [USER_W-1:0] stg_tuser [0:SWAP_STAGES]; 61 wire stg_tlast [0:SWAP_STAGES]; 62 wire stg_tvalid[0:SWAP_STAGES]; 63 wire stg_tready[0:SWAP_STAGES]; 64 65 // Connect input and output to stage wires 66 generate 67 assign stg_tdata [0] = s_axis_tdata; 68 assign stg_tswap [0] = s_axis_tswap; 69 assign stg_tuser [0] = s_axis_tuser; 70 assign stg_tlast [0] = s_axis_tlast; 71 assign stg_tvalid[0] = s_axis_tvalid; 72 assign s_axis_tready = stg_tready[0]; 73 74 assign m_axis_tdata = stg_tdata [SWAP_STAGES]; 75 assign m_axis_tuser = stg_tuser [SWAP_STAGES]; 76 assign m_axis_tlast = stg_tlast [SWAP_STAGES]; 77 assign m_axis_tvalid = stg_tvalid[SWAP_STAGES]; 78 assign stg_tready[SWAP_STAGES] = m_axis_tready; 79 endgenerate 80 81 // Instantiate AXIS flip-flops for each stage 82 generate 83 for (s = 0; s < SWAP_STAGES; s=s+1) begin 84 if (STAGES_EN[SWAP_STAGES-s-1]) begin 85 // Swap Logic 86 for (w = 0; w < (1<<s); w=w+1) begin 87 assign stg_tdata_swp[s][(w*(DATA_W/(1<<s)))+:(DATA_W/(1<<s))] = 88 stg_tdata[s][(((1<<s)-w-1)*(DATA_W/(1<<s)))+:(DATA_W/(1<<s))]; 89 end 90 if (DYNAMIC) begin 91 // Honor tswap in DYNAMIC mode. 92 // Also add a flip_flop to break the long start-to-end critical path 93 assign stg_tdata_res[s] = (s > 0 && stg_tswap[s][SWAP_W-s]) ? 94 stg_tdata_swp[s] : stg_tdata[s]; 95 // Flip-flop 96 axi_fifo_flop #(.WIDTH(DATA_W+SWAP_W+USER_W+1)) reg_i ( 97 .clk(clk), .reset(rst), .clear(1'b0), 98 .i_tdata({stg_tlast[s], stg_tuser[s], stg_tswap[s], stg_tdata_res[s]}), 99 .i_tvalid(stg_tvalid[s]), .i_tready(stg_tready[s]), 100 .o_tdata({stg_tlast[s+1], stg_tuser[s+1], stg_tswap[s+1], stg_tdata[s+1]}), 101 .o_tvalid(stg_tvalid[s+1]), .o_tready(stg_tready[s+1]), 102 .occupied(), .space() 103 ); 104 end else begin 105 // Static swapping logic 106 assign stg_tdata [s+1] = stg_tdata_swp[s]; 107 assign stg_tswap [s+1] = stg_tswap [s]; 108 assign stg_tuser [s+1] = stg_tuser [s]; 109 assign stg_tlast [s+1] = stg_tlast [s]; 110 assign stg_tvalid[s+1] = stg_tvalid [s]; 111 assign stg_tready[s] = stg_tready [s+1]; 112 end 113 end else begin 114 // Skip this stage 115 assign stg_tdata [s+1] = stg_tdata [s]; 116 assign stg_tswap [s+1] = stg_tswap [s]; 117 assign stg_tuser [s+1] = stg_tuser [s]; 118 assign stg_tlast [s+1] = stg_tlast [s]; 119 assign stg_tvalid[s+1] = stg_tvalid[s]; 120 assign stg_tready[s] = stg_tready[s+1]; 121 end 122 end 123 endgenerate 124 125endmodule // axis_data_swap 126