From b4ebd4357ffe80061dd3021f579a0ae3e307f01f Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Fri, 16 Oct 2020 16:46:25 +0100 Subject: [PATCH] common/ad_pack: Generic packer core and testbench Packer: - pack I_W number of data units into O_W number of data units - data unit defined in bits by UNIT_W e.g 8 is a byte --- library/common/ad_pack.v | 172 +++++++++++++++++++++++++++++++++ library/common/tb/ad_pack_tb | 7 ++ library/common/tb/ad_pack_tb.v | 98 +++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 library/common/ad_pack.v create mode 100755 library/common/tb/ad_pack_tb create mode 100644 library/common/tb/ad_pack_tb.v diff --git a/library/common/ad_pack.v b/library/common/ad_pack.v new file mode 100644 index 000000000..342969d2e --- /dev/null +++ b/library/common/ad_pack.v @@ -0,0 +1,172 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright 2014 - 2020 (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 + +// Packer: +// - pack I_W number of data units into O_W number of data units +// - data unit defined in bits by UNIT_W e.g 8 is a byte +// +// Constraints: +// - O_W >= I_W +// - no backpressure +// +// Data format: +// idata [U(I_W-1) .... U(0)] +// odata [U(O_W-1) .... U(0)] +// +// e.g +// I_W = 4 +// O_W = 6 +// UNIT_W = 8 +// +// idata : [B3,B2,B1,B0],[B7,B6,B5,B4],[B11,B10,B9,B8] +// odata: [B5,B4,B3,B2,B1,B0],[B11,B10,B9,B8,B7,B6] +// + +module ad_pack #( + parameter I_W = 4, + parameter O_W = 6, + parameter UNIT_W = 8, + parameter I_REG = 0, + parameter O_REG = 1 +) ( + input clk, + input reset, + input [I_W*UNIT_W-1:0] idata, + input ivalid, + + output reg [O_W*UNIT_W-1:0] odata = 'h0, + output reg ovalid = 'b0 +); + +// Width of shift reg is integer multiple of input data width +localparam SH_W = ((O_W/I_W)+|(O_W % I_W))*I_W; +localparam STEP = O_W % I_W; + +reg [O_W*UNIT_W-1:0] idata_packed; +reg [SH_W*UNIT_W-1:0] idata_d = 'h0; +reg ivalid_d = 'h0; +reg [SH_W*UNIT_W-1:0] idata_dd = 'h0; +reg [SH_W-1:0] in_use = 'b0; +reg [SH_W-1:0] out_mask; + +wire [SH_W*UNIT_W-1:0] idata_dd_nx; +wire [SH_W-1:0] in_use_nx; +wire pack_wr; + +generate + if (I_REG) begin : i_reg + + always @(posedge clk) begin + ivalid_d <= ivalid; + idata_d <= idata; + end + + end else begin + + always @(*) begin + ivalid_d = ivalid; + idata_d = idata; + end + + end +endgenerate + +assign idata_dd_nx = {idata_d,idata_dd[SH_W*UNIT_W-1:I_W*UNIT_W]}; +assign in_use_nx = {{I_W{ivalid_d}},in_use[SH_W-1:I_W]}; + +always @(posedge clk) begin + if (reset) begin + in_use <= 'h0; + end else if (ivalid_d) begin + in_use <= in_use_nx &(~out_mask); + end +end + +always @(posedge clk) begin + if (ivalid_d) begin + idata_dd <= idata_dd_nx; + end +end + +integer i; +always @(*) begin + out_mask = 'b0; + idata_packed = 'bx; + if (STEP>0) begin + for (i = SH_W-O_W; i >= 0; i=i-STEP) begin + if (in_use_nx[i]) begin + out_mask = {O_W{1'b1}} << i; + idata_packed = idata_dd_nx >> i*UNIT_W; + end + end + end else begin + if (in_use_nx[0]) begin + out_mask = {O_W{1'b1}}; + idata_packed = idata_dd_nx; + end + end +end + +assign pack_wr = ivalid_d & |in_use_nx[SH_W-O_W:0]; + +generate + if (O_REG) begin : o_reg + + always @(posedge clk) begin + if (reset) begin + ovalid <= 1'b0; + end else begin + ovalid <= pack_wr; + end + end + + always @(posedge clk) begin + odata <= idata_packed; + end + + end else begin + + always @(*) begin + ovalid = pack_wr; + odata = idata_packed; + end + + end +endgenerate + +endmodule + diff --git a/library/common/tb/ad_pack_tb b/library/common/tb/ad_pack_tb new file mode 100755 index 000000000..ce15a7b87 --- /dev/null +++ b/library/common/tb/ad_pack_tb @@ -0,0 +1,7 @@ +#!/bin/bash + +SOURCE="ad_pack_tb.v" +SOURCE+=" ../ad_pack.v" + +cd `dirname $0` +source run_tb.sh diff --git a/library/common/tb/ad_pack_tb.v b/library/common/tb/ad_pack_tb.v new file mode 100644 index 000000000..a84b419c8 --- /dev/null +++ b/library/common/tb/ad_pack_tb.v @@ -0,0 +1,98 @@ +`timescale 1ns/100ps + +module ad_pack_tb; + parameter VCD_FILE = "ad_pack_tb.vcd"; + + parameter I_W = 4; // Width of input channel + parameter O_W = 6; // Width of output channel + parameter UNIT_W = 8; + parameter VECT_W = 1024*8; // Multiple of 8 + + `include "tb_base.v" + + reg [I_W*UNIT_W-1 : 0] idata; + wire [O_W*UNIT_W-1 : 0] odata; + reg ivalid = 'b0; + reg [VECT_W-1:0] input_vector; + reg [VECT_W-1:0] output_vector; + + integer i=0; + integer j=0; + + ad_pack #( + .I_W(I_W), + .O_W(O_W), + .UNIT_W(UNIT_W) + ) DUT ( + .clk(clk), + .reset(reset), + .idata(idata), + .ivalid(ivalid), + .odata(odata), + .ovalid(ovalid) + ); + + task test(); + begin + @(posedge clk); + i = 0; + j = 0; + while (i < VECT_W/(I_W*UNIT_W)) begin + @(posedge clk); + if ($urandom % 2 == 0) begin + idata <= input_vector[i*(I_W*UNIT_W) +: (I_W*UNIT_W)]; + ivalid <= 1'b1; + i = i + 1; + end else begin + idata <= 'bx; + ivalid <= 1'b0; + end + end + @(posedge clk); + idata <= 'bx; + ivalid <= 1'b0; + + // Check output vector + repeat (20) @(posedge clk); + for (i=0; i<(VECT_W/(O_W*UNIT_W))*(O_W*UNIT_W)/8; i=i+1) begin + if (input_vector[i*8+:8] !== output_vector[i*8+:8]) begin + failed <= 1'b1; + $display("i=%d Expected=%x Found=%x",i,input_vector[i*8+:8],output_vector[i*8+:8]); + end + end + end + endtask + + initial begin + + @(negedge reset); + + // Test with incremental data + for (i=0; i