forked from github/verilator
Fix partial slicing with pattern assignments, bug991.
This commit is contained in:
parent
4c35a76cdb
commit
ae9179f412
10
Changes
10
Changes
@ -10,20 +10,22 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
*** Support $size/$bits/etc on type references.
|
||||
|
||||
**** Fix MacOS portability, bug1232. [Jeff Bush]
|
||||
*** Add error when driving input-only modport, bug1110. [Trevor Elbourne]
|
||||
|
||||
*** Add BSSPACE and COLONPLUS lint warnings.
|
||||
|
||||
**** Detect MSB overflow when under VL_DEBUG, bug1238. [Junyi Xi]
|
||||
|
||||
**** Add data types to --xml. [Rui Terra]
|
||||
|
||||
**** Add error when driving input-only modport, bug1110. [Trevor Elbourne]
|
||||
|
||||
**** Add BSSPACE and COLONPLUS lint warnings.
|
||||
**** Fix partial slicing with pattern assignments, bug991. [Johan Bjork]
|
||||
|
||||
**** Fix false unused warning on interfaces, bug1241. [Laurens van Dam]
|
||||
|
||||
**** Fix error on "unique case" with no cases.
|
||||
|
||||
**** Fix MacOS portability, bug1232. [Jeff Bush]
|
||||
|
||||
|
||||
* Verilator 3.914 2017-10-14
|
||||
|
||||
|
@ -681,10 +681,14 @@ struct VNumRange {
|
||||
return false;
|
||||
}
|
||||
//
|
||||
class LeftRight {};
|
||||
VNumRange() : m_hi(0), m_lo(0), mu_flags(0) {}
|
||||
VNumRange(int hi, int lo, bool littleEndian)
|
||||
: m_hi(0), m_lo(0), mu_flags(0)
|
||||
{ init(hi,lo,littleEndian); }
|
||||
VNumRange(LeftRight, int left, int right)
|
||||
: m_hi(0), m_lo(0), mu_flags(0)
|
||||
{ init((right>left)?right:left, (right>left)?left:right, (right>left)); }
|
||||
~VNumRange() {}
|
||||
// MEMBERS
|
||||
void init(int hi, int lo, bool littleEndian) {
|
||||
|
@ -906,6 +906,12 @@ void AstSel::dump(ostream& str) {
|
||||
if (declElWidth()!=1) str<<"/"<<declElWidth();
|
||||
}
|
||||
}
|
||||
void AstSliceSel::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (declRange().ranged()) {
|
||||
str<<" decl"<<declRange();
|
||||
}
|
||||
}
|
||||
void AstTypeTable::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
for (int i=0; i<(int)(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
|
||||
|
@ -931,6 +931,40 @@ public:
|
||||
void declElWidth(int flag) { m_declElWidth = flag; }
|
||||
};
|
||||
|
||||
class AstSliceSel : public AstNodeTriop {
|
||||
// Multiple array element extraction
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math, constant math
|
||||
private:
|
||||
VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid
|
||||
public:
|
||||
AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange)
|
||||
: AstNodeTriop(fl, fromp,
|
||||
new AstConst(fl, declRange.lo()),
|
||||
new AstConst(fl, declRange.elements()))
|
||||
, m_declRange(declRange) { }
|
||||
ASTNODE_NODE_FUNCS(SliceSel)
|
||||
virtual void dump(ostream& str);
|
||||
virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, const V3Number& width) {
|
||||
V3ERROR_NA; }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
|
||||
virtual string emitC() { V3ERROR_NA; return ""; } // Removed before EmitC
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual bool cleanLhs() { return false; }
|
||||
virtual bool cleanRhs() { return true; }
|
||||
virtual bool cleanThs() { return true; }
|
||||
virtual bool sizeMattersLhs() { return false; }
|
||||
virtual bool sizeMattersRhs() { return false; }
|
||||
virtual bool sizeMattersThs() { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
virtual int instrCount() const { return 10; } // Removed before matters
|
||||
AstNode* fromp() const { return op1p(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
// For widthConst()/loConst etc, see declRange().elements() and other VNumRange methods
|
||||
VNumRange& declRange() { return m_declRange; }
|
||||
void declRange(const VNumRange& flag) { m_declRange = flag; }
|
||||
};
|
||||
|
||||
class AstMemberSel : public AstNodeMath {
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math
|
||||
|
@ -493,6 +493,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
puts("]");
|
||||
}
|
||||
virtual void visit(AstSliceSel* nodep) {
|
||||
nodep->fromp()->iterateAndNext(*this);
|
||||
puts(cvtToStr(nodep->declRange()));
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
putfs(nodep,"typedef ");
|
||||
nodep->dtypep()->iterateAndNext(*this); puts(" ");
|
||||
|
@ -34,6 +34,9 @@
|
||||
// Clone and iterate the clone:
|
||||
// ARRAYSEL
|
||||
// Modify bitp() for the new value and set ->length(1)
|
||||
//
|
||||
// TODO: This code was written before SLICESEL was a type it might be
|
||||
// simplified to look primarily for SLICESELs.
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
@ -101,6 +104,12 @@ class SliceVisitor : public AstNVisitor {
|
||||
cloneAndSel(snodep->expr1p(), elements, offset),
|
||||
cloneAndSel(snodep->expr2p(), elements, offset));
|
||||
}
|
||||
else if (AstSliceSel* snodep = nodep->castSliceSel()) {
|
||||
UINFO(9," cloneSliceSel("<<elements<<","<<offset<<") "<<nodep<<endl);
|
||||
int leOffset = (snodep->declRange().lo()
|
||||
+ (!snodep->declRange().littleEndian() ? snodep->declRange().elements()-1-offset : offset));
|
||||
newp = new AstArraySel(nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset);
|
||||
}
|
||||
else if (nodep->castArraySel()
|
||||
|| nodep->castNodeVarRef()
|
||||
|| nodep->castNodeSel()) {
|
||||
@ -137,8 +146,8 @@ class SliceVisitor : public AstNVisitor {
|
||||
if (debug()>=9) { newp->dumpTree(cout,"-new "); }
|
||||
newlistp = AstNode::addNextNull(newlistp, newp);
|
||||
}
|
||||
nodep->replaceWith(newlistp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
if (debug()>=9) { cout<<endl; nodep->dumpTree(cout," Deslice-Dn: "); }
|
||||
nodep->replaceWith(newlistp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
// Normal edit iterator will now iterate on all of the expansion assignments
|
||||
// This will potentially call this function again to resolve next level of slicing
|
||||
return;
|
||||
|
@ -303,6 +303,11 @@ class TristatePinVisitor : public TristateBaseVisitor {
|
||||
if (m_lvalue) nodep->v3fatalSrc("ArraySel conversion to output, under tristate node");
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstSliceSel* nodep) {
|
||||
// Doesn't work because we'd set lvalue on the array index's var
|
||||
if (m_lvalue) nodep->v3fatalSrc("SliceSel conversion to output, under tristate node");
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
@ -295,6 +295,10 @@ private:
|
||||
// Arrays are rarely constant assigned, so for now we punt and do all entries
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstSliceSel* nodep) {
|
||||
// Arrays are rarely constant assigned, so for now we punt and do all entries
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstSel* nodep) {
|
||||
AstNodeVarRef* varrefp = nodep->fromp()->castNodeVarRef();
|
||||
AstConst* constp = nodep->lsbp()->castConst();
|
||||
|
@ -375,6 +375,9 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// visit(AstSliceSel) not needed as its bounds are constant and checked
|
||||
// in V3Width.
|
||||
|
||||
virtual void visit(AstArraySel* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
|
@ -700,6 +700,43 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSliceSel* nodep) {
|
||||
// Always creates as output an unpacked array
|
||||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->fromp(), WidthVP(SELF,BOTH).p());
|
||||
//
|
||||
// Array indices are always constant
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefp();
|
||||
AstUnpackArrayDType* adtypep = fromDtp->castUnpackArrayDType();
|
||||
if (!adtypep) {
|
||||
UINFO(1," Related dtype: "<<fromDtp<<endl);
|
||||
nodep->v3fatalSrc("Packed array reference exceeds dimension of array");
|
||||
}
|
||||
// Build new array Dtype based on the original's base type, but with new bounds
|
||||
AstNodeDType* newDtp = new AstUnpackArrayDType(nodep->fileline(),
|
||||
adtypep->subDTypep(),
|
||||
new AstRange(nodep->fileline(),
|
||||
nodep->declRange()));
|
||||
v3Global.rootp()->typeTablep()->addTypesp(newDtp);
|
||||
nodep->dtypeFrom(newDtp);
|
||||
|
||||
if (!m_doGenerate) {
|
||||
// Must check bounds before adding a select that truncates the bound
|
||||
// Note we've already subtracted off LSB
|
||||
if ((nodep->declRange().hi() > adtypep->declRange().hi())
|
||||
|| nodep->declRange().lo() < adtypep->declRange().lo()) {
|
||||
// Other simulators warn too
|
||||
nodep->v3error("Slice selection index '"<< nodep->declRange() << "'"
|
||||
<<" outside data type's '"<< adtypep->declRange() << "'");
|
||||
}
|
||||
else if ((nodep->declRange().littleEndian() != adtypep->declRange().littleEndian())) {
|
||||
nodep->v3error("Slice selection '"<< nodep->declRange() << "'"
|
||||
<<" has backward indexing versus data type's '"<< adtypep->declRange() << "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSelBit* nodep) {
|
||||
// Just a quick check as after V3Param these nodes instead are AstSel's
|
||||
userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT,PRELIM).p()); //FINAL in AstSel
|
||||
|
@ -294,19 +294,24 @@ private:
|
||||
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
|
||||
vlsint32_t msb = msbp->castConst()->toSInt();
|
||||
vlsint32_t lsb = lsbp->castConst()->toSInt();
|
||||
vlsint32_t elem = (msb>lsb) ? (msb-lsb+1) : (lsb-msb+1);
|
||||
FromData fromdata = fromDataForArray(nodep, fromp, false);
|
||||
AstNodeDType* ddtypep = fromdata.m_dtypep;
|
||||
VNumRange fromRange = fromdata.m_fromRange;
|
||||
if (ddtypep->castUnpackArrayDType()) {
|
||||
// Slice extraction
|
||||
if (fromRange.elements() == (msb-lsb+1)
|
||||
if (fromRange.elements() == elem
|
||||
&& fromRange.lo() == lsb) { // Extracting whole of original array
|
||||
nodep->replaceWith(fromp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
} else {
|
||||
// TODO when unpacked arrays fully supported probably need new data type here
|
||||
AstArraySel* newp = new AstArraySel (nodep->fileline(), fromp, lsbp);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
} else if (fromRange.elements() == 1) { // Extracting single element
|
||||
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, lsbp);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
} else { // Slice
|
||||
AstSliceSel* newp = new AstSliceSel(nodep->fileline(), fromp,
|
||||
VNumRange(VNumRange::LeftRight(),
|
||||
msb, lsb));
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
}
|
||||
else if (AstPackArrayDType* adtypep = ddtypep->castPackArrayDType()) {
|
||||
// SELEXTRACT(array, msb, lsb) -> SEL(array, lsb*width-of-subindex, width-of-subindex*(msb-lsb))
|
||||
|
21
test_regress/t/t_array_backw_index_bad.pl
Executable file
21
test_regress/t/t_array_backw_index_bad.pl
Executable file
@ -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 (
|
||||
fails=>1,
|
||||
expect=>
|
||||
q{%Error: t/t_array_backw_index_bad.v:\d+: Slice selection '\[1:3\]' has backward indexing versus data type's '\[3:0\]'
|
||||
%Error: t/t_array_backw_index_bad.v:\d+: Slice selection '\[3:1\]' has backward indexing versus data type's '\[0:3\]'
|
||||
%Error: t/t_array_backw_index_bad.v:\d+: Slice selection index '\[4:3\]' outside data type's '\[3:0\]'
|
||||
%Error: t/t_array_backw_index_bad.v:\d+: Slice selection index '\[1:-1\]' outside data type's '\[3:0\]'
|
||||
.*%Error: Exiting due to.*},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
22
test_regress/t/t_array_backw_index_bad.v
Normal file
22
test_regress/t/t_array_backw_index_bad.v
Normal file
@ -0,0 +1,22 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
logic [31:0] array_assign [3:0];
|
||||
|
||||
logic [31:0] larray_assign [0:3];
|
||||
|
||||
initial begin
|
||||
array_assign[1:3] = '{32'd4, 32'd3, 32'd2};
|
||||
larray_assign[3:1] = '{32'd4, 32'd3, 32'd2};
|
||||
|
||||
array_assign[4:3] = '{32'd4, 32'd3};
|
||||
array_assign[1:-1] = '{32'd4, 32'd3};
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
18
test_regress/t/t_array_pattern_2d.pl
Executable file
18
test_regress/t/t_array_pattern_2d.pl
Executable file
@ -0,0 +1,18 @@
|
||||
#!/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 (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
39
test_regress/t/t_array_pattern_2d.v
Normal file
39
test_regress/t/t_array_pattern_2d.v
Normal file
@ -0,0 +1,39 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2009 by Iztok Jeras.
|
||||
|
||||
//bug991
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
logic [31:0] array_assign [3:0];
|
||||
logic [31:0] array_other [3:0];
|
||||
|
||||
logic [31:0] larray_assign [0:3];
|
||||
logic [31:0] larray_other [0:3];
|
||||
|
||||
initial begin
|
||||
array_assign[0] = 32'd1;
|
||||
array_assign[3:1] = '{32'd4, 32'd3, 32'd2};
|
||||
|
||||
array_other[0] = array_assign[0]+10;
|
||||
array_other[3:1] = array_assign[3:1];
|
||||
if (array_other[0] != 11) $stop;
|
||||
if (array_other[1] != 2) $stop;
|
||||
if (array_other[2] != 3) $stop;
|
||||
if (array_other[3] != 4) $stop;
|
||||
|
||||
larray_assign[0] = 32'd1;
|
||||
larray_assign[1:3] = '{32'd4, 32'd3, 32'd2};
|
||||
|
||||
larray_other[0] = larray_assign[0]+10;
|
||||
larray_other[1:3] = larray_assign[1:3];
|
||||
if (larray_other[0] != 11) $stop;
|
||||
if (larray_other[1] != 4) $stop;
|
||||
if (larray_other[2] != 3) $stop;
|
||||
if (larray_other[3] != 2) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
@ -13,10 +13,11 @@ compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments have different unpacked dimensions, 9 versus 8
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments have different unpacked dimensions, 4 versus 3
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments have different unpacked dimensions, 9 versus 8
|
||||
%Error: Exiting due to.*',
|
||||
q{%Error: t/t_mem_slice_bad.v:\d+: Slice selection index '\[2:0\]' outside data type's '\[1:0\]'
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slice selection index '\[3:0\]' outside data type's '\[2:0\]'
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slice selection index '\[3:0\]' outside data type's '\[1:0\]'
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slice selection index '\[8:0\]' outside data type's '\[7:0\]'
|
||||
%Error: Exiting due to.*},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
Loading…
Reference in New Issue
Block a user