From 510fe8e6341cb37ac30370f5aed33628454e8bd9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Jul 2009 14:49:34 -0400 Subject: [PATCH] Explicitly size all parameters, even if not used for module cells --- src/V3Const.cpp | 9 ++++++++- src/V3Param.cpp | 8 ++++++++ src/V3Width.cpp | 11 ++++++++--- test_regress/t/t_func_const_bad.pl | 21 +++++++++++++++++++++ test_regress/t/t_func_const_bad.v | 28 ++++++++++++++++++++++++++++ test_regress/t/t_param.v | 4 +++- 6 files changed, 76 insertions(+), 5 deletions(-) create mode 100755 test_regress/t/t_func_const_bad.pl create mode 100644 test_regress/t/t_func_const_bad.v diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 42b1993c3..dc34f1f5f 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1713,7 +1713,14 @@ void V3Const::constifyParam(AstNode* nodep) { V3Signed::signedParams(nodep); } ConstVisitor visitor (true,false,false,false); - visitor.main(nodep); + if (AstVar* varp=nodep->castVar()) { + // If a var wants to be constified, it's really a param, and + // we want the value to be constant. We aren't passed just the + // init value because we need widthing above to handle the var's type. + if (varp->initp()) visitor.main(varp->initp()); + } else { + visitor.main(nodep); + } // Because we do edits, nodep links may get trashed and core dump this. //if (debug()>0) nodep->dumpTree(cout," forceConDONE: "); } diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 68b8e3813..b1e228be2 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -127,6 +127,14 @@ private: } virtual void visit(AstCell* nodep, AstNUser*); + // Make sure all parameters are constantified + virtual void visit(AstVar* nodep, AstNUser*) { + if (nodep->isParam()) { + if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); } + V3Const::constifyParam(nodep); // The variable, not just the var->init() + } + } + // Generate Statements virtual void visit(AstGenerate* nodep, AstNUser*) { if (debug()>=9) nodep->dumpTree(cout,"-genin: "); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e5bc2d1d9..6ba7edd04 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -442,6 +442,8 @@ private: virtual void visit(AstVar* nodep, AstNUser* vup) { //if (debug()) nodep->dumpTree(cout," InitPre: "); // Must have deterministic constant width + // We can't skip this step when width()!=0, as creating a AstVar + // with non-constant range gets size 1, not size 0. int width=1; int mwidth=1; nodep->arraysp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); if (nodep->rangep()) { @@ -457,8 +459,11 @@ private: } if (nodep->initp()) { nodep->initp()->iterateAndNext(*this,WidthVP(width,0,BOTH).p()); - if (nodep->isParam() && !nodep->rangep()) { - if (nodep->initp()->widthSized()) { + if (nodep->isParam()) { + if (nodep->rangep()) { + // Parameters need to preserve widthMin from the value, not get a constant size + mwidth = nodep->initp()->widthMin(); + } else if (nodep->initp()->widthSized()) { width = mwidth = nodep->initp()->width(); } else { if (nodep->initp()->width()>32) nodep->initp()->v3warn(WIDTH,"Assigning >32 bit to unranged parameter (defaults to 32 bits)\n"); @@ -847,7 +852,7 @@ public: m_taskDepth = 0; m_cellRangep = NULL; m_casep = NULL; - nodep->accept(*this); + nodep->accept(*this, WidthVP(ANYSIZE,0,BOTH).p()); } virtual ~WidthVisitor() {} }; diff --git a/test_regress/t/t_func_const_bad.pl b/test_regress/t/t_func_const_bad.pl new file mode 100755 index 000000000..f33c2f4cc --- /dev/null +++ b/test_regress/t/t_func_const_bad.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + v_flags2 => ["--lint-only"], + fails=>1, + expect=> +q{%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't convert a FUNCREF 'f_bad_output' to constant. +%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't convert a FUNCREF 'f_bad_dotted' to constant. +%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't convert a FUNCREF 'f_bad_nonparam' to constant. +%Error: Exiting due to.*}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_const_bad.v b/test_regress/t/t_func_const_bad.v new file mode 100644 index 000000000..d84911234 --- /dev/null +++ b/test_regress/t/t_func_const_bad.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +module t; + + // Speced ignored: system calls. I think this is nasty, so we error instead. + // Speced Illegal: inout/output/ref not allowed + localparam B1 = f_bad_output(1,2); + function integer f_bad_output(input [31:0] a, output [31:0] o); + f_bad_output = 0; + endfunction + // Speced Illegal: void + // Speced Illegal: dotted + localparam EIGHT = 8; + localparam B2 = f_bad_dotted(2); + function integer f_bad_dotted(input [31:0] a); + f_bad_dotted = t.EIGHT; + endfunction + // Speced Illegal: ref to non-local var + integer modvar; + localparam B3 = f_bad_nonparam(3); + function integer f_bad_nonparam(input [31:0] a); + f_bad_nonparam = modvar; + endfunction + // Speced Illegal: needs constant function itself +endmodule diff --git a/test_regress/t/t_param.v b/test_regress/t/t_param.v index 1b4c3fca1..76be2159b 100644 --- a/test_regress/t/t_param.v +++ b/test_regress/t/t_param.v @@ -36,8 +36,10 @@ module t (/*AUTOARG*/ endmodule module m1; + localparam PAR1MINUS1 = PAR1DUP-2-1; + localparam PAR1DUP = PAR1+2; // Check we propagate parameters properly parameter PAR1 = 0; - m2 #(PAR1-1) m2 (); + m2 #(PAR1MINUS1) m2 (); endmodule module m2;