1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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
);
localparam SWAP_STAGES = $clog2(DATA_W);
localparam 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
|