parameterized module in verilog

The favorite HDL language in North America

parameterized module in verilog

Postby duane » Tue Dec 09, 2008 12:55 pm

I want to create a parametrized module. An async cpu interface. I in the instantiation of the module I want to specify (actually require) a few parameters.

Based on those parameters, I want to calculate the widths of a few port widths into and out of the module.

The example is an ASYNC cpu interface to an exteral CPU, and interternally to several peripherals implemented in the FPGA.

On the "instantiation" side I see how to do it - I use named parameters prefixed with a "#" sign, for example

myinterface #(.ADDR_BITS(16)) foo ( .addr_bus(addr_pins) );

On the MODULE side... I see how to do this with the Verilog (OLD) syntax in the module definition, I do the following

Code: Select all
   // this is alot like the "old style of C"
   module  myinterface( addr_bus, pselects );
            // required parameters
            parameter ADDR_BITS = 16;
            parameter SELECTLOG2 = 3;

            // calculate other port widths
            parameter SELECT_WIDTH = (1<<SELECTLOG2);

            // define PORTs & widths
            input [ADDR_BITS - 1 : 0 ] addr_bus;
            output [ SELECT_WIDTH-1:0] pselects );
   
             ... implementation goes here ...
   endmodule

=============

Question #1.

How do I do the same thing with Verilog2001 syntax? (which resembles ANSI C with parameter types) When I try, I get syntax errors. I can find no examples.

Question #2.

Am I *REQUIRED* to give a parameter value for each? For example, I have seen that one can "over-ride" the parameter. I want to *require* the parameter to always be over-ridden, and *FAIL* if they are not given. In effect, the parameter (port) size is an integral *REQUIRED* part of the instantiation.

The only solution I can think of is something like this

Code: Select all
    // in the port definition supply a crazy value
    parameter WIDTH = 1000000;

   // later..
   if( WIDTH == 1000000 ) begin
            $display("THE WIDTH WAS NOT SPECIFIED");
            $stop
    end
duane
 
Posts: 8
Joined: Sun Dec 07, 2008 11:46 pm
Location: usa-east-coast

Postby rberek » Tue Dec 09, 2008 2:47 pm

To define parameters in your module (I'm making one up):

Code: Select all

module myModule #(
   parameter SPEED = "FAST",
   parameter async_enable = 1,
   parameter count_limit = 9'h1d5
)
(   
   // pinlist goes here
);

   // code and stuff

endmodule



Then when you instantiate that module:

Code: Select all

myModule #("FAST",1,9'h1d5) myModule_inst (

    // pinlist

);



It is good practice to always have the parameters specifically listed when instantiating your module. Not sure if it is expressly required, but it helps others to understand your code. And of course, when you instantiate it you can change the parameters to be anything you want.

As for question #2, yes you can do what you say. But of course it is not synthesizeable.

r.b.
rberek
 
Posts: 65
Joined: Wed May 23, 2007 5:32 pm

Postby duane » Wed Dec 10, 2008 3:29 am

Close :-( but that is not working.

What I want to do is basically a variation of
Code: Select all

module multiplier2
  #(parameter AWIDTH=8, BWIDTH=8,
     localparam YWIDTH=AWIDTH+BWIDTH)
    (output [YWIDTH-1:0] y,
    input [AWIDTH-1:0] a,
    input [BWIDTH-1:0] b);
    assign y = a * b;
endmodule



The above comes from here: (page 8, section 14 right side top)

http://csg.csail.mit.edu/6.375/papers/cummings-paramdesign-hdlcon02.pdf

Problem Part #1.

Sadly that PDF says - the above is illegal, but does not offer a solution or reference of how to do this sort of stuff.

Problem Parm #2

I do not want to specify the NBITS as a parameter, I want NTHINGS - and calculate NBITS based on NTHINGS.

In effect the "clog2b" function, or so I have heard described, evidently it is in some IEEE standard document - and laughed about because it has bugs in it.

Or is what I want to do - just not possible?

-Duane.
duane
 
Posts: 8
Joined: Sun Dec 07, 2008 11:46 pm
Location: usa-east-coast

Postby rberek » Fri Dec 12, 2008 1:18 pm

Sorry, I understood your question to be how does one use instantiation parameters in Verilog 2001.

I think the first example you give might work if you made YWIDTH a standard parameter:

Code: Select all

module multiplier2
  #(parameter AWIDTH=8, BWIDTH=8
     )
    (output [YWIDTH-1:0] y,
    input [AWIDTH-1:0] a,
    input [BWIDTH-1:0] b);
    parameter YWIDTH=AWIDTH+BWIDTH;
    assign y = a * b;
endmodule


I have not tried it though.

If you want to use a parameter to generate N instances , you can use the generate structure. I'm not sure exactly what you're seeking to do though, so if generate doesn't help, I'm not sure what other help I can offer.

r.b.
rberek
 
Posts: 65
Joined: Wed May 23, 2007 5:32 pm

Postby duane » Sun Dec 14, 2008 1:56 am

Thanks - as a "C" programmer - I find Verilog _SO_ limiting - the macro language seems to be in the stone ages, (1) I cannot believe there are not examples of how to do this, and (2) more frustrating - is what works in one package does not work in the other package - yuck.

I seem to get the idea that "parametrized modules" is a new concept in Verilog, we software types have had #define macros for years!

I do thank you for your help.

I'm on to the next stage of my experiments - my test bench.

Thanks.
duane
 
Posts: 8
Joined: Sun Dec 07, 2008 11:46 pm
Location: usa-east-coast

Postby billt » Mon Jun 28, 2010 10:11 pm

I'm trying to learn my way through this issue as well. I'm trying to look at examples from FPGA Prototyping by Verilog Examples Spartan 3 Edition as well as what google gives me. The examples seem a bit limited compared to what I'd like to do, showing only one parameter instead of many, showing one width parameter when I want many different width definitions for different register types, (i2c data vs dadr, shift register vs bit counter) and I'd like to include a file there to share some of these parameters with various modules defined in different files (an i2c communicator module, a testbench module, and a register file module each in their own files all `including the i2c_params.v file)

Some of what I have done may be causing verilog 95 and verilog 2001 conflicts, I don't know enough yet to tell what is a problem or how to fix t well.

I do NOT want to use instantiation-overriding of any parameters at this point, I just want a single place to define these things and leave the values as they are defined. I've been strongly discouraged from using `defines or that's how I'd have done all this from the beginning.

Lets try to make up some examples rather than copy my work files:

file i2c_params.v
Code: Select all
parameter I2C_DATA_BITS = 8; //I2C data is sent one byte at a time with ack in between bytes
parameter I2C_DATA_MSB = I2C_DATA_BITS - 1;
parameter I2C_SHIFT_REG_BITS = I2C_DATA_BITS; //shift register is same size as i2c data
parameter I2C_SHIFT_REG_MSB = I2C_SHIFT_REG_BITS - 1;

parameter I2C_DADR_BITS = 7,
          I2C_DADR_MSB  = I2C_DADR_BITS - 1;

//currently have an 8-bit data size, with ack bit gives 9 transfer bits
// which fits in 4-bit counter
parameter SDA_COUNTER_BITS = 4,
          SDA_COUNTER_MSB = SDA_COUNTER_BITS - 1;


file i2c.v
Code: Select all
module i2c
//parameters
#(
    `include "i2c_params.v"
)
//I/O port declarations
(
    input wire clock,
    input wire reset,
    input wire sdain,
    input wire sclin,
    input wire [I2C_DATA_MSB:0] read_data,  //data to be read from config registers -
                                 // always current value of selected register
                                 // regardless of read/write operation
    input wire [I2C_DADR_MSB:0] id_config,  //inputs to set i2c slave address
    output wire sdaout,          //to sda pad (open-collector pullup on board)
    output reg [I2C_DATA_MSB:0] write_data, //data to be written to config registers
    ...
)

    ... rtl implementation code

endmodule


file testbench.v
Code: Select all
`timescale 1 ns / 1 ps

`include "i2c.v"
`include "tb_regfile.v"

module testbench;
// no I/O ports for testbench
    //include verilog tasks from other files
    `include "i2c_params.v"

//should these be localparams instead?  I wrote a lot of this before learning about 2001's new parameter/localparam styling
//temporarily use faster timing for simulation run time reduction
//    parameter sys_clk_period = 31; //32MHz is 31.25ns period, round to 31
    parameter sys_clk_period = 8; //32MHz is 31.25ns period, round to 31
//    parameter scl_period = 2500;   //i2c 400KHz clock is 2500ns period
    parameter scl_period = 400;   //i2c 400KHz clock is 2500ns period
   
    reg  tb_sys_clk;    //system clock
    reg  tb_sys_reset;  //active-high reset

    reg [I2C_SHIFT_REG_MSB:0] tb_sda_shiftreg;
    reg [SDA_COUNTER_MSB:0] tb_sda_bit_counter;

    //registers the testbench will control as if it was i2c master
    reg  tb_scl;
    reg  tb_scl_prev;
    wire tb_scl_posedge;
    wire tb_scl_negedge;

    reg [I2C_DADR_MSB:0] tb_id_config; //selected base address for i2c slave

    wire tb_sda_to_DUT;
    reg  tb_sda_data_to_DUT;
    reg  tb_sda_ack_to_DUT;
    reg  tb_sda_to_DUT_prev;
    wire tb_sda_to_DUT_posedge;
    wire tb_sda_to_DUT_negedge;
    wire tb_sda_from_DUT; //sda output from the i2c DUT
    reg  tb_ack_from_DUT;
    wire [I2C_DATA_MSB:0] tb_read_data;
    wire [I2C_DATA_MSB:0] tb_write_data;
    wire tb_read_reg;
    wire tb_write_reg;
    reg tb_i2c_busy;
    reg tb_i2c_start_cond;
    reg tb_i2c_stop_cond;
   
    reg [I2C_DADR_MSB:0] test_dadr;  //a different parameter name than most places
    reg test_read_writen;
    reg [I2C_DATA_MSB:0] test_iadr;
    reg [I2C_DATA_MSB:0] tb_byte_expected;
    reg       tb_ack_expected;
    integer   tb_error_count;
    wire [I2C_DATA_MSB:0] test_dadr_w; //combined dadr and read_write bits
    reg [I2C_DATA_MSB:0] tb_byte_from_DUT;
    reg [I2C_DATA_MSB:0] tb_byte_to_transmit;

    ...
    //various other regs/wires and testbench code
    ...

    i2c DUT_i2c (port connections); //no instantiation parameter overrides here

    test_regfile i2c_regfile(port connections); //no instantiation parameter overrides here

    initial
    begin
        ... //simulation commands to communicate with the DUT_i2c
    end

endmodule


I'm trying to compile/simulate using Cadence irun from our ius-5.6SR1 toolset and am getting this error:

Code: Select all
parameter I2C_DATA_BITS = 8; //I2C data is sent one byte at a time with ack in between bytes
                           |
ncvlog: *E,EXPRPA (i2c_params.v,4|27): expecting a right parenthesis (')') [12.1(IEEE-2001)].


For the i2c.v file, I am using the I/O port declaration style of input reg [I2C_DADR_MSB:0] i2c_dadr rather than simply list port names there and do input/output and reg/wire sections later on. The portlist was given to me in this format, and my attempts to split it into the separate portname, input/output and reg/wire groups just led to a lot of errors which I didn't understand so I left it this way. Examples seem to do parameter group, then I/O portnames, then the input/output and reg/wire groups for the ports, OR do I/O portnames, then parameters, then input/output and reg/wire groups for the ports. I've nto found anything anywhere that does an include, so I'm wondering if it's legal for what I want to do, and I do not know another way to accomplish my goal.

That's a missing close paren on line 4 of the i2c_params.v include file, previous lines are all comment or whitespace.

Do I need to adjust my style here from a 95 way of doing things in the i2c_params.v file? Is this include parameters style simply not allowed?

Do I need to change it to a chain of parameters separated by commas rather than redoing the parameter keyword in different groups of parameter names?

Are there any more advanced examples of parameter usage out there more like what I'm trying to do?
billt
 
Posts: 1
Joined: Mon Jun 28, 2010 9:24 pm


Return to Verilog HDL