2012-04-13 01:08:20 +00:00
|
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2010-01-19 15:52:11 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Parse module/signal name references
|
|
|
|
|
//
|
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2019-01-04 00:17:22 +00:00
|
|
|
|
// Copyright 2003-2019 by Wilson Snyder. This program is free software; you can
|
2010-01-19 15:52:11 +00:00
|
|
|
|
// 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.
|
|
|
|
|
//
|
|
|
|
|
// Verilator is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// Slice TRANSFORMATIONS:
|
2019-05-19 20:13:13 +00:00
|
|
|
|
// Top-down traversal (SliceVisitor):
|
|
|
|
|
// NODEASSIGN
|
|
|
|
|
// ARRAYSEL
|
|
|
|
|
// Compare the dimensions to the Var to check for implicit slices.
|
|
|
|
|
// Using ->length() calculate the number of clones needed.
|
|
|
|
|
// VARREF
|
|
|
|
|
// Check the dimensions of the Var for an implicit slice.
|
|
|
|
|
// Replace with ArraySel nodes if needed.
|
|
|
|
|
// SEL, EXTEND
|
|
|
|
|
// We might be assigning a 1-D packed array to a 2-D packed array,
|
|
|
|
|
// this is unsupported.
|
|
|
|
|
// SliceCloneVisitor (called if this node is a slice):
|
|
|
|
|
// NODEASSIGN
|
|
|
|
|
// Clone and iterate the clone:
|
|
|
|
|
// ARRAYSEL
|
|
|
|
|
// Modify bitp() for the new value and set ->length(1)
|
2017-11-23 19:55:32 +00:00
|
|
|
|
//
|
|
|
|
|
// TODO: This code was written before SLICESEL was a type it might be
|
|
|
|
|
// simplified to look primarily for SLICESELs.
|
2010-01-19 15:52:11 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3Slice.h"
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
2018-10-14 17:43:24 +00:00
|
|
|
|
#include <cstdarg>
|
|
|
|
|
|
2010-01-19 15:52:11 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
class SliceVisitor : public AstNVisitor {
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on netlist
|
2019-05-19 20:13:13 +00:00
|
|
|
|
// AstNodeAssign::user1() -> bool. True if find is complete
|
2018-06-22 10:35:27 +00:00
|
|
|
|
// AstNodeUniop::user1() -> bool. True if find is complete
|
2019-05-19 20:13:13 +00:00
|
|
|
|
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
|
|
|
|
AstUser1InUse m_inuser1;
|
2010-04-10 01:05:46 +00:00
|
|
|
|
|
2010-01-19 15:52:11 +00:00
|
|
|
|
// STATE
|
2019-05-19 20:13:13 +00:00
|
|
|
|
AstNode* m_assignp; // Assignment we are under
|
|
|
|
|
bool m_assignError; // True if the current assign already has an error
|
2010-01-19 15:52:11 +00:00
|
|
|
|
|
|
|
|
|
// METHODS
|
2018-05-14 10:50:47 +00:00
|
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2010-01-19 15:52:11 +00:00
|
|
|
|
|
2017-10-05 01:27:34 +00:00
|
|
|
|
AstNode* cloneAndSel(AstNode* nodep, int elements, int offset) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
// Insert an ArraySel, except for a few special cases
|
2018-02-02 02:32:58 +00:00
|
|
|
|
AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
|
2019-05-19 20:13:13 +00:00
|
|
|
|
if (!arrayp) { // V3Width should have complained, but...
|
2018-03-10 21:32:04 +00:00
|
|
|
|
if (!m_assignError) {
|
|
|
|
|
nodep->v3error(nodep->prettyTypeName()
|
|
|
|
|
<<" is not an unpacked array, but is in an unpacked array context");
|
|
|
|
|
}
|
2019-05-19 20:13:13 +00:00
|
|
|
|
m_assignError = true;
|
|
|
|
|
return nodep->cloneTree(false); // Likely will cause downstream errors
|
|
|
|
|
}
|
|
|
|
|
if (arrayp->rangep()->elementsConst() != elements) {
|
|
|
|
|
if (!m_assignError) nodep->v3error("Slices of arrays in assignments have different unpacked dimensions, "
|
|
|
|
|
<<elements<<" versus "
|
|
|
|
|
<<arrayp->rangep()->elementsConst());
|
|
|
|
|
m_assignError = true;
|
|
|
|
|
elements = 1; offset = 0;
|
|
|
|
|
}
|
|
|
|
|
AstNode* newp;
|
2018-02-02 02:32:58 +00:00
|
|
|
|
if (AstInitArray* initp = VN_CAST(nodep, InitArray)) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
UINFO(9," cloneInitArray("<<elements<<","<<offset<<") "<<nodep<<endl);
|
|
|
|
|
AstNode* itemp = initp->initsp();
|
|
|
|
|
int leOffset = !arrayp->rangep()->littleEndian()
|
|
|
|
|
? arrayp->rangep()->elementsConst()-1-offset : offset;
|
|
|
|
|
for (int pos = 0; itemp && pos < leOffset; ++pos) {
|
|
|
|
|
itemp = itemp->nextp();
|
|
|
|
|
}
|
|
|
|
|
if (!itemp) {
|
|
|
|
|
nodep->v3error("Array initialization has too few elements, need element "<<offset);
|
|
|
|
|
itemp = initp->initsp();
|
|
|
|
|
}
|
|
|
|
|
newp = itemp->cloneTree(false);
|
|
|
|
|
}
|
2018-02-02 02:32:58 +00:00
|
|
|
|
else if (AstNodeCond* snodep = VN_CAST(nodep, NodeCond)) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
UINFO(9," cloneCond("<<elements<<","<<offset<<") "<<nodep<<endl);
|
|
|
|
|
return snodep->cloneType(snodep->condp()->cloneTree(false),
|
|
|
|
|
cloneAndSel(snodep->expr1p(), elements, offset),
|
|
|
|
|
cloneAndSel(snodep->expr2p(), elements, offset));
|
|
|
|
|
}
|
2018-02-02 02:32:58 +00:00
|
|
|
|
else if (AstSliceSel* snodep = VN_CAST(nodep, SliceSel)) {
|
2017-11-23 19:55:32 +00:00
|
|
|
|
UINFO(9," cloneSliceSel("<<elements<<","<<offset<<") "<<nodep<<endl);
|
|
|
|
|
int leOffset = (snodep->declRange().lo()
|
2019-05-19 20:13:13 +00:00
|
|
|
|
+ (!snodep->declRange().littleEndian()
|
|
|
|
|
? snodep->declRange().elements()-1-offset : offset));
|
2017-11-23 19:55:32 +00:00
|
|
|
|
newp = new AstArraySel(nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset);
|
|
|
|
|
}
|
2018-02-02 02:32:58 +00:00
|
|
|
|
else if (VN_IS(nodep, ArraySel)
|
|
|
|
|
|| VN_IS(nodep, NodeVarRef)
|
|
|
|
|
|| VN_IS(nodep, NodeSel)) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
UINFO(9," cloneSel("<<elements<<","<<offset<<") "<<nodep<<endl);
|
|
|
|
|
int leOffset = !arrayp->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
|
|
|
|
|
}
|
|
|
|
|
return newp;
|
2010-01-19 15:52:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-27 13:11:38 +00:00
|
|
|
|
virtual void visit(AstNodeAssign* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
// Called recursively on newly created assignments
|
|
|
|
|
if (!nodep->user1()
|
2018-02-02 02:32:58 +00:00
|
|
|
|
&& !VN_IS(nodep, AssignAlias)) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
nodep->user1(true);
|
|
|
|
|
m_assignError = false;
|
|
|
|
|
if (debug()>=9) { cout<<endl; nodep->dumpTree(cout, " Deslice-In: "); }
|
|
|
|
|
AstNodeDType* dtp = nodep->lhsp()->dtypep()->skipRefp();
|
2018-02-02 02:32:58 +00:00
|
|
|
|
if (AstUnpackArrayDType* arrayp = VN_CAST(dtp, UnpackArrayDType)) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
// 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) { 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;
|
|
|
|
|
}
|
|
|
|
|
m_assignp = nodep;
|
2018-05-11 00:55:37 +00:00
|
|
|
|
iterateChildren(nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
|
m_assignp = NULL;
|
|
|
|
|
}
|
2010-01-19 15:52:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-05 01:27:34 +00:00
|
|
|
|
virtual void visit(AstInitArray* nodep) {
|
2019-07-06 16:57:50 +00:00
|
|
|
|
UASSERT_OBJ(!m_assignp, nodep,
|
|
|
|
|
"Array initialization should have been removed earlier");
|
2010-04-10 01:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 20:58:30 +00:00
|
|
|
|
void expandBiOp(AstNodeBiop* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
if (!nodep->user1()) {
|
|
|
|
|
nodep->user1(true);
|
|
|
|
|
// 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 "<<nodep<<endl);
|
2018-02-02 02:32:58 +00:00
|
|
|
|
if (AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
AstNodeBiop* logp = NULL;
|
|
|
|
|
for (int index = 0; index < adtypep->rangep()->elementsConst(); ++index) {
|
|
|
|
|
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
|
2018-02-02 02:32:58 +00:00
|
|
|
|
AstNodeBiop* clonep
|
|
|
|
|
= VN_CAST(nodep->cloneType
|
|
|
|
|
(new AstArraySel(nodep->fileline(),
|
|
|
|
|
nodep->lhsp()->cloneTree(false),
|
|
|
|
|
index),
|
|
|
|
|
new AstArraySel(nodep->fileline(),
|
|
|
|
|
nodep->rhsp()->cloneTree(false),
|
|
|
|
|
index)),
|
|
|
|
|
NodeBiop);
|
2019-05-19 20:13:13 +00:00
|
|
|
|
if (!logp) logp = clonep;
|
|
|
|
|
else {
|
|
|
|
|
switch (nodep->type()) {
|
|
|
|
|
case AstType::atEq: // FALLTHRU
|
|
|
|
|
case AstType::atEqCase:
|
|
|
|
|
logp = new AstLogAnd(nodep->fileline(), logp, clonep);
|
|
|
|
|
break;
|
|
|
|
|
case AstType::atNeq: // FALLTHRU
|
|
|
|
|
case AstType::atNeqCase:
|
|
|
|
|
logp = new AstLogOr(nodep->fileline(), logp, clonep);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
nodep->v3fatalSrc("Unknown node type processing array slice");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-06 16:57:50 +00:00
|
|
|
|
UASSERT_OBJ(logp, nodep, "Unpacked array with empty indices range");
|
2019-05-19 20:13:13 +00:00
|
|
|
|
nodep->replaceWith(logp);
|
|
|
|
|
pushDeletep(nodep); VL_DANGLING(nodep);
|
|
|
|
|
nodep = logp;
|
|
|
|
|
}
|
2018-05-11 00:55:37 +00:00
|
|
|
|
iterateChildren(nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
|
}
|
2016-07-23 20:58:30 +00:00
|
|
|
|
}
|
2016-11-27 13:11:38 +00:00
|
|
|
|
virtual void visit(AstEq* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
expandBiOp(nodep);
|
2016-07-23 20:58:30 +00:00
|
|
|
|
}
|
2016-11-27 13:11:38 +00:00
|
|
|
|
virtual void visit(AstNeq* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
expandBiOp(nodep);
|
2016-07-23 20:58:30 +00:00
|
|
|
|
}
|
2016-11-27 13:11:38 +00:00
|
|
|
|
virtual void visit(AstEqCase* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
expandBiOp(nodep);
|
2016-07-23 20:58:30 +00:00
|
|
|
|
}
|
2016-11-27 13:11:38 +00:00
|
|
|
|
virtual void visit(AstNeqCase* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
expandBiOp(nodep);
|
2016-07-23 20:58:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-27 13:11:38 +00:00
|
|
|
|
virtual void visit(AstNode* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
// Default: Just iterate
|
2018-05-11 00:55:37 +00:00
|
|
|
|
iterateChildren(nodep);
|
2010-01-19 15:52:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTUCTORS
|
2018-10-14 22:39:33 +00:00
|
|
|
|
explicit SliceVisitor(AstNetlist* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
|
m_assignp = NULL;
|
|
|
|
|
m_assignError = false;
|
2018-10-14 22:39:33 +00:00
|
|
|
|
iterate(nodep);
|
2010-01-19 15:52:11 +00:00
|
|
|
|
}
|
|
|
|
|
virtual ~SliceVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Link class functions
|
|
|
|
|
|
2018-10-14 22:39:33 +00:00
|
|
|
|
void V3Slice::sliceAll(AstNetlist* nodep) {
|
2010-04-10 01:05:46 +00:00
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
2018-03-10 17:57:50 +00:00
|
|
|
|
{
|
2018-10-14 22:39:33 +00:00
|
|
|
|
SliceVisitor visitor(nodep);
|
2018-03-10 17:57:50 +00:00
|
|
|
|
} // Destruct before checking
|
2017-09-18 02:52:57 +00:00
|
|
|
|
V3Global::dumpCheckGlobalTree("slice", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
2010-01-19 15:52:11 +00:00
|
|
|
|
}
|