diff --git a/library/common/ad_mux.v b/library/common/ad_mux.v new file mode 100644 index 000000000..f6ece940e --- /dev/null +++ b/library/common/ad_mux.v @@ -0,0 +1,118 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright 2014 - 2017 (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 responsibilities 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 + +// Constraints : CH_CNT must be power of 2 +// Build a large mux from smaller ones defined by the MUX_SZ parameter +// Use EN_REG to add a register at the output of the small muxes to help +// timing closure. + +module ad_mux #( + parameter CH_W = 16, // Width of input channel + parameter CH_CNT = 64, // Number of input channels + parameter REQ_MUX_SZ = 8, // Size of mux which acts as a building block + parameter EN_REG = 1, // Enable register at output of each mux + parameter DW = CH_W*CH_CNT + +) ( + input clk, + input [DW-1:0] data_in, + input [$clog2(CH_CNT)-1:0] ch_sel, + output [CH_W-1:0] data_out +); + +localparam MUX_SZ = CH_CNT < REQ_MUX_SZ ? CH_CNT : REQ_MUX_SZ; +localparam CLOG2_CH_CNT = $clog2(CH_CNT); +localparam CLOG2_MUX_SZ = $clog2(MUX_SZ); +localparam NUM_STAGES = $clog2(CH_CNT) / $clog2(MUX_SZ); + +wire [NUM_STAGES*DW+CH_W-1:0] mux_in; +wire [NUM_STAGES*CLOG2_CH_CNT-1:0] ch_sel_pln; + + +assign mux_in[DW-1:0] = data_in; +assign ch_sel_pln[CLOG2_CH_CNT-1:0] = ch_sel; + +genvar i; +genvar j; + +generate + + + for (i = 0; i < NUM_STAGES; i = i + 1) begin: g_stage + + wire [CLOG2_CH_CNT-1:0] ch_sel_cur; + assign ch_sel_cur = ch_sel_pln[i*CLOG2_CH_CNT+:CLOG2_CH_CNT]; + + wire [CLOG2_MUX_SZ-1:0] ch_sel_w; + assign ch_sel_w = ch_sel_cur >> i*CLOG2_MUX_SZ; + + if (EN_REG) begin + reg [CLOG2_CH_CNT-1:0] ch_sel_d; + always @(posedge clk) begin + ch_sel_d <= ch_sel_cur; + end + if (i +// +// 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 ad_mux_core #( + parameter CH_W = 16, + parameter CH_CNT = 8, + parameter EN_REG = 0 +) ( + input clk, + input [CH_W*CH_CNT-1:0] data_in, + input [$clog2(CH_CNT)-1:0] ch_sel, + output [CH_W-1:0] data_out +); + +wire [CH_W-1:0] data_out_loc; + +assign data_out_loc = data_in >> CH_W*ch_sel; + +generate if (EN_REG) begin + reg [CH_W-1:0] data_out_reg; + always @(posedge clk) begin + data_out_reg <= data_out_loc; + end + assign data_out = data_out_reg; +end else begin + assign data_out = data_out_loc; +end +endgenerate + +endmodule + + diff --git a/library/common/tb/ad_mux_tb b/library/common/tb/ad_mux_tb new file mode 100755 index 000000000..e707994b6 --- /dev/null +++ b/library/common/tb/ad_mux_tb @@ -0,0 +1,8 @@ +#!/bin/bash + +SOURCE="ad_mux_tb.v" +SOURCE+=" ../ad_mux.v" +SOURCE+=" ../ad_mux_core.v" + +cd `dirname $0` +source run_tb.sh diff --git a/library/common/tb/ad_mux_tb.v b/library/common/tb/ad_mux_tb.v new file mode 100644 index 000000000..410acdc55 --- /dev/null +++ b/library/common/tb/ad_mux_tb.v @@ -0,0 +1,71 @@ +`timescale 1ns/100ps + +module ad_mux_tb; + parameter VCD_FILE = "ad_mux_tb.vcd"; + + parameter CH_W = 16; // Width of input channel + parameter CH_CNT = 64; // Number of input channels + parameter REQ_MUX_SZ = 8; // Size of mux which acts as a building block + parameter EN_REG = 1; // Enable register at output of each mux + + localparam MUX_SZ = CH_CNT < REQ_MUX_SZ ? CH_CNT : REQ_MUX_SZ; + localparam NUM_STAGES = $clog2(CH_CNT) / $clog2(MUX_SZ); + localparam DW = CH_W*CH_CNT; + + `include "tb_base.v" + + reg [CH_W*CH_CNT-1:0] data_in = 'h0; + reg [$clog2(CH_CNT)-1:0] ch_sel = 'h0; + wire [CH_W-1:0] data_out; + + ad_mux #( + .CH_W(CH_W), + .CH_CNT(CH_CNT), + .REQ_MUX_SZ(REQ_MUX_SZ), + .EN_REG(EN_REG) + ) DUT ( + .clk(clk), + .data_in(data_in), + .ch_sel(ch_sel), + .data_out(data_out) + ); + + wire [CH_W-1:0] ref_data; + generate + if (EN_REG) begin + integer ii; + reg [CH_W*CH_CNT-1:0] mux_pln [1:NUM_STAGES]; + always @(posedge clk) begin + mux_pln[1] <= data_in >> ch_sel*CH_W; + for (ii=2; ii<=NUM_STAGES; ii=ii+1) begin + mux_pln[ii] <= mux_pln[ii-1]; + end + end + assign ref_data = mux_pln[NUM_STAGES]; + end else begin + assign ref_data = data_in >> ch_sel*CH_W; + end + endgenerate + + integer i; + initial begin + for (i=0; i. +// +// Commercial licenses (with commercial support) of this JESD204 core are also +// available under terms different than the General Public License. (e.g. they +// do not require you to accompany any image (FPGA or ASIC) using the JESD204 +// core with any corresponding source code.) For these alternate terms you must +// purchase a license from Analog Devices Technology Licensing Office. Users +// interested in such a license should contact jesd204-licensing@analog.com for +// more information. This commercial license is sub-licensable (if you purchase +// chips from Analog Devices, incorporate them into your PCB level product, and +// purchase a JESD204 license, end users of your product will also have a +// license to use this core in a commercial setting without releasing their +// source code). +// +// In addition, we kindly ask you to acknowledge ADI in any program, application +// or publication in which you use this JESD204 HDL core. (You are not required +// to do so; it is up to your common sense to decide whether you want to comply +// with this request or not.) For general publications, we suggest referencing : +// “The design and implementation of the JESD204 HDL Core used in this project +// is copyright © 2016-2017, Analog Devices, Inc.” +// + + reg clk = 1'b0; + reg [3:0] reset_shift = 4'b1111; + reg trigger_reset = 1'b0; + wire reset; + + reg failed = 1'b0; + + initial + begin + $dumpfile (VCD_FILE); + $dumpvars; +`ifdef TIMEOUT + #`TIMEOUT +`else + #100000 +`endif + if (failed == 1'b0) + $display("SUCCESS"); + else + $display("FAILED"); + $finish; + end + + always @(*) #10 clk <= ~clk; + always @(posedge clk) begin + if (trigger_reset == 1'b1) begin + reset_shift <= 3'b111; + end else begin + reset_shift <= {reset_shift[2:0],1'b0}; + end + end + + assign reset = reset_shift[3]; + + + + task do_trigger_reset; + begin + @(posedge clk) trigger_reset <= 1'b1; + @(posedge clk) trigger_reset <= 1'b0; + end + endtask