2012-04-13 01:08:20 +00:00
|
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2011-07-06 23:03:40 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Cleanup stage in V3Width
|
|
|
|
|
//
|
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2014-01-07 00:28:57 +00:00
|
|
|
|
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
|
2011-07-06 23:03:40 +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.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#ifndef _V3WIDTHCOMMIT_H_
|
|
|
|
|
#define _V3WIDTHCOMMIT_H_ 1
|
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
#include "V3Error.h"
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
|
|
|
|
#ifndef _V3WIDTH_CPP_
|
|
|
|
|
# error "V3WidthCommit for V3Width internal use only"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
2011-07-24 19:01:51 +00:00
|
|
|
|
/// Remove all $signed, $unsigned, we're done with them.
|
|
|
|
|
|
|
|
|
|
class WidthRemoveVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// VISITORS
|
|
|
|
|
virtual void visit(AstSigned* nodep, AstNUser*) {
|
|
|
|
|
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstUnsigned* nodep, AstNUser*) {
|
|
|
|
|
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
|
|
|
|
|
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
|
|
|
|
|
nodep->replaceWith(newp);
|
2012-04-29 13:42:17 +00:00
|
|
|
|
newp->dtypeFrom(nodep);
|
2011-07-24 19:01:51 +00:00
|
|
|
|
pushDeletep(nodep); nodep=NULL;
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
WidthRemoveVisitor() {}
|
|
|
|
|
virtual ~WidthRemoveVisitor() {}
|
|
|
|
|
AstNode* mainAcceptEdit(AstNode* nodep) {
|
|
|
|
|
return nodep->acceptSubtreeReturnEdits(*this);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// Now that all widthing is complete,
|
|
|
|
|
// Copy all width() to widthMin(). V3Const expects this
|
2011-07-24 19:01:51 +00:00
|
|
|
|
|
2011-07-06 23:03:40 +00:00
|
|
|
|
class WidthCommitVisitor : public AstNVisitor {
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// NODE STATE
|
|
|
|
|
// AstVar::user1p -> bool, processed
|
|
|
|
|
AstUser1InUse m_inuser1;
|
|
|
|
|
|
2014-04-02 03:16:16 +00:00
|
|
|
|
public:
|
|
|
|
|
// METHODS
|
|
|
|
|
static AstConst* newIfConstCommitSize (AstConst* nodep) {
|
2014-11-29 01:24:42 +00:00
|
|
|
|
if (((nodep->dtypep()->width() != nodep->num().width())
|
|
|
|
|
|| !nodep->num().sized())
|
2014-12-25 00:27:46 +00:00
|
|
|
|
&& !nodep->num().isString()) { // Need to force the number from unsized to sized
|
2014-04-02 03:16:16 +00:00
|
|
|
|
V3Number num (nodep->fileline(), nodep->dtypep()->width());
|
|
|
|
|
num.opAssign(nodep->num());
|
|
|
|
|
num.isSigned(nodep->isSigned());
|
|
|
|
|
AstConst* newp = new AstConst(nodep->fileline(), num);
|
|
|
|
|
newp->dtypeFrom(nodep);
|
|
|
|
|
return newp;
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-06 23:03:40 +00:00
|
|
|
|
private:
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// METHODS
|
|
|
|
|
void editDType(AstNode* nodep) {
|
|
|
|
|
// Edit dtypes for this node
|
|
|
|
|
nodep->dtypep(editOneDType(nodep->dtypep()));
|
|
|
|
|
}
|
|
|
|
|
AstNodeDType* editOneDType(AstNodeDType* nodep) {
|
|
|
|
|
// See if the dtype/refDType can be converted to a standard one
|
|
|
|
|
// This reduces the number of dtypes in the system, and since
|
|
|
|
|
// dtypep() figures into sameTree() results in better optimizations
|
|
|
|
|
if (!nodep) return NULL;
|
|
|
|
|
// Recurse to handle the data type, as may change the size etc of this type
|
|
|
|
|
if (!nodep->user1()) nodep->accept(*this,NULL);
|
|
|
|
|
// Look for duplicate
|
|
|
|
|
if (AstBasicDType* bdtypep = nodep->castBasicDType()) {
|
|
|
|
|
AstBasicDType* newp = nodep->findInsertSameDType(bdtypep);
|
|
|
|
|
if (newp != bdtypep && debug()>=9) {
|
|
|
|
|
UINFO(9,"dtype replacement "); nodep->dumpSmall(cout);
|
|
|
|
|
cout<<" ----> "; newp->dumpSmall(cout); cout<<endl;
|
|
|
|
|
}
|
|
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
2011-07-06 23:03:40 +00:00
|
|
|
|
// VISITORS
|
|
|
|
|
virtual void visit(AstConst* nodep, AstNUser*) {
|
2012-04-29 14:14:13 +00:00
|
|
|
|
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype");
|
|
|
|
|
nodep->dtypep()->accept(*this); // Do datatype first
|
2014-04-02 03:16:16 +00:00
|
|
|
|
if (AstConst* newp = newIfConstCommitSize(nodep)) {
|
2011-07-06 23:03:40 +00:00
|
|
|
|
nodep->replaceWith(newp);
|
2012-04-29 14:14:13 +00:00
|
|
|
|
AstNode* oldp = nodep; nodep = newp;
|
|
|
|
|
//if (debug()>4) oldp->dumpTree(cout," fixConstSize_old: ");
|
|
|
|
|
//if (debug()>4) newp->dumpTree(cout," _new: ");
|
|
|
|
|
pushDeletep(oldp); oldp=NULL;
|
2011-07-06 23:03:40 +00:00
|
|
|
|
}
|
2012-04-29 14:14:13 +00:00
|
|
|
|
editDType(nodep);
|
2011-07-06 23:03:40 +00:00
|
|
|
|
}
|
2012-04-29 14:14:13 +00:00
|
|
|
|
virtual void visit(AstNodeDType* nodep, AstNUser*) {
|
2012-07-29 14:16:20 +00:00
|
|
|
|
visitIterateNodeDType(nodep);
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNodeClassDType* nodep, AstNUser*) {
|
|
|
|
|
visitIterateNodeDType(nodep);
|
|
|
|
|
nodep->clearCache();
|
|
|
|
|
}
|
|
|
|
|
void visitIterateNodeDType(AstNodeDType* nodep) {
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// Rather than use dtypeChg which may make new nodes, we simply edit in place,
|
|
|
|
|
// as we don't need to preserve any widthMin's, and every dtype with the same width
|
|
|
|
|
// gets an identical edit.
|
|
|
|
|
if (nodep->user1SetOnce()) return; // Process once
|
|
|
|
|
nodep->widthMinFromWidth();
|
|
|
|
|
// Too late to any unspecified sign to be anything but unsigned
|
|
|
|
|
if (nodep->numeric().isNosign()) nodep->numeric(AstNumeric::UNSIGNED);
|
2011-07-06 23:03:40 +00:00
|
|
|
|
nodep->iterateChildren(*this);
|
2012-04-29 14:14:13 +00:00
|
|
|
|
nodep->virtRefDTypep(editOneDType(nodep->virtRefDTypep()));
|
2011-07-06 23:03:40 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
|
|
|
|
// This check could go anywhere after V3Param
|
|
|
|
|
nodep->v3fatalSrc("Presels should have been removed before this point");
|
|
|
|
|
}
|
2012-04-29 14:14:13 +00:00
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
editDType(nodep);
|
|
|
|
|
}
|
2011-07-06 23:03:40 +00:00
|
|
|
|
public:
|
|
|
|
|
// CONSTUCTORS
|
|
|
|
|
WidthCommitVisitor(AstNetlist* nodep) {
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// Were changing widthMin's, so the table is now somewhat trashed
|
|
|
|
|
nodep->typeTablep()->clearCache();
|
2011-07-06 23:03:40 +00:00
|
|
|
|
nodep->accept(*this);
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// Don't want to repairCache, as all needed nodes have been added back in
|
|
|
|
|
// a repair would prevent dead nodes from being detected
|
2011-07-06 23:03:40 +00:00
|
|
|
|
}
|
|
|
|
|
virtual ~WidthCommitVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
#endif // Guard
|