// ***************************************************************************/
//Microsemi Corporation Proprietary and Confidential
//Copyright 2011 Microsemi Corporation. All rights reserved.
//
//ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
//ACCORDANCE WITH THE MICROSEMI LICENSE AGREEMENT AND MUST BE APPROVED
//IN ADVANCE IN WRITING.
//
//Description:  CoreFIR
//              Top module of the Fully enumerated type supporting PA4M FPGA
//
//Revision Information:
//Date         Description
//21July2011   Initial Release
//
//SVN Revision Information:
//SVN $Revision: 14801 $
//SVN $Data: $
//
//Resolved SARs
//SAR     Date    Who     Description
//
//Notes:
//      June 2012 VVD     Inter-row regs = 4          

`timescale 1 ns/100 ps

//               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+
//               |S|i|g|n|e|d|-|U|n|s|i|g|n|e|d| |F|i|l|t|e|r|
//               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+
// Unsigned filter operates over unsigned data AND coefficients.  If either one
// is signed, the other one must be as well, as the results are signed, too.
// In such case, the core internally sign-extends the unsigned data or coef by  
// a bit adding a leading zero sign bit (then _WIDTH is limited to 17).  The 
// filter output is still OUT_WIDTH as a product of q-bit signed number (sign 
// plus q-1 significant bits) by p-bit unsigned (p significant bits) fits  
// q+p bits  

// The datapath widths is as follows then:
// Coef/Data  |FIR Output |HW data path's always signed
// -----------+-----------+---------------------------- 
// Signed     |           |     OUT_WIDTH
// Unsigned   |OUT_WIDTH* |     OUT_WIDTH+2
// Sign/Unsign|           |     OUT_WIDTH+1
// -----------+-----------+----------------------------
// *OUT_WIDTH defined in the code below
module LMS_FIR_TOP_COREFIR_0_COREENUMFIR_G4 (NGRST, RSTN, CLK,
              DATAI,
              DATAI_VALID,
              COEFI,
              COEFI_VALID,
              FIRO,
              DATAO_VALID,
              COEF_ON,    // load coef_set in coef register
              COEF_SEL ); // select coef_set
  parameter TAPS          = 16;
  parameter COEF_TYPE     = 0;      // 0-const, 1-reloadable
  parameter COEF_SETS     = 1;      // Num of coef sets; 1-single, etc
  parameter COEF_SYMM     = 0;      // 0-no symm, 1-symm, 2-antisymm
  parameter COEF_WIDTH    = 12;
  parameter COEF_SIGN     = 0;      // 0-signed, 1-unsigned
  parameter DATA_WIDTH    = 12;
  parameter DATA_SIGN     = 0;      // 0-signed, 1-unsigned
  parameter SYSTOLIC      = 0;
  parameter VALID_O       = 1;
  parameter INP_REG       = 1;      // Include two-layer wrapper
  parameter CASCADE       = 16;     // Cascade chain length: MAC's in a row
  parameter PERFORMANCE   = 0;
  
  localparam OUT_WIDTH = DATA_WIDTH+COEF_WIDTH+ceil_log2(TAPS);  
  
  // If data and/or coef are unsigned, internal bitwidth is larger   
  localparam HW_WIDTH1 = (COEF_SIGN==1)? OUT_WIDTH+1 : OUT_WIDTH;
  localparam HW_WIDTH  = (DATA_SIGN==1)? HW_WIDTH1+1 : HW_WIDTH1;
  // ACC_WIDTH is at least as big as OUT_WIDTH
  localparam ACC_WIDTH  = (HW_WIDTH < 44)? 44 : HW_WIDTH;

  localparam XREG_COEF = 4;   //June 2012

  localparam WRAP_LAYERS = 2*INP_REG;

  input NGRST, RSTN, CLK;
  input DATAI_VALID;
  input [DATA_WIDTH-1:0] DATAI;
  input [COEF_WIDTH-1:0] COEFI;
  output [OUT_WIDTH-1:0] FIRO;
  output DATAO_VALID;
  input COEF_ON;
  input COEFI_VALID;
  input [3:0] COEF_SEL;

  wire [ACC_WIDTH-1:0] firo_w;
  wire [DATA_WIDTH-1:0] datai_wrap;
  wire [COEF_WIDTH-1:0] coefi_wrap;
  wire [3:0] coef_sel_wrap;
  wire datai_valid_wrap, coefi_valid_wrap, coef_on_wrap;
  
  enum_kitDelay_reg # (.BITWIDTH(DATA_WIDTH), .DELAY(WRAP_LAYERS) ) wrap_datai (
      .nGrst(NGRST), 
      .rst(1'b0), .clk(CLK), .clkEn(1'b1),
      .inp(DATAI),
      .outp(datai_wrap) );
  enum_kitDelay_reg # (.BITWIDTH(COEF_WIDTH), .DELAY(WRAP_LAYERS) ) wrap_coefi (
      .nGrst(NGRST), 
      .rst(1'b0), .clk(CLK), .clkEn(1'b1),
      .inp(COEFI),
      .outp(coefi_wrap) );
  enum_kitDelay_reg # (.BITWIDTH(4), .DELAY(WRAP_LAYERS) ) wrap_coef_sel (
      .nGrst(NGRST), 
      .rst(1'b0), .clk(CLK), .clkEn(1'b1),
      .inp(COEF_SEL),
      .outp(coef_sel_wrap) );

  enum_kitDelay_bit_reg # (.DELAY(WRAP_LAYERS) ) wrap_data_valid (
      .nGrst(NGRST), 
      .rst(1'b0), .clk(CLK), .clkEn(1'b1),
      .inp(DATAI_VALID),
      .outp(datai_valid_wrap) );

  enum_kitDelay_bit_reg # (.DELAY(WRAP_LAYERS) ) wrap_coef_valid (
      .nGrst(NGRST), 
      .rst(1'b0), .clk(CLK), .clkEn(1'b1),
      .inp(COEFI_VALID),
      .outp(coefi_valid_wrap) );
  enum_kitDelay_bit_reg # (.DELAY(WRAP_LAYERS) ) wrap_coef_on (
      .nGrst(NGRST), 
      .rst(1'b0), .clk(CLK), .clkEn(1'b1),
      .inp(COEF_ON),
      .outp(coef_on_wrap) );

  assign FIRO = firo_w[OUT_WIDTH-1:0];

  LMS_FIR_TOP_COREFIR_0_fir_enum_g4 # (
    .TAPS           (TAPS      ),
    .COEF_TYPE      (COEF_TYPE ),
    .COEF_SETS      (COEF_SETS ),
    .COEF_SYMM      (COEF_SYMM ),
    .COEF_BITS     (COEF_WIDTH),
    .COEF_UNSIGN    (COEF_SIGN ),
    .DATA_BITS     (DATA_WIDTH),
    .DATA_UNSIGN    (DATA_SIGN ),
    .ACC_WIDTH       (ACC_WIDTH  ),
    .SYSTOLIC       (SYSTOLIC  ),
    .VALID_O        (VALID_O   ),
    .COLUMN         (CASCADE    ),
    .XREG_COEF      (XREG_COEF),
    .PERFORMANCE    (PERFORMANCE)   ) fir_enum_g4_0 (
      .nGrst(NGRST), 
      .rstn       (RSTN       ),
      .clk        (CLK        ),
      .clkEn      (1'b1       ),
      .datai      (datai_wrap      ),
      .datai_valid(datai_valid_wrap),
      .coefi      (coefi_wrap      ),
      .coefi_valid(coefi_valid_wrap),
      .firo       (firo_w     ),
      .datao_valid(DATAO_VALID),
      .coef_on    (coef_on_wrap    ),
      .coef_sel   (coef_sel_wrap   )  );


  // -----------------------------
  function [31:0] ceil_log2;
      input integer x;
      integer tmp, res;
    begin
      tmp = 1;
      res = 0;
      while (tmp < x) begin
        tmp = tmp * 2;
        res = res + 1;
      end
      ceil_log2 = res;
    end
  endfunction
endmodule

