Compare commits

...
23 Commits
Author SHA1 Message Date
Wilson Snyder 7a65df7636 Version bump 2013-06-02 14:47:36 -04:00
Wilson Snyder eab46d547d Version bump. 2013-06-02 14:38:53 -04:00
Wilson Snyder 3dd552c4a2 Duplicate clock gate optimization on by default, use -Od to disable 2013-05-27 22:39:59 -04:00
Wilson Snyder 23bb045a72 Support interfaces and modports, bug102. 2013-05-27 21:39:19 -04:00
Wilson Snyder 7c834ad118 Internals: Misc cleanups from interface branch. No functional change. 2013-05-27 20:56:20 -04:00
Wilson Snyder 8e2617ab8d Internals: V3Inline support for future hard-no-inline. No functional change. 2013-05-26 11:17:42 -04:00
Wilson Snyder 24fcae4f49 Internals: When broken link fatal, say which rule violated 2013-05-25 17:05:22 -04:00
Wilson Snyder ce18674d88 Internals: (see last) also dump on first non-fatal 2013-05-25 13:31:17 -04:00
Wilson Snyder 6b8d9b5c36 Internals: If registered, dump symtable on any error 2013-05-25 12:15:38 -04:00
Wilson Snyder 81bf95763c Internals: Refactor V3Inline to simplify if(m_cellp) out. No functional change. 2013-05-25 10:42:44 -04:00
Wilson Snyder 2d64077fd0 Internals: Prep to allow future move of wrapping. No functional change. 2013-05-25 10:15:10 -04:00
Wilson Snyder 38faebcf20 Fix packed array select internal error, bug652. 2013-05-24 21:32:54 -04:00
Wilson Snyder 48d177a9d0 Fix packed array select internal error, bug652. 2013-05-24 21:14:42 -04:00
Wilson Snyder 3b3a7f7354 Commentary 2013-05-24 19:09:41 -04:00
Wilson Snyder 99cd2818a1 Tests: Allow driver to find 't' signals when not first in file. 2013-05-23 22:00:55 -04:00
Wilson Snyder 5765e099a6 Debug: More digits for debug file sorting. 2013-05-23 20:50:48 -04:00
Wilson Snyder 175d59ecba Fix GCC version runtime changes, bug651. 2013-05-23 20:19:51 -04:00
Wilson Snyder 3bd3d01968 Tests: Move driver.pl tee into perl to avoid process issue, bug650. 2013-05-23 20:08:39 -04:00
Wilson Snyder 85e2a6bb45 Tests 2013-05-21 22:38:35 -04:00
Wilson Snyder 84efd239a5 Fix arrayed input compile error, bug645. Try 2. 2013-05-18 20:17:17 -04:00
Wilson Snyder 6a69813326 Internals: Renames for interfaces. No functional change. 2013-05-18 19:45:52 -04:00
Wilson Snyder 2c9dcc3913 Fix arrayed input compile error, bug645. 2013-05-15 22:00:28 -04:00
Wilson Snyder 20ea1ca018 devel release 2013-05-11 16:16:22 -04:00
90 changed files with 2890 additions and 628 deletions
+13
View File
@@ -3,6 +3,19 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.850 2013-06-02
** Support interfaces and modports, bug102. [Byron Bradley, Jeremy Bennett]
*** Duplicate clock gate optimization on by default, bug621.
**** Fix arrayed input compile error, bug645. [Krzysztof Jankowski]
**** Fix GCC version runtime changes, bug651. [Jeremy Bennett]
**** Fix packed array select internal error, bug652. [Krzysztof Jankowski]
* Verilator 3.847 2013-05-11
*** Add ALWCOMBORDER warning. [KC Buckenmaier]
+9 -7
View File
@@ -1920,16 +1920,12 @@ uwire keyword.
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support
Verilator currently has some support for SystemVerilog synthesis
constructs. As SystemVerilog features enter common usage they are added;
please file a bug if a feature you need is missing.
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
const, do-while, enum, export, final, import, int, logic, longint, package,
program, shortint, struct, time, typedef, union, var, void, priority
case/if, and unique case/if.
const, do-while, enum, export, final, import, int, interface, logic,
longint, modport, package, program, shortint, struct, time, typedef, union,
var, void, priority case/if, and unique case/if.
It also supports .name and .* interconnection.
@@ -2605,6 +2601,12 @@ and continue keywords.
Inside expressions may not include unpacked array traversal or $ as an
upper bound. Case inside and case matches are also unsupported.
=item interface
Interfaces and modports, including with generated data types are supported.
Generate blocks around modports are not supported, nor are virtual
interfaces nor unnamed interfaces.
=item priority if, unique if
Priority and unique if's are treated as normal ifs and not asserted to be
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.847 2013-05-11])
AC_INIT([Verilator],[3.850 2013-06-02])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
+19 -23
View File
@@ -24,14 +24,14 @@ more details.
=head1 DESCRIPTION
Verilator converts synthesizable (not behavioral) Verilog code into C++ or
SystemC code. It is not a complete simulator, just a translator.
Verilator converts synthesizable (generally not behavioral) Verilog code
into C++ or SystemC code. It is not a complete simulator, just a
translator.
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
reads the specified Verilog code, lints it, and optionally adds coverage
code. For C++ format, it outputs .cpp and .h files. For SystemC format,
it outputs .sp files for the SystemPerl preprocessor available at
http://www.veripool.org.
it outputs .cpp and .h files using the standard SystemC headers.
The resulting files are then compiled with C++. The user writes a little
C++ wrapper file, which instantiates the top level module. This is
@@ -41,14 +41,11 @@ The resulting executable will perform the actual simulation.
=head1 SUPPORTED SYSTEMS
Verilator is developed and has primary testing on:
SuSE 11.1 AMD64 i686-linux-2.6.27, GCC 4.3.2
Versions have also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It
should run with minor porting on any Linix-ish platform. Verilator also
works on Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin).
Verilated output (not Verilator itself) compiles under MSVC++ 2008.
Verilator is developed and has primary testing on Ubuntu. Versions have
also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It should run
with minor porting on any Linix-ish platform. Verilator also works on
Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
output (not Verilator itself) compiles under MSVC++ 2008 and newer.
=head1 INSTALLATION
@@ -71,11 +68,11 @@ Download the latest package from that site, and decompress.
=item
If you will be using SystemC (vs straight C++ output), download SystemC
2.0.1 from L<http://www.systemc.org>. Follow their installation
instructions. You will need to set SYSTEMC_INCLUDE to point to the
include directory with systemc.h in it, and SYSTEMC_LIBDIR to points
to the directory with libsystemc.a in it. (Older installations may
set SYSTEMC and SYSTEMC_ARCH instead.)
from L<http://www.systemc.org>. Follow their installation instructions.
You will need to set SYSTEMC_INCLUDE to point to the include directory with
systemc.h in it, and SYSTEMC_LIBDIR to points to the directory with
libsystemc.a in it. (Older installations may set SYSTEMC and SYSTEMC_ARCH
instead.)
=item
@@ -107,7 +104,7 @@ executable, so try to have them correct before configuring.
Our personal favorite is to always run Verilator from the kit directory.
This allows the easiest experimentation and upgrading. It's also how most
EDA tools operate; to run any of them you point to the tarball.
EDA tools operate; to run you point to the tarball, no install is needed.
export VERILATOR_ROOT=`pwd` # if your shell is bash
setenv VERILATOR_ROOT `pwd` # if your shell is csh
@@ -156,11 +153,10 @@ PATH.
Type C<make> to compile Verilator.
Type C<make test_c> to check the compilation.
Type C<make test> to check the compilation.
Type C<make test> for a more complete test. You may get a error about the
Bit::Vector Perl package. You will need to install it and SystemPerl if
you want all tests to pass.
Configure with C<--enable-longtests> for more complete developer tests.
Additional packages may be required for these tests.
You may get a error about a typedef conflict for uint32_t. Edit
verilated.h to change the typedef to work, probably to @samp{typedef
@@ -195,7 +191,7 @@ The directories in the kit after de-taring are as follows:
bin/verilator => Compiler Wrapper invoked to Verilate code
include/ => Files that should be in your -I compiler path
include/verilated*.cpp => Global routines to link into your simulator
include/verilated.h => Global headers
include/verilated*.h => Global headers
include/verilated.v => Stub defines for linting
include/verilated.mk => Common makefile
src/ => Translator source code
+18 -8
View File
@@ -38,6 +38,9 @@ class VFlagLogicPacked {};
class VFlagBitPacked {};
class VFlagChildDType {}; // Used by parser.y to select constructor that sets childDType
// For broken() function, return error string if have a match
#define BROKEN_RTN(test) do { if (VL_UNLIKELY(test)) return # test; } while(0)
//######################################################################
class AstType {
@@ -407,7 +410,8 @@ public:
BLOCKTEMP,
MODULETEMP,
STMTTEMP,
XTEMP
XTEMP,
IFACEREF // Used to link Interfaces between modules
};
enum en m_e;
inline AstVarType () : m_e(UNKNOWN) {}
@@ -421,7 +425,8 @@ public:
"SUPPLY0","SUPPLY1","WIRE","IMPLICITWIRE",
"TRIWIRE","TRI0","TRI1",
"PORT",
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP"};
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP",
"IFACEREF"};
return names[m_e]; }
bool isSignal() const { return (m_e==WIRE || m_e==IMPLICITWIRE
|| m_e==TRIWIRE
@@ -1171,7 +1176,7 @@ public:
virtual bool hasDType() const { return false; } // Iff has a data type; dtype() must be non null
virtual AstNodeDType* getChildDTypep() const { return NULL; } // Iff has a non-null childDTypep(), as generic node function
virtual bool maybePointedTo() const { return false; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc.
virtual bool broken() const { return false; }
virtual const char* broken() const { return NULL; }
// INVOKERS
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) = 0;
@@ -1472,7 +1477,7 @@ public:
}
ASTNODE_BASE_FUNCS(NodeVarRef)
virtual bool hasDType() const { return true; }
virtual bool broken() const;
virtual const char* broken() const;
virtual int instrCount() const { return widthInstrs(); }
virtual void cloneRelink();
virtual string name() const { return m_name; } // * = Var name
@@ -1579,7 +1584,7 @@ public:
numeric(numericUnpack.isSigned() ? AstNumeric::SIGNED : AstNumeric::UNSIGNED);
}
ASTNODE_BASE_FUNCS(NodeClassDType)
virtual bool broken() const;
virtual const char* broken() const;
virtual void dump(ostream& str);
// For basicp() we reuse the size to indicate a "fake" basic type of same size
virtual AstBasicDType* basicp() const { return findLogicDType(width(),width(),numeric())->castBasicDType(); }
@@ -1615,8 +1620,8 @@ public:
ASTNODE_BASE_FUNCS(NodeArrayDType)
virtual void dump(ostream& str);
virtual void dumpSmall(ostream& str);
virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())); }
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -1740,7 +1745,7 @@ public:
addNOp2p(pinsp);
}
ASTNODE_BASE_FUNCS(NodeFTaskRef)
virtual bool broken() const { return m_taskp && !m_taskp->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_taskp && m_taskp->clonep()) {
m_taskp = m_taskp->clonep()->castNodeFTask();
}}
@@ -1847,4 +1852,9 @@ inline int AstNodeArrayDType::lsb() const { return rangep()->lsbConst(); }
inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); }
inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange(msb(), lsb(), rangep()->littleEndian()); }
inline void AstIfaceRefDType::cloneRelink() {
if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep()->castCell();
if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep()->castIface();
if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep()->castModport(); }
#endif // Guard
+46 -11
View File
@@ -35,8 +35,22 @@
// Special methods
// We need these here, because the classes they point to aren't defined when we declare the class
bool AstNodeVarRef::broken() const { return ((m_varScopep && !m_varScopep->brokeExists())
|| (m_varp && !m_varp->brokeExists())); }
const char* AstIfaceRefDType::broken() const {
BROKEN_RTN(m_ifacep && !m_ifacep->brokeExists());
BROKEN_RTN(m_cellp && !m_cellp->brokeExists());
BROKEN_RTN(m_modportp && !m_modportp->brokeExists());
return NULL;
}
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
return ((m_cellp && m_cellp->modp()) ? m_cellp->modp()->castIface() : m_ifacep);
}
const char* AstNodeVarRef::broken() const {
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
BROKEN_RTN(m_varp && !m_varp->brokeExists());
return NULL;
}
void AstNodeVarRef::cloneRelink() {
if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep()->castVar(); }
@@ -54,18 +68,18 @@ void AstNodeClassDType::repairMemberCache() {
}
}
bool AstNodeClassDType::broken() const {
const char* AstNodeClassDType::broken() const {
set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
exists.insert(itemp);
}
for (MemberNameMap::const_iterator it=m_members.begin(); it!=m_members.end(); ++it) {
if (exists.find(it->second) == exists.end()) {
if (VL_UNLIKELY(exists.find(it->second) == exists.end())) {
this->v3error("Internal: Structure member broken: "<<it->first);
return true;
return "member broken";
}
}
return false;
return NULL;
}
int AstBasicDType::widthAlignBytes() const {
@@ -419,10 +433,12 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable
return nodep;
}
bool AstScope::broken() const {
return ((m_aboveScopep && !m_aboveScopep->brokeExists())
|| (m_aboveCellp && !m_aboveCellp->brokeExists())
|| !m_modp || !m_modp->brokeExists());
const char* AstScope::broken() const {
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
BROKEN_RTN(!m_modp);
BROKEN_RTN(m_modp && !m_modp->brokeExists());
return NULL;
}
void AstScope::cloneRelink() {
@@ -718,12 +734,31 @@ void AstEnumItemRef::dump(ostream& str) {
if (itemp()) { itemp()->dump(str); }
else { str<<"UNLINKED"; }
}
void AstIfaceRefDType::dump(ostream& str) {
this->AstNode::dump(str);
if (cellName()!="") { str<<" cell="<<cellName(); }
if (ifaceName()!="") { str<<" if="<<ifaceName(); }
if (modportName()!="") { str<<" mp="<<modportName(); }
if (cellp()) { str<<" -> "; cellp()->dump(str); }
else if (ifacep()) { str<<" -> "; ifacep()->dump(str); }
else { str<<" -> UNLINKED"; }
}
void AstIfaceRefDType::dumpSmall(ostream& str) {
this->AstNodeDType::dumpSmall(str);
str<<"iface";
}
void AstJumpGo::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; }
}
void AstModportVarRef::dump(ostream& str) {
this->AstNode::dump(str);
str<<" "<<varType();
if (varp()) { str<<" -> "; varp()->dump(str); }
else { str<<" -> UNLINKED"; }
}
void AstPin::dump(ostream& str) {
this->AstNode::dump(str);
if (modVarp()) { str<<" -> "; modVarp()->dump(str); }
@@ -839,7 +874,7 @@ void AstVarXRef::dump(ostream& str) {
if (lvalue()) str<<" [LV] => ";
else str<<" [RV] <- ";
str<<dotted()<<". - ";
if (inlinedDots()!="") str<<" flat.="<<inlinedDots()<<" - ";
if (inlinedDots()!="") str<<" inline.="<<inlinedDots()<<" - ";
if (varScopep()) { varScopep()->dump(str); }
else if (varp()) { varp()->dump(str); }
else { str<<"UNLINKED"; }
+134 -31
View File
@@ -244,16 +244,16 @@ public:
refDTypep(NULL);
setOp2p(rangep);
dtypep(NULL); // V3Width will resolve
// For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
widthFromSub(subDTypep());
int width = subDTypep()->width() * rangep->elementsConst();
widthForce(width,width);
}
AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep)
: AstNodeArrayDType(fl) {
refDTypep(dtp);
setOp2p(rangep);
dtypep(this);
// For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
widthFromSub(subDTypep());
int width = subDTypep()->width() * rangep->elementsConst();
widthForce(width,width);
}
ASTNODE_NODE_FUNCS(PackArrayDType, PACKARRAYDTYPE)
};
@@ -357,7 +357,7 @@ public:
virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere
return samep->castBasicDType()->m == m; }
virtual string name() const { return m.m_keyword.ascii(); }
virtual bool broken() const { return dtypep()!=this; }
virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; }
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
void rangep(AstRange* nodep) { setNOp1p(nodep); }
void setSignedState(VSignedState signst) {
@@ -410,8 +410,8 @@ public:
widthFromSub(subDTypep());
}
ASTNODE_NODE_FUNCS(ConstDType, CONSTDTYPE)
virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())); }
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -432,6 +432,48 @@ public:
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
struct AstIfaceRefDType : public AstNodeDType {
// Reference to an interface, either for a port, or inside parent cell
private:
string m_cellName; // "" = no cell, such as when connects to 'input' iface
string m_ifaceName; // Interface name
string m_modportName; // "" = no modport
AstIface* m_ifacep; // Pointer to interface; note cellp() should override
AstCell* m_cellp; // When exact parent cell known; not a guess
AstModport* m_modportp; // NULL = unlinked or no modport
public:
AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName)
: AstNodeDType(fl), m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(""),
m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { }
AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName, const string& modport)
: AstNodeDType(fl), m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(modport),
m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { }
ASTNODE_NODE_FUNCS(IfaceRefDType, IFACEREFDTYPE)
// METHODS
virtual const char* broken() const;
virtual void dump(ostream& str=cout);
virtual void dumpSmall(ostream& str);
virtual void cloneRelink();
virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return 1; }
virtual int widthTotalBytes() const { return 1; }
string cellName() const { return m_cellName; }
void cellName(const string& name) { m_cellName=name; }
string ifaceName() const { return m_ifaceName; }
void ifaceName(const string& name) { m_ifaceName=name; }
string modportName() const { return m_modportName; }
void modportName(const string& name) { m_modportName=name; }
AstIface* ifaceViaCellp() const; // Use cellp or ifacep
AstIface* ifacep() const { return m_ifacep; }
void ifacep(AstIface* nodep) { m_ifacep=nodep; }
AstCell* cellp() const { return m_cellp; }
void cellp(AstCell* nodep) { m_cellp=nodep; }
AstModport* modportp() const { return m_modportp; }
void modportp(AstModport* modportp) { m_modportp=modportp; }
bool isModport() { return !m_modportName.empty(); }
};
struct AstRefDType : public AstNodeDType {
private:
AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef
@@ -447,7 +489,7 @@ public:
}
ASTNODE_NODE_FUNCS(RefDType, REFDTYPE)
// METHODS
virtual bool broken() const { return m_refDTypep && !m_refDTypep->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -571,7 +613,7 @@ public:
ASTNODE_NODE_FUNCS(EnumItemRef, ENUMITEMREF)
virtual void dump(ostream& str);
virtual string name() const { return itemp()->name(); }
virtual bool broken() const { return !itemp(); }
virtual const char* broken() const { BROKEN_RTN(!itemp()); return NULL; }
virtual int instrCount() const { return 0; }
virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = m_itemp->clonep()->castEnumItem(); }
virtual bool same(AstNode* samep) const {
@@ -601,8 +643,8 @@ public:
m_uniqueNum = uniqueNumInc();
}
ASTNODE_NODE_FUNCS(EnumDType, ENUMDTYPE)
virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())); }
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -843,6 +885,7 @@ private:
bool m_isStatic:1; // Static variable
bool m_isPulldown:1; // Tri0
bool m_isPullup:1; // Tri1
bool m_isIfaceParent:1; // dtype is reference to interface present in this module
bool m_trace:1; // Trace this variable
void init() {
@@ -854,6 +897,7 @@ private:
m_funcLocal=false; m_funcReturn=false;
m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false;
m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false;
m_isIfaceParent=false;
m_trace=false;
}
public:
@@ -944,6 +988,7 @@ public:
void primaryIO(bool flag) { m_primaryIO = flag; }
void isConst(bool flag) { m_isConst = flag; }
void isStatic(bool flag) { m_isStatic = flag; }
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
void funcLocal(bool flag) { m_funcLocal = flag; }
void funcReturn(bool flag) { m_funcReturn = flag; }
void trace(bool flag) { m_trace=flag; }
@@ -959,6 +1004,8 @@ public:
bool isPrimaryIO() const { return m_primaryIO; }
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
bool isIO() const { return (m_input||m_output); }
bool isIfaceRef() const { return (varType()==AstVarType::IFACEREF); }
bool isIfaceParent() const { return m_isIfaceParent; }
bool isSignal() const { return varType().isSignal(); }
bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP
|| varType()==AstVarType::STMTTEMP || varType()==AstVarType::XTEMP); }
@@ -1079,7 +1126,7 @@ public:
,m_name(name) ,m_aboveScopep(aboveScopep) ,m_aboveCellp(aboveCellp), m_modp(modp) {}
ASTNODE_NODE_FUNCS(Scope, SCOPE)
virtual void cloneRelink();
virtual bool broken() const;
virtual const char* broken() const;
virtual bool maybePointedTo() const { return true; }
virtual string name() const { return m_name; } // * = Scope name
virtual void name(const string& name) { m_name = name; }
@@ -1133,8 +1180,8 @@ public:
UASSERT(m_scopep->clonep(), "No clone cross link: "<<this);
m_scopep = m_scopep->clonep()->castScope();
}}
virtual bool broken() const { return ( (m_varp && !m_varp->brokeExists())
|| (m_scopep && !m_scopep->brokeExists())); }
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists());
BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); return NULL; }
virtual bool maybePointedTo() const { return true; }
virtual string name() const {return scopep()->name()+"->"+varp()->name();} // * = Var name
virtual void dump(ostream& str);
@@ -1234,7 +1281,7 @@ public:
}
ASTNODE_NODE_FUNCS(Pin, PIN)
virtual void dump(ostream& str);
virtual bool broken() const { return (m_modVarp && !m_modVarp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); return NULL; }
virtual string name() const { return m_name; } // * = Pin name, ""=go by number
virtual void name(const string& name) { m_name = name; }
bool dotStar() const { return name() == ".*"; } // Special fake name for .* connections until linked
@@ -1290,7 +1337,7 @@ public:
AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name)
: AstNode (fl), m_name(name), m_packagep(packagep) {}
ASTNODE_NODE_FUNCS(PackageImport, PACKAGEIMPORT)
virtual bool broken() const { return (!m_packagep || !m_packagep->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep()->castPackage(); }
virtual void dump(ostream& str);
virtual string name() const { return m_name; }
@@ -1298,6 +1345,49 @@ public:
void packagep(AstPackage* nodep) { m_packagep=nodep; }
};
struct AstIface : public AstNodeModule {
// A module declaration
AstIface(FileLine* fl, const string& name)
: AstNodeModule (fl,name) { }
ASTNODE_NODE_FUNCS(Iface, IFACE)
};
struct AstModportVarRef : public AstNode {
// A input/output/etc variable referenced under a modport
// The storage for the variable itself is inside the interface, thus this is a reference
// PARENT: AstIface
private:
string m_name; // Name of the variable referenced
AstVarType m_type; // Type of the variable (in/out)
AstVar* m_varp; // Link to the actual Var
public:
AstModportVarRef(FileLine* fl, const string& name, AstVarType::en type)
: AstNode(fl), m_name(name), m_type(type), m_varp(NULL) { }
ASTNODE_NODE_FUNCS(ModportVarRef, MODPORTVARREF)
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
virtual void dump(ostream& str);
AstVarType varType() const { return m_type; } // * = Type of variable
virtual string name() const { return m_name; }
bool isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); }
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp) { m_varp=varp; }
};
struct AstModport : public AstNode {
// A modport in an interface
private:
string m_name; // Name of the modport
public:
AstModport(FileLine* fl, const string& name, AstModportVarRef* varsp)
: AstNode(fl), m_name(name) {
addNOp1p(varsp); }
virtual string name() const { return m_name; }
virtual bool maybePointedTo() const { return true; }
ASTNODE_NODE_FUNCS(Modport, MODPORT)
AstModportVarRef* varsp() const { return op1p()->castModportVarRef(); } // op1 = List of Vars
};
struct AstCell : public AstNode {
// A instantiation cell or interface call (don't know which until link)
private:
@@ -1305,17 +1395,18 @@ private:
string m_origName; // Original name before dot addition
string m_modName; // Module the cell instances
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
bool m_hasIfaceVar; // True if a Var has been created for this cell
public:
AstCell(FileLine* fl, const string& instName, const string& modName,
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
: AstNode(fl)
, m_name(instName), m_origName(instName), m_modName(modName)
, m_modp(NULL) {
, m_modp(NULL), m_hasIfaceVar(false) {
addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); }
ASTNODE_NODE_FUNCS(Cell, CELL)
// No cloneRelink, we presume cloneee's want the same module linkages
virtual void dump(ostream& str);
virtual bool broken() const { return (m_modp && !m_modp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_modp && !m_modp->brokeExists()); return NULL; }
virtual bool maybePointedTo() const { return true; }
// ACCESSORS
virtual string name() const { return m_name; } // * = Cell name
@@ -1331,6 +1422,8 @@ public:
void addPinsp(AstPin* nodep) { addOp1p(nodep); }
void addParamsp(AstPin* nodep) { addOp2p(nodep); }
void modp(AstNodeModule* nodep) { m_modp = nodep; }
bool hasIfaceVar() const { return m_hasIfaceVar; }
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
};
struct AstCellInline : public AstNode {
@@ -1440,7 +1533,7 @@ public:
: AstNode(fl), m_packagep(packagep) {}
ASTNODE_NODE_FUNCS(PackageRef, PACKAGEREF)
// METHODS
virtual bool broken() const { return !m_packagep || !m_packagep->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) {
m_packagep = m_packagep->clonep()->castPackage();
}}
@@ -1713,6 +1806,16 @@ struct AstAssignW : public AstNodeAssign {
}
};
struct AstAssignVarScope : public AstNodeAssign {
// Assign two VarScopes to each other
AstAssignVarScope(FileLine* fileline, AstNode* lhsp, AstNode* rhsp)
: AstNodeAssign(fileline, lhsp, rhsp) {
dtypeFrom(rhsp);
}
ASTNODE_NODE_FUNCS(AssignVarScope, ASSIGNVARSCOPE)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignVarScope(this->fileline(), lhsp, rhsp); }
};
struct AstPull : public AstNode {
private:
bool m_direction;
@@ -1799,10 +1902,10 @@ public:
m_dataDeclp = NULL;
}
ASTNODE_NODE_FUNCS(CoverDecl, COVERDECL)
virtual bool broken() const {
if (m_dataDeclp && !m_dataDeclp->brokeExists()) return true;
virtual const char* broken() const {
BROKEN_RTN(m_dataDeclp && !m_dataDeclp->brokeExists());
if (m_dataDeclp && m_dataDeclp->m_dataDeclp) v3fatalSrc("dataDeclp should point to real data, not be a list"); // Avoid O(n^2) accessing
return false; }
return NULL; }
virtual void cloneRelink() { if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep()->castCoverDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 1+2*instrCountLd(); }
@@ -1840,7 +1943,7 @@ public:
m_declp = declp;
}
ASTNODE_NODE_FUNCS(CoverInc, COVERINC)
virtual bool broken() const { return !declp()->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(!declp()->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep()->castCoverDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 1+2*instrCountLd(); }
@@ -1991,7 +2094,7 @@ public:
}
ASTNODE_NODE_FUNCS(Display, DISPLAY)
virtual void dump(ostream& str);
virtual bool broken() const { return !fmtp(); }
virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; }
virtual string verilogKwd() const { return (filep() ? (string)"$f"+(string)displayType().ascii()
: (string)"$"+(string)displayType().ascii()); }
virtual bool isGateOptimizable() const { return false; }
@@ -2021,7 +2124,7 @@ struct AstSFormat : public AstNode {
setOp3p(lhsp);
}
ASTNODE_NODE_FUNCS(SFormat, SFORMAT)
virtual bool broken() const { return !fmtp(); }
virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; }
virtual string verilogKwd() const { return "$sformat"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
@@ -2442,7 +2545,7 @@ public:
m_labelp = labelp;
}
ASTNODE_NODE_FUNCS(JumpGo, JUMPGO)
virtual bool broken() const { return !labelp()->brokeExistsAbove(); }
virtual const char* broken() const { BROKEN_RTN(!labelp()->brokeExistsAbove()); return NULL; }
virtual void cloneRelink() { if (m_labelp->clonep()) m_labelp = m_labelp->clonep()->castJumpLabel(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return instrCountBranch(); }
@@ -2719,7 +2822,7 @@ public:
addNOp2p(valuep);
}
ASTNODE_NODE_FUNCS(TraceInc, TRACEINC)
virtual bool broken() const { return !declp()->brokeExists(); }
virtual const char* broken() const { BROKEN_RTN(!declp()->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep()->castTraceDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 10+2*instrCountLd(); }
@@ -2756,7 +2859,7 @@ public:
ASTNODE_NODE_FUNCS(Active, ACTIVE)
virtual void dump(ostream& str=cout);
virtual string name() const { return m_name; }
virtual bool broken() const { return (m_sensesp && !m_sensesp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); return NULL; }
virtual void cloneRelink() {
if (m_sensesp->clonep()) {
m_sensesp = m_sensesp->clonep()->castSenTree();
@@ -4358,7 +4461,7 @@ public:
}
ASTNODE_NODE_FUNCS(CFunc, CFUNC)
virtual string name() const { return m_name; }
virtual bool broken() const { return ( (m_scopep && !m_scopep->brokeExists())); }
virtual const char* broken() const { BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); return NULL; }
virtual bool maybePointedTo() const { return true; }
virtual void dump(ostream& str=cout);
virtual V3Hash sameHash() const { return V3Hash(); }
@@ -4446,7 +4549,7 @@ public:
virtual void cloneRelink() { if (m_funcp && m_funcp->clonep()) {
m_funcp = m_funcp->clonep()->castCFunc();
}}
virtual bool broken() const { return (m_funcp && !m_funcp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); return NULL; }
virtual int instrCount() const { return instrCountCall(); }
virtual V3Hash sameHash() const { return V3Hash(funcp()); }
virtual bool same(AstNode* samep) const {
@@ -4578,7 +4681,7 @@ public:
m_dollarUnitPkgp = NULL;
}
ASTNODE_NODE_FUNCS(Netlist, NETLIST)
virtual bool broken() const { return (m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); }
virtual const char* broken() const { BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); return NULL; }
AstNodeModule* modulesp() const { return op1p()->castNodeModule();} // op1 = List of modules
AstNodeModule* topModulep() const { return op1p()->castNodeModule(); } // * = Top module in hierarchy (first one added, for now)
void addModulep(AstNodeModule* modulep) { addOp1p(modulep); }
+2 -2
View File
@@ -202,8 +202,8 @@ class BrokenCheckVisitor : public AstNVisitor {
private:
virtual void visit(AstNode* nodep, AstNUser*) {
BrokenTable::setUnder(nodep,true);
if (nodep->broken()) {
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)");
if (const char* whyp=nodep->broken()) {
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo): "<<whyp);
}
if (nodep->dtypep()) {
if (!nodep->dtypep()->brokeExists()) { nodep->v3fatalSrc("Broken link in node->dtypep() to "<<(void*)nodep->dtypep()); }
+1 -1
View File
@@ -526,7 +526,7 @@ private:
}
}
}
sort(report.begin(), report.end());
stable_sort(report.begin(), report.end());
for (deque<string>::iterator it = report.begin(); it!=report.end(); ++it) {
*ofp << *it;
}
+4 -1
View File
@@ -1413,7 +1413,7 @@ private:
for (AstNodeSenItem* senp = nodep->sensesp()->castNodeSenItem(); senp; senp=senp->nextp()->castNodeSenItem()) {
vec.push_back(senp);
}
sort(vec.begin(), vec.end(), SenItemCmp());
stable_sort(vec.begin(), vec.end(), SenItemCmp());
for (vector<AstNodeSenItem*>::iterator it=vec.begin(); it!=vec.end(); ++it) {
(*it)->unlinkFrBack();
}
@@ -1466,6 +1466,9 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
// Don't perform any optimizations, keep the alias around
}
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
// Don't perform any optimizations, the node won't be linked yet
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_doNConst && replaceNodeAssign(nodep)) return;
+8 -4
View File
@@ -64,6 +64,7 @@ private:
bool m_checkBlock; // Should this block get covered?
AstNodeModule* m_modp; // Current module to add statement to
bool m_inToggleOff; // In function/task etc
bool m_inModOff; // In module with no coverage
FileMap m_fileps; // Column counts for each fileline
string m_beginHier; // AstBegin hier name for user coverage points
@@ -124,9 +125,11 @@ private:
// VISITORS - BOTH
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_modp = nodep;
m_inModOff = nodep->isTop(); // Ignore coverage on top module; it's a shell we created
m_fileps.clear();
nodep->iterateChildren(*this);
m_modp = NULL;
m_inModOff = true;
}
// VISITORS - TOGGLE COVERAGE
@@ -140,7 +143,7 @@ private:
}
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_modp && !m_inToggleOff
if (m_modp && !m_inModOff && !m_inToggleOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageToggle()) {
const char* disablep = varIgnoreToggle(nodep);
if (disablep) {
@@ -231,7 +234,7 @@ private:
UINFO(4," IF: "<<nodep<<endl);
if (m_checkBlock) {
nodep->ifsp()->iterateAndNext(*this);
if (m_checkBlock
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "if" branch didn't disable it
if (!nodep->backp()->castIf()
|| nodep->backp()->castIf()->elsesp()!=nodep) { // Ignore if else; did earlier
@@ -243,7 +246,7 @@ private:
if (nodep->elsesp()) {
m_checkBlock = true;
nodep->elsesp()->iterateAndNext(*this);
if (m_checkBlock
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "else" branch didn't disable it
UINFO(4," COVER: "<<nodep<<endl);
if (nodep->elsesp()->castIf()) {
@@ -258,7 +261,7 @@ private:
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
UINFO(4," CASEI: "<<nodep<<endl);
if (m_checkBlock
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) {
nodep->bodysp()->iterateAndNext(*this);
if (m_checkBlock) { // if the case body didn't disable it
@@ -327,6 +330,7 @@ public:
m_checkBlock = true;
m_beginHier = "";
m_inToggleOff = false;
m_inModOff = true;
rootp->iterateChildren(*this);
}
virtual ~CoverageVisitor() {}
+3 -3
View File
@@ -124,10 +124,10 @@ private:
AstVar* varp;
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
VarMap::iterator iter = m_modVarMap.find(make_pair(addmodp,name));
if (iter != m_modVarMap.end()) {
VarMap::iterator it = m_modVarMap.find(make_pair(addmodp,name));
if (it != m_modVarMap.end()) {
// Created module's AstVar earlier under some other scope
varp = iter->second;
varp = it->second;
} else {
if (width==0) {
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, oldvarscp->varp());
+21 -39
View File
@@ -86,6 +86,13 @@ public:
}
void emitOpName(AstNode* nodep, const string& format,
AstNode* lhsp, AstNode* rhsp, AstNode* thsp);
void emitDeclArrayBrackets(AstVar* nodep) {
// This isn't very robust and may need cleanup for other data types
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
}
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
@@ -788,7 +795,7 @@ class EmitCImp : EmitCStmts {
if (!m_blkChangeDetVec.empty()) puts("return __req;\n");
// puts("__Vm_activity = true;\n");
//puts("__Vm_activity = true;\n");
puts("}\n");
}
@@ -875,7 +882,6 @@ public:
void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
AstBasicDType* basicp = nodep->basicp(); if (!basicp) nodep->v3fatalSrc("Unimplemented: Outputting this data type");
if (nodep->isIO()) {
bool isArray = !nodep->dtypeSkipRefp()->castBasicDType();
if (nodep->isSc()) {
m_ctorVarsVec.push_back(nodep);
ofp()->putAlign(nodep->isStatic(), 4); // sc stuff is a structure, so bigger alignment
@@ -891,12 +897,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
puts(">\t");
}
puts(nodep->name());
if (isArray) {
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
}
emitDeclArrayBrackets(nodep);
puts(";\n");
} else { // C++ signals
ofp()->putAlign(nodep->isStatic(), nodep->dtypeSkipRefp()->widthAlignBytes(),
@@ -909,36 +910,20 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
if (nodep->isQuad()) puts("64");
else if (nodep->widthMin() <= 8) puts("8");
else if (nodep->widthMin() <= 16) puts("16");
else if (nodep->isWide()) puts("W");
if (isArray) {
if (nodep->isWide()) puts("W");
puts("("+nodep->name());
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
puts(","+cvtToStr(basicp->msb())+","+cvtToStr(basicp->lsb()));
if (basicp->isWide()) puts(","+cvtToStr(basicp->widthWords()));
} else {
if (!basicp->isWide())
puts("("+nodep->name()
+","+cvtToStr(basicp->msb())
+","+cvtToStr(basicp->lsb()));
else puts("W("+nodep->name()
+","+cvtToStr(basicp->msb())
+","+cvtToStr(basicp->lsb())
+","+cvtToStr(basicp->widthWords()));
}
puts("("+nodep->name());
emitDeclArrayBrackets(nodep);
// If it's a packed struct/array then nodep->width is the whole thing, msb/lsb is just lowest dimension
puts(","+cvtToStr(basicp->lsb()+nodep->width()-1)
+","+cvtToStr(basicp->lsb()));
if (nodep->isWide()) puts(","+cvtToStr(nodep->widthWords()));
puts(");\n");
}
} else if (basicp && basicp->isOpaque()) {
// strings and other fundamental c types
puts(nodep->vlArgType(true,false));
// This isn't very robust and may need cleanup for other data types
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
emitDeclArrayBrackets(nodep);
puts(";\n");
} else {
// Arrays need a small alignment, but may need different padding after.
@@ -960,13 +945,10 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
}
if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); }
puts(nodep->name());
// This isn't very robust and may need cleanup for other data types
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
emitDeclArrayBrackets(nodep);
// If it's a packed struct/array then nodep->width is the whole thing, msb/lsb is just lowest dimension
puts(","+cvtToStr(basicp->lsb()+nodep->width())+","+cvtToStr(basicp->lsb()));
puts(","+cvtToStr(basicp->lsb()+nodep->width()-1)
+","+cvtToStr(basicp->lsb()));
if (nodep->isWide()) puts(","+cvtToStr(nodep->widthWords()));
puts(");\n");
}
@@ -1735,7 +1717,7 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
}
}
sort(funcsp.begin(), funcsp.end(), CmpName());
stable_sort(funcsp.begin(), funcsp.end(), CmpName());
for (vector<AstCFunc*>::iterator it = funcsp.begin(); it != funcsp.end(); ++it) {
AstCFunc* funcp = *it;
+2 -2
View File
@@ -168,8 +168,8 @@ class EmitCSyms : EmitCBaseVisitor {
varsExpand();
// Sort by names, so line/process order matters less
sort(m_scopes.begin(), m_scopes.end(), CmpName());
sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
stable_sort(m_scopes.begin(), m_scopes.end(), CmpName());
stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
// Output
emitSymHdr();
+10 -3
View File
@@ -44,6 +44,7 @@ bool V3Error::s_describedEachWarn[V3ErrorCode::_ENUM_MAX];
bool V3Error::s_describedWarnings = false;
bool V3Error::s_pretendError[V3ErrorCode::_ENUM_MAX];
V3Error::MessagesSet V3Error::s_messages;
V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL;
struct v3errorIniter {
v3errorIniter() { V3Error::init(); }
@@ -89,8 +90,8 @@ const string FileLineSingleton::filenameLetters(int no) {
//! We associate a language with each source file, so we also set the default
//! for this.
int FileLineSingleton::nameToNumber(const string& filename) {
FileNameNumMap::const_iterator iter = m_namemap.find(filename);
if (VL_LIKELY(iter != m_namemap.end())) return iter->second;
FileNameNumMap::const_iterator it = m_namemap.find(filename);
if (VL_LIKELY(it != m_namemap.end())) return it->second;
int num = m_names.size();
m_names.push_back(filename);
m_languages.push_back(V3LangCode::mostRecent());
@@ -482,7 +483,8 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
}
#ifndef _V3ERROR_NO_GLOBAL_
if (debug()) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",99));
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",990));
if (s_errorExitCb) s_errorExitCb();
V3Stats::statsFinalAll(v3Global.rootp());
V3Stats::statsReport();
}
@@ -491,5 +493,10 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
vlAbort();
}
else if (isError(s_errorCode, s_errorSuppressed)) {
// We don't dump tree on any error because a Visitor may be in middle of
// a tree cleanup and cause a false broken problem.
if (s_errorExitCb) s_errorExitCb();
}
}
}
+4
View File
@@ -181,6 +181,7 @@ class V3Error {
// Base class for any object that wants debugging and error reporting
typedef set<string> MessagesSet;
typedef void (*ErrorExitCb)(void);
private:
static bool s_describedWarnings; // Told user how to disable warns
@@ -194,6 +195,8 @@ class V3Error {
static V3ErrorCode s_errorCode; // Error string being formed will abort
static bool s_errorSuppressed; // Error being formed should be suppressed
static MessagesSet s_messages; // What errors we've outputted
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
V3Error() { cerr<<("Static class"); abort(); }
@@ -218,6 +221,7 @@ class V3Error {
static bool isError(V3ErrorCode code, bool supp);
static string lineStr (const char* filename, int lineno);
static V3ErrorCode errorCode() { return s_errorCode; }
static void errorExitCb(ErrorExitCb cb) { s_errorExitCb = cb; }
// When printing an error/warning, print prefix for multiline message
static string warnMore();
+1 -1
View File
@@ -80,7 +80,7 @@ public:
string debugFilename(const string& nameComment, int newNumber=0) {
++m_debugFileNumber;
if (newNumber) m_debugFileNumber = newNumber;
char digits[100]; sprintf(digits, "%02d", m_debugFileNumber);
char digits[100]; sprintf(digits, "%03d", m_debugFileNumber);
return opt.makeDir()+"/"+opt.prefix()+"_"+digits+"_"+nameComment;
}
bool needHInlines() const { return m_needHInlines; }
+1 -1
View File
@@ -461,7 +461,7 @@ void GraphAcyc::place() {
}
// Sort by weight, then by vertex (so that we completely process one vertex, when possible)
sort(edges.begin(), edges.end(), GraphAcycEdgeCmp());
stable_sort(edges.begin(), edges.end(), GraphAcycEdgeCmp());
// Process each edge in weighted order
m_placeStep = 10;
+2 -2
View File
@@ -464,7 +464,7 @@ void V3Graph::sortVertices() {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
vertices.push_back(vertexp);
}
std::sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
std::stable_sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
this->verticesUnlink();
for (vector<V3GraphVertex*>::iterator it = vertices.begin(); it!=vertices.end(); ++it) {
(*it)->verticesPushBack(this);
@@ -480,7 +480,7 @@ void V3Graph::sortEdges() {
edges.push_back(edgep);
}
// Sort
std::sort(edges.begin(), edges.end(), GraphSortEdgeCmp());
std::stable_sort(edges.begin(), edges.end(), GraphSortEdgeCmp());
// Relink edges in specified order
// We know the vector contains all of the edges that were
+378 -278
View File
@@ -42,11 +42,376 @@
#include "V3Stats.h"
#include "V3Ast.h"
// CONFIG
static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it
//######################################################################
// Inline state, as a visitor of each AstNode
// CONFIG
static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it
class InlineMarkVisitor : public AstNVisitor {
private:
// NODE STATE
// Output
// AstNodeModule::user1() // OUTPUT: bool. User request to inline this module
// Entire netlist (can be cleared after this visit completes)
// AstNodeModule::user2() // CIL_*. Allowed to automatically inline module
// AstNodeModule::user3() // int. Number of cells referencing this module
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
enum {CIL_NOTHARD=0, // For user2, inline not supported
CIL_NOTSOFT, // For user2, don't inline unless user overrides
CIL_MAYBE}; // For user2, might inline
// STATE
AstNodeModule* m_modp; // Flattened cell's containing module
int m_stmtCnt; // Statements in module
V3Double0 m_statUnsup; // Statistic tracking
// METHODS
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
void cantInline(const char* reason, bool hard) {
if (hard) {
if (m_modp->user2() != CIL_NOTHARD) {
UINFO(4," No inline hard: "<<reason<<" "<<m_modp<<endl);
m_modp->user2(CIL_NOTHARD);
m_statUnsup++;
}
} else {
if (m_modp->user2() == CIL_MAYBE) {
UINFO(4," No inline soft: "<<reason<<" "<<m_modp<<endl);
m_modp->user2(CIL_NOTSOFT);
}
}
}
// VISITORS
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_stmtCnt = 0;
m_modp = nodep;
m_modp->user2(CIL_MAYBE);
if (m_modp->castIface()) {
// Inlining an interface means we no longer have a cell handle to resolve to.
// If inlining moves post-scope this can perhaps be relaxed.
cantInline("modIface",true);
}
if (m_modp->modPublic()) cantInline("modPublic",false);
//
nodep->iterateChildren(*this);
//
bool userinline = nodep->user1();
int allowed = nodep->user2();
int refs = nodep->user3();
// Should we automatically inline this module?
// inlineMult = 2000 by default. If a mod*#instances is < this # nodes, can inline it
bool doit = ((allowed == CIL_NOTSOFT || allowed == CIL_MAYBE)
&& (userinline
|| ((allowed == CIL_MAYBE)
&& (refs==1
|| m_stmtCnt < INLINE_MODS_SMALLER
|| v3Global.opt.inlineMult() < 1
|| refs*m_stmtCnt < v3Global.opt.inlineMult()))));
// Packages aren't really "under" anything so they confuse this algorithm
if (nodep->castPackage()) doit = false;
UINFO(4, " Inline="<<doit<<" Possible="<<allowed<<" Usr="<<userinline<<" Refs="<<refs<<" Stmts="<<m_stmtCnt
<<" "<<nodep<<endl);
nodep->user1(doit);
m_modp = NULL;
}
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->modp()->user3Inc();
nodep->iterateChildren(*this);
}
virtual void visit(AstPragma* nodep, AstNUser*) {
if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
//UINFO(0,"PRAG MARK "<<m_modp<<endl);
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
} else {
m_modp->user1(1);
}
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
} else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
} else {
cantInline("Pragma NO_INLINE_MODULE",false);
}
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
} else {
nodep->iterateChildren(*this);
}
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
nodep->varp(NULL);
}
virtual void visit(AstVar* nodep, AstNUser*) {
// Can't look at AstIfaceRefDType directly as it is no longer underneath the module
if (nodep->isIfaceRef()) {
// Unsupported: Inlining of modules with ifaces (see AstIface comment above)
if (m_modp) cantInline("Interfaced",true);
}
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
if (!nodep->packagep()) nodep->taskp(NULL);
nodep->iterateChildren(*this);
}
// Nop's to speed up the loop
virtual void visit(AstAlways* nodep, AstNUser*) {
nodep->iterateChildren(*this);
m_stmtCnt++;
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// Don't count assignments, as they'll likely flatten out
// Still need to iterate though to nullify VarXRefs
int oldcnt = m_stmtCnt;
nodep->iterateChildren(*this);
m_stmtCnt = oldcnt;
}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
m_stmtCnt++;
}
public:
// CONSTUCTORS
InlineMarkVisitor(AstNode* nodep) {
m_modp = NULL;
m_stmtCnt = 0;
nodep->accept(*this);
}
virtual ~InlineMarkVisitor() {
V3Stats::addStat("Optimizations, Inline unsupported", m_statUnsup);
// Done with these, are not outputs
AstNode::user2ClearTree();
AstNode::user3ClearTree();
}
};
//######################################################################
// Using clonep(), find cell cross references.
// clone() must not be called inside this visitor
class InlineCollectVisitor : public AstNVisitor {
private:
// NODE STATE
// Output:
// AstCell::user4p() // AstCell* of the created clone
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// VISITORS
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->user4p(nodep->clonep());
}
// Accelerate
virtual void visit(AstNodeStmt* nodep, AstNUser*) {}
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
InlineCollectVisitor(AstNodeModule* nodep) { // passed OLD module, not new one
nodep->accept(*this);
}
virtual ~InlineCollectVisitor() {}
};
//######################################################################
// After cell is cloned, relink the new module's contents
class InlineRelinkVisitor : public AstNVisitor {
private:
// NODE STATE
// Input:
// See InlineVisitor
// STATE
AstNodeModule* m_modp; // Current module
AstCell* m_cellp; // Cell being cloned
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// VISITORS
virtual void visit(AstCellInline* nodep, AstNUser*) {
// Inlined cell under the inline cell, need to move to avoid conflicts
nodep->unlinkFrBack();
m_modp->addInlinesp(nodep);
// Rename
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
UINFO(6, " Inline "<<nodep<<endl);
// Do CellInlines under this, but don't move them
nodep->iterateChildren(*this);
}
virtual void visit(AstCell* nodep, AstNUser*) {
// Cell under the inline cell, need to rename to avoid conflicts
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
nodep->iterateChildren(*this);
}
virtual void visit(AstVar* nodep, AstNUser*) {
if (nodep->user2p()) {
// Make an assignment, so we'll trace it properly
// user2p is either a const or a var.
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
UINFO(8,"connectto: "<<nodep->user2p()->castNode()<<endl);
if (!exprconstp && !exprvarrefp) {
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
}
if (exprconstp) {
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
exprconstp->cloneTree(true)));
} else if (nodep->user3()) {
// Public variable at the lower module end - we need to make sure we propagate
// the logic changes up and down; if we aliased, we might remove the change detection
// on the output variable.
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
} else if (nodep->isIfaceRef()) {
m_modp->addStmtp(new AstAssignVarScope(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp=exprvarrefp->varp();
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
} else {
// Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp=exprvarrefp->varp();
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
}
}
// Variable under the inline cell, need to rename to avoid conflicts
// Also clear I/O bits, as it is now local.
string name = m_cellp->name() + "__DOT__" + nodep->name();
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
// Iterate won't hit AstIfaceRefDType directly as it is no longer underneath the module
if (AstIfaceRefDType* ifacerefp = nodep->dtypep()->castIfaceRefDType()) {
// Relink to point to newly cloned cell
if (ifacerefp->cellp()) {
if (AstCell* newcellp = ifacerefp->cellp()->user4p()->castNode()->castCell()) {
ifacerefp->cellp(newcellp);
ifacerefp->cellName(newcellp->name());
}
}
}
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
// Function under the inline cell, need to rename to avoid conflicts
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
nodep->iterateChildren(*this);
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
// Typedef under the inline cell, need to rename to avoid conflicts
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
nodep->iterateChildren(*this);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (nodep->varp()->user2p() // It's being converted to an alias.
&& !nodep->varp()->user3()
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
if (exprconstp) {
nodep->replaceWith(exprconstp->cloneTree(true));
nodep->deleteTree(); nodep=NULL;
return;
}
else if (exprvarrefp) {
nodep->varp( exprvarrefp->varp() );
}
else {
nodep->v3fatalSrc("Null connection?\n");
}
}
nodep->name(nodep->varp()->name());
nodep->iterateChildren(*this);
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
// Track what scope it was originally under so V3LinkDot can resolve it
string newname = m_cellp->name();
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
nodep->inlinedDots(newname);
UINFO(8," "<<nodep<<endl);
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Track what scope it was originally under so V3LinkDot can resolve it
string newname = m_cellp->name();
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
nodep->inlinedDots(newname);
UINFO(8," "<<nodep<<endl);
nodep->iterateChildren(*this);
}
// Not needed, as V3LinkDot doesn't care about typedefs
//virtual void visit(AstRefDType* nodep, AstNUser*) {}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Begin
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
if (afterp) nodep->scopeAttrp(afterp);
nodep->iterateChildren(*this);
}
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
// Fix path in coverage statements
nodep->hier(m_cellp->prettyName()
+ (nodep->hier()!="" ? ".":"")
+ nodep->hier());
nodep->iterateChildren(*this);
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
InlineRelinkVisitor(AstNodeModule* cloneModp, AstNodeModule* oldModp, AstCell* cellp) {
m_modp = oldModp;
m_cellp = cellp;
cloneModp->accept(*this);
}
virtual ~InlineRelinkVisitor() {}
};
//######################################################################
// Inline state, as a visitor of each AstNode
class InlineVisitor : public AstNVisitor {
private:
@@ -56,11 +421,13 @@ private:
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
// Cleared each cell
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
// AstVar::user3() // bool Don't alias the user4, keep it as signal
// AstVar::user3() // bool Don't alias the user2, keep it as signal
// AstCell::user4 // AstCell* of the created clone
AstUser4InUse m_inuser4;
// STATE
AstNodeModule* m_modp; // Current module
AstCell* m_cellp; // Cell being cloned
V3Double0 m_statCells; // Statistic tracking
static int debug() {
@@ -75,34 +442,11 @@ private:
nodep->iterateChildrenBackwards(*this);
}
virtual void visit(AstNodeModule* nodep, AstNUser*) {
if (m_cellp) {
} else {
m_modp = nodep;
}
m_modp = nodep;
nodep->iterateChildren(*this);
}
virtual void visit(AstCellInline* nodep, AstNUser*) {
// Inlined cell under the inline cell, need to move to avoid conflicts
if (m_cellp) {
nodep->unlinkFrBack();
m_modp->addInlinesp(nodep);
// Rename
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
UINFO(6, " Inline "<<nodep<<endl);
// Do CellInlines under this, but don't move them
nodep->iterateChildren(*this);
}
}
virtual void visit(AstCell* nodep, AstNUser*) {
if (m_cellp) {
// Cell under the inline cell, need to rename to avoid conflicts
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
nodep->iterateChildren(*this);
}
if (nodep->modp()->user1()) { // Marked with inline request
if (m_cellp) nodep->v3error("Cloning should have already been done bottom-up");
UINFO(5," Inline CELL "<<nodep<<endl);
UINFO(5," To MOD "<<m_modp<<endl);
++m_statCells;
@@ -121,8 +465,10 @@ private:
//if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); }
AstNodeModule* newmodp = nodep->modp()->cloneTree(false);
if (debug()>=9) { newmodp->dumpTree(cout,"newmod:"); }
// Clear var markings
// Clear var markings and find cell cross references
AstNode::user2ClearTree();
AstNode::user4ClearTree();
{ InlineCollectVisitor(nodep->modp()); } // {} to destroy visitor immediately
// Create data for dotted variable resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
nodep->name(), nodep->modp()->origName());
@@ -163,9 +509,7 @@ private:
pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly());
}
// Cleanup var names, etc, to not conflict
m_cellp = nodep;
newmodp->iterate(*this); // Not iterateAndNext because newmodp isn't linked; no back
m_cellp = NULL;
{ InlineRelinkVisitor(newmodp, m_modp, nodep); }
// Move statements to top module
if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); }
AstNode* stmtsp = newmodp->stmtsp();
@@ -178,133 +522,10 @@ private:
if (debug()>=9) { m_modp->dumpTree(cout,"donemod:"); }
}
}
virtual void visit(AstVar* nodep, AstNUser*) {
if (m_cellp) {
if (nodep->user2p()) {
// Make an assignment, so we'll trace it properly
// user2p is either a const or a var.
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
UINFO(8,"connectto: "<<nodep->user2p()->castNode()<<endl);
if (!exprconstp && !exprvarrefp) {
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
}
if (exprconstp) {
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
exprconstp->cloneTree(true)));
} else if (nodep->user3()) {
// Public variable at the lower module end - we need to make sure we propagate
// the logic changes up and down; if we aliased, we might remove the change detection
// on the output variable.
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
} else {
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp=exprvarrefp->varp();
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
}
}
// Variable under the inline cell, need to rename to avoid conflicts
// Also clear I/O bits, as it is now local.
string name = m_cellp->name() + "__DOT__" + nodep->name();
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
}
if (nodep) nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
if (m_cellp) {
// Function under the inline cell, need to rename to avoid conflicts
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
}
nodep->iterateChildren(*this);
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
if (m_cellp) {
// Typedef under the inline cell, need to rename to avoid conflicts
nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
}
nodep->iterateChildren(*this);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (m_cellp) {
if (nodep->varp()->user2p() // It's being converted to an alias.
&& !nodep->varp()->user3()
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
if (exprconstp) {
nodep->replaceWith(exprconstp->cloneTree(true));
nodep->deleteTree(); nodep=NULL;
return;
}
else if (exprvarrefp) {
nodep->varp( exprvarrefp->varp() );
}
else {
nodep->v3fatalSrc("Null connection?\n");
}
}
nodep->name(nodep->varp()->name());
}
nodep->iterateChildren(*this);
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
if (m_cellp) {
// Track what scope it was originally under so V3LinkDot can resolve it
string newname = m_cellp->name();
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
nodep->inlinedDots(newname);
UINFO(8," "<<nodep<<endl);
}
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
if (m_cellp) {
// Track what scope it was originally under so V3LinkDot can resolve it
string newname = m_cellp->name();
if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
nodep->inlinedDots(newname);
UINFO(8," "<<nodep<<endl);
}
nodep->iterateChildren(*this);
}
// Not needed, as V3LinkDot doesn't care about typedefs
//virtual void visit(AstRefDType* nodep, AstNUser*) {}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Begin
if (m_cellp) {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
if (afterp) nodep->scopeAttrp(afterp);
}
nodep->iterateChildren(*this);
}
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
// Fix path in coverage statements
if (m_cellp) {
nodep->hier(m_cellp->prettyName()
+ (nodep->hier()!="" ? ".":"")
+ nodep->hier());
}
nodep->iterateChildren(*this);
}
//--------------------
// Default: Just iterate
virtual void visit(AstNodeMath* nodep, AstNUser*) {} // Accelerate
virtual void visit(AstNodeStmt* nodep, AstNUser*) {} // Accelerate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
@@ -312,7 +533,6 @@ private:
public:
// CONSTUCTORS
InlineVisitor(AstNode* nodep) {
m_cellp = NULL;
m_modp = NULL;
nodep->accept(*this);
}
@@ -321,126 +541,6 @@ public:
}
};
//######################################################################
// Inline state, as a visitor of each AstNode
class InlineMarkVisitor : public AstNVisitor {
private:
// NODE STATE
// Entire netlist
// AstNodeModule::user1() // OUTPUT: bool. User request to inline this module
// AstNodeModule::user2() // bool. Allowed to automatically inline module
// AstNodeModule::user3() // int. Number of cells referencing this module
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
// STATE
AstNodeModule* m_modp; // Current module
int m_stmtCnt; // Statements in module
// METHODS
void cantInline(const char* reason) {
if (m_modp->user2()) {
UINFO(4," No inline: "<<reason<<" "<<m_modp<<endl);
m_modp->user2(false);
}
}
// VISITORS
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_stmtCnt = 0;
m_modp = nodep;
m_modp->user2(true); // Allowed = true
if (m_modp->modPublic()) cantInline("modPublic");
//
nodep->iterateChildren(*this);
//
bool userinline = nodep->user1();
bool allowed = nodep->user2();
int refs = nodep->user3();
// Should we automatically inline this module?
// inlineMult = 2000 by default. If a mod*#instances is < this # nodes, can inline it
bool doit = (userinline || (allowed && (refs==1
|| m_stmtCnt < INLINE_MODS_SMALLER
|| v3Global.opt.inlineMult() < 1
|| refs*m_stmtCnt < v3Global.opt.inlineMult())));
// Packages aren't really "under" anything so they confuse this algorithm
if (nodep->castPackage()) doit = false;
UINFO(4, " Inline="<<doit<<" Possible="<<allowed<<" Usr="<<userinline<<" Refs="<<refs<<" Stmts="<<m_stmtCnt
<<" "<<nodep<<endl);
if (doit) {
UINFO(4," AutoInline "<<nodep<<endl);
nodep->user1(true);
}
m_modp = NULL;
}
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->modp()->user3Inc();
nodep->iterateChildren(*this);
}
virtual void visit(AstPragma* nodep, AstNUser*) {
if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
//UINFO(0,"PRAG MARK "<<m_modp<<endl);
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
} else {
m_modp->user1(1);
}
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
} else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
} else {
cantInline("Pragma NO_INLINE_MODULE");
}
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
} else {
nodep->iterateChildren(*this);
}
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
nodep->varp(NULL);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
if (!nodep->packagep()) nodep->taskp(NULL);
nodep->iterateChildren(*this);
}
// Nop's to speed up the loop
virtual void visit(AstAlways* nodep, AstNUser*) {
nodep->iterateChildren(*this);
m_stmtCnt++;
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// Don't count assignments, as they'll likely flatten out
// Still need to iterate though to nullify VarXRefs
int oldcnt = m_stmtCnt;
nodep->iterateChildren(*this);
m_stmtCnt = oldcnt;
}
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
m_stmtCnt++;
}
public:
// CONSTUCTORS
InlineMarkVisitor(AstNode* nodep) {
m_modp = NULL;
m_stmtCnt = 0;
//VV***** We reset all userp() on the whole netlist!!!
AstNode::user1ClearTree();
AstNode::user2ClearTree();
AstNode::user3ClearTree();
nodep->accept(*this);
}
virtual ~InlineMarkVisitor() {}
};
//######################################################################
// Inline class functions
+12 -1
View File
@@ -105,6 +105,13 @@ private:
exprp);
m_modp->addStmtp(assp);
if (debug()>=9) assp->dumpTree(cout," _new: ");
} else if (nodep->modVarp()->isIfaceRef()) {
// Create an AstAssignVarScope for Vars to Cells so we can link with their scope later
AstNode* lhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
AstVarRef* refp = exprp->castVarRef();
if (!refp) exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef");
AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, refp);
m_modp->addStmtp(assp);
} else {
nodep->v3error("Assigned pin is neither input nor output");
}
@@ -252,7 +259,11 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
&& connectRefp
&& connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
// Done. Same data type
// Done. Same data type
} else if (!alwaysCvt
&& connectRefp
&& connectRefp->varp()->isIfaceRef()) {
// Done. Interface
} else if (!alwaysCvt
&& connBasicp
&& pinBasicp
+3 -3
View File
@@ -37,9 +37,9 @@ class V3LanguageWords {
}
public:
string isKeyword(const string& kwd) {
map<string,string>::iterator iter = m_kwdMap.find(kwd);
if (iter == m_kwdMap.end()) return "";
return iter->second;
map<string,string>::iterator it = m_kwdMap.find(kwd);
if (it == m_kwdMap.end()) return "";
return it->second;
}
public:
+37
View File
@@ -190,6 +190,7 @@ private:
<<"' does not match "<<nodep->typeName()<<" name: "<<nodep->prettyName());
}
}
if (nodep->castIface() || nodep->castPackage()) nodep->inLibrary(true); // Interfaces can't be at top, unless asked
bool topMatch = (v3Global.opt.topModule()==nodep->prettyName());
if (topMatch) {
m_topVertexp = vertex(nodep);
@@ -210,6 +211,25 @@ private:
m_modp = NULL;
}
virtual void visit(AstIfaceRefDType* nodep, AstNUser*) {
// Cell: Resolve its filename. If necessary, parse it.
UINFO(4,"Link IfaceRef: "<<nodep<<endl);
// Use findIdUpward instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday.
AstNodeModule* modp = resolveModule(nodep, nodep->ifaceName());
if (modp) {
if (modp->castIface()) {
// Track module depths, so can sort list from parent down to children
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false);
if (!nodep->cellp()) nodep->ifacep(modp->castIface());
} else if (modp->castNotFoundModule()) { // Will error out later
} else {
nodep->v3error("Non-interface used as an interface: "<<nodep->prettyName());
}
}
// Note cannot do modport resolution here; modports are allowed underneath generates
}
virtual void visit(AstPackageImport* nodep, AstNUser*) {
// Package Import: We need to do the package before the use of a package
nodep->iterateChildren(*this);
@@ -314,6 +334,23 @@ private:
}
}
}
if (nodep->modp()->castIface()) {
// Cell really is the parent's instantiation of an interface, not a normal module
// Make sure we have a variable to refer to this cell, so can <ifacename>.<innermember>
// in the same way that a child does. Rename though to avoid conflict with cell.
// This is quite similar to how classes work; when unpacked classes are better supported
// may remap interfaces to be more like a class.
if (!nodep->hasIfaceVar()) {
string varName = nodep->name()+"__Viftop"; // V3LinkDot looks for this naming
AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(), nodep->modp()->name());
idtypep->cellp(nodep); // Only set when real parent cell known
idtypep->ifacep(NULL); // cellp overrides
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
varp->isIfaceParent(true);
nodep->addNextHere(varp);
nodep->hasIfaceVar(true);
}
}
if (nodep->modp()) {
nodep->iterateChildren(*this);
}
+364 -47
View File
@@ -31,6 +31,26 @@
// VarXRef/Func's:
// Find appropriate named cell and link to var they reference
//*************************************************************************
// Interfaces:
// CELL (.port (ifref)
// ^--- cell -> IfaceDTypeRef(iface)
// ^--- cell.modport -> IfaceDTypeRef(iface,modport)
// ^--- varref(input_ifref) -> IfaceDTypeRef(iface)
// ^--- varref(input_ifref).modport -> IfaceDTypeRef(iface,modport)
// FindVisitor:
// #1: Insert interface Vars
// #2: Insert ModPort names
// IfaceVisitor:
// #3: Update ModPortVarRef to point at interface vars (after #1)
// #4: Create ModPortVarRef symbol table entries
// FindVisitor-insertIfaceRefs()
// #5: Resolve IfaceRefDtype modport names (after #2)
// #7: Record sym of IfaceRefDType and aliased interface and/or modport (after #4,#5)
// insertAllScopeAliases():
// #8: Insert modport's symbols under IfaceRefDType (after #7)
// ResolveVisitor:
// #9: Resolve general variables, which may point into the interface or modport (after #8)
//*************************************************************************
// TOP
// {name-of-top-modulename}
// a (VSymEnt->AstCell)
@@ -77,17 +97,26 @@ private:
AstUser4InUse m_inuser4;
// TYPES
typedef std::multimap<string,VSymEnt*> NameScopeMap;
typedef set <pair<AstNodeModule*,string> > ImplicitNameSet;
typedef multimap<string,VSymEnt*> NameScopeSymMap;
typedef map<VSymEnt*,VSymEnt*> ScopeAliasMap;
typedef set<pair<AstNodeModule*,string> > ImplicitNameSet;
typedef vector<VSymEnt*> IfaceVarSyms;
typedef vector<pair<AstIface*,VSymEnt*> > IfaceModSyms;
static LinkDotState* s_errorThisp; // Last self, for error reporting only
// MEMBERS
VSymGraph m_syms; // Symbol table
VSymEnt* m_dunitEntp; // $unit entry
NameScopeMap m_nameScopeMap; // Hash of scope referenced by non-pretty textual name
NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name
ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it
ScopeAliasMap m_scopeAliasMap; // Map of <lhs,rhs> aliases
IfaceVarSyms m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported
IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed
bool m_forPrimary; // First link
bool m_forPrearray; // Compress cell__[array] refs
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
public:
static int debug() {
@@ -95,14 +124,27 @@ public:
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
void dump() {
if (debug()>=6) m_syms.dumpFilePrefixed("linkdot");
void dump(const string& nameComment="linkdot", bool force=false) {
if (debug()>=6 || force) {
string filename = v3Global.debugFilename(nameComment)+".txt";
const auto_ptr<ofstream> logp (V3File::new_ofstream(filename));
if (logp->fail()) v3fatalSrc("Can't write "<<filename);
ostream& os = *logp;
m_syms.dump(os);
if (!m_scopeAliasMap.empty()) os<<"\nScopeAliasMap:\n";
for (ScopeAliasMap::iterator it = m_scopeAliasMap.begin(); it != m_scopeAliasMap.end(); ++it) {
os<<"\t"<<it->first<<" -> "<<it->second<<endl;
}
}
}
static void preErrorDumpHandler() {
if (s_errorThisp) s_errorThisp->preErrorDump();
}
void preErrorDump() {
static bool diddump = false;
if (!diddump && v3Global.opt.dumpTree()) {
diddump = true;
m_syms.dumpFilePrefixed("linkdot-preerr");
dump("linkdot-preerr",true);
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr.tree"));
}
}
@@ -115,8 +157,13 @@ public:
m_forPrearray = (step == LDS_PARAMED || step==LDS_PRIMARY);
m_forScopeCreation = (step == LDS_SCOPED);
m_dunitEntp = NULL;
s_errorThisp = this;
V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
}
~LinkDotState() {
V3Error::errorExitCb(NULL);
s_errorThisp = NULL;
}
~LinkDotState() {}
// ACCESSORS
VSymGraph* symsp() { return &m_syms; }
@@ -131,6 +178,7 @@ public:
else if (nodep->castTask()) return "task";
else if (nodep->castFunc()) return "function";
else if (nodep->castBegin()) return "block";
else if (nodep->castIface()) return "interface";
else return nodep->prettyTypeName();
}
static string ucfirst(const string& text) {
@@ -161,7 +209,6 @@ public:
// Begin: ... blocks often replicate under genif/genfor, so simply suppress duplicate checks
// See t_gen_forif.v for an example.
} else {
preErrorDump();
UINFO(4,"name "<<name<<endl); // Not always same as nodep->name
UINFO(4,"Var1 "<<nodep<<endl);
UINFO(4,"Var2 "<<fnodep<<endl);
@@ -195,7 +242,7 @@ public:
nodep->user1p(symp);
checkDuplicate(rootEntp(), nodep, nodep->origName());
rootEntp()->insert(nodep->origName(),symp);
if (forScopeCreation()) m_nameScopeMap.insert(make_pair(scopename, symp));
if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp));
return symp;
}
VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* modSymp,
@@ -214,7 +261,7 @@ public:
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
modSymp->reinsert(nodep->name(), symp);
}
if (forScopeCreation()) m_nameScopeMap.insert(make_pair(scopename, symp));
if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp));
return symp;
}
VSymEnt* insertInline(VSymEnt* abovep, VSymEnt* modSymp,
@@ -246,7 +293,7 @@ public:
UINFO(9," INSERTblk se"<<(void*)symp<<" above=se"<<(void*)abovep<<" node="<<nodep<<endl);
symp->parentp(abovep);
symp->packagep(packagep);
symp->fallbackp(abovep); // Needed so can find $unit stuff
symp->fallbackp(abovep);
nodep->user1p(symp);
if (name != "") {
checkDuplicate(abovep, nodep, name);
@@ -278,17 +325,17 @@ public:
return symp;
}
VSymEnt* getScopeSym(AstScope* nodep) {
NameScopeMap::iterator iter = m_nameScopeMap.find(nodep->name());
if (iter == m_nameScopeMap.end()) {
NameScopeSymMap::iterator it = m_nameScopeSymMap.find(nodep->name());
if (it == m_nameScopeSymMap.end()) {
nodep->v3fatalSrc("Scope never assigned a symbol entry?");
}
return iter->second;
return it->second;
}
void implicitOkAdd(AstNodeModule* nodep, const string& varname) {
// Mark the given variable name as being allowed to be implicitly declared
if (nodep) {
ImplicitNameSet::iterator iter = m_implicitNameSet.find(make_pair(nodep,varname));
if (iter == m_implicitNameSet.end()) {
ImplicitNameSet::iterator it = m_implicitNameSet.find(make_pair(nodep,varname));
if (it == m_implicitNameSet.end()) {
m_implicitNameSet.insert(make_pair(nodep,varname));
}
}
@@ -298,6 +345,69 @@ public:
&& (m_implicitNameSet.find(make_pair(nodep,varname)) != m_implicitNameSet.end());
}
// Track and later recurse interface modules
void insertIfaceModSym(AstIface* nodep, VSymEnt* symp) {
m_ifaceModSyms.push_back(make_pair(nodep, symp));
}
void computeIfaceModSyms();
// Track and later insert interface references
void insertIfaceVarSym(VSymEnt* symp) { // Where sym is for a VAR of dtype IFACEREFDTYPE
m_ifaceVarSyms.push_back(symp);
}
void computeIfaceVarSyms() {
for (IfaceVarSyms::iterator it = m_ifaceVarSyms.begin(); it != m_ifaceVarSyms.end(); ++it) {
VSymEnt* varSymp = *it;
AstVar* varp = varSymp->nodep()->castVar();
UINFO(9, " insAllIface se"<<(void*)varSymp<<" "<<varp<<endl);
AstIfaceRefDType* ifacerefp = varp->subDTypep()->castIfaceRefDType();
if (!ifacerefp) varp->v3fatalSrc("Non-ifacerefs on list!");
if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
VSymEnt* ifaceSymp = getNodeSym(ifacerefp->ifaceViaCellp());
VSymEnt* ifOrPortSymp = ifaceSymp;
// Link Modport names to the Modport Node under the Interface
if (ifacerefp->isModport()) {
VSymEnt* foundp = ifaceSymp->findIdFallback(ifacerefp->modportName());
bool ok = false;
if (foundp) {
if (AstModport* modportp = foundp->nodep()->castModport()) {
UINFO(4,"Link Modport: "<<modportp<<endl);
ifacerefp->modportp(modportp);
ifOrPortSymp = foundp;
ok = true;
}
}
if (!ok) ifacerefp->v3error("Modport not found under interface '"
<<ifacerefp->prettyName(ifacerefp->ifaceName())
<<"': "<<ifacerefp->prettyName(ifacerefp->modportName()));
}
// Alias won't expand until interfaces and modport names are known; see notes at top
insertScopeAlias(varSymp, ifOrPortSymp);
}
m_ifaceVarSyms.clear();
}
// Track and later insert scope aliases
void insertScopeAlias(VSymEnt* lhsp, VSymEnt* rhsp) { // Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell
UINFO(9," insertScopeAlias se"<<(void*)lhsp<<" se"<<(void*)rhsp<<endl);
m_scopeAliasMap.insert(make_pair(lhsp, rhsp));
}
void computeScopeAliases() {
UINFO(9,"computeIfaceAliases\n");
for (ScopeAliasMap::iterator it=m_scopeAliasMap.begin(); it!=m_scopeAliasMap.end(); ++it) {
VSymEnt* lhsp = it->first;
VSymEnt* srcp = lhsp;
while (1) { // Follow chain of aliases up to highest level non-alias
ScopeAliasMap::iterator it2 = m_scopeAliasMap.find(srcp);
if (it2 != m_scopeAliasMap.end()) { srcp = it2->second; continue; }
else break;
}
UINFO(9," iiasa: Insert alias se"<<lhsp<<" <- se"<<srcp<<" "<<srcp->nodep()<<endl);
// srcp should be an interface reference pointing to the interface we want to import
lhsp->importFromIface(symsp(), srcp);
}
m_scopeAliasMap.clear();
}
private:
VSymEnt* findWithAltFallback(VSymEnt* symp, const string& name, const string& altname) {
VSymEnt* findp = symp->findIdFallback(name);
@@ -399,10 +509,11 @@ public:
}
};
LinkDotState* LinkDotState::s_errorThisp = NULL;
//======================================================================
class LinkDotFindVisitor : public AstNVisitor {
private:
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
AstPackage* m_packagep; // Current package
@@ -486,6 +597,10 @@ private:
// Iterate
nodep->iterateChildren(*this);
nodep->user4(true);
// Interfaces need another pass when signals are resolved
if (AstIface* ifacep = nodep->castIface()) {
m_statep->insertIfaceModSym(ifacep, m_curSymp);
}
} else { //!doit
// Will be optimized away later
// Can't remove now, as our backwards iterator will throw up
@@ -525,7 +640,6 @@ private:
VSymEnt* okSymp;
aboveSymp = m_statep->findDotted(aboveSymp, scope, baddot, okSymp);
if (!aboveSymp) {
m_statep->preErrorDump();
nodep->v3fatalSrc("Can't find cell insertion point at '"<<baddot<<"' in: "<<nodep->prettyName());
}
}
@@ -554,7 +668,6 @@ private:
VSymEnt* okSymp;
aboveSymp = m_statep->findDotted(aboveSymp, dotted, baddot, okSymp);
if (!aboveSymp) {
m_statep->preErrorDump();
nodep->v3fatalSrc("Can't find cellinline insertion point at '"<<baddot<<"' in: "<<nodep->prettyName());
}
m_statep->insertInline(aboveSymp, m_modSymp, nodep, ident);
@@ -666,7 +779,6 @@ private:
if (!foundp) {
ins=true;
} else if (!findvarp && foundp && m_curSymp->findIdFlat(nodep->name())) {
m_statep->preErrorDump();
nodep->v3error("Unsupported in C: Variable has same name as "
<<LinkDotState::nodeTextType(foundp->nodep())<<": "<<nodep->prettyName());
} else if (findvarp != nodep) {
@@ -705,12 +817,16 @@ private:
}
}
if (ins) {
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
VSymEnt* insp = m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
if (m_statep->forPrimary() && nodep->isGParam()) {
m_paramNum++;
VSymEnt* symp = m_statep->insertSym(m_curSymp, "__paramNumber"+cvtToStr(m_paramNum), nodep, m_packagep);
symp->exported(false);
}
if (nodep->subDTypep()->castIfaceRefDType()) {
// Can't resolve until interfaces and modport names are known; see notes at top
m_statep->insertIfaceVarSym(insp);
}
}
}
}
@@ -763,7 +879,7 @@ private:
nodep->v3error("Import object not found: "<<nodep->packagep()->prettyName()<<"::"<<nodep->prettyName());
}
}
m_curSymp->import(m_statep->symsp(), srcp, nodep->name());
m_curSymp->importFromPackage(m_statep->symsp(), srcp, nodep->name());
UINFO(9," Link Done: "<<nodep<<endl);
// No longer needed, but can't delete until any multi-instantiated modules are expanded
}
@@ -885,8 +1001,8 @@ private:
AstVar* refp = foundp->nodep()->castVar();
if (!refp) {
nodep->v3error("Input/output/inout declaration not found for port: "<<nodep->prettyName());
} else if (!refp->isIO()) {
nodep->v3error("Pin is not an in/out/inout: "<<nodep->prettyName());
} else if (!refp->isIO() && !refp->isIfaceRef()) {
nodep->v3error("Pin is not an in/out/inout/interface: "<<nodep->prettyName());
} else {
refp->user4(true);
VSymEnt* symp = m_statep->insertSym(m_statep->getNodeSym(m_modp),
@@ -942,9 +1058,10 @@ public:
//======================================================================
class LinkDotScopeVisitor : public AstNVisitor {
private:
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
AstScope* m_scopep; // The current scope
VSymEnt* m_modSymp; // Symbol entry for current module
int debug() { return LinkDotState::debug(); }
@@ -960,12 +1077,36 @@ private:
// Using the CELL names, we created all hierarchy. We now need to match this Scope
// up with the hierarchy created by the CELL names.
m_modSymp = m_statep->getScopeSym(nodep);
m_scopep = nodep;
nodep->iterateChildren(*this);
m_modSymp = NULL;
m_scopep = NULL;
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
if (!nodep->varp()->isFuncLocal()) {
m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
VSymEnt* varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
if (nodep->varp()->isIfaceRef()
&& nodep->varp()->isIfaceParent()) {
UINFO(9,"Iface parent ref var "<<nodep->varp()->name()<<" "<<nodep<<endl);
// Find the interface cell the var references
AstIfaceRefDType* dtypep = nodep->varp()->dtypep()->castIfaceRefDType();
if (!dtypep) nodep->v3fatalSrc("Non AstIfaceRefDType on isIfaceRef() var");
UINFO(9,"Iface parent dtype "<<dtypep<<endl);
string ifcellname = dtypep->cellName();
string baddot; VSymEnt* okSymp;
VSymEnt* cellSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
if (!cellSymp) nodep->v3fatalSrc("No symbol for interface cell: " <<nodep->prettyName(ifcellname));
UINFO(5, " Found interface cell: se"<<(void*)cellSymp<<" "<<cellSymp->nodep()<<endl);
if (dtypep->modportName()!="") {
VSymEnt* mpSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
if (!mpSymp) { nodep->v3fatalSrc("No symbol for interface modport: " <<nodep->prettyName(dtypep->modportName())); }
else cellSymp = mpSymp;
UINFO(5, " Found modport cell: se"<<(void*)cellSymp<<" "<<mpSymp->nodep()<<endl);
}
// Interface reference; need to put whole thing into symtable, but can't clone it now
// as we may have a later alias for it.
m_statep->insertScopeAlias(varSymp, cellSymp);
}
}
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
@@ -976,15 +1117,44 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
// we'll need to replace it with a VARXREF(aliased_to)
if (m_statep->forScopeCreation()) {
if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\talias: ");
AstVarScope* fromVscp = nodep->lhsp()->castVarRef()->varScopep();
AstVarScope* toVscp = nodep->rhsp()->castVarRef()->varScopep();
if (!fromVscp || !toVscp) nodep->v3fatalSrc("Bad alias scopes");
fromVscp->user2p(toVscp);
}
if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\talias: ");
AstVarScope* fromVscp = nodep->lhsp()->castVarRef()->varScopep();
AstVarScope* toVscp = nodep->rhsp()->castVarRef()->varScopep();
if (!fromVscp || !toVscp) nodep->v3fatalSrc("Bad alias scopes");
fromVscp->user2p(toVscp);
nodep->iterateChildren(*this);
}
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
UINFO(5,"ASSIGNVARSCOPE "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\tavs: ");
VSymEnt* rhsSymp;
{
AstVarRef* refp = nodep->rhsp()->castVarRef();
if (!refp) nodep->v3fatalSrc("Unsupported: Non VarRef attached to interface pin");
string scopename = refp->name();
string baddot; VSymEnt* okSymp;
VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
if (!symp) nodep->v3fatalSrc("No symbol for interface alias rhs");
UINFO(5, " Found a linked scope RHS: "<<scopename<<" se"<<(void*)symp<<" "<<symp->nodep()<<endl);
rhsSymp = symp;
}
VSymEnt* lhsSymp;
{
AstVarXRef* refp = nodep->lhsp()->castVarXRef();
if (!refp) nodep->v3fatalSrc("Unsupported: Non VarXRef attached to interface pin");
string scopename = refp->dotted()+"."+refp->name();
string baddot; VSymEnt* okSymp;
VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
if (!symp) nodep->v3fatalSrc("No symbol for interface alias lhs");
UINFO(5, " Found a linked scope LHS: "<<scopename<<" se"<<(void*)symp<<" "<<symp->nodep()<<endl);
lhsSymp = symp;
}
// Remember the alias - can't do it yet because we may have additional symbols to be added,
// or maybe an alias of an alias
m_statep->insertScopeAlias(lhsSymp, rhsSymp);
// We have stored the link, we don't need these any more
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
// For speed, don't recurse things that can't have scope
// Note we allow AstNodeStmt's as generates may be under them
virtual void visit(AstCell*, AstNUser*) {}
@@ -1000,6 +1170,7 @@ public:
LinkDotScopeVisitor(AstNetlist* rootp, LinkDotState* statep) {
UINFO(4,__FUNCTION__<<": "<<endl);
m_modSymp = NULL;
m_scopep = NULL;
m_statep = statep;
//
rootp->accept(*this);
@@ -1009,6 +1180,78 @@ public:
//======================================================================
// Iterate an interface to resolve modports
class LinkDotIfaceVisitor : public AstNVisitor {
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert
// METHODS
int debug() { return LinkDotState::debug(); }
// VISITs
virtual void visit(AstModport* nodep, AstNUser*) {
// Modport: Remember its name for later resolution
UINFO(5," fiv: "<<nodep<<endl);
VSymEnt* oldCurSymp = m_curSymp;
{
// Create symbol table for the vars
m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, NULL);
m_curSymp->fallbackp(oldCurSymp);
nodep->iterateChildren(*this);
}
m_curSymp = oldCurSymp;
}
virtual void visit(AstModportVarRef* nodep, AstNUser*) {
UINFO(5," fiv: "<<nodep<<endl);
nodep->iterateChildren(*this);
VSymEnt* symp = m_curSymp->findIdFallback(nodep->name());
if (!symp) {
nodep->v3error("Modport item not found: "<<nodep->prettyName());
} else if (AstVar* varp = symp->nodep()->castVar()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep->varp(varp);
m_statep->insertSym(m_curSymp, nodep->name(), varp, NULL/*package*/);
} else if (AstVarScope* vscp = symp->nodep()->castVarScope()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep->varp(vscp->varp());
m_statep->insertSym(m_curSymp, nodep->name(), vscp, NULL/*package*/);
} else {
nodep->v3error("Modport item is not a variable: "<<nodep->prettyName());
}
if (m_statep->forScopeCreation()) {
// Done with AstModportVarRef.
// Delete to prevent problems if we dead-delete pointed to variable
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
LinkDotIfaceVisitor(AstIface* nodep, VSymEnt* curSymp, LinkDotState* statep) {
UINFO(4,__FUNCTION__<<": "<<endl);
m_curSymp = curSymp;
m_statep = statep;
nodep->accept(*this);
}
virtual ~LinkDotIfaceVisitor() {}
};
void LinkDotState::computeIfaceModSyms() {
for (IfaceModSyms::iterator it=m_ifaceModSyms.begin(); it!=m_ifaceModSyms.end(); ++it) {
AstIface* nodep = it->first;
VSymEnt* symp = it->second;
LinkDotIfaceVisitor(nodep, symp, this);
}
m_ifaceModSyms.clear();
}
//======================================================================
class LinkDotResolveVisitor : public AstNVisitor {
private:
// NODE STATE
@@ -1037,6 +1280,7 @@ private:
AstCell* m_cellp; // Current cell
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
int m_modportNum; // Uniqueify modport numbers
struct DotStates {
DotPosition m_dotPos; // Scope part of dotted resolution
@@ -1087,12 +1331,21 @@ private:
}
inline void checkNoDot(AstNode* nodep) {
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
m_statep->preErrorDump();
UINFO(1,"ds="<<m_ds.ascii()<<endl);
//UINFO(9,"ds="<<m_ds.ascii()<<endl);
nodep->v3error("Syntax Error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type()<<" in dotted expression");
m_ds.m_dotErr = true;
}
}
AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep, AstModport* modportp) {
// Create iface variable, using duplicate var when under same module scope
string varName = ifacep->name()+"__Vmp__"+modportp->name()+"__Viftop"+cvtToStr(++m_modportNum);
AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, cellp->name(), ifacep->name(), modportp->name());
idtypep->cellp(cellp);
AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
varp->isIfaceParent(true);
m_modp->addStmtp(varp);
return varp;
}
// VISITs
virtual void visit(AstNetlist* nodep, AstNUser* vup) {
@@ -1108,6 +1361,7 @@ private:
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); // Until overridden by a SCOPE
m_cellp = NULL;
m_modp = nodep;
m_modportNum = 0;
nodep->iterateChildren(*this);
m_modp = NULL;
m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL;
@@ -1130,7 +1384,7 @@ private:
}
}
virtual void visit(AstCell* nodep, AstNUser*) {
// Cell: Resolve its filename. If necessary, parse it.
// Cell: Recurse inside or cleanup not founds
checkNoDot(nodep);
m_cellp = nodep;
AstNode::user5ClearTree();
@@ -1172,8 +1426,8 @@ private:
return;
}
nodep->v3error("Pin not found: "<<nodep->prettyName());
} else if (!refp->isIO() && !refp->isParam()) {
nodep->v3error("Pin is not an in/out/inout/param: "<<nodep->prettyName());
} else if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) {
nodep->v3error("Pin is not an in/out/inout/param/interface: "<<nodep->prettyName());
} else {
nodep->modVarp(refp);
if (refp->user5p() && refp->user5p()->castNode()!=nodep) {
@@ -1212,10 +1466,12 @@ private:
} else {
m_ds.m_dotPos = DP_SCOPE;
nodep->lhsp()->iterateAndNext(*this);
//if (debug()>=9) nodep->dumpTree("-dot-lho: ");
}
if (!m_ds.m_dotErr) { // Once something wrong, give up
if (start && m_ds.m_dotPos==DP_SCOPE) m_ds.m_dotPos = DP_FINAL; // Top 'final' dot RHS is final RHS, else it's a DOT(DOT(x,*here*),real-rhs) which we consider a RHS
nodep->rhsp()->iterateAndNext(*this);
//if (debug()>=9) nodep->dumpTree("-dot-rho: ");
}
if (start) {
AstNode* newp;
@@ -1299,7 +1555,8 @@ private:
} else {
foundp = m_ds.m_dotSymp->findIdFallback(nodep->name());
}
if (foundp) UINFO(9," found=se"<<(void*)foundp<<" n="<<foundp->nodep()<<endl);
if (foundp) UINFO(9," found=se"<<(void*)foundp<<" exp="<<expectWhat
<<" n="<<foundp->nodep()<<endl);
// What fell out?
bool ok = false;
if (foundp->nodep()->castCell() || foundp->nodep()->castBegin()
@@ -1312,9 +1569,41 @@ private:
m_ds.m_dotPos = DP_SCOPE;
// Upper AstDot visitor will handle it from here
}
else if (foundp->nodep()->castCell()
&& allowVar && m_cellp
&& foundp->nodep()->castCell()->modp()->castIface()) {
// Interfaces can be referenced like a variable for interconnect
AstCell* cellp = foundp->nodep()->castCell();
VSymEnt* cellEntp = m_statep->getNodeSym(cellp); if (!cellEntp) nodep->v3fatalSrc("No interface sym entry");
VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a module or generate begin
string findName = nodep->name()+"__Viftop";
AstVar* ifaceRefVarp = parentEntp->findIdFallback(findName)->nodep()->castVar();
if (!ifaceRefVarp) nodep->v3fatalSrc("Can't find interface var ref: "<<findName);
//
ok = true;
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = foundp;
m_ds.m_dotPos = DP_SCOPE;
UINFO(9," cell -> iface varref "<<foundp->nodep()<<endl);
AstNode* newp = new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false);
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
}
}
else if (AstVar* varp = foundp->nodep()->castVar()) {
if (allowVar) {
if (AstIfaceRefDType* ifacerefp = varp->subDTypep()->castIfaceRefDType()) {
if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
// Really this is a scope reference into an interface
UINFO(9,"varref-ifaceref "<<m_ds.m_dotText<<" "<<nodep<<endl);
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp());
m_ds.m_dotPos = DP_SCOPE;
ok = true;
AstNode* newp = new AstVarRef(nodep->fileline(), varp, false);
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
}
else if (allowVar) {
AstNodeVarRef* newp;
if (m_ds.m_dotText != "") {
newp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, false); // lvalue'ness computed later
@@ -1331,6 +1620,34 @@ private:
ok = true;
}
}
else if (AstModport* modportp = foundp->nodep()->castModport()) {
// A scope reference into an interface's modport (not necessarily at a pin connection)
UINFO(9,"cell-ref-to-modport "<<m_ds.m_dotText<<" "<<nodep<<endl);
UINFO(9,"dotSymp "<<m_ds.m_dotSymp<<" "<<m_ds.m_dotSymp->nodep()<<endl);
// Iface was the previously dotted component
if (!m_ds.m_dotSymp
|| !m_ds.m_dotSymp->nodep()->castCell()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()->castIface()) {
nodep->v3error("Modport not referenced as <interface>."<<modportp->prettyName());
} else if (!m_ds.m_dotSymp->nodep()->castCell()->modp()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()->castIface()) {
nodep->v3error("Modport not referenced from underneath an interface: "<<modportp->prettyName());
} else {
AstCell* cellp = m_ds.m_dotSymp->nodep()->castCell();
if (!cellp) nodep->v3fatalSrc("Modport not referenced from a cell");
AstIface* ifacep = cellp->modp()->castIface();
//string cellName = m_ds.m_dotText; // Use cellp->name
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = m_statep->getNodeSym(modportp);
m_ds.m_dotPos = DP_SCOPE;
ok = true;
AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp);
AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false);
nodep->replaceWith(refp); pushDeletep(nodep); nodep = NULL;
}
}
else if (AstEnumItem* valuep = foundp->nodep()->castEnumItem()) {
if (allowVar) {
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep());
@@ -1344,7 +1661,6 @@ private:
bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="");
bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
if (err) {
m_statep->preErrorDump();
if (foundp) {
nodep->v3error("Found definition of '"<<m_ds.m_dotText<<(m_ds.m_dotText==""?"":".")<<nodep->prettyName()
<<"'"<<" as a "<<foundp->nodep()->typeName()
@@ -1388,7 +1704,6 @@ private:
nodep->packagep(foundp->packagep()); // Generally set by parse, but might be an import
}
if (!nodep->varp()) {
m_statep->preErrorDump();
nodep->v3error("Can't find definition of signal, again: "<<nodep->prettyName());
}
}
@@ -1412,7 +1727,6 @@ private:
string inl = AstNode::dedotName(nodep->inlinedDots());
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
if (!dotSymp) {
m_statep->preErrorDump();
nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
}
}
@@ -1423,7 +1737,6 @@ private:
nodep->varp(varp);
UINFO(7," Resolved "<<nodep<<endl); // Also prints varp
if (!nodep->varp()) {
m_statep->preErrorDump();
nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
okSymp->cellErrorScopes(nodep);
}
@@ -1432,7 +1745,6 @@ private:
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
AstVarScope* vscp = foundp->nodep()->castVarScope(); // maybe NULL
if (!vscp) {
m_statep->preErrorDump();
nodep->v3error("Can't find varpin scope of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
okSymp->cellErrorScopes(nodep);
} else {
@@ -1499,7 +1811,6 @@ private:
UINFO(8,"\t\tInlined "<<inl<<endl);
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
if (!dotSymp) {
m_statep->preErrorDump();
okSymp->cellErrorScopes(nodep);
nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
}
@@ -1516,7 +1827,6 @@ private:
UINFO(7," Resolved "<<nodep<<endl); // Also prints taskp
} else {
// Note ParseRef has similar error handling/message output
m_statep->preErrorDump();
UINFO(7," ErrFtask curSymp=se"<<(void*)m_curSymp<<" dotSymp=se"<<(void*)dotSymp<<endl);
if (foundp) {
nodep->v3error("Found definition of '"<<m_ds.m_dotText<<(m_ds.m_dotText==""?"":".")<<nodep->prettyName()
@@ -1670,6 +1980,7 @@ public:
m_cellp = NULL;
m_modp = NULL;
m_ftaskp = NULL;
m_modportNum = 0;
//
rootp->accept(*this);
}
@@ -1691,12 +2002,18 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) {
LinkDotParamVisitor visitors(rootp,&state);
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree"));
}
else if (step == LDS_ARRAYED) {}
else if (step == LDS_SCOPED) {
// Well after the initial link when we're ready to operate on the flat design,
// process AstScope's. This needs to be separate pass after whole hierarchy graph created.
LinkDotScopeVisitor visitors(rootp,&state);
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
}
else v3fatalSrc("Bad case");
state.dump();
state.computeIfaceModSyms();
state.computeIfaceVarSyms();
state.computeScopeAliases();
state.dump();
LinkDotResolveVisitor visitorb(rootp,&state);
}
+16 -4
View File
@@ -67,7 +67,7 @@ void V3LinkLevel::modSortByLevel() {
}
vec.push_back(nodep);
}
sort(vec.begin(), vec.end(), CmpLevel()); // Sort the vector
stable_sort(vec.begin(), vec.end(), CmpLevel()); // Sort the vector
for (ModVec::iterator it = vec.begin(); it != vec.end(); ++it) {
AstNodeModule* nodep = *it;
nodep->unlinkFrBack();
@@ -95,6 +95,18 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) {
newmodp->modPublic(true);
netlistp->addModulep(newmodp);
// TODO the module creation above could be done after linkcells, but
// the rest must be done after data type resolution
wrapTopCell(netlistp);
wrapTopPackages(netlistp);
}
void V3LinkLevel::wrapTopCell(AstNetlist* netlistp) {
AstNodeModule* newmodp = netlistp->modulesp();
if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
AstNodeModule* oldmodp = newmodp->nextp()->castNodeModule();
if (!oldmodp) netlistp->v3fatalSrc("No module found to process");
// Add instance
AstCell* cellp = new AstCell(newmodp->fileline(),
(v3Global.opt.l2Name() ? "v" : oldmodp->name()),
@@ -126,13 +138,13 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) {
}
}
}
wrapTopPackages(netlistp, newmodp);
}
void V3LinkLevel::wrapTopPackages(AstNetlist* netlistp, AstNodeModule* newmodp) {
void V3LinkLevel::wrapTopPackages(AstNetlist* netlistp) {
// Instantiate all packages under the top wrapper
// This way all later SCOPE based optimizations can ignore packages
AstNodeModule* newmodp = netlistp->modulesp();
if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
for (AstNodeModule* modp = netlistp->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
if (modp->castPackage()) {
AstCell* cellp = new AstCell(modp->fileline(),
+2 -1
View File
@@ -29,7 +29,8 @@
class V3LinkLevel {
private:
static void wrapTopPackages(AstNetlist* nodep, AstNodeModule* newmodp);
static void wrapTopCell(AstNetlist* nodep);
static void wrapTopPackages(AstNetlist* nodep);
public:
static void modSortByLevel();
static void wrapTop(AstNetlist* nodep);
+6
View File
@@ -152,6 +152,12 @@ private:
nodep->valuep()->unlinkFrBack()));
}
}
if (nodep->isIfaceRef() && !nodep->isIfaceParent()) {
// Only AstIfaceRefDType's at this point correspond to ports;
// haven't made additional ones for interconnect yet, so assert is simple
// What breaks later is we don't have a Scope/Cell representing the interface to attach to
if (m_modp->level()<=2) nodep->v3error("Unsupported: Interfaced port on top level module");
}
}
virtual void visit(AstAttrOf* nodep, AstNUser*) {
+1 -1
View File
@@ -1307,7 +1307,7 @@ void V3Options::optimize(int level) {
m_oSubst = flag;
m_oSubstConst = flag;
m_oTable = flag;
m_oDedupe = level >= 3;
m_oDedupe = flag;
// And set specific optimization levels
if (level >= 3) {
m_inlineMult = -1; // Maximum inlining
+4 -4
View File
@@ -476,7 +476,7 @@ private:
// elements. Up to 10 of the widest
cerr<<V3Error::msgPrefix()
<<" Widest candidate vars to split:"<<endl;
sort (m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
std::stable_sort (m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
@@ -489,8 +489,8 @@ private:
// Up to 10 of the most fanned out
cerr<<V3Error::msgPrefix()
<<" Most fanned out candidate vars to split:"<<endl;
sort (m_unoptflatVars.begin(), m_unoptflatVars.end(),
OrderVarFanoutCmp());
std::stable_sort (m_unoptflatVars.begin(), m_unoptflatVars.end(),
OrderVarFanoutCmp());
lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
@@ -1324,7 +1324,7 @@ void OrderVisitor::processEdgeReport() {
}
*logp<<"Signals and their clock domains:"<<endl;
sort(report.begin(), report.end());
stable_sort(report.begin(), report.end());
for (deque<string>::iterator it=report.begin(); it!=report.end(); ++it) {
*logp<<(*it)<<endl;
}
+123 -18
View File
@@ -21,13 +21,31 @@
// Top down traversal:
// For each cell:
// If parameterized,
// Determine all parameter widths, constant values
// Determine all parameter widths, constant values.
// (Interfaces also matter, as if an interface is parameterized
// this effectively changes the width behavior of all that
// reference the iface.)
// Clone module cell calls, renaming with __{par1}_{par2}_...
// Substitute constants for cell's module's parameters
// Relink pins and cell to point to new module
// Then process all modules called by that cell
// Substitute constants for cell's module's parameters.
// Relink pins and cell and ifacerefdtype to point to new module.
//
// For interface Parent's we have the AstIfaceRefDType::cellp()
// pointing to this module. If that parent cell's interface
// module gets parameterized, AstIfaceRefDType::cloneRelink
// will update AstIfaceRefDType::cellp(), and AstLinkDot will
// see the new interface.
//
// However if a submodule's AstIfaceRefDType::ifacep() points
// to the old (unparameterized) interface and needs correction.
// To detect this we must walk all pins looking for interfaces
// that the parent has changed and propagate down.
//
// Then process all modules called by that cell.
// (Cells never referenced after parameters expanded must be ignored.)
//
// After we complete parameters, the varp's will be wrong (point to old module)
// and must be relinked.
//
//*************************************************************************
#include "config_build.h"
@@ -62,23 +80,34 @@ private:
AstUser5InUse m_inuser5;
// User1/2/3 used by constant function simulations
// TYPES
typedef deque<pair<AstIfaceRefDType*,AstIfaceRefDType*> > IfaceRefRefs; // Note may have duplicate entries
// STATE
typedef std::map<AstVar*,AstVar*> VarCloneMap;
typedef map<AstVar*,AstVar*> VarCloneMap;
struct ModInfo {
AstNodeModule* m_modp; // Module with specified name
VarCloneMap m_cloneMap; // Map of old-varp -> new cloned varp
ModInfo(AstNodeModule* modp) { m_modp=modp; }
};
typedef std::map<string,ModInfo> ModNameMap;
typedef map<string,ModInfo> ModNameMap;
ModNameMap m_modNameMap; // Hash of created module flavors by name
typedef std::map<string,string> LongMap;
typedef map<string,string> LongMap;
LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId;
typedef map<AstNode*,int> ValueMap;
typedef map<int,int> NextValueMap;
ValueMap m_valueMap; // Hash of node to param value
NextValueMap m_nextValueMap;// Hash of param value to next value to be used
typedef multimap<int,AstNodeModule*> LevelModMap;
LevelModMap m_todoModps; // Modules left to process
typedef deque<AstCell*> CellList;
CellList m_cellps; // Cells left to process (in this module)
// METHODS
static int debug() {
static int level = -1;
@@ -91,7 +120,7 @@ private:
// Pass 1, assign first letter to each gparam's name
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* varp = stmtp->castVar()) {
if (varp->isGParam()) {
if (varp->isGParam()||varp->isIfaceRef()) {
char ch = varp->name()[0];
ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z';
varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
@@ -113,6 +142,27 @@ private:
}
return st;
}
string paramValueNumber(AstNode* nodep) {
// Given a compilcated object create a number to use for param module assignment
// Ideally would be relatively stable if design changes (not use pointer value),
// and must return same value given same input node
// Return must presently be numberic so doesn't collide with 'small' alphanumeric parameter names
ValueMap::iterator it = m_valueMap.find(nodep);
if (it != m_valueMap.end()) {
return cvtToStr(it->second);
} else {
static int BUCKETS = 1000;
V3Hash hash (nodep->name());
int bucket = hash.hshval() % BUCKETS;
int offset = 0;
NextValueMap::iterator it = m_nextValueMap.find(bucket);
if (it != m_nextValueMap.end()) { offset = it->second; it->second = offset + 1; }
else { m_nextValueMap.insert(make_pair(bucket, offset + 1)); }
int num = bucket + offset * BUCKETS;
m_valueMap.insert(make_pair(nodep, num));
return cvtToStr(num);
}
}
void relinkPins(VarCloneMap* clonemapp, AstPin* startpinp) {
for (AstPin* pinp = startpinp; pinp; pinp=pinp->nextp()->castPin()) {
if (!pinp->modVarp()) pinp->v3fatalSrc("Not linked?\n");
@@ -123,9 +173,10 @@ private:
pinp->modVarp(cloneiter->second);
}
}
void visitCell(AstCell* nodep);
void visitModules() {
// Loop on all modules left to process
// Hitting a cell adds to the appropriate leval of this level-sorted list,
// Hitting a cell adds to the appropriate level of this level-sorted list,
// so since cells originally exist top->bottom we process in top->bottom order too.
while (!m_todoModps.empty()) {
LevelModMap::iterator it = m_todoModps.begin();
@@ -134,7 +185,19 @@ private:
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again
UINFO(4," MOD "<<nodep<<endl);
nodep->iterateChildren(*this);
// Note this may add to m_todoModps
// Note above iterate may add to m_todoModps
//
// Process interface cells, then non-interface which may ref an interface cell
for (int nonIf=0; nonIf<2; ++nonIf) {
for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
AstCell* nodep = *it;
if ((nonIf==0 && nodep->modp()->castIface())
|| (nonIf==1 && !nodep->modp()->castIface())) {
visitCell(nodep);
}
}
}
m_cellps.clear();
}
}
}
@@ -157,7 +220,10 @@ private:
UINFO(4," MOD-dead? "<<nodep<<endl); // Should have been done by now, if not dead
}
}
virtual void visit(AstCell* nodep, AstNUser*);
virtual void visit(AstCell* nodep, AstNUser*) {
// Must do ifaces first, so push to list and do in proper order
m_cellps.push_back(nodep);
}
// Make sure all parameters are constantified
virtual void visit(AstVar* nodep, AstNUser*) {
@@ -218,7 +284,7 @@ private:
//! Parameter subsitution for generated for loops.
//! @todo Unlike generated IF, we don't have to worry about short-circuiting the conditional
//! expression, since this is currently restricted to simple comparisons. If we ever do
//! move to more generic constant expressions, such code will be neede here.
//! move to more generic constant expressions, such code will be needed here.
virtual void visit(AstBegin* nodep, AstNUser*) {
if (nodep->genforp()) {
AstGenFor* forp = nodep->genforp()->castGenFor();
@@ -317,11 +383,13 @@ public:
//----------------------------------------------------------------------
// VISITs
void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
void ParamVisitor::visitCell(AstCell* nodep) {
// Cell: Check for parameters in the instantiation.
nodep->iterateChildren(*this);
if (!nodep->modp()) { nodep->dumpTree(cerr,"error:"); nodep->v3fatalSrc("Not linked?"); }
if (nodep->paramsp()) {
if (!nodep->modp()) nodep->v3fatalSrc("Not linked?");
if (nodep->paramsp()
|| 1 // Need to look for interfaces; could track when one exists, but should be harmless to always do this
) {
UINFO(4,"De-parameterize: "<<nodep<<endl);
// Create new module name with _'s between the constants
if (debug()>=10) nodep->dumpTree(cout,"-cell:\t");
@@ -336,7 +404,6 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
longname += "_";
if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout,"-cellparams:\t");
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
if (!pinp) nodep->v3fatalSrc("Non pin under cell params\n");
if (!pinp->exprp()) continue; // No-connect
AstVar* modvarp = pinp->modVarp();
if (!modvarp) {
@@ -360,6 +427,30 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
}
}
}
IfaceRefRefs ifaceRefRefs;
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
AstVar* modvarp = pinp->modVarp();
if (modvarp->isIfaceRef()) {
AstIfaceRefDType* portIrefp = modvarp->subDTypep()->castIfaceRefDType();
//UINFO(9," portIfaceRef "<<portIrefp<<endl);
if (!pinp->exprp()
|| !pinp->exprp()->castVarRef()
|| !pinp->exprp()->castVarRef()->varp()
|| !pinp->exprp()->castVarRef()->varp()->subDTypep()
|| !pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType()) {
pinp->v3error("Interface port '"<<modvarp->prettyName()<<"' is not connected to interface/modport pin expression");
} else {
AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType();
//UINFO(9," pinIfaceRef "<<pinIrefp<<endl);
if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
UINFO(9," IfaceRefDType needs reconnect "<<pinIrefp<<endl);
longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+paramValueNumber(pinIrefp);
any_overrides = true;
ifaceRefRefs.push_back(make_pair(portIrefp,pinIrefp));
}
}
}
}
if (!any_overrides) {
UINFO(8,"Cell parameters all match original values, skipping expansion.\n");
@@ -402,7 +493,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Note we allow multiple users of a parameterized model, thus we need to stash this info.
for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = stmtp->castVar()) {
if (varp->isIO() || varp->isGParam()) {
if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
// Cloning saved a pointer to the new node for us, so just follow that link.
AstVar* oldvarp = varp->clonep()->castVar();
//UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl);
@@ -414,7 +505,21 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Relink parameter vars to the new module
relinkPins(clonemapp, nodep->paramsp());
// Fix any interface references
for (IfaceRefRefs::iterator it=ifaceRefRefs.begin(); it!=ifaceRefRefs.end(); ++it) {
AstIfaceRefDType* portIrefp = it->first;
AstIfaceRefDType* pinIrefp = it->second;
AstIfaceRefDType* cloneIrefp = portIrefp->clonep()->castIfaceRefDType();
UINFO(8," IfaceOld "<<portIrefp<<endl);
UINFO(8," IfaceTo "<<pinIrefp<<endl);
if (!cloneIrefp) portIrefp->v3fatalSrc("parameter clone didn't hit AstIfaceRefDType");
UINFO(8," IfaceClo "<<cloneIrefp<<endl);
cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
UINFO(8," IfaceNew "<<cloneIrefp<<endl);
}
// Assign parameters to the constants specified
// DOES clone() so must be finished with module clonep() before here
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
AstVar* modvarp = pinp->modVarp();
if (modvarp && pinp->exprp()) {
@@ -440,7 +545,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
} // if any_overrides
// Delete the parameters from the cell; they're not relevant any longer.
nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
UINFO(8," Done with "<<nodep<<endl);
//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
}
+1
View File
@@ -66,6 +66,7 @@ struct V3ParseBisonYYSType {
AstCell* cellp;
AstConst* constp;
AstMemberDType* memberp;
AstModportVarRef* modportvarrefp;
AstNodeModule* modulep;
AstNodeClassDType* classp;
AstNodeDType* dtypep;
+1 -1
View File
@@ -128,7 +128,7 @@ public:
}
// Walk old sym table and reinsert into current table
// We let V3LinkDot report the error instead of us
symCurrentp()->import(&m_syms, symp, id_or_star);
symCurrentp()->importFromPackage(&m_syms, symp, id_or_star);
}
public:
// CREATORS
+22 -6
View File
@@ -150,6 +150,14 @@ private:
m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone*
}
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
// Copy under the scope but don't recurse
UINFO(4," Move "<<nodep<<endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone*
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
@@ -215,12 +223,17 @@ private:
virtual void visit(AstVarRef* nodep, AstNUser*) {
// VarRef needs to point to VarScope
// Make sure variable has made user1p.
nodep->varp()->accept(*this);
AstVarScope* varscp = nodep->packagep()
? (AstVarScope*)nodep->varp()->user3p()
: (AstVarScope*)nodep->varp()->user1p();
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
nodep->varScopep(varscp);
if (!nodep->varp()) nodep->v3fatalSrc("Unlinked");
if (nodep->varp()->isIfaceRef()) {
nodep->varScopep(NULL);
} else {
nodep->varp()->accept(*this);
AstVarScope* varscp = nodep->packagep()
? (AstVarScope*)nodep->varp()->user3p()
: (AstVarScope*)nodep->varp()->user1p();
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
nodep->varScopep(varscp);
}
}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
@@ -298,6 +311,9 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
+17 -5
View File
@@ -137,11 +137,11 @@ public:
VSymEnt* findIdFlat(const string& name) const {
// Find identifier without looking upward through symbol hierarchy
// First, scan this begin/end block or module for the name
IdNameMap::const_iterator iter = m_idNameMap.find(name);
IdNameMap::const_iterator it = m_idNameMap.find(name);
UINFO(9, " SymFind se"<<(void*)this<<" '"<<name
<<"' -> "<<(iter == m_idNameMap.end() ? "NONE"
: "se"+cvtToStr((void*)(iter->second))+" n="+cvtToStr((void*)(iter->second->nodep())))<<endl);
if (iter != m_idNameMap.end()) return (iter->second);
<<"' -> "<<(it == m_idNameMap.end() ? "NONE"
: "se"+cvtToStr((void*)(it->second))+" n="+cvtToStr((void*)(it->second->nodep())))<<endl);
if (it != m_idNameMap.end()) return (it->second);
return NULL;
}
VSymEnt* findIdFallback(const string& name) const {
@@ -166,7 +166,7 @@ private:
}
}
public:
bool import(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) {
bool importFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) {
// Import tokens from source symbol table into this symbol table
// Returns true if successful
bool any = false;
@@ -183,6 +183,18 @@ public:
}
return any;
}
void importFromIface(VSymGraph* graphp, const VSymEnt* srcp) {
// Import interface tokens from source symbol table into this symbol table, recursively
UINFO(9, " importIf se"<<(void*)this<<" from se"<<(void*)srcp<<endl);
for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
const string& name = it->first;
VSymEnt* srcp = it->second;
VSymEnt* symp = new VSymEnt(graphp, srcp);
reinsert(name, symp);
// And recurse to create children
srcp->importFromIface(graphp, symp);
}
}
void cellErrorScopes(AstNode* lookp, string prettyName="") {
if (prettyName=="") prettyName = lookp->prettyName();
string scopes;
+8
View File
@@ -1073,6 +1073,14 @@ private:
nodep->dtypeFrom(nodep->lhsp());
}
virtual void visit(AstIfaceRefDType* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5," IFACEREF "<<nodep<<endl);
nodep->iterateChildren(*this, vup);
nodep->dtypep(nodep);
nodep->widthForce(1, 1); // Not really relevant
UINFO(4,"dtWidthed "<<nodep<<endl);
}
virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5," NODECLASS "<<nodep<<endl);
+4 -2
View File
@@ -307,13 +307,15 @@ private:
newp->dtypeFrom(adtypep);
} else {
// Need a slice data type, which is an array of the extracted type, but with (presumably) different size
VNumRange newRange (msb, lsb, fromRange.littleEndian());
AstNodeDType* vardtypep = new AstPackArrayDType(nodep->fileline(),
adtypep->subDTypep(), // Need to strip off array reference
new AstRange(nodep->fileline(), fromRange));
new AstRange(nodep->fileline(), newRange));
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
newp->dtypeFrom(vardtypep);
}
if (debug()>=9) newp->dumpTree(cout,"--EXTBTn: ");
//if (debug()>=9) newp->dumpTree(cout,"--EXTBTn: ");
if (newp->widthMin()!=(int)newp->widthConst()) nodep->v3fatalSrc("Width mismatch");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else if (ddtypep->castBasicDType()) {
+2 -3
View File
@@ -228,8 +228,7 @@ void process () {
if (!v3Global.opt.xmlOnly()) {
// Add top level wrapper with instance pointing to old top
// Move packages to under new top
// Must do this after we know the width of any parameters
// We also do it after coverage/assertion insertion so we don't 'cover' the top level.
// Must do this after we know parameters and dtypes (as don't clone dtype decls)
V3LinkLevel::wrapTop(v3Global.rootp());
}
@@ -677,7 +676,7 @@ int main(int argc, char** argv, char** env) {
}
// Final steps
V3Global::dumpGlobalTree("final.tree",99);
V3Global::dumpGlobalTree("final.tree",990);
V3Error::abortIfWarnings();
if (!v3Global.opt.lintOnly() && !v3Global.opt.cdc()
+3 -3
View File
@@ -417,6 +417,7 @@ word [a-zA-Z0-9_]+
"do" { FL; return yDO; }
"endclocking" { FL; return yENDCLOCKING; }
"endpackage" { FL; return yENDPACKAGE; }
"endinterface" { FL; return yENDINTERFACE; }
"endprogram" { FL; return yENDPROGRAM; }
"endproperty" { FL; return yENDPROPERTY; }
"enum" { FL; return yENUM; }
@@ -425,9 +426,11 @@ word [a-zA-Z0-9_]+
"iff" { FL; return yIFF; }
"import" { FL; return yIMPORT; }
"inside" { FL; return yINSIDE; }
"interface" { FL; return yINTERFACE; }
"int" { FL; return yINT; }
"logic" { FL; return yLOGIC; }
"longint" { FL; return yLONGINT; }
"modport" { FL; return yMODPORT; }
"package" { FL; return yPACKAGE; }
"packed" { FL; return yPACKED; }
"priority" { FL; return yPRIORITY; }
@@ -460,7 +463,6 @@ word [a-zA-Z0-9_]+
"dist" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endclass" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endinterface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@@ -470,13 +472,11 @@ word [a-zA-Z0-9_]+
"forkjoin" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"join_none" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"local" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"matches" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"protected" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
+111 -10
View File
@@ -310,6 +310,7 @@ class AstSenTree;
%token<fl> yENDCLOCKING "endclocking"
%token<fl> yENDFUNCTION "endfunction"
%token<fl> yENDGENERATE "endgenerate"
%token<fl> yENDINTERFACE "endinterface"
%token<fl> yENDMODULE "endmodule"
%token<fl> yENDPACKAGE "endpackage"
%token<fl> yENDPRIMITIVE "endprimitive"
@@ -337,9 +338,11 @@ class AstSenTree;
%token<fl> yINSIDE "inside"
%token<fl> yINT "int"
%token<fl> yINTEGER "integer"
%token<fl> yINTERFACE "interface"
%token<fl> yLOCALPARAM "localparam"
%token<fl> yLOGIC "logic"
%token<fl> yLONGINT "longint"
%token<fl> yMODPORT "modport"
%token<fl> yMODULE "module"
%token<fl> yNAND "nand"
%token<fl> yNEGEDGE "negedge"
@@ -650,7 +653,7 @@ descriptionList: // IEEE: part of source_text
description: // ==IEEE: description
module_declaration { }
// // udp_declaration moved into module_declaration
//UNSUP interface_declaration { }
| interface_declaration { }
| program_declaration { }
| package_declaration { }
| package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
@@ -844,14 +847,24 @@ port<nodep>: // ==IEEE: port
// // IEEE: interface_port_header port_identifier { unpacked_dimension }
// // Expanded interface_port_header
// // We use instantCb here because the non-port form looks just like a module instantiation
//UNSUP portDirNetE id/*interface*/ idAny/*port*/ rangeListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>3, $3, $4); PARSEP->instantCb($<fl>2, $2, $3, $4); PINNUMINC(); }
//UNSUP portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>3, $3, $4); PINNUMINC(); }
//UNSUP portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>5, $5, $6); PARSEP->instantCb($<fl>2, $2, $5, $6); PINNUMINC(); }
//UNSUP portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>5, $5, $6); PINNUMINC(); }
portDirNetE id/*interface*/ idAny/*port*/ variable_dimensionListE sigAttrListE
{ $$ = new AstPort($<fl>2,PINNUMINC(),*$3);
AstVar* varp=new AstVar($<fl>2,AstVarType(AstVarType::IFACEREF),*$3,VFlagChildDType(),
new AstIfaceRefDType($<fl>2,"",*$2));
if ($4) varp->v3error("Unsupported: Arrayed interfaces");
varp->addAttrsp($5);
$$->addNext(varp); }
| portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE
{ $<fl>2->v3error("Unsupported: virtual interfaces"); }
| portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
{ $$ = new AstPort($3,PINNUMINC(),*$5);
AstVar* varp=new AstVar($<fl>2,AstVarType(AstVarType::IFACEREF),*$5,VFlagChildDType(),
new AstIfaceRefDType($<fl>2,"",*$2,*$4));
if ($6) varp->v3error("Unsupported: Arrayed interfaces");
varp->addAttrsp($7);
$$->addNext(varp); }
| portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
{ $<fl>2->v3error("Unsupported: virtual interfaces"); }
//
// // IEEE: ansi_port_declaration, with [port_direction] removed
// // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ]
@@ -889,7 +902,7 @@ port<nodep>: // ==IEEE: port
//UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE
//UNSUP { UNSUP }
//
portDirNetE data_type portSig variable_dimensionListE sigAttrListE
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE
{ $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); }
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
@@ -932,6 +945,54 @@ portSig<nodep>:
//**********************************************************************
// Interface headers
interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header:
// // timeunits_delcarationE is instead in interface_item
intFront parameter_port_listE portsStarE ';'
interface_itemListE yENDINTERFACE endLabelE
{ if ($2) $1->addStmtp($2);
if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
SYMP->popScope($1); }
//UNSUP yEXTERN intFront parameter_port_listE portsStarE ';' { }
;
intFront<modulep>:
yINTERFACE lifetimeE idAny/*new_interface*/
{ $$ = new AstIface($1,*$3);
$$->inLibrary(true);
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
interface_itemListE<nodep>:
/* empty */ { $$ = NULL; }
| interface_itemList { $$ = $1; }
;
interface_itemList<nodep>:
interface_item { $$ = $1; }
| interface_itemList interface_item { $$ = $1->addNextNull($2); }
;
interface_item<nodep>: // IEEE: interface_item + non_port_interface_item
port_declaration ';' { $$ = $1; }
// // IEEE: non_port_interface_item
//UNSUP generate_region { $$ = $1; }
| interface_or_generate_item { $$ = $1; }
//UNSUP program_declaration { $$ = $1; }
//UNSUP interface_declaration { $$ = $1; }
| timeunits_declaration { $$ = $1; }
// // See note in interface_or_generate item
| module_common_item { $$ = $1; }
;
interface_or_generate_item<nodep>: // ==IEEE: interface_or_generate_item
// // module_common_item in interface_item, as otherwise duplicated
// // with module_or_generate_item's module_common_item
modport_declaration { $$ = $1; }
//UNSUP extern_tf_declaration { $$ = $1; }
;
//**********************************************************************
// Program headers
@@ -989,6 +1050,46 @@ program_generate_item<nodep>: // ==IEEE: program_generate_item
//UNSUP elaboration_system_task { $$ = $1; }
;
modport_declaration<nodep>: // ==IEEE: modport_declaration
yMODPORT modport_itemList ';' { $$ = $2; }
;
modport_itemList<nodep>: // IEEE: part of modport_declaration
modport_item { $$ = $1; }
| modport_itemList ',' modport_item { $$ = $1->addNextNull($3); }
;
modport_item<nodep>: // ==IEEE: modport_item
id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
;
modportPortsDeclList<modportvarrefp>:
modportPortsDecl { $$ = $1; }
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3)->castModportVarRef(); }
;
// IEEE: modport_ports_declaration + modport_simple_ports_declaration
// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration
// We've expanded the lists each take to instead just have standalone ID ports.
// We track the type as with the V2k series of defines, then create as each ID is seen.
modportPortsDecl<modportvarrefp>:
// // IEEE: modport_simple_ports_declaration
port_direction modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$2,GRAMMARP->m_varIO); }
// // IEEE: modport_clocking_declaration
//UNSUP yCLOCKING idAny/*clocking_identifier*/ { }
//UNSUP yIMPORT modport_tf_port { }
//UNSUP yEXPORT modport_tf_port { }
// Continuations of above after a comma.
// // IEEE: modport_simple_ports_declaration
| modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$1,AstVarType::INOUT); }
;
modportSimplePort<strp>: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier
id { $$ = $1; }
//UNSUP '.' idAny '(' ')' { }
//UNSUP '.' idAny '(' expr ')' { }
;
//************************************************
// Variable Declarations
+52 -23
View File
@@ -861,30 +861,50 @@ sub _run {
print " > $param{logfile}" if $param{logfile};
print "\n";
if ($param{logfile}) {
open(SAVEOUT, ">&STDOUT") or die "%Error: Can't dup stdout";
open(SAVEERR, ">&STDERR") or die "%Error: Can't dup stderr";
if (0) {close(SAVEOUT); close(SAVEERR);} # Prevent unused warning
if ($param{tee}) {
open(STDOUT, "|tee $param{logfile}") or die "%Error: Can't redirect stdout";
} else {
open(STDOUT, ">$param{logfile}") or die "%Error: Can't open $param{logfile}";
# Execute command redirecting output, keeping order between stderr and stdout.
# Must do low-level IO so GCC interaction works (can't be line-based)
my $status;
{
pipe(PARENTRD, CHILDWR) or die "%Error: Can't Pipe, stopped";
autoflush PARENTRD 1;
autoflush CHILDWR 1;
my $logfh;
if ($param{logfile}) {
$logfh = IO::File->new(">$param{logfile}") or die "%Error: Can't open $param{logfile}";
}
open(STDERR, ">&STDOUT") or die "%Error: Can't dup stdout";
autoflush STDOUT 1;
autoflush STDERR 1;
my $pid=fork();
if ($pid) { # Parent
close CHILDWR;
while (1) {
my $buf = '';
my $got = sysread PARENTRD,$buf,10000;
last if defined $got && $got==0;
print $buf if $param{tee};
print $logfh $buf if $logfh;
}
close PARENTRD;
close $logfh if $logfh;
}
else { # Child
close PARENTRD;
close $logfh if $logfh;
# Reset signals
$SIG{ALRM} = 'DEFAULT';
$SIG{CHLD} = 'DEFAULT';
# Logging
open(STDOUT, ">&CHILDWR") or croak "%Error: Can't redirect stdout, stopped";
open(STDERR, ">&STDOUT") or croak "%Error: Can't dup stdout, stopped";
autoflush STDOUT 1;
autoflush STDERR 1;
system "$command";
exit ($? ? 10 : 0); # $?<<8 misses coredumps
}
waitpid($pid,0);
$status = $? || 0;
}
system "$command";
my $status = $?;
flush STDOUT;
flush STDERR;
if ($param{logfile}) {
open (STDOUT, ">&SAVEOUT");
open (STDERR, ">&SAVEERR");
}
if (!$param{fails} && $status) {
$self->error("Exec of $param{cmd}[0] failed\n");
}
@@ -1277,14 +1297,23 @@ sub _read_inputs_v {
my $filename = $self->top_filename;
$filename = "$self->{t_dir}/$filename" if !-r $filename;
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
my $get_sigs=1;
my %inputs;
while (defined(my $line = $fh->getline)) {
if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) {
$self->{inputs}{$1} = $1;
if ($get_sigs) {
if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) {
$inputs{$1} = $1;
}
if ($line =~ /^\s*(function|task|endmodule)/) {
$get_sigs = 0;
}
}
if ($line =~ /^\s*(function|task|endmodule)/) {
last;
if ($line =~ /^\s*module\s+t\b/) { # Ignore any earlier inputs; Module 't' has precedence
%inputs = ();
$get_sigs = 1;
}
}
$self->{inputs}{$_} = $inputs{$_} foreach keys %inputs;
$fh->close();
}
+5 -4
View File
@@ -38,10 +38,11 @@ if (!-r "$root/.git") {
# Check empty
my @files;
$finds = `find $destdir -type f -print`;
foreach my $f (split /\n/, $finds) {
print "\tLEFT: $f\n";
$f =~ s!^$cwd!.!;
push @files, $f;
foreach my $file (split /\n/, $finds) {
next if $file =~ /\.status/; # Made by driver.pl, not Verilator
print "\tLEFT: $file\n";
$file =~ s!^$cwd!.!;
push @files, $file;
}
if ($#files >= 0) {
$Self->error("Uninstall missed files: ",join(' ',@files));
-2
View File
@@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile (
);
+3 -3
View File
@@ -100,7 +100,7 @@ interface handshake #(
// local logic (counter)
always @ (posedge clk, posedge rst)
if (rst) cnt <= '0;
else cnt <= cnt + inc;
else cnt <= cnt + {31'h0, inc};
endinterface : handshake
@@ -129,7 +129,7 @@ module source #(
// counter
always @ (posedge clk, posedge rst)
if (rst) cnt <= 32'd0;
else cnt <= cnt + (inf.req & inf.grt);
else cnt <= cnt + {31'd0, (inf.req & inf.grt)};
// request signal
assign inf.req = rnd[0];
@@ -161,7 +161,7 @@ module drain #(
// counter
always @ (posedge clk, posedge rst)
if (rst) cnt <= 32'd0;
else cnt <= cnt + (inf.req & inf.grt);
else cnt <= cnt + {31'd0, (inf.req & inf.grt)};
// grant signal
assign inf.grt = rnd[0];
@@ -7,10 +7,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile (
verilator_flags2 => ["--lint-only"]
);
execute (
check_finished=>1,
);
ok(1);
+45
View File
@@ -0,0 +1,45 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
interface ifc;
logic [3:0] value;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop();
sub c1 (.isub(itop),
.i_value(4'h4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (c1.i_value != 4) $stop; // 'Normal' crossref just for comparison
if (itop.value != 4) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
(
ifc isub,
input logic [3:0] i_value
);
always @* begin
isub.value = i_value;
end
endmodule : sub
+18
View 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-2009 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;
+48
View File
@@ -0,0 +1,48 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
interface ifc;
integer hidden_from_isub;
integer value;
modport out_modport (output value);
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop();
sub c1 (.isub(itop),
.i_value(4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop.value != 4) $stop;
itop.hidden_from_isub = 20;
if (itop.hidden_from_isub != 20) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
(
ifc.out_modport isub,
input integer i_value
);
always @* begin
isub.value = i_value;
end
endmodule
+1 -3
View File
@@ -7,10 +7,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile (
v_flags => []
verilator_flags2 => ["--top-module t"],
);
execute (
+53 -26
View File
@@ -3,11 +3,6 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
interface counter_io;
logic [3:0] value;
logic reset;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
@@ -18,17 +13,24 @@ module t (/*AUTOARG*/
counter_io c1_data();
counter_io c2_data();
//counter_io c3_data; // IEEE illegal, and VCS doesn't allow non-() as it does with cells
counter_io c3_data();
counter c1 (.clkm(clk),
.c_data(c1_data),
.i_value(4'h1));
counter2 c2 (.clkm(clk),
.c_data(c2_data),
.i_value(4'h2));
counter_ansi c1 (.clkm(clk),
.c_data(c1_data),
.i_value(4'h1));
counter_ansi c2 (.clkm(clk),
.c_data(c2_data),
.i_value(4'h2));
`ifdef VERILATOR counter_ansi `else counter_nansi `endif
/**/ c3 (.clkm(clk),
.c_data(c3_data),
.i_value(4'h3));
initial begin
c1_data.value = 4'h4;
c2_data.value = 4'h5;
c3_data.value = 4'h6;
end
always @ (posedge clk) begin
@@ -36,46 +38,71 @@ module t (/*AUTOARG*/
if (cyc<2) begin
c1_data.reset <= 1;
c2_data.reset <= 1;
c3_data.reset <= 1;
end
if (cyc==2) begin
c1_data.reset <= 0;
c2_data.reset <= 0;
c3_data.reset <= 0;
end
if (cyc==3) begin
if (c1_data.get_lcl() != 12345) $stop;
end
if (cyc==20) begin
$write("[%0t] c1 cyc%0d: %0x %0x\n", $time, cyc, c1_data.value, c1_data.reset);
$write("[%0t] c2 cyc%0d: %0x %0x\n", $time, cyc, c2_data.value, c2_data.reset);
$write("[%0t] c1 cyc%0d: c1 %0x %0x c2 %0x %0x c3 %0x %0x\n", $time, cyc,
c1_data.value, c1_data.reset,
c2_data.value, c2_data.reset,
c3_data.value, c3_data.reset);
if (c1_data.value != 2) $stop;
if (c2_data.value != 3) $stop;
if (c3_data.value != 4) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module counter
interface counter_io;
logic [3:0] value;
logic reset;
integer lcl;
task set_lcl (input integer a); lcl=a; endtask
function integer get_lcl (); return lcl; endfunction
endinterface
interface ifunused;
logic unused;
endinterface
module counter_ansi
(
input clkm,
counter_io c_data,
input logic [3:0] i_value
);
always @ (posedge clkm) begin
if (c_data.reset)
c_data.value <= i_value;
else
c_data.value <= c_data.value + 1;
initial begin
c_data.set_lcl(12345);
end
endmodule : counter
module counter2(clkm, c_data, i_value);
always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_ansi
`ifndef VERILATOR
// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
module counter_nansi(clkm, c_data, i_value);
input clkm;
counter_io c_data;
input logic [3:0] i_value;
always @ (posedge clkm) begin
if (c_data.reset)
c_data.value <= i_value;
else
c_data.value <= c_data.value + 1;
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter2
endmodule : counter_nansi
`endif
module modunused (ifunused ifinunused);
ifunused ifunused();
endmodule
+18
View 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-2009 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;
+72
View File
@@ -0,0 +1,72 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
interface ifc;
integer value;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
`ifdef INLINE_A //verilator inline_module
`else //verilator no_inline_module
`endif
input clk;
integer cyc=1;
ifc itop1a();
ifc itop1b();
ifc itop2a();
ifc itop2b();
wrapper c1 (.isuba(itop1a),
.isubb(itop1b),
.i_valuea(14),
.i_valueb(15));
wrapper c2 (.isuba(itop2a),
.isubb(itop2b),
.i_valuea(24),
.i_valueb(25));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop1a.value != 14) $stop;
if (itop1b.value != 15) $stop;
if (itop2a.value != 24) $stop;
if (itop2b.value != 25) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module wrapper
(
ifc isuba,
ifc isubb,
input integer i_valuea,
input integer i_valueb
);
`ifdef INLINE_B //verilator inline_module
`else //verilator no_inline_module
`endif
lower subsuba (.isub(isuba), .i_value(i_valuea));
lower subsubb (.isub(isubb), .i_value(i_valueb));
endmodule
module lower
(
ifc isub,
input integer i_value
);
`ifdef INLINE_C //verilator inline_module
`else //verilator no_inline_module
`endif
always @* begin
isub.value = i_value;
end
endmodule
+21
View 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-2009 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.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, interface generates changing types");
$Self->{vcs} and $Self->unsupported("Commercially unsupported, interface crossrefs");
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+78
View File
@@ -0,0 +1,78 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// This test demonstrates how not only parameters but the type of a parent
// interface could propagate down to child modules, changing their data type
// determinations. Note presently unsupported in all commercial simulators.
interface ifc;
parameter MODE = 0;
generate
// Note block must be named per SystemVerilog 2005
if (MODE==1) begin : g
integer value;
end
else if (MODE==2) begin : g
real value;
end
endgenerate
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(1) itop1a();
ifc #(1) itop1b();
ifc #(2) itop2a();
ifc #(2) itop2b();
wrapper c1 (.isuba(itop1a),
.isubb(itop1b),
.i_valuea(14.1),
.i_valueb(15.2));
wrapper c2 (.isuba(itop2a),
.isubb(itop2b),
.i_valuea(24.3),
.i_valueb(25.4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop1a.g.value != 14) $stop;
if (itop1b.g.value != 15) $stop;
if (itop2a.g.value != 24) $stop;
if (itop2b.g.value != 25) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module wrapper
(
ifc isuba,
ifc isubb,
input real i_valuea,
input real i_valueb
);
lower subsuba (.isub(isuba), .i_value(i_valuea));
lower subsubb (.isub(isubb), .i_value(i_valueb));
endmodule
module lower
(
ifc isub,
input real i_value
);
always @* begin
`error Commercial sims choke on cross ref here
isub.g.value = i_value;
end
endmodule
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_A'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_B'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_B'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_B +define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_B +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_C +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+18
View 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-2009 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;
+87
View File
@@ -0,0 +1,87 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
`ifdef VCS
`define UNSUPPORTED_MOD_IN_GENS
`endif
`ifdef VERILATOR
`define UNSUPPORTED_MOD_IN_GENS
`endif
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(1) itopa();
ifc #(2) itopb();
sub #(1) ca (.isub(itopa),
.i_value(4));
sub #(2) cb (.isub(itopb),
.i_value(5));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==1) begin
if (itopa.MODE != 1) $stop;
if (itopb.MODE != 2) $stop;
end
if (cyc==20) begin
if (itopa.get_value() != 4) $stop;
if (itopb.get_value() != 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
#(parameter MODE = 0)
(
ifc.out_modport isub,
input integer i_value
);
`ifdef UNSUPPORTED_MOD_IN_GENS
always @* isub.value = i_value;
`else
generate if (MODE == 1) begin
always @* isub.valuea = i_value;
end
else if (MODE == 2) begin
always @* isub.valueb = i_value;
end
endgenerate
`endif
endmodule
interface ifc;
parameter MODE = 0;
// Modports under generates not supported by all commercial simulators
`ifdef UNSUPPORTED_MOD_IN_GENS
integer value;
modport out_modport (output value);
function integer get_value(); return value; endfunction
`else
generate if (MODE == 0) begin
integer valuea;
modport out_modport (output valuea);
function integer get_valuea(); return valuea; endfunction
end
else begin
integer valueb;
modport out_modport (output valueb);
function integer get_valueb(); return valueb; endfunction
end
endgenerate
`endif
endinterface
+18
View 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-2009 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;
+70
View File
@@ -0,0 +1,70 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(2) itopa();
ifc #(4) itopb();
sub ca (.isub(itopa),
.clk);
sub cb (.isub(itopb),
.clk);
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d result=%b %b\n",$time, cyc, itopa.valueo, itopb.valueo);
`endif
cyc <= cyc + 1;
itopa.valuei <= cyc[1:0];
itopb.valuei <= cyc[3:0];
if (cyc==1) begin
if (itopa.WIDTH != 2) $stop;
if (itopb.WIDTH != 4) $stop;
if ($bits(itopa.valueo) != 2) $stop;
if ($bits(itopb.valueo) != 4) $stop;
if ($bits(itopa.out_modport.valueo) != 2) $stop;
if ($bits(itopb.out_modport.valueo) != 4) $stop;
end
if (cyc==4) begin
if (itopa.valueo != 2'b11) $stop;
if (itopb.valueo != 4'b0011) $stop;
end
if (cyc==5) begin
if (itopa.valueo != 2'b00) $stop;
if (itopb.valueo != 4'b0100) $stop;
end
if (cyc==20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
interface ifc
#(parameter WIDTH = 1);
// verilator lint_off MULTIDRIVEN
logic [WIDTH-1:0] valuei;
logic [WIDTH-1:0] valueo;
// verilator lint_on MULTIDRIVEN
modport out_modport (input valuei, output valueo);
endinterface
// Note not parameterized
module sub
(
ifc.out_modport isub,
input clk
);
always @(posedge clk) isub.valueo <= isub.valuei + 1;
endmodule
+18
View 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-2009 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;
+70
View File
@@ -0,0 +1,70 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(2) itopa();
ifc #(4) itopb();
sub ca (.isub(itopa.out_modport),
.clk);
sub cb (.isub(itopb.out_modport),
.clk);
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d result=%b %b\n",$time, cyc, itopa.valueo, itopb.valueo);
`endif
cyc <= cyc + 1;
itopa.valuei <= cyc[1:0];
itopb.valuei <= cyc[3:0];
if (cyc==1) begin
if (itopa.WIDTH != 2) $stop;
if (itopb.WIDTH != 4) $stop;
if ($bits(itopa.valueo) != 2) $stop;
if ($bits(itopb.valueo) != 4) $stop;
if ($bits(itopa.out_modport.valueo) != 2) $stop;
if ($bits(itopb.out_modport.valueo) != 4) $stop;
end
if (cyc==4) begin
if (itopa.valueo != 2'b11) $stop;
if (itopb.valueo != 4'b0011) $stop;
end
if (cyc==5) begin
if (itopa.valueo != 2'b00) $stop;
if (itopb.valueo != 4'b0100) $stop;
end
if (cyc==20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
interface ifc
#(parameter WIDTH = 1);
// verilator lint_off MULTIDRIVEN
logic [WIDTH-1:0] valuei;
logic [WIDTH-1:0] valueo;
// verilator lint_on MULTIDRIVEN
modport out_modport (input valuei, output valueo);
endinterface
// Note not parameterized
module sub
(
ifc.out_modport isub,
input clk
);
always @(posedge clk) isub.valueo <= isub.valuei + 1;
endmodule
+1 -3
View File
@@ -7,13 +7,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
top_filename("t/t_interface.v");
compile (
# Avoid inlining so we find bugs in the non-inliner connection code
v_flags => ["-Oi"],
verilator_flags2 => ["-Oi"],
);
execute (
+22
View File
@@ -0,0 +1,22 @@
#!/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 (
verilator_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
fails => 1,
expect=>
'%Error: t/t_interface_mismodport_bad.v:\d+: Can\'t find definition of \'bad\' in dotted signal: isub.bad
.*%Error: Exiting due to.*',
);
ok(1);
1;
@@ -0,0 +1,37 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
interface ifc;
integer ok;
integer bad;
modport out_modport (output ok);
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop();
counter_ansi c1 (.isub(itop),
.i_value(4'h4));
endmodule
module counter_ansi
(
ifc.out_modport isub,
input logic [3:0] i_value
);
always @* begin
isub.ok = i_value;
isub.bad = i_value; // Illegal access
end
endmodule
-3
View File
@@ -7,10 +7,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile (
v_flags => [],
);
execute (
+81 -20
View File
@@ -3,13 +3,26 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
interface counter_io;
interface counter_if;
logic [3:0] value;
logic reset;
modport counter_side (input reset, output value);
modport core_side (output reset, input value);
modport counter_mp (input reset, output value);
modport core_mp (output reset, input value);
endinterface
// Check can have inst module before top module
module counter_ansi
(
input clkm,
counter_if c_data,
input logic [3:0] i_value
);
always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_ansi
module t (/*AUTOARG*/
// Inputs
clk
@@ -18,19 +31,31 @@ module t (/*AUTOARG*/
input clk;
integer cyc=1;
counter_io c1_data();
counter_io c2_data();
counter_if c1_data();
counter_if c2_data();
counter_if c3_data();
counter_if c4_data();
counter c1 (.clkm(clk),
.c_data(c1_data),
.i_value(4'h1));
counter c2 (.clkm(clk),
.c_data(c2_data.counter_side),
.i_value(4'h2));
counter_ansi c1 (.clkm(clk),
.c_data(c1_data.counter_mp),
.i_value(4'h1));
`ifdef VERILATOR counter_ansi `else counter_nansi `endif
/**/ c2 (.clkm(clk),
.c_data(c2_data.counter_mp),
.i_value(4'h2));
counter_ansi_m c3 (.clkm(clk),
.c_data(c3_data),
.i_value(4'h3));
`ifdef VERILATOR counter_ansi_m `else counter_nansi_m `endif
/**/ c4 (.clkm(clk),
.c_data(c4_data),
.i_value(4'h4));
initial begin
c1_data.value = 4'h4;
c2_data.value = 4'h5;
c3_data.value = 4'h6;
c4_data.value = 4'h7;
end
always @ (posedge clk) begin
@@ -38,33 +63,69 @@ module t (/*AUTOARG*/
if (cyc<2) begin
c1_data.reset <= 1;
c2_data.reset <= 1;
c3_data.reset <= 1;
c4_data.reset <= 1;
end
if (cyc==2) begin
c1_data.reset <= 0;
c2_data.reset <= 0;
c3_data.reset <= 0;
c4_data.reset <= 0;
end
if (cyc==20) begin
$write("[%0t] c1 cyc%0d: %0x %0x\n", $time, cyc, c1_data.value, c1_data.reset);
$write("[%0t] c2 cyc%0d: %0x %0x\n", $time, cyc, c2_data.value, c2_data.reset);
$write("[%0t] cyc%0d: c1 %0x %0x c2 %0x %0x c3 %0x %0x c4 %0x %0x\n", $time, cyc,
c1_data.value, c1_data.reset,
c2_data.value, c2_data.reset,
c3_data.value, c3_data.reset,
c4_data.value, c4_data.reset);
if (c1_data.value != 2) $stop;
if (c2_data.value != 3) $stop;
if (c3_data.value != 4) $stop;
if (c4_data.value != 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module counter
`ifndef VERILATOR
// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
module counter_nansi
(clkm, c_data, i_value);
input clkm;
counter_if c_data;
input logic [3:0] i_value;
always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_nansi
`endif
module counter_ansi_m
(
input clkm,
counter_io c_data,
counter_if.counter_mp c_data,
input logic [3:0] i_value
);
always @ (posedge clkm) begin
if (c_data.reset)
c_data.value <= i_value;
else
c_data.value <= c_data.value + 1;
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter
endmodule : counter_ansi_m
`ifndef VERILATOR
// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
module counter_nansi_m
(clkm, c_data, i_value);
input clkm;
counter_if.counter_mp c_data;
input logic [3:0] i_value;
always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_nansi_m
`endif
+1 -3
View File
@@ -7,13 +7,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
top_filename("t/t_interface_modport.v");
compile (
# Avoid inlining so we find bugs in the non-inliner connection code
v_flags => ["-Oi"],
verilator_flags2 => ["-Oi"],
);
execute (
+21
View 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-2009 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 (
verilator_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
fails => 1,
expect=>
'%Error: t/t_interface_top_bad.v:\d+: Unsupported: Interfaced port on top level module',
);
ok(1);
1;
@@ -3,17 +3,17 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
interface counter_io;
interface ifc;
logic [3:0] value;
logic reset;
modport counter_side (input reset, output value);
modport core_side (output reset, input value);
modport counter_mp (input reset, output value);
modport core_mp (output reset, input value);
endinterface
module t
(// Inputs
input clk,
counter_io.counter_side c_data
ifc.counter_mp c_data
);
integer cyc=1;
+1 -1
View File
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
v_flags => ["-Wno-IMPLICIT"],
v_flags2 => ["-Wno-IMPLICIT"],
);
ok(1);
+1
View File
@@ -18,6 +18,7 @@ compile (
foreach my $file (glob("$Self->{obj_dir}/*t_lint_only*")) {
next if $file =~ /simx_compile.log/; # Made by driver.pl, not Verilator
next if $file =~ /\.status/; # Made by driver.pl, not Verilator
$Self->error("%Error: Created $file, but --lint-only shouldn't create files");
}
+18
View 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;
+82
View File
@@ -0,0 +1,82 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire pick1 = crc[0];
wire [13:0][1:0] data1 = crc[27+1:1];
wire [3:0][2:0][1:0] data2 = crc[23+29:29];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
logic [15:0] [1:0] datao; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.datao (datao/*[15:0][1:0]*/),
// Inputs
.pick1 (pick1),
.data1 (data1/*[13:0][1:0]*/),
.data2 (data2/*[2:0][3:0][1:0]*/));
// Aggregate outputs into a single result vector
wire [63:0] result = {32'h0, datao};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= 64'h0;
end
else if (cyc<10) begin
sum <= 64'h0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'h3ff4bf0e6407b281
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test
(
input logic pick1,
input logic [13:0] [1:0] data1, // 14 x 2 = 28 bits
input logic [ 3:0] [2:0] [1:0] data2, // 4 x 3 x 2 = 24 bits
output logic [15:0] [1:0] datao // 16 x 2 = 32 bits
);
// verilator lint_off WIDTH
always_comb datao[13: 0] // 28 bits
= (pick1)
? {data1} // 28 bits
: {'0, data2}; // 25-28 bits, perhaps not legal as '0 is unsized
// verilator lint_on WIDTH
always_comb datao[15:14] = '0;
endmodule
+1 -1
View File
@@ -14,7 +14,7 @@ $Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp"],
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp -Oi"],
);
execute (
+1 -1
View File
@@ -14,7 +14,7 @@ $Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp --sc"],
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp --sc -Oi"],
);
execute (
+34
View File
@@ -0,0 +1,34 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
#if defined(T_MEM_MULTI_IO3_CC)
# include "Vt_mem_multi_io3_cc.h"
#elif defined(T_MEM_MULTI_IO3_SC)
# include "Vt_mem_multi_io3_sc.h"
#else
# error "Unknown test"
#endif
VM_PREFIX* tb = NULL;
bool pass = true;
double sc_time_stamp() {
return 0;
}
int main() {
Verilated::debug(0);
tb = new VM_PREFIX ("tb");
// Just a constructor test
bool pass = true;
if (pass) {
VL_PRINTF("*-* All Finished *-*\n");
} else {
vl_fatal(__FILE__,__LINE__,"top", "Unexpected results from test\n");
}
return 0;
}
+52
View File
@@ -0,0 +1,52 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013.
module t
(
input logic clk,
input logic daten,
input logic [8:0] datval,
output logic signed [3:0][3:0][35:0] datao
);
logic signed [3:0][3:0][3:0][8:0] datat;
genvar i;
generate
for (i=0; i<4; i++)begin
testio dut(.clk(clk), .arr3d_in(datat[i]), .arr2d_out(datao[i]));
end
endgenerate
genvar j;
generate
for (i=0; i<4; i++) begin
for (j=0; j<4; j++) begin
always_comb datat[i][j][0] = daten ? 9'h0 : datval;
always_comb datat[i][j][1] = daten ? 9'h1 : datval;
always_comb datat[i][j][2] = daten ? 9'h2 : datval;
always_comb datat[i][j][3] = daten ? 9'h3 : datval;
end
end
endgenerate
endmodule
module testio
(
input clk,
input logic signed [3:0] [3:0] [8:0] arr3d_in,
output logic signed [3:0] [35:0] arr2d_out
);
logic signed [3:0] [35:0] ar2d_out_pre;
always_comb ar2d_out_pre[0][35:0] = {arr3d_in[0][0][8:0], arr3d_in[0][1][8:0], arr3d_in[0][2][8:0], arr3d_in[0][3][8:0]};
always_comb ar2d_out_pre[0][35:0] = {arr3d_in[0][0][8:0], arr3d_in[0][1][8:0], arr3d_in[0][2][8:0], arr3d_in[0][3][8:0]};
always_comb ar2d_out_pre[0][35:0] = {arr3d_in[0][0][8:0], arr3d_in[0][1][8:0], arr3d_in[0][2][8:0], arr3d_in[0][3][8:0]};
always_comb ar2d_out_pre[0][35:0] = {arr3d_in[0][0][8:0], arr3d_in[0][1][8:0], arr3d_in[0][2][8:0], arr3d_in[0][3][8:0]};
always_ff @(posedge clk) begin
if (clk)
arr2d_out <= ar2d_out_pre;
end
endmodule
+21
View 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-2009 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.
top_filename("t/t_mem_multi_io3.v");
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp -Oi"],
);
ok(1);
1;
+21
View 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-2009 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.
top_filename("t/t_mem_multi_io3.v");
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp --sc -Oi"],
);
ok(1);
1;
-1
View File
@@ -8,7 +8,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
v_flags => [],
);
execute (
+18
View 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;
+140
View File
@@ -0,0 +1,140 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013.
// bug648
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [7:0] datai = crc[7:0];
wire enable = crc[8];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
logic [7:0] datao; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.datao (datao[7:0]),
// Inputs
.clk (clk),
.datai (datai[7:0]),
.enable (enable));
// Aggregate outputs into a single result vector
wire [63:0] result = {56'h0, datao};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= 64'h0;
end
else if (cyc<10) begin
sum <= 64'h0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'h9d550d82d38926fa
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
`define FAIL 1
module Nested
(
input logic clk,
input logic x,
output logic y
);
logic t;
always_comb t = x ^ 1'b1;
always_ff @(posedge clk) begin
if (clk)
y <= t;
end
endmodule
module Test
(
input logic clk,
input logic [7:0] datai,
input logic enable,
output logic [7:0] datao
);
// verilator lint_off BLKANDNBLK
logic [7:0] datat;
// verilator lint_on BLKANDNBLK
for (genvar i = 0; i < 8; i++) begin
if (i%4 != 3) begin
`ifndef FAIL
logic t;
always_comb begin
t = datai[i] ^ 1'b1;
end
always_ff @(posedge clk) begin
if (clk)
datat[i] <= t;
end
`else
Nested nested_i
(
.clk(clk),
.x(datai[i]),
.y(datat[i]) //<== via Vcellout wire
);
`endif
always_comb begin
casez (enable)
1'b1: datao[i] = datat[i];
1'b0: datao[i] = '0;
default: datao[i] = 'x;
endcase
end
end
else begin
always_ff @(posedge clk) begin
if (clk)
datat[i] <= 0; //<== assign delayed
end
always_comb begin
casez (enable)
1'b1: datao[i] = datat[i] ^ 1'b1;
1'b0: datao[i] = '1;
default: datao[i] = 'x;
endcase
end
end
end
endmodule