From 75aab4e9d2e204f27efbf999768125b824acdbf4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 4 Oct 2017 21:27:34 -0400 Subject: [PATCH] Fix conditional slices and add related optimizations. --- Changes | 2 + src/V3AstNodes.cpp | 4 - src/V3AstNodes.h | 11 +- src/V3Slice.cpp | 459 ++++---------------------- src/V3WidthSel.cpp | 2 - test_regress/t/t_array_compare.v | 6 +- test_regress/t/t_inst_misarray_bad.pl | 7 +- test_regress/t/t_mem_packed_bad.pl | 4 +- test_regress/t/t_mem_slice_bad.pl | 8 +- test_regress/t/t_slice_cond.pl | 14 + test_regress/t/t_slice_cond.v | 38 +++ test_regress/t/t_slice_init.pl | 18 + test_regress/t/t_slice_init.v | 59 ++++ 13 files changed, 218 insertions(+), 414 deletions(-) create mode 100755 test_regress/t/t_slice_cond.pl create mode 100644 test_regress/t/t_slice_cond.v create mode 100755 test_regress/t/t_slice_init.pl create mode 100644 test_regress/t/t_slice_init.v diff --git a/Changes b/Changes index 2d790d658..82c21cea4 100644 --- a/Changes +++ b/Changes @@ -23,6 +23,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix unnecessary Vdly variables, bug1224 partial. [John Coiner] +**** Fix conditional slices and add related optimizations. + * Verilator 3.912 2017-09-23 diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d42e41f20..f05391006 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -763,10 +763,6 @@ void AstAlways::dump(ostream& str) { if (keyword() != VAlwaysKwd::ALWAYS) str<<" ["<AstNode::dump(str); - str<<" [start:"<AstNode::dump(str); str<<" ["<dtypep()->skipRefp()->castNodeArrayDType()) { // Strip off array to find what array references @@ -776,11 +774,11 @@ private: } public: AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) - :AstNodeSel(fl, fromp, bitp), m_start(0), m_length(1) { + :AstNodeSel(fl, fromp, bitp) { init(fromp); } AstArraySel(FileLine* fl, AstNode* fromp, int bit) - :AstNodeSel(fl, fromp, new AstConst(fl,bit)), m_start(0), m_length(1) { + :AstNodeSel(fl, fromp, new AstConst(fl,bit)) { init(fromp); } ASTNODE_NODE_FUNCS(ArraySel) @@ -797,13 +795,8 @@ public: virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(AstNode* samep) const { return true; } virtual int instrCount() const { return widthInstrs(); } - unsigned length() const { return m_length; } - void length(unsigned length) { m_length = length; } - void start(unsigned start) { m_start = start; } - unsigned start() const { return m_start; } // Special operators static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences? - virtual void dump(ostream& str); }; class AstWordSel : public AstNodeSel { diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 20827f3df..6ac7b5496 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -45,153 +45,6 @@ #include "V3Global.h" #include "V3Slice.h" #include "V3Ast.h" -#include - -class SliceCloneVisitor : public AstNVisitor { - // NODE STATE - // Inputs: - // AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to - // AstNodeAssign::user2() -> int. The number of clones needed for this assign - // AstArraySel::user3() -> bool. Error detected - - // STATE - vector > m_selBits; // Indexes of the ArraySel we are expanding - int m_vecIdx; // Current vector index - unsigned m_depth; // Number of ArraySel's from the VarRef - AstVarRef* m_refp; // VarRef under this ArraySel - - // METHODS - static int debug() { - static int level = -1; - if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); - return level; - } - - // VISITORS - virtual void visit(AstArraySel* nodep) { - if (!nodep->backp()->castArraySel()) { - // This is the top of an ArraySel, setup for iteration - m_refp = nodep->user1p()->castVarRef(); - m_vecIdx += 1; - if (m_vecIdx == (int)m_selBits.size()) { - m_selBits.push_back(vector()); - AstVar* varp = m_refp->varp(); - pair arrDim = varp->dtypep()->dimensions(false); - uint32_t dimensions = arrDim.second; - // for 3-dimensions we want m_selBits[m_vecIdx]=[0,0,0] - for (uint32_t i = 0; i < dimensions; ++i) { - m_selBits[m_vecIdx].push_back(0); - } - } - } - nodep->iterateChildren(*this); - if (nodep->fromp()->castVarRef()) { - m_depth = 0; - } else { - ++m_depth; - } - // Check if m_selBits has overflowed - if (m_selBits[m_vecIdx][m_depth] >= nodep->length()) { - m_selBits[m_vecIdx][m_depth] = 0; - if (m_depth + 1 < m_selBits[m_vecIdx].size()) - m_selBits[m_vecIdx][m_depth+1] += 1; - } - // Reassign the bitp() - if (nodep->length() > 1) { - if (AstConst* bitp = nodep->bitp()->castConst()) { - AstUnpackArrayDType* adtypep = nodep->fromp()->dtypep()->skipRefp()->castUnpackArrayDType(); - if (!adtypep) nodep->v3fatalSrc("slice select tried to expand an array without an ArrayDType"); - unsigned idx = nodep->start() + m_selBits[m_vecIdx][m_depth] - adtypep->lsb(); - if (adtypep->rangep()->littleEndian()) { // Little must iterate backwards - idx = adtypep->rangep()->elementsConst() - 1 - idx; - } - AstNode* constp = new AstConst(bitp->fileline(), V3Number(bitp->fileline(), bitp->castConst()->num().width(), idx)); - bitp->replaceWith(constp); - } else { - nodep->v3error("Unsupported: Only constants supported in slices"); - } - } - if (!nodep->backp()->castArraySel()) { - // Top ArraySel, increment m_selBits - m_selBits[m_vecIdx][0] += 1; - } - nodep->length(1); - } - - virtual void visit(AstNodeAssign* nodep) { - if (nodep->user2() < 2) return; // Don't need clones - m_selBits.clear(); - UINFO(4, "Cloning "<user2()<<" times: "<user2(); ++i) { - // Clone the node and iterate over the clone - m_vecIdx = -1; - AstNodeAssign* clonep = nodep->cloneTree(false)->castNodeAssign(); - clonep->iterateChildren(*this); - nodep->addNextHere(clonep); - } - nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); - } - - // Not all Uniop nodes should be cloned down to a single bit - void cloneUniop(AstNodeUniop* nodep) { - if (nodep->user2() < 2) return; // Don't need clones - m_selBits.clear(); - UINFO(4, "Cloning "<user2()<<" times: "<user2(); ++i) { - // Clone the node and iterate over the clone - m_vecIdx = -1; - AstNodeUniop* clonep = nodep->cloneTree(false)->castNodeUniop(); - clonep->iterateChildren(*this); - if (!lhsp) lhsp = clonep; - else { - switch (nodep->type()) { - case AstType::atRedOr: - lhsp = new AstOr(nodep->fileline(), lhsp, clonep); - break; - case AstType::atRedAnd: - lhsp = new AstAnd(nodep->fileline(), lhsp, clonep); - break; - case AstType::atRedXor: - lhsp = new AstXor(nodep->fileline(), lhsp, clonep); - break; - case AstType::atRedXnor: - lhsp = new AstXnor(nodep->fileline(), lhsp, clonep); - break; - default: - nodep->v3fatalSrc("Unsupported: Unary operation on multiple packed dimensions"); - break; - } - } - } - nodep->replaceWith(lhsp); - nodep->deleteTree(); VL_DANGLING(nodep); - } - virtual void visit(AstRedOr* nodep) { - cloneUniop(nodep); - } - virtual void visit(AstRedAnd* nodep) { - cloneUniop(nodep); - } - virtual void visit(AstRedXor* nodep) { - cloneUniop(nodep); - } - virtual void visit(AstRedXnor* nodep) { - cloneUniop(nodep); - } - - virtual void visit(AstNode* nodep) { - // Default: Just iterate - nodep->iterateChildren(*this); - } -public: - // CONSTUCTORS - explicit SliceCloneVisitor(AstNode* nodep) { - nodep->accept(*this); - } - virtual ~SliceCloneVisitor() {} -}; //************************************************************************* @@ -201,18 +54,10 @@ class SliceVisitor : public AstNVisitor { // AstNodeAssign::user1() -> bool. True if find is complete // AstUniop::user1() -> bool. True if find is complete // AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to - // AstNode::user2() -> int. The number of clones needed for this node AstUser1InUse m_inuser1; - AstUser2InUse m_inuser2; - AstUser3InUse m_inuser3; - - // TYPEDEFS - typedef pair ArrayDimensions; // Array Dimensions (packed, unpacked) // STATE AstNode* m_assignp; // Assignment we are under - AstNodeVarRef* m_lhsVarRefp; // Var on the LHS - bool m_extend; // We have found an extend node bool m_assignError; // True if the current assign already has an error // METHODS @@ -222,265 +67,103 @@ class SliceVisitor : public AstNVisitor { return level; } - unsigned explicitDimensions(AstArraySel* nodep) { - // Find out how many explicit dimensions are in a given ArraySel. - unsigned dim = 0; - AstNode* fromp = nodep; - AstArraySel* selp; - do { - selp = fromp->castArraySel(); - if (!selp) { - nodep->user1p(fromp->castVarRef()); - selp = NULL; - break; - } else { - fromp = selp->fromp(); - if (fromp) ++dim; - } - } while (fromp && selp); - if (!nodep->user1p()) nodep->v3fatalSrc("Couldn't find VarRef under the ArraySel"); - return dim; - } - - int countClones(AstArraySel* nodep) { - // Count how many clones we need to make from this ArraySel - int clones = 1; - AstNode* fromp = nodep; - AstArraySel* selp; - do { - selp = fromp->castArraySel(); - fromp = (selp) ? selp->fromp() : NULL; - if (fromp && selp) clones *= selp->length(); - } while (fromp && selp); - return clones; - } - - AstArraySel* insertImplicit(AstNode* nodep, unsigned startDim, unsigned numDimensions) { - // Insert any implicit slices as explicit slices (ArraySel nodes). - // Return a new pointer to replace nodep() in the ArraySel. - UINFO(9," insertImplicit (startDim="<user1p()->castVarRef(); - if (!refp) nodep->v3fatalSrc("No VarRef in user1 of node "<varp(); - AstNode* topp = nodep; - for (unsigned i = startDim; i < startDim + numDimensions; ++i) { - AstNodeDType* dtypep = varp->dtypep()->dtypeDimensionp(i-1); - AstUnpackArrayDType* adtypep = dtypep->castUnpackArrayDType(); - if (!adtypep) nodep->v3fatalSrc("insertImplicit tried to expand an array without an ArrayDType"); - vlsint32_t msb = adtypep->msb(); - vlsint32_t lsb = adtypep->lsb(); - if (lsb > msb) { - // Below code assumes big bit endian; just works out if we swap - int x = msb; msb = lsb; lsb = x; - } - UINFO(9," ArraySel-child: "<fileline(), topp, - // Arrays are zero-based so index 0 is always lsb (e.g. lsb-lsb -> 0) - new AstConst(nodep->fileline(), 0)); - if (!newp->dtypep()) { - newp->v3fatalSrc("ArraySel dtyping failed when resolving slice"); // see ArraySel constructor - } - newp->user1p(refp); - newp->start(lsb); - newp->length(msb - lsb + 1); - topp = newp; - } - return topp->castArraySel(); - } - - // VISITORS - virtual void visit(AstVarRef* nodep) { - // The LHS/RHS of an Assign may be to a Var that is an array. In this - // case we need to create a slice across the entire Var - if (m_assignp && !nodep->backp()->castArraySel()) { - pair arrDim = nodep->varp()->dtypep()->dimensions(false); - uint32_t dimensions = arrDim.second; // unpacked only - if (dimensions > 0) { - AstVarRef* clonep = nodep->cloneTree(false); - clonep->user1p(nodep); - AstNode* newp = insertImplicit(clonep, 1, dimensions); - nodep->replaceWith(newp); VL_DANGLING(nodep); - newp->accept(*this); - } - } - } - - virtual void visit(AstExtend* nodep) { - m_extend = true; - if (m_assignp && m_assignp->user2() > 1 && !m_assignError) { - m_assignp->v3error("Unsupported: Assignment between unpacked arrays of different dimensions"); + AstNode* cloneAndSel(AstNode* nodep, int elements, int offset) { + // Insert an ArraySel, except for a few special cases + AstUnpackArrayDType* arrayp = nodep->dtypep()->skipRefp()->castUnpackArrayDType(); + if (!arrayp) { // V3Width should have complained, but... + if (!m_assignError) nodep->v3error(nodep->prettyTypeName()<<" is not an unpacked array, but is in an unpacked array context"); m_assignError = true; + return nodep->cloneTree(false); // Likely will cause downstream errors } - nodep->iterateChildren(*this); - } - - virtual void visit(AstConst* nodep) { - m_extend = true; - if (m_assignp && m_assignp->user2() > 1 && !m_assignError) { - m_assignp->v3error("Unsupported: Assignment between a constant and an array slice"); + if (arrayp->rangep()->elementsConst() != elements) { + if (!m_assignError) nodep->v3error("Slices of arrays in assignments have different unpacked dimensions, " + <rangep()->elementsConst()); m_assignError = true; + elements = 1; offset = 0; } - } - - virtual void visit(AstArraySel* nodep) { - if (!m_assignp) return; - if (nodep->user3()) return; // Prevent recursion on just created nodes - unsigned dim = explicitDimensions(nodep); - AstVarRef* refp = nodep->user1p()->castVarRef(); - pair arrDim = refp->varp()->dtypep()->dimensions(false); - uint32_t implicit = (arrDim.second) - dim; - if (implicit > 0) { - AstArraySel* newp = insertImplicit(nodep->cloneTree(false), dim+1, implicit); - nodep->replaceWith(newp); nodep = newp; - nodep->user3(true); - } - int clones = countClones(nodep); - if (m_assignp->user2() > 0 && m_assignp->user2() != clones) { - m_assignp->v3error("Slices of arrays in assignments must have the same unpacked dimensions"); - } else if (!m_assignp->user2()) { - if (m_extend && clones > 1 && !m_assignError) { - m_assignp->v3error("Unsupported: Assignment between unpacked arrays of different dimensions"); - m_assignError = true; + AstNode* newp; + if (AstInitArray* initp = nodep->castInitArray()) { + UINFO(9," cloneInitArray("<initsp(); + int leOffset = !arrayp->rangep()->littleEndian() ? arrayp->rangep()->elementsConst()-1-offset : offset; + for (int pos = 0; itemp && pos < leOffset; ++pos) { + itemp = itemp->nextp(); } - if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhsVarRefp->varp() - && !m_assignp->castAssignDly() && !m_assignError) { - // LHS Var != RHS Var for a non-delayed assignment - m_assignp->v3error("Unsupported: Slices in a non-delayed assignment with the same Var on both sides"); - m_assignError = true; + if (!itemp) { + nodep->v3error("Array initialization has too few elements, need element "<initsp(); } - m_assignp->user2(clones); + newp = itemp->cloneTree(false); } - } - - virtual void visit(AstSel* nodep) { - m_extend = true; - if (m_assignp && m_assignp->user2() > 1 && !m_assignError) { - m_assignp->v3error("Unsupported: Assignment between unpacked arrays of different dimensions"); + else if (AstNodeCond* snodep = nodep->castNodeCond()) { + UINFO(9," cloneCond("<cloneType(snodep->condp()->cloneTree(false), + cloneAndSel(snodep->expr1p(), elements, offset), + cloneAndSel(snodep->expr2p(), elements, offset)); + } + else if (nodep->castArraySel() + || nodep->castNodeVarRef() + || nodep->castNodeSel()) { + UINFO(9," cloneSel("<rangep()->littleEndian() ? arrayp->rangep()->elementsConst()-1-offset : offset; + newp = new AstArraySel(nodep->fileline(), nodep->cloneTree(false), leOffset); + } + else { + if (!m_assignError) nodep->v3error(nodep->prettyTypeName()<<" unexpected in assignment to unpacked array"); m_assignError = true; + newp = nodep->cloneTree(false); // Likely will cause downstream errors } - nodep->iterateChildren(*this); - } - - virtual void visit(AstNodeCond* nodep) { - // The conditional must be a single bit so only look at the expressions - nodep->expr1p()->accept(*this); - nodep->expr2p()->accept(*this); - // Downstream data type may have changed; propagate up - nodep->dtypeFrom(nodep->expr1p()); - } - - // Return the first AstVarRef under the node - AstVarRef* findVarRefRecurse(AstNode* nodep) { - AstVarRef* refp = nodep->castVarRef(); - if (refp) return refp; - if (nodep->op1p()) { - refp = findVarRefRecurse(nodep->op1p()); - if (refp) return refp; - } - if (nodep->op2p()) { - refp = findVarRefRecurse(nodep->op2p()); - if (refp) return refp; - } - if (nodep->op3p()) { - refp = findVarRefRecurse(nodep->op3p()); - if (refp) return refp; - } - if (nodep->op4p()) { - refp = findVarRefRecurse(nodep->op4p()); - if (refp) return refp; - } - if (nodep->nextp()) { - refp = findVarRefRecurse(nodep->nextp()); - if (refp) return refp; - } - return NULL; - } - - void findImplicit(AstNodeAssign* nodep) { - if (m_assignp) nodep->v3fatalSrc("Found a NodeAssign under another NodeAssign"); - m_assignp = nodep; - m_assignError = false; - m_extend = false; - nodep->user1(true); - // Record the LHS Var so we can check if the Var on the RHS is the same - m_lhsVarRefp = findVarRefRecurse(nodep->lhsp()); - if (!m_lhsVarRefp) nodep->v3fatalSrc("Couldn't find a VarRef on the LHSP of an Assign"); - // Iterate children looking for ArraySel nodes. From that we get the number of elements - // in the array so we know how many times we need to clone this assignment. - nodep->iterateChildren(*this); - if (nodep->user2() > 1) SliceCloneVisitor scv(nodep); - m_assignp = NULL; + return newp; } virtual void visit(AstNodeAssign* nodep) { - if (!nodep->user1()) { - // Cleanup initArrays - if (AstInitArray* initp = nodep->rhsp()->castInitArray()) { - //if (debug()>=9) nodep->dumpTree(cout, "-InitArrayIn: "); - AstNode* newp = NULL; - for (int pos = 0; AstNode* itemp=initp->initsp(); ++pos) { - int index = initp->posIndex(pos); - AstNode* lhsp = new AstArraySel(nodep->fileline(), - nodep->lhsp()->cloneTree(false), - index); - newp = AstNode::addNext(newp, nodep->cloneType(lhsp, itemp->unlinkFrBack())); - // Deleted from list of items without correcting posIndex, but that's ok as about - // to delete the entire InitArray + // Called recursively on newly created assignments + if (!nodep->user1() + && !nodep->castAssignAlias()) { + nodep->user1(true); + m_assignError = false; + if (debug()>=9) { cout<dumpTree(cout," Deslice-In: "); } + AstNodeDType* dtp = nodep->lhsp()->dtypep()->skipRefp(); + if (AstUnpackArrayDType* arrayp = dtp->castUnpackArrayDType()) { + // Left and right could have different msb/lsbs/endianness, but #elements is common + // and all variables are realigned to start at zero + // Assign of a little endian'ed slice to a big endian one must reverse the elements + AstNode* newlistp = NULL; + int elements = arrayp->rangep()->elementsConst(); + for (int offset = 0; offset < elements; ++offset) { + AstNode* newp = nodep->cloneType // AstNodeAssign + (cloneAndSel(nodep->lhsp(), elements, offset), + cloneAndSel(nodep->rhsp(), elements, offset)); + if (debug()>=9) { newp->dumpTree(cout,"-new "); } + newlistp = AstNode::addNextNull(newlistp, newp); } - //if (debug()>=9) newp->dumpTreeAndNext(cout, "-InitArrayOut: "); - nodep->replaceWith(newp); - pushDeletep(nodep); VL_DANGLING(nodep); - return; // Will iterate in a moment + nodep->replaceWith(newlistp); nodep->deleteTree(); VL_DANGLING(nodep); + if (debug()>=9) { cout<dumpTree(cout," Deslice-Dn: "); } + // 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; } - // Hasn't been searched for implicit slices yet - findImplicit(nodep); + m_assignp = nodep; + nodep->iterateChildren(*this); + m_assignp = NULL; } } - void expandUniOp(AstNodeUniop* nodep) { - if (!nodep->user1()) { - nodep->user1(true); - unsigned dim = 0; - if (AstArraySel* selp = nodep->lhsp()->castArraySel()) { - // We have explicit dimensions, either packed or unpacked - dim = explicitDimensions(selp); - } - if (dim == 0 && !nodep->lhsp()->castVarRef()) { - // No ArraySel nor VarRef, not something we can expand - nodep->iterateChildren(*this); - } else { - AstVarRef* refp = findVarRefRecurse(nodep->lhsp()); - ArrayDimensions varDim = refp->varp()->dtypep()->dimensions(false); - if ((int)(dim - varDim.second) < 0) { - // Unpacked dimensions are referenced first, make sure we have them all - nodep->v3error("Unary operator used across unpacked dimensions"); - } - } + virtual void visit(AstInitArray* nodep) { + if (m_assignp) { + nodep->v3fatalSrc("Array initialization should have been removed earlier"); } } - virtual void visit(AstRedOr* nodep) { - expandUniOp(nodep); - } - virtual void visit(AstRedAnd* nodep) { - expandUniOp(nodep); - } - virtual void visit(AstRedXor* nodep) { - expandUniOp(nodep); - } - virtual void visit(AstRedXnor* nodep) { - expandUniOp(nodep); - } void expandBiOp(AstNodeBiop* nodep) { if (!nodep->user1()) { nodep->user1(true); - // If it's a unpacked array, blow it up into comparing each element + // If it's an unpacked array, blow it up into comparing each element AstNodeDType* fromDtp = nodep->lhsp()->dtypep()->skipRefp(); UINFO(9, " Bi-Eq/Neq expansion "<castUnpackArrayDType()) { AstNodeBiop* logp = NULL; - for (int index = adtypep->rangep()->lsbConst(); - index <= adtypep->rangep()->msbConst(); ++index) { + for (int index = 0; index <= adtypep->rangep()->elementsConst(); ++index) { // EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1]) AstNodeBiop* clonep = nodep->cloneType (new AstArraySel(nodep->fileline(), @@ -536,7 +219,7 @@ public: // CONSTUCTORS explicit SliceVisitor(AstNetlist* rootp) { m_assignp = NULL; - m_lhsVarRefp = NULL; + m_assignError = false; rootp->accept(*this); } virtual ~SliceVisitor() {} diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 1bb86acf0..5be3c603e 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -305,8 +305,6 @@ private: } else { // TODO when unpacked arrays fully supported probably need new data type here AstArraySel* newp = new AstArraySel (nodep->fileline(), fromp, lsbp); - newp->start(lsb); - newp->length((msb - lsb) + 1); nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep); } } diff --git a/test_regress/t/t_array_compare.v b/test_regress/t/t_array_compare.v index 7060d1e01..d94464815 100644 --- a/test_regress/t/t_array_compare.v +++ b/test_regress/t/t_array_compare.v @@ -35,12 +35,16 @@ module t (/*AUTOARG*/ array_3[2] = 4'b0100; array_3[3] = 4'b0100; - // Comparisons only compare elements 0 array_1_ne_array_2 = array_1 != array_2; // 0 array_1_eq_array_2 = array_1 == array_2; // 0 array_1_ne_array_3 = array_1 != array_3; // 1 array_1_eq_array_3 = array_1 == array_3; // 1 + //Not legal: array_rxor = ^ array_1; + //Not legal: array_rxnor = ^~ array_1; + //Not legal: array_ror = | array_1; + //Not legal: array_rand = & array_1; + `ifdef TEST_VERBOSE $write("array_1_ne_array2==%0d\n", array_1_ne_array_2); $write("array_1_ne_array3==%0d\n", array_1_ne_array_3); diff --git a/test_regress/t/t_inst_misarray_bad.pl b/test_regress/t/t_inst_misarray_bad.pl index 569aa04b3..aa6e86031 100755 --- a/test_regress/t/t_inst_misarray_bad.pl +++ b/test_regress/t/t_inst_misarray_bad.pl @@ -9,12 +9,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di compile ( verilator_flags2 => ["--lint-only"], - fails=>0, + fails => 1, verilator_make_gcc => 0, make_top_shell => 0, make_main => 0, - # Once got illegal assignment, but new slicing rules don't always detect this. - # Due to V3Width.cpp pinwidth != conwidth requirement on data type mismatches + expect=> +q{%Error: t/t_inst_misarray_bad.v:16: VARREF 't.foo' is not an unpacked array, but is in an unpacked array context +%Error: Exiting due to.*}, ); diff --git a/test_regress/t/t_mem_packed_bad.pl b/test_regress/t/t_mem_packed_bad.pl index 32f91116e..dc42ba5b8 100755 --- a/test_regress/t/t_mem_packed_bad.pl +++ b/test_regress/t/t_mem_packed_bad.pl @@ -13,8 +13,8 @@ compile ( verilator_flags2 => ["--lint-only"], fails=>1, expect=> -'%Error: t/t_mem_packed_bad.v:\d+: Unsupported: Assignment between unpacked arrays of different dimensions -%Error: Exiting due to.*', +q{%Error: t/t_mem_packed_bad.v:\d+: CONST '28'h0' unexpected in assignment to unpacked array +%Error: Exiting due to.*}, ); ok(1); diff --git a/test_regress/t/t_mem_slice_bad.pl b/test_regress/t/t_mem_slice_bad.pl index 8fd4613c2..b8c2da841 100755 --- a/test_regress/t/t_mem_slice_bad.pl +++ b/test_regress/t/t_mem_slice_bad.pl @@ -13,11 +13,9 @@ compile ( v_flags2 => ["--lint-only"], fails=>1, expect=> -'%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions -%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions -%Error: t/t_mem_slice_bad.v:\d+: Unsupported: Slices in a non-delayed assignment with the same Var on both sides -%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions -%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions +'%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.*', ); diff --git a/test_regress/t/t_slice_cond.pl b/test_regress/t/t_slice_cond.pl new file mode 100755 index 000000000..385b6a57e --- /dev/null +++ b/test_regress/t/t_slice_cond.pl @@ -0,0 +1,14 @@ +#!/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 ( + ); + +ok(1); +1; diff --git a/test_regress/t/t_slice_cond.v b/test_regress/t/t_slice_cond.v new file mode 100644 index 000000000..7e3be3c92 --- /dev/null +++ b/test_regress/t/t_slice_cond.v @@ -0,0 +1,38 @@ +// 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*/ + // Outputs + dataout, + // Inputs + clk, sel, d0, d1 + ); + + input clk; + input sel; + + logic [7:0] data [1:0][3:0]; + input [7:0] d0, d1; + + output wire [8*2*4-1:0] dataout; + + always_comb begin + for ( integer j = 0; j <= 1; j++ ) begin + if (sel) + data[j] = '{ d0, d1, 8'h00, 8'h00 }; + else + data[j] = '{ 8'h00, 8'h00, 8'h00, 8'h00 }; + end + for ( integer j = 0; j <= 1; j++ ) begin + data[j] = sel + ? '{ d0, d1, 8'h00, 8'h00 } + : '{ 8'h00, 8'h00, 8'h00, 8'h00 }; + end + end + + assign dataout = {data[0][0], data[0][1], data[0][2], data[0][3], + data[1][0], data[1][1], data[1][2], data[1][3]}; + +endmodule diff --git a/test_regress/t/t_slice_init.pl b/test_regress/t/t_slice_init.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_slice_init.pl @@ -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; diff --git a/test_regress/t/t_slice_init.v b/test_regress/t/t_slice_init.v new file mode 100644 index 000000000..828a914eb --- /dev/null +++ b/test_regress/t/t_slice_init.v @@ -0,0 +1,59 @@ +// 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*/ + // Inputs + clk, d0, d1 + ); + + input clk; + input [7:0] d0, d1; + + logic [7:0] inia [1:0][3:0] = '{ '{ '0, '1, 8'hfe, 8'hed }, + '{ '1, '1, 8'h11, 8'h22 }}; + logic [7:0] inil [0:1][0:3] = '{ '{ '0, '1, 8'hfe, 8'hed }, + '{ '1, '1, 8'h11, 8'h22 }}; + + logic [7:0] data [1:0][3:0]; + logic [7:0] datl [0:1][0:3]; + + initial begin + data = '{ '{ d0, d1, 8'hfe, 8'hed }, + '{ d1, d1, 8'h11, 8'h22 }}; + data[0] = '{ d0, d1, 8'h19, 8'h39 }; + + datl = '{ '{ d0, d1, 8'hfe, 8'hed }, + '{ d1, d1, 8'h11, 8'h22 }}; + datl[0] = '{ d0, d1, 8'h19, 8'h39 }; + +`ifdef TEST_VERBOSE + $display("D=%x %x %x %x -> 39 19 x x", data[0][0], data[0][1], data[0][2], data[0][3]); + $display("D=%x %x %x %x -> ed fe x x", data[1][0], data[1][1], data[1][2], data[1][3]); + $display("L=%x %x %x %x -> x x 19 39", datl[0][0], datl[0][1], datl[0][2], datl[0][3]); + $display("L=%x %x %x %x -> x x 11 12", datl[1][0], datl[1][1], datl[1][2], datl[1][3]); +`endif + if (inia[0][0] !== 8'h22) $stop; + if (inia[0][1] !== 8'h11) $stop; + if (inia[1][0] !== 8'hed) $stop; + if (inia[1][1] !== 8'hfe) $stop; + + if (inil[0][2] !== 8'hfe) $stop; + if (inil[0][3] !== 8'hed) $stop; + if (inil[1][2] !== 8'h11) $stop; + if (inil[1][3] !== 8'h22) $stop; + + if (data[0][0] !== 8'h39) $stop; + if (data[0][1] !== 8'h19) $stop; + if (data[1][0] !== 8'hed) $stop; + if (data[1][1] !== 8'hfe) $stop; + + if (datl[0][2] !== 8'h19) $stop; + if (datl[0][3] !== 8'h39) $stop; + if (datl[1][2] !== 8'h11) $stop; + if (datl[1][3] !== 8'h22) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule