verilogsignal-processingfpgavivadodigital-design

How to initialize coefficients of a large digital filter in Verilog?


I am trying to make a synthesizable filter in verilog. I have the fixed-point filter coefficients in a text file. I am looking for an elegant and scalable way to pass on these filter coefficients. The filter will not be a simple beast: it will contain multiple sub-modules, and each of which may need a single co-efficient.

Since the filter coefficients will be constant, I would like them to be hardcoded, i.e., not consume any registers in implementation.

I have a few options/wishes below, along with their possible downsides:

  1. Use readmemh or some similar trick to read the coefficients into a memory (reg [15:0] coeff [0:1023]) in the enclosing module, and pass on the coefficients from memory to FIR stages using a generate block. It should look something like:
generate
    for (i = 0; i < 3 ; i = i + 1) begin: k
        filter_stage(input[k], coeff[k], output[k]);
    end
endgenerate

The downside is that the memory must be in the module that encloses the filter stages, otherwise I will have to go through portlist hell.

  1. Use systemverilog packed arrays as module ports. The downside is that systemverilog support for some synthesis tools is sub-optimal.

  2. This is a wish: Some sort of global lookup structure which is accessible to each module, so I don't have to manually wrap modules and adjust portlists just to pass coefficients to the right place.

I would want to know if option 3 is at all possible. If not, what else could I do?

Thanks.


Solution

  • If you are able to use SystemVerilog, then you can put constants (maybe an array of constants) in a package, and import (not include) the package in other modules which need access.
    Its been written about a lot, here is a starting point include/import.

    SystemVerilog packages are synthesizable, they not just for verification.

    I have used them for Vivado RTL work for several years, seems like since Vivado 2016.
    This link says packages are supported for Quartus Synthesis in 2012 Altera support for SV

    The only place you might have synthesis support issues is with ISE; the last release was 2014. I don't know about Microsemi or the other mid-sized or small FPGA vendors.

    You don't need option 1, you don't need ports as mentioned in 2, and you don't have to wrap anything or use ports as mentioned in 3.

    An array of constants in a package should work well.

    The package syntax is lightweight, you could have Matlab or Python or whatever you use for coefficient generation write out the SystemVerilog package with the constants.

    Example package defines an array of constants

    // Write me out with Python or Matlab generated coefficients
    package my_coef_pk;
    
    // type int is 32 bit, treated as signed
    localparam int my_coef_array [4:0] = 
     '{
       2**16,
       1,
       2, 
      -1,
      -(2**16)
      };
    
    endpackage
    

    Example testbench imports the package and prints the array

    module tb ();
      // import the contents of the package here
      import my_coef_pk::*;
      
      // example access the localparam array defined in the package
      initial 
        foreach(my_coef_array [i])
          $display("my_coef_array = %d", my_coef_array [i]);
        
    endmodule
    

    Produces

    my_coef_array =       65536
    my_coef_array =           1
    my_coef_array =           2
    my_coef_array =          -1
    my_coef_array =      -65536