// *************************************************************************** // *************************************************************************** // Copyright 2018 (c) Analog Devices, Inc. All rights reserved. // // In this HDL repository, there are many different and unique modules, consisting // of various HDL (Verilog or VHDL) components. The individual modules are // developed independently, and may be accompanied by separate and unique license // terms. // // The user should read each of these license terms, and understand the // freedoms and responsabilities that he or she has by using this source/core. // // This core is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR // A PARTICULAR PURPOSE. // // Redistribution and use of source or resulting binaries, with or without modification // of this file, are permitted under one of the following two license terms: // // 1. The GNU General Public License version 2 as published by the // Free Software Foundation, which can be found in the top level directory // of this repository (LICENSE_GPL2), and also online at: // // // OR // // 2. An ADI specific BSD license, which can be found in the top level directory // of this repository (LICENSE_ADIBSD), and also on-line at: // https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD // This will allow to generate bit files and not release the source code, // as long as it attaches to an ADI device. // // *************************************************************************** // *************************************************************************** `timescale 1ns/100ps module pack_interconnect #( parameter PORT_DATA_WIDTH = 16, parameter PORT_ADDRESS_WIDTH = 3, parameter MUX_ORDER = 2, parameter NUM_STAGES = 2, parameter PACK = 0 // 0 = Unpack, 1 = Pack ) ( input [2**PORT_ADDRESS_WIDTH*MUX_ORDER*NUM_STAGES-1:0] ctrl, input [PORT_DATA_WIDTH * 2**PORT_ADDRESS_WIDTH-1:0] data_in, output [PORT_DATA_WIDTH * 2**PORT_ADDRESS_WIDTH-1:0] data_out ); /* * This module implements the interconnect for pack or unpack core. * The interconnect is made up of NUM_STAGES stages. Each stage is made up of * multiple MUXs (one for each port) and a perfect shuffle. * * The number of inputs per MUX is 2**MUX_ORDER. * The number of ports is 2**PORT_ADDRESS_WIDTH. */ localparam NUM_PORTS = 2**PORT_ADDRESS_WIDTH; localparam TOTAL_DATA_WIDTH = PORT_DATA_WIDTH * NUM_PORTS; wire [TOTAL_DATA_WIDTH-1:0] interconnect[0:NUM_STAGES]; assign interconnect[0] = data_in; assign data_out = interconnect[NUM_STAGES]; generate genvar i, j; localparam z = 2**MUX_ORDER; localparam w = PORT_DATA_WIDTH; localparam NUM_SWITCHES = NUM_PORTS / z; /* Do perfect shuffle, either in forward or reverse direction */ for (i = 0; i < NUM_STAGES; i = i + 1) begin: gen_stages /* Pack network are in the opposite direction */ localparam ctrl_stage = PACK ? NUM_STAGES - i - 1 : i; wire [TOTAL_DATA_WIDTH-1:0] shuffle_in; wire [TOTAL_DATA_WIDTH-1:0] shuffle_out; wire [TOTAL_DATA_WIDTH-1:0] mux_in; wire [TOTAL_DATA_WIDTH-1:0] mux_out; /* Unpack uses forward shuffle and pack a reverse shuffle */ ad_perfect_shuffle #( .NUM_GROUPS (PACK ? NUM_SWITCHES : z), .WORDS_PER_GROUP (PACK ? z : NUM_SWITCHES), .WORD_WIDTH (w) ) i_shuffle ( .data_in (shuffle_in), .data_out (shuffle_out) ); for (j = 0; j < NUM_PORTS; j = j + 1) begin: gen_ports localparam ctrl_base = (ctrl_stage * NUM_PORTS + j) * MUX_ORDER; localparam sel_base = j & ~(z-1); /* base increments in 2**MUX_ORDER steps */ /* * To be able to better share MUX control signals and reduce overall * resource consumption the control signal gets rotated by the offset of * MUX in a switch. * * E.g. a control signal of 0 for the first MUX means that the first * input should be selected. A control signal of 0 for the second switch * means that the second input will be used. To implement this (j % z) * is added to the control signal when selecting the input bits. This * addition does not result in additional resources being used. It just * results in a different look-up table. */ wire [MUX_ORDER-1:0] sel = ctrl[ctrl_base+:MUX_ORDER];// + j % z; assign mux_out[j*w+:w] = mux_in[(sel_base+sel)*w+:w]; end /* * Pack is MUX followed by shuffle. * Unpack is shuffle followed by MUX. */ if (PACK) begin assign mux_in = interconnect[i]; assign shuffle_in = mux_out; assign interconnect[i+1] = shuffle_out; end else begin assign shuffle_in = interconnect[i]; assign mux_in = shuffle_out; assign interconnect[i+1] = mux_out; end end endgenerate endmodule