diff --git a/src/V3Const.cpp b/src/V3Const.cpp index a9c273918..a3c16f85d 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -313,15 +313,24 @@ private: if (m_warn && nodep->lsbp()->castConst() && nodep->widthp()->castConst() - && (!varp->rangep() || varp->msb()) // else it's non-resolvable parameterized - && ( ( (nodep->msbConst() > varp->msbMaxSelect()) - || (nodep->lsbConst() > varp->msbMaxSelect())))) { - // See also warning in V3Width - nodep->v3error("Selection index out of range: " - <msbConst()<<":"<lsbConst() - <<" outside "<msbMaxSelect()<<":0" - <<(varp->lsb()>=0 ? "" - :" (adjusted +"+cvtToStr(-varp->lsb())+" to account for negative lsb)")); + && (!varp->rangep() || varp->msb())) { // else it's non-resolvable parameterized + if (nodep->lsbp()->castConst()->num().isFourState() + || nodep->widthp()->castConst()->num().isFourState()) { + nodep->v3error("Selection index is constantly unknown or tristated: " + "lsb="<lsbp()->name()<<" width="<widthp()->name()); + // Replacing nodep will make a mess above, so we replace the offender + replaceZero(nodep->lsbp()); + } + else if ((nodep->msbConst() > varp->msbMaxSelect()) + || (nodep->lsbConst() > varp->msbMaxSelect())) { + // See also warning in V3Width + nodep->v3error("Selection index out of range: " + <msbConst()<<":"<lsbConst() + <<" outside "<msbMaxSelect()<<":0" + <<(varp->lsb()>=0 ? "" + :" (adjusted +"+cvtToStr(-varp->lsb())+" to account for negative lsb)")); + // Don't replace with zero, we'll do it later + } } } return false; // Not a transform, so NOP @@ -367,7 +376,9 @@ private: void replaceNum (AstNode* oldp, const V3Number& num) { // Replace oldp node with a constant set to specified value UASSERT (oldp, "Null old\n"); - if (oldp->castConst()) oldp->v3fatalSrc("Already constant??\n"); + if (oldp->castConst() && !oldp->castConst()->num().isFourState()) { + oldp->v3fatalSrc("Already constant??\n"); + } AstNode* newp = new AstConst(oldp->fileline(), num); newp->widthSignedFrom(oldp); if (debug()>5) oldp->dumpTree(cout," const_old: "); diff --git a/test_regress/t/t_select_bad_tri.pl b/test_regress/t/t_select_bad_tri.pl new file mode 100755 index 000000000..1dd538e88 --- /dev/null +++ b/test_regress/t/t_select_bad_tri.pl @@ -0,0 +1,20 @@ +#!/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=>$Self->{v3}, + expect=> +q{%Error: t/t_select_bad_tri.v:\d+: Selection index is constantly unknown or tristated: lsb=7'bxxxxxxx width=\?32\?sh47 +%Error: Exiting due to.*}, + ); + +ok(1); +1; + diff --git a/test_regress/t/t_select_bad_tri.v b/test_regress/t/t_select_bad_tri.v new file mode 100644 index 000000000..e7eed140e --- /dev/null +++ b/test_regress/t/t_select_bad_tri.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2008 by Wilson Snyder. + +module t (/*AUTOARG*/); + + reg [72:1] in; + initial begin + if (in[( (1'h0 / 1'b0) )+:71] != 71'h0) $stop; + end + +endmodule