#893 defparams under a generate fail to propagate to localparams

Kent Dickey

The attached files show a bug in Icarus Verilog in handling parameters of blocks under a generate when using defparam.

It may sound "obscure", but I need this to work to simulate Xilinx BRAM models instantiated under generate statements.

I like Icarus Verilog, and I'm willing to pay for the fix. Let me know your rates. Could you make the fix available on the ftp site as a .tar.gz bundle since I don't use git?

The attached fail4.tar.gz has 2 files: build.sh with my commands to run Icarus Verilog, and top.v, the file which shows the problem. I'm using verilog-20120501.tar.gz, from the ftp site icarus.com, in pub/eda/verilog/snapshots/verilog-20120501.tar.gz.

The failing output is (it uses $displays to show the bug):
top.test1.not1.test2_0.test3_0 wide: 00000012, width1:00000012, width2:00000012
top.test1.not1.test2_0.test3_1 wide: 00000000, width1:00000012, width2:00000012
top.test1.not1.test2_0 big_width: 12
top.test1.not1.test2_1.test3_0 wide: 00000012, width1:00000012, width2:00000012
top.test1.not1.test2_1.test3_1 wide: 00000000, width1:00000012, width2:00000012
top.test1.not1.test2_1 big_width: 12
top.test2_top.test3_0 wide: 00000012, width1:00000012, width2:00000012
top.test2_top.test3_1 wide: 00000012, width1:00000012, width2:00000012
top.test2_top big_width: 12

The bug is the "wide: 00000000" lines. They should all be 00000012.

Here's test3's Verilog:
module test3 (sys_clk, sys_rst);
input sys_clk;
input sys_rst;

parameter WIDTH1 = 0;
parameter WIDTH2 = 0;

localparam big_width = (WIDTH1 >= WIDTH2) ? WIDTH1 : WIDTH2;

wire [31:0] wide = big_width;
wire [31:0] width1 = WIDTH1;
wire [31:0] width2 = WIDTH2;
initial begin
$display("%m wide: %h, width1:%h, width2:%h", wide, width1, width2);

Basically, it's comparing parameters and choosing the largest. Very simple. And it generally works.

Test2 instantiates test3 two different ways:

module test2
parameter WIDTH1 = 3,
parameter WIDTH2 = 4
) (
input sys_clk,
input sys_rst

localparam big_width = (WIDTH1 >= WIDTH2) ? WIDTH1 : WIDTH2;

initial begin
$display("%m big_width: %h", big_width);

wire [15:0] w1 = WIDTH1;
wire [15:0] w2 = WIDTH2;
wire [15:0] bigw = big_width;

wire [31:0] out_data_a, out_data_b;
test3 #(
) test3_0 (

test3 test3_1 (
defparam test3_1.WIDTH1 = WIDTH1;
defparam test3_1.WIDTH2 = WIDTH2;



The first form, with the newer Verilog syntax of #(...parameters...), always works. The second, old-style Verilog using defparam, can sometimes fail to initialize the parameters properly.

And test1() uses a generate statement and then instantiates two test2's. A generate is needed somewhere in the hierarchy for the failure.

The failure is in test3(), the line:

localparam big_width = (WIDTH1 >= WIDTH2) ? WIDTH1 : WIDTH2;

sometimes uses the default WIDTH1 and WIDTH2 values to make its decision, not the one overridden when instantiated with defparam. However, assigning WIDTH1 or WIDTH2 to wires shows the correct values, but when Icarus evaluates big_width, it uses the wrong WIDTH1 and WIDTH2 values.

The files in fail4.tar.gz are in the public domain, so you can add them to your test suite.



  • Kent Dickey

    Kent Dickey - 2012-05-17

    files showing the failure

  • Kent Dickey

    Kent Dickey - 2012-05-17
    • priority: 5 --> 6
  • Stephen Williams

    • assigned_to: nobody --> stevewilliams
  • Stephen Williams

    • status: open --> closed-fixed
  • Stephen Williams

    Fixed in git master.

    I've also added the test to the ivtest regression test suite.

  • Cary R.

    Cary R. - 2012-05-18

    If you don't want to deal with git to get the latest files you can go to github and download a file with the latest files for the master branch.


Log in to post a comment.