Merge from master for release.

This commit is contained in:
Wilson Snyder 2020-10-15 08:25:44 -04:00
commit 818318ddd5
192 changed files with 3430 additions and 833 deletions

View File

@ -85,7 +85,7 @@ jobs:
# OS X build
- {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}}
# FreeBSD build
- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
#- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
############################################################################
# Jobs in the 'test' stage
############################################################################
@ -136,10 +136,10 @@ jobs:
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1}
# FreeBSD tests
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
notifications:
email:

33
Changes
View File

@ -3,6 +3,37 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.102 2020-10-15
**** Support const object new() assignments.
**** Support # as a comment in -f files (#2497). [phantom-killua]
**** Support 'this' (#2585). [Rafal Kapuscik]
**** Support defines for FST tracing (#2592). [Markus Krause]
**** Support |=> inside properties (#1292). [Peter Monsson]
**** Fix timescale with --hierarchical (#2554). [Yutetsu TAKATSUKASA]
**** Fix cmake build with --hierarchical (#2560). [Yutetsu TAKATSUKASA]
**** Fix -G dropping public indication (#2561). [Andrew Goessling]
**** Fix $urandom_range passed variable (#2563). [nanduraj1]
**** Fix method calls to package class functions (#2565). [Peter Monsson]
**** Fix class wide member display (#2567). [Nandu Raj P]
**** Fix hierarchical references inside function (#2267) (#2572). [James Pallister]
**** Fix flushCall for backward compatibility (#2580). [chenguokai]
**** Fix preprocessor stringify of undefined macro. [Martin Whitaker]
* Verilator 4.100 2020-09-07
** C++11 or newer compilers are now required.
@ -27,6 +58,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Add support for assume property. [Peter Monsson]
**** Add support for |=> inside properties (#1292). [Peter Monsson]
* Verilator 4.040 2020-08-15

View File

@ -170,6 +170,8 @@ DISTFILES_INC = $(INFOS) .gitignore \
test_regress/t/t*/*.v* \
test_regress/t/t*/*/*.sv* \
test_regress/t/t*/*/*.v* \
test_regress/t/t*/*.cpp \
test_regress/t/t*/CMakeLists.txt \
test_regress/t/*.cpp \
test_regress/t/*.h \
test_regress/t/*.dat \

View File

@ -156,7 +156,8 @@ sub report {
print "\nAnalysis:\n";
printf " Total threads = %d\n", $nthreads;
printf " Total mtasks = %d\n", scalar(keys %Mtasks);
printf " Total cpus used = %d\n", scalar(keys %{$Global{cpus}});
my $ncpus = scalar(keys %{$Global{cpus}});
printf " Total cpus used = %d\n", $ncpus;
printf " Total yields = %d\n", $Global{stats}{yields};
printf " Total eval time = %d rdtsc ticks\n", $Global{last_end};
printf " Longest mtask time = %d rdtsc ticks\n", $long_mtask_time;
@ -206,6 +207,12 @@ sub report {
print " stddev = " . ($stddev) . "\n";
print " e ^ stddev = " . exp($stddev). "\n";
print "\n";
if ($nthreads > $ncpus) {
print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n";
print " : See docs on use of numactl.\n";
print "\n";
}
}
sub report_graph {

View File

@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.100 2020-09-07],
AC_INIT([Verilator],[4.102 2020-10-15],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file

View File

@ -25,6 +25,7 @@ Iztok Jeras
James Hanlon
James Hutchinson
Jamey Hicks
James Pallister
Jan Van Winkel
Jeremy Bennett
John Coiner
@ -39,6 +40,7 @@ Lukasz Dalek
Maarten De Braekeleer
Maciej Sobkowski
Marco Widmer
Markus Krause
Marshal Qiao
Matthew Ballance
Michael Killough
@ -52,6 +54,7 @@ Philipp Wagner
Pieter Kapsenberg
Piotr Binkowski
Qingyao Sun
Rafal Kapuscik
Richard Myers
Rupert Swarbrick
Sean Cross
@ -65,6 +68,7 @@ Tobias Wölfel
Todd Strader
Tomasz Gorochowik
Tymoteusz Blazejczyk
Victor Besyakov
Vassilis Papaefstathiou
Veripool API Bot
Wilson Snyder

View File

@ -586,7 +586,7 @@ dealing with. For example a visitor might not implement separate `visit`
methods for `AstIf` and `AstGenIf`, but just a single method for the base
class:
void visit (AstNodeIf* nodep)
void visit(AstNodeIf* nodep)
However that method might want to specify additional code if it is called
for `AstGenIf`. Verilator does this by providing a `VN_IS` method for each
@ -672,7 +672,7 @@ Set to 1 to indicate that the compilation or execution is intended to fail.
For example the following would specify that compilation requires two
defines and is expected to fail.
compile (
compile(
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
fails => 1,
);
@ -758,6 +758,15 @@ may be required to setup the system for fuzzing.
== Debugging
=== Debug Levels
The "UINFO" calls in the source indicate a debug level. Messages level 3
and below are globally enabled with `--debug`. Higher levels may be
controlled with `--debugi <level>`. An individual source file levels may
be controlled with `-debugi-<srcfile> <level>`. For example `--debug
--debugi 5 --debugi-V3Width 9` will use the debug binary at default debug
level 5, with the V3Width.cpp file at level 9.
=== --debug
When you run with `--debug` there are two primary output file types placed

View File

@ -913,10 +913,11 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
output += "0123456789abcdef"[charval];
}
break;
default:
default: { // LCOV_EXCL_START
std::string msg = std::string("Unknown _vl_vsformat code: ") + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
break;
} // LCOV_EXCL_STOP
} // switch
}
} // switch
@ -1182,10 +1183,12 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
break;
}
default:
default: { // LCOV_EXCL_START
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
break;
} // LCOV_EXCL_STOP
} // switch
if (!inIgnore) ++got;
@ -2596,7 +2599,7 @@ vluint32_t VerilatedVarProps::entSize() const {
case VLVT_UINT32: size = sizeof(IData); break;
case VLVT_UINT64: size = sizeof(QData); break;
case VLVT_WDATA: size = VL_WORDS_I(packed().elements()) * sizeof(IData); break;
default: size = 0; break;
default: size = 0; break; // LCOV_EXCL_LINE
}
return size;
}

View File

@ -499,6 +499,7 @@ public:
static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void runFlushCallbacks() VL_MT_SAFE;
static void flushCall() VL_MT_SAFE { runFlushCallbacks(); } // Deprecated
/// Callbacks to run prior to termination
static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;

View File

@ -54,6 +54,7 @@ VK_CPPFLAGS_ALWAYS += \
-DVM_COVERAGE=$(VM_COVERAGE) \
-DVM_SC=$(VM_SC) \
-DVM_TRACE=$(VM_TRACE) \
-DVM_TRACE_FST=$(VM_TRACE_FST) \
$(CFG_CXXFLAGS_NO_UNUSED) \
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users

View File

@ -42,9 +42,10 @@
// clang-format on
// CONSTANTS
static const char* const VLTSAVE_HEADER_STR
= "verilatorsave01\n"; ///< Value of first bytes of each file
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
/// Value of first bytes of each file (must be multiple of 8 bytes)
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n";
/// Value of last bytes of each file (must be multiple of 8 bytes)
static const char* const VLTSAVE_TRAILER_STR = "vltsaved";
//=============================================================================
//=============================================================================
@ -64,10 +65,10 @@ VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict da
size_t size) VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(readDiffers(datap, size))) {
std::string fn = filename();
std::string msg
= "Can't deserialize save-restore file as was made from different model:" + filename();
std::string msg = "Can't deserialize save-restore file as was made from different model: "
+ filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
// Die before we close() as close would infinite loop
}
return *this; // For function chaining
}
@ -88,9 +89,11 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
std::string fn = filename();
std::string msg
= std::string("Can't deserialize; file has wrong header signature: ") + filename();
= std::string(
"Can't deserialize; file has wrong header signature, or file not found: ")
+ filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
// Die before we close() as close would infinite loop
}
os.read(Verilated::serialized1Ptr(), Verilated::serialized1Size());
os.read(Verilated::serialized2Ptr(), Verilated::serialized2Size());
@ -109,7 +112,7 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ")
+ filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
// Die before we close() as close would infinite loop
}
}

View File

@ -139,7 +139,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
if (VL_UNLIKELY(!fp)) {
VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable");
// cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr
return;
return; // LCOV_EXCL_LINE
}
// TODO Perhaps merge with verilated_coverage output format, so can

View File

@ -22,6 +22,15 @@
#include "verilatedos.h"
#include "verilated.h" // for VerilatedMutex and clang annotations
#ifndef VL_THREADED
// Hitting this likely means verilated_threads.cpp is being compiled when
// 'verilator --threads' was not used. 'verilator --threads' sets
// VL_THREADED.
// Alternatively it is always safe but may harm performance to always
// define VL_THREADED for all compiles.
#error "verilated_threads.h/cpp expected VL_THREADED (from verilator --threads)"
#endif
#include <condition_variable>
#include <set>
#include <vector>

View File

@ -46,14 +46,17 @@ remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
exclude_line_regexp(qr/(\bv3fatalSrc\b
|\bfatalSrc\b
|\bVL_UNCOVERABLE\b
|\bVL_UNREACHABLE\b
|\bVL_FATAL
|\bUASSERT
|\bNUM_ASSERT
|\bERROR_RSVD_WORD
|\bV3ERROR_NA
|\bUINFO\b)/x);
# Exclude for branch coverage only
exclude_branch_regexp(qr/(\bdebug\(\)
|\bassert\(
|\bSELF_CHECK)/x);
1;

View File

@ -81,6 +81,10 @@ prefiles:: config_rev.h
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
# Human convenience
clang-format:
$(MAKE) -C .. $@
maintainer-copy::
clean mostlyclean distclean maintainer-clean::
-rm -rf obj_* *.log *.dmp *.vpd core

View File

@ -317,12 +317,12 @@ private:
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
inp->dtypep());
m_modp->addStmtp(outvarp);
AstNode* assp = new AstAssignDly(nodep->fileline(),
new AstVarRef(nodep->fileline(), outvarp, true), inp);
AstNode* assp = new AstAssignDly(
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
alwaysp->addStmtp(assp);
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
invarp = outvarp;
inp = new AstVarRef(nodep->fileline(), invarp, false);
inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ);
}
nodep->replaceWith(inp);
}

View File

@ -39,6 +39,8 @@ private:
AstSenItem* m_senip = nullptr; // Last sensitivity
// Reset each always:
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
// Reset each assertion:
AstNode* m_disablep = nullptr; // Last disable
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -58,7 +60,10 @@ private:
}
return newp;
}
void clearAssertInfo() { m_senip = nullptr; }
void clearAssertInfo() {
m_senip = nullptr;
m_disablep = nullptr;
}
// VISITORS
//========== Statements
@ -129,8 +134,25 @@ private:
AstNode* exprp = nodep->exprp()->unlinkFrBack();
AstNode* past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstEq(fl, past,
exprp->cloneTree(false)); // new AstVarRef(fl, exprp, true)
exprp = new AstEq(fl, past, exprp->cloneTree(false));
exprp->dtypeSetLogicBool();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstImplication* nodep) override {
if (nodep->sentreep()) return; // Already processed
FileLine* fl = nodep->fileline();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
if (m_disablep) { lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); }
AstNode* past = new AstPast(fl, lhsp, nullptr);
past->dtypeFrom(lhsp);
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
exprp->dtypeSetLogicBool();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
@ -145,6 +167,7 @@ private:
// Block is the new expression to evaluate
AstNode* blockp = nodep->propp()->unlinkFrBack();
if (nodep->disablep()) {
m_disablep = nodep->disablep()->cloneTree(false);
if (VN_IS(nodep->backp(), Cover)) {
blockp = new AstAnd(
nodep->disablep()->fileline(),

View File

@ -58,9 +58,10 @@ std::ostream& operator<<(std::ostream& os, AstType rhs);
//######################################################################
// Creators
void AstNode::init() {
AstNode::AstNode(AstType t, FileLine* fl)
: m_type{t}
, m_fileline{fl} {
editCountInc();
m_fileline = nullptr;
m_nextp = nullptr;
m_backp = nullptr;
m_headtailp = this; // When made, we're a list of only a single element

View File

@ -123,6 +123,33 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
//######################################################################
class VAccess {
public:
enum en : uint8_t { READ, WRITE };
enum en m_e;
const char* ascii() const {
static const char* const names[] = {"RD", "WR"};
return names[m_e];
}
inline VAccess()
: m_e{READ} {}
// cppcheck-suppress noExplicitConstructor
inline VAccess(en _e)
: m_e{_e} {}
explicit inline VAccess(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; }
VAccess invert() const { return (m_e == WRITE) ? VAccess(READ) : VAccess(WRITE); }
bool isRead() const { return m_e == READ; }
bool isWrite() const { return m_e == WRITE; }
};
inline bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VAccess::en lhs, const VAccess& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return os << rhs.ascii(); }
//######################################################################
class VSigning {
public:
enum en : uint8_t {
@ -1422,7 +1449,6 @@ class AstNode {
if (nodep) nodep->m_backp = this;
}
void init(); // initialize value of AstNode
private:
AstNode* cloneTreeIter();
AstNode* cloneTreeIterList();
@ -1442,15 +1468,7 @@ public:
protected:
// CONSTRUCTORS
AstNode(AstType t)
: m_type{t} {
init();
}
AstNode(AstType t, FileLine* fl)
: m_type{t} {
init();
m_fileline = fl;
}
AstNode(AstType t, FileLine* fl);
virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead
virtual void cloneRelink() {}
void cloneRelinkTree();
@ -1889,6 +1907,7 @@ public:
: AstNode{t, fl} {}
ASTNODE_BASE_FUNCS(NodeMath)
// METHODS
virtual void dump(std::ostream& str) const override;
virtual bool hasDType() const override { return true; }
virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV
// For documentation on emitC format see EmitCStmts::emitOpName
@ -1911,6 +1930,7 @@ public:
// See checkTreeIter also that asserts no children
// cppcheck-suppress functionConst
void iterateChildren(AstNVisitor& v) {}
virtual void dump(std::ostream& str) const override;
};
class AstNodeUniop : public AstNodeMath {
@ -1925,6 +1945,7 @@ public:
AstNode* lhsp() const { return op1p(); }
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
// METHODS
virtual void dump(std::ostream& str) const override;
// Set out to evaluation of a AstConst'ed lhs
virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0;
virtual bool cleanLhs() const = 0;
@ -1987,6 +2008,7 @@ public:
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
void thsp(AstNode* nodep) { return setOp3p(nodep); }
// METHODS
virtual void dump(std::ostream& str) const override;
// Set out to evaluation of a AstConst'ed
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths)
@ -2142,6 +2164,7 @@ public:
}
ASTNODE_BASE_FUNCS(NodeProcedure)
// METHODS
virtual void dump(std::ostream& str) const override;
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
@ -2158,8 +2181,11 @@ public:
// METHODS
bool isStatement() const { return m_statement; } // Really a statement
void statement(bool flag) { m_statement = flag; }
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
virtual void addNextStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
virtual void addBeforeStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
virtual void dump(std::ostream& str = std::cout) const override;
};
class AstNodeAssign : public AstNodeStmt {
@ -2255,7 +2281,7 @@ public:
class AstNodeVarRef : public AstNodeMath {
// An AstVarRef or AstVarXRef
private:
bool m_lvalue; // Left hand side assignment
VAccess m_access; // Left hand side assignment
AstVar* m_varp; // [AfterLink] Pointer to variable itself
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
AstNodeModule* m_packagep = nullptr; // Package hierarchy
@ -2264,28 +2290,29 @@ private:
bool m_hierThis = false; // Hiername points to "this" function
public:
AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue)
AstNodeVarRef(AstType t, FileLine* fl, const string& name, const VAccess& access)
: AstNodeMath{t, fl}
, m_lvalue{lvalue}
, m_access{access}
, m_name{name} {
this->varp(nullptr);
}
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue)
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access)
: AstNodeMath{t, fl}
, m_lvalue{lvalue}
, m_access{access}
, m_name{name} {
// May have varp==nullptr
this->varp(varp);
}
ASTNODE_BASE_FUNCS(NodeVarRef)
virtual void dump(std::ostream& str) const override;
virtual bool hasDType() const override { return true; }
virtual const char* broken() const override;
virtual int instrCount() const override { return widthInstrs(); }
virtual void cloneRelink() override;
virtual string name() const override { return m_name; } // * = Var name
virtual void name(const string& name) override { m_name = name; }
bool lvalue() const { return m_lvalue; }
void lvalue(bool lval) { m_lvalue = lval; } // Avoid using this; Set in constructor
VAccess access() const { return m_access; }
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp);
AstVarScope* varScopep() const { return m_varScopep; }
@ -2862,6 +2889,7 @@ public:
AstNodeRange(AstType t, FileLine* fl)
: AstNode{t, fl} {}
ASTNODE_BASE_FUNCS(NodeRange)
virtual void dump(std::ostream& str) const override;
};
//######################################################################

View File

@ -87,8 +87,10 @@ const char* AstNodeUOrStructDType::broken() const {
return nullptr;
}
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeCCall::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (funcp()) {
str << " " << funcp()->name() << " => ";
funcp()->dump(str);
@ -331,7 +333,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
string ostatic;
if (isStatic() && namespc.empty()) ostatic = "static ";
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false);
string oname;
if (named) {
@ -1035,8 +1037,10 @@ void AstNode::dump(std::ostream& str) const {
}
}
void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstAlways::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeProcedure::dump(str);
if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]";
}
@ -1057,8 +1061,12 @@ string AstBasicDType::prettyDTypeName() const {
}
return os.str();
}
void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstCCast::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeUniop::dump(str);
str << " sz" << size();
}
void AstCell::dump(std::ostream& str) const {
@ -1119,15 +1127,15 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const {
str << "class:" << name();
}
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (immediate()) str << " [IMMEDIATE]";
}
void AstDisplay::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
// str<<" "<<displayType().ascii();
}
void AstEnumItemRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeMath::dump(str);
str << " -> ";
if (itemp()) {
itemp()->dump(str);
@ -1167,7 +1175,7 @@ void AstInitArray::dump(std::ostream& str) const {
}
}
void AstJumpGo::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (labelp()) {
labelp()->dump(str);
@ -1176,7 +1184,7 @@ void AstJumpGo::dump(std::ostream& str) const {
}
}
void AstJumpLabel::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (blockp()) {
blockp()->dump(str);
@ -1185,7 +1193,7 @@ void AstJumpLabel::dump(std::ostream& str) const {
}
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeMath::dump(str);
str << " -> ";
if (varp()) {
varp()->dump(str);
@ -1194,7 +1202,7 @@ void AstMemberSel::dump(std::ostream& str) const {
}
}
void AstMethodCall::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (isStatement()) str << " [STMT]";
str << " -> ";
if (taskp()) {
@ -1235,27 +1243,30 @@ void AstPin::dump(std::ostream& str) const {
if (svImplicit()) str << " [.SV]";
}
void AstPrintTimeScale::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " " << timeunit();
}
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstTime::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeTermop::dump(str);
str << " " << timeunit();
}
void AstTimeD::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeTermop::dump(str);
str << " " << timeunit();
}
void AstTimeImport::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeUniop::dump(str);
str << " " << timeunit();
}
void AstTypedef::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (attrPublic()) str << " [PUBLIC]";
}
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstRange::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeRange::dump(str);
if (littleEndian()) str << " [LITTLE]";
}
void AstRefDType::dump(std::ostream& str) const {
@ -1352,15 +1363,16 @@ void AstPackageImport::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << packagep();
}
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeTriop::dump(str);
if (declRange().ranged()) {
str << " decl" << declRange() << "]";
if (declElWidth() != 1) str << "/" << declElWidth();
}
}
void AstSliceSel::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeTriop::dump(str);
if (declRange().ranged()) str << " decl" << declRange();
}
void AstMTaskBody::dump(std::ostream& str) const {
@ -1428,10 +1440,11 @@ void AstVarScope::dump(std::ostream& str) const {
str << " ->UNLINKED";
}
}
void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstVarXRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeVarRef::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
if (access().isWrite()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
@ -1447,9 +1460,9 @@ void AstVarXRef::dump(std::ostream& str) const {
}
}
void AstVarRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeVarRef::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) {
if (access().isWrite()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
@ -1522,7 +1535,7 @@ void AstActive::dump(std::ostream& str) const {
}
}
void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
str << " -> ";
if (dotted() != "") { str << ".=" << dotted() << " "; }
@ -1554,7 +1567,7 @@ void AstBegin::dump(std::ostream& str) const {
if (implied()) str << " [IMPLIED]";
}
void AstCoverDecl::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
if (!page().empty()) str << " page=" << page();
if (!linescov().empty()) str << " lc=" << linescov();
if (this->dataDeclNullp()) {
@ -1565,7 +1578,7 @@ void AstCoverDecl::dump(std::ostream& str) const {
}
}
void AstCoverInc::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (declp()) {
declp()->dump(str);
@ -1578,7 +1591,7 @@ void AstFork::dump(std::ostream& str) const {
if (!joinType().join()) str << " [" << joinType() << "]";
}
void AstTraceInc::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeStmt::dump(str);
str << " -> ";
if (declp()) {
declp()->dump(str);
@ -1597,10 +1610,11 @@ void AstNodeText::dump(std::ostream& str) const {
str << " \"" << out << "\"";
}
void AstVFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); }
void AstCFile::dump(std::ostream& str) const {
this->AstNode::dump(str);
this->AstNodeFile::dump(str);
if (source()) str << " [SRC]";
if (slow()) str << " [SLOW]";
}

View File

@ -539,10 +539,13 @@ public:
}
virtual bool same(const AstNode* samep) const override {
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
if (!asamep->keyDTypep()) return false;
return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep());
}
virtual bool similarDType(AstNodeDType* samep) const override {
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual string prettyDTypeName() const override;
@ -635,10 +638,12 @@ public:
}
virtual bool same(const AstNode* samep) const override {
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return subDTypep() == asamep->subDTypep();
}
virtual bool similarDType(AstNodeDType* samep) const override {
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual string prettyDTypeName() const override;
@ -741,10 +746,12 @@ public:
}
virtual bool same(const AstNode* samep) const override {
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
virtual bool similarDType(AstNodeDType* samep) const override {
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual void dumpSmall(std::ostream& str) const override;
@ -1104,10 +1111,12 @@ public:
}
virtual bool same(const AstNode* samep) const override {
const AstQueueDType* asamep = static_cast<const AstQueueDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
virtual bool similarDType(AstNodeDType* samep) const override {
const AstQueueDType* asamep = static_cast<const AstQueueDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual void dumpSmall(std::ostream& str) const override;
@ -1669,7 +1678,7 @@ class AstSel : public AstNodeTriop {
// Multiple bit range extraction
// Parents: math|stmt
// Children: varref|arraysel, math, constant math
// Tempting to have an lvalue() style method here as LHS selects are quite
// Tempting to have an access() style method here as LHS selects are quite
// different, but that doesn't play well with V3Inst and bidirects which don't know direction
private:
VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid
@ -2177,7 +2186,7 @@ public:
private:
class VlArgTypeRecursed;
VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool compound = false) const;
bool compound) const;
};
class AstDefParam : public AstNode {
@ -2319,15 +2328,15 @@ public:
class AstVarRef : public AstNodeVarRef {
// A reference to a variable (lvalue or rvalue)
public:
AstVarRef(FileLine* fl, const string& name, bool lvalue)
: ASTGEN_SUPER(fl, name, nullptr, lvalue) {}
AstVarRef(FileLine* fl, const string& name, const VAccess& access)
: ASTGEN_SUPER(fl, name, nullptr, access) {}
// This form only allowed post-link because output/wire compression may
// lead to deletion of AstVar's
AstVarRef(FileLine* fl, AstVar* varp, bool lvalue)
: ASTGEN_SUPER(fl, varp->name(), varp, lvalue) {}
AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
: ASTGEN_SUPER(fl, varp->name(), varp, access) {}
// This form only allowed post-link (see above)
AstVarRef(FileLine* fl, AstVarScope* varscp, bool lvalue)
: ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), lvalue) {
AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access)
: ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), access) {
varScopep(varscp);
}
ASTNODE_NODE_FUNCS(VarRef)
@ -2340,21 +2349,23 @@ public:
}
inline bool same(const AstVarRef* samep) const {
if (varScopep()) {
return (varScopep() == samep->varScopep() && lvalue() == samep->lvalue());
return (varScopep() == samep->varScopep() && access() == samep->access());
} else {
return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name()
&& lvalue() == samep->lvalue());
&& access() == samep->access());
}
}
inline bool sameNoLvalue(AstVarRef* samep) const {
if (varScopep()) {
return (varScopep() == samep->varScopep());
} else {
return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name());
return (hiername() == samep->hiername()
&& (hiername() != "" || samep->hiername() != "")
&& varp()->name() == samep->varp()->name());
}
}
virtual int instrCount() const override {
return widthInstrs() * (lvalue() ? 1 : instrCountLd());
return widthInstrs() * (access().isWrite() ? 1 : instrCountLd());
}
virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
@ -2368,11 +2379,11 @@ private:
string m_dotted; // Dotted part of scope the name()'ed reference is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
public:
AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue)
: ASTGEN_SUPER(fl, name, nullptr, lvalue)
AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access)
: ASTGEN_SUPER(fl, name, nullptr, access)
, m_dotted{dotted} {}
AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, bool lvalue)
: ASTGEN_SUPER(fl, varp->name(), varp, lvalue)
AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access)
: ASTGEN_SUPER(fl, varp->name(), varp, access)
, m_dotted{dotted} {
dtypeFrom(varp);
}
@ -8235,6 +8246,32 @@ public:
void isDefault(bool flag) { m_default = flag; }
};
class AstImplication : public AstNodeMath {
// Verilog |-> |=>
// Parents: math
// Children: expression
public:
AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs)
: ASTGEN_SUPER(fl) {
setOp1p(lhs);
setOp2p(rhs);
}
ASTNODE_NODE_FUNCS(Implication)
virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain
void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
//======================================================================
// Assertions
@ -8461,6 +8498,7 @@ public:
m_name = name;
}
ASTNODE_BASE_FUNCS(NodeFile)
virtual void dump(std::ostream& str) const override;
virtual string name() const override { return m_name; }
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }

View File

@ -203,7 +203,7 @@ private:
}
virtual void visit(AstVarXRef* nodep) override {
UINFO(9, " VARXREF " << nodep << endl);
if (m_namedScope != "" && nodep->inlinedDots() == "") {
if (m_namedScope != "" && nodep->inlinedDots() == "" && !m_ftaskp) {
nodep->inlinedDots(m_namedScope);
UINFO(9, " rescope to " << nodep << endl);
}

View File

@ -275,7 +275,7 @@ private:
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWrite()),
nodep, "Assignment LHS is not an lvalue");
}
virtual void visit(AstNode* nodep) override {

View File

@ -111,7 +111,7 @@ void V3CCtors::evalAsserts() {
int lastWordWidth = varp->width() % storedWidth;
if (lastWordWidth != 0) {
// if (signal & CONST(upper_non_clean_mask)) { fail; }
AstNode* newp = new AstVarRef(varp->fileline(), varp, false);
AstNode* newp = new AstVarRef(varp->fileline(), varp, VAccess::READ);
if (varp->isWide()) {
newp = new AstWordSel(
varp->fileline(), newp,
@ -151,8 +151,9 @@ void V3CCtors::cctorsAll() {
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) {
if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) {
var_reset.add(new AstCReset(varp->fileline(),
new AstVarRef(varp->fileline(), varp, true)));
var_reset.add(
new AstCReset(varp->fileline(),
new AstVarRef(varp->fileline(), varp, VAccess::WRITE)));
}
}
}

View File

@ -167,7 +167,14 @@ class CUseVisitor : public AstNVisitor {
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + VL_TO_STRING(";
stmt += ":\" + ";
if (itemp->isWide()) {
stmt += "VL_TO_STRING_W(";
stmt += cvtToStr(itemp->widthWords());
stmt += ", ";
} else {
stmt += "VL_TO_STRING(";
}
stmt += itemp->nameProtect();
stmt += ");\n";
nodep->user1(true); // So what we extend dumps this

View File

@ -154,9 +154,9 @@ private:
}
}
virtual void visit(AstVarRef* nodep) override {
if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath)
&& !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width()
&& castSize(nodep) != castSize(nodep->varp())) {
if (nodep->access().isRead() && !VN_IS(nodep->backp(), CCast)
&& VN_IS(nodep->backp(), NodeMath) && !VN_IS(nodep->backp(), ArraySel)
&& nodep->backp()->width() && castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
// CData x=3; out = (QData)(x<<30);
insertCast(nodep, castSize(nodep));

View File

@ -661,7 +661,7 @@ private:
// We use weight of one for normal edges,
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
// When simplify we'll take the MAX weight
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
if (m_inDly) {
varvertexp->fromFlop(true);

View File

@ -199,9 +199,9 @@ public:
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
m_statep->m_scopetopp->addVarp(m_newvscp);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, VAccess::READ);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::WRITE);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::READ);
}
iterate(vscp->dtypep()->skipRefp());
m_varEqnp->deleteTree();

View File

@ -79,15 +79,15 @@ private:
vscp->user1p(newvscp);
m_scopep->addVarp(newvscp);
// Add init
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ);
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
AstNode* newinitp = new AstAssign(
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp);
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, VAccess::WRITE), fromp);
addToInitial(newinitp);
// At bottom, assign them
AstAssign* finalp
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
new AstVarRef(vscp->fileline(), vscp, false));
AstAssign* finalp = new AstAssign(vscp->fileline(),
new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
m_evalFuncp->addFinalsp(finalp);
//
UINFO(4, "New Last: " << newvscp << endl);
@ -112,25 +112,28 @@ private:
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), lastVscp, false)));
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)));
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(
nodep->fileline(),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false)),
new AstVarRef(nodep->fileline(), lastVscp, false));
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(),
VAccess::READ)),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstXor(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
new AstVarRef(nodep->fileline(), lastVscp, false));
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
} else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) {
newp = new AstVarRef(nodep->fileline(), clkvscp, false);
newp = new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ);
} else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) {
newp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), clkvscp, false));
newp = new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ));
} else {
nodep->v3fatalSrc("Bad edge type");
}

View File

@ -314,7 +314,7 @@ private:
// It was an expression, then got constified. In reality, the WordSel
// must be wrapped in a Cond, that will be false.
return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef)
&& !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->lvalue()
&& !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isWrite()
&& (static_cast<int>(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt())
>= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords()));
}
@ -1132,18 +1132,22 @@ private:
VFlagLogicPacked(), msb2 - lsb2 + 1);
m_modp->addStmtp(temp1p);
m_modp->addStmtp(temp2p);
AstNodeAssign* asn1ap = VN_CAST(
nodep->cloneType(new AstVarRef(sel1p->fileline(), temp1p, true), sel1p),
NodeAssign);
AstNodeAssign* asn2ap = VN_CAST(
nodep->cloneType(new AstVarRef(sel2p->fileline(), temp2p, true), sel2p),
NodeAssign);
AstNodeAssign* asn1bp = VN_CAST(
nodep->cloneType(lc1p, new AstVarRef(sel1p->fileline(), temp1p, false)),
NodeAssign);
AstNodeAssign* asn2bp = VN_CAST(
nodep->cloneType(lc2p, new AstVarRef(sel2p->fileline(), temp2p, false)),
NodeAssign);
AstNodeAssign* asn1ap
= VN_CAST(nodep->cloneType(
new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p),
NodeAssign);
AstNodeAssign* asn2ap
= VN_CAST(nodep->cloneType(
new AstVarRef(sel2p->fileline(), temp2p, VAccess::WRITE), sel2p),
NodeAssign);
AstNodeAssign* asn1bp
= VN_CAST(nodep->cloneType(
lc1p, new AstVarRef(sel1p->fileline(), temp1p, VAccess::READ)),
NodeAssign);
AstNodeAssign* asn2bp
= VN_CAST(nodep->cloneType(
lc2p, new AstVarRef(sel2p->fileline(), temp2p, VAccess::READ)),
NodeAssign);
asn1ap->dtypeFrom(temp1p);
asn1bp->dtypeFrom(temp1p);
asn2ap->dtypeFrom(temp2p);
@ -1601,7 +1605,7 @@ private:
// if (debug()) valuep->dumpTree(cout, " visitvaref: ");
iterateAndNextNull(nodep->varp()->valuep()); // May change nodep->varp()->valuep()
AstNode* valuep = nodep->varp()->valuep();
if (!nodep->lvalue()
if (!nodep->access().isWrite()
&& ((!m_params // Can reduce constant wires into equations
&& m_doNConst
&& v3Global.opt.oConst()

View File

@ -130,8 +130,8 @@ private:
m_modp->addStmtp(varp);
UINFO(5, "New coverage trace: " << varp << endl);
AstAssign* assp = new AstAssign(
incp->fileline(), new AstVarRef(incp->fileline(), varp, true),
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, false),
incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE),
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ),
new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1)));
incp->addNext(assp);
}
@ -288,8 +288,9 @@ private:
// This is necessarily an O(n^2) expansion, which is why
// we limit coverage to signals with < 256 bits.
ToggleEnt newvec(string(""), new AstVarRef(nodep->fileline(), nodep, false),
new AstVarRef(nodep->fileline(), chgVarp, true));
ToggleEnt newvec(string(""),
new AstVarRef(nodep->fileline(), nodep, VAccess::READ),
new AstVarRef(nodep->fileline(), chgVarp, VAccess::WRITE));
toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep, chgVarp);
newvec.cleanup();
}

View File

@ -228,9 +228,10 @@ private:
AstVarScope* bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
AstAssign* bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), dimp);
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
dimp);
nodep->addNextHere(bitassignp);
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ));
}
}
//
@ -247,9 +248,10 @@ private:
AstVarScope* bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
AstAssign* bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), lsbvaluep);
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
lsbvaluep);
nodep->addNextHere(bitassignp);
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ);
}
}
//
@ -263,8 +265,8 @@ private:
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
AstVarScope* valvscp
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
newlhsp = new AstVarRef(nodep->fileline(), valvscp, VAccess::WRITE);
valreadp = new AstVarRef(nodep->fileline(), valvscp, VAccess::READ);
}
//
//=== Setting/not setting boolean: __Vdlyvset__
@ -283,11 +285,11 @@ private:
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
setinitp = new AstAssignPre(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, true),
new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), 0));
AstAssign* setassignp
= new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true),
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
AstAssign* setassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
nodep->addNextHere(setassignp);
}
if (m_nextDlyp) { // Tell next assigndly it can share the variable
@ -332,9 +334,9 @@ private:
UASSERT_OBJ(postLogicp, nodep,
"Delayed assignment misoptimized; prev var found w/o associated IF");
} else {
postLogicp
= new AstIf(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, false),
nullptr, nullptr);
postLogicp = new AstIf(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, VAccess::READ),
nullptr, nullptr);
UINFO(9, " Created " << postLogicp << endl);
finalp->addBodysp(postLogicp);
finalp->user3p(setvscp); // Remember IF's vset variable
@ -406,7 +408,7 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (!nodep->user2Inc()) { // Not done yet
if (m_inDly && nodep->lvalue()) {
if (m_inDly && nodep->access().isWrite()) {
UINFO(4, "AssignDlyVar: " << nodep << endl);
markVarUsage(nodep->varScopep(), VU_DLY);
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
@ -429,16 +431,19 @@ private:
if (basicp && basicp->isEventValue()) {
// Events go to zero on next timestep unless reactivated
prep = new AstAssignPre(
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::LogicFalse()));
} else {
prep = new AstAssignPre(nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, true),
new AstVarRef(nodep->fileline(), oldvscp, false));
prep = new AstAssignPre(
nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
new AstVarRef(nodep->fileline(), oldvscp, VAccess::READ));
}
AstNodeAssign* postp = new AstAssignPost(
nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true),
new AstVarRef(nodep->fileline(), dlyvscp, false));
nodep->fileline(),
new AstVarRef(nodep->fileline(), oldvscp, VAccess::WRITE),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::READ));
postp->lhsp()->user2(true); // Don't detect this assignment
oldvscp->user1p(dlyvscp); // So we can find it later
// Make new ACTIVE with identical sensitivity tree
@ -447,11 +452,11 @@ private:
newactp->addStmtsp(prep); // Add to FRONT of statements
newactp->addStmtsp(postp);
}
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
newrefp->user2(true); // No reason to do it again
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (!m_inDly && nodep->lvalue()) {
} else if (!m_inDly && nodep->access().isWrite()) {
// UINFO(9, "NBA " << nodep << endl);
if (!m_inInitial) {
UINFO(4, "AssignNDlyVar: " << nodep << endl);

View File

@ -64,11 +64,11 @@ private:
UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function");
m_funcp->addInitsp(varp);
// Replace node tree with reference to var
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, false);
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
nodep->replaceWith(newp);
// Put assignment before the referencing statement
AstAssign* assp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, true), nodep);
AstAssign* assp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep);
AstNRelinker linker2;
m_stmtp->unlinkFrBack(&linker2);
assp->addNext(m_stmtp);

View File

@ -184,8 +184,9 @@ private:
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
AstNode* newp
= new AstVarRef(portp->fileline(), portp, portp->isWritable());
AstNode* newp = new AstVarRef(portp->fileline(), portp,
portp->isWritable() ? VAccess::WRITE
: VAccess::READ);
argsp = argsp ? argsp->addNextNull(newp) : newp;
}
}

View File

@ -204,15 +204,14 @@ class CMakeEmitter {
*of << "# Verilate hierarchical blocks\n";
// Sorted hierarchical blocks in order of leaf-first.
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
const string topTarget = v3Global.opt.protectLib().empty() ? v3Global.opt.prefix()
: v3Global.opt.protectLib();
*of << "get_target_property(TOP_TARGET_NAME \"${TARGET}\" NAME)\n";
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
it != hierBlocks.end(); ++it) {
const V3HierBlock* hblockp = *it;
const V3HierBlock::HierBlockSet& children = hblockp->children();
const string prefix = hblockp->hierPrefix();
*of << "add_library(" << prefix << " STATIC)\n";
*of << "target_link_libraries(" << topTarget << " PRIVATE " << prefix << ")\n";
*of << "target_link_libraries(${TOP_TARGET_NAME} PRIVATE " << prefix << ")\n";
if (!children.empty()) {
*of << "target_link_libraries(" << prefix << " INTERFACE";
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
@ -223,14 +222,17 @@ class CMakeEmitter {
}
*of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE "
<< hblockp->modp()->name() << " DIRECTORY "
<< deslash("${CMAKE_CURRENT_BINARY_DIR}/" + prefix) << " SOURCES ";
<< deslash(v3Global.opt.makeDir() + "/" + prefix) << " SOURCES ";
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
child != children.end(); ++child) {
*of << deslash(" ${CMAKE_CURRENT_BINARY_DIR}/" + (*child)->hierWrapper(true));
*of << " "
<< deslash(v3Global.opt.makeDir() + "/" + (*child)->hierWrapper(true));
}
*of << " ";
const string vFile = hblockp->vFileIfNecessary();
if (!vFile.empty()) *of << vFile << " ";
const V3StringList& vFiles = v3Global.opt.vFiles();
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i);
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " ";
*of << " VERILATOR_ARGS ";
*of << "-f " << deslash(hblockp->commandArgsFileName(true))
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked
@ -238,11 +240,12 @@ class CMakeEmitter {
<< ")\n";
}
*of << "\n# Verilate the top module that refers protect-lib wrappers of above\n";
*of << "verilate(" << topTarget << " PREFIX " << v3Global.opt.prefix()
<< " TOP_MODULE " << v3Global.rootp()->topModulep()->name() << " DIRECTORY "
<< deslash("${CMAKE_CURRENT_BINARY_DIR}/" + topTarget + ".dir") << " SOURCES ";
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
<< deslash(v3Global.opt.makeDir()) << " SOURCES ";
for (V3HierBlockPlan::const_iterator it = planp->begin(); it != planp->end(); ++it) {
*of << deslash(" ${CMAKE_CURRENT_BINARY_DIR}/" + it->second->hierWrapper(true));
*of << " "
<< deslash(v3Global.opt.makeDir() + "/" + it->second->hierWrapper(true));
}
*of << " " << deslash(cmake_list(v3Global.opt.vFiles()));
*of << " VERILATOR_ARGS ";

View File

@ -65,6 +65,10 @@ public:
of.puts("VM_TRACE = ");
of.puts(v3Global.opt.trace() ? "1" : "0");
of.puts("\n");
of.puts("# Tracing output mode in FST format? 0/1 (from --trace-fst)\n");
of.puts("VM_TRACE_FST = ");
of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0");
of.puts("\n");
of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n");
of.puts("VM_TRACE_THREADS = ");
of.puts(cvtToStr(v3Global.opt.trueTraceThreads()));

View File

@ -31,6 +31,7 @@
class EmitVBaseVisitor : public EmitCBaseVisitor {
// MEMBERS
bool m_suppressSemi = false;
bool m_suppressUnknown = false;
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
// METHODS
@ -51,12 +52,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstNetlist* nodep) override { iterateChildren(nodep); }
virtual void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); }
virtual void visit(AstNodeModule* nodep) override {
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
iterateChildren(nodep);
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
}
virtual void visit(AstPort* nodep) override {}
virtual void visit(AstNodeFTask* nodep) override {
putfs(nodep, nodep->isFunction() ? "function" : "task");
puts(" ");
@ -212,14 +214,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
AstNode* exprsp) {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (fileOrStrgp) {
iterateAndNextNull(fileOrStrgp);
putbs(",");
putbs(", ");
}
putsQuoted(text);
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
puts(",");
puts(", ");
iterateAndNextNull(expp);
}
puts(");\n");
@ -247,7 +249,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, nodep->verilogKwd());
putbs("(");
iterateAndNextNull(nodep->filenamep());
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->modep());
puts(");\n");
}
@ -259,13 +261,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstFClose* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
virtual void visit(AstFFlush* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
@ -282,16 +284,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstNodeReadWriteMem* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
putbs(",");
putbs(", ");
if (nodep->memp()) iterateAndNextNull(nodep->memp());
if (nodep->lsbp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->lsbp());
}
if (nodep->msbp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->msbp());
}
puts(");\n");
@ -302,7 +304,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstSysIgnore* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
iterateAndNextNull(nodep->exprsp());
puts(");\n");
}
@ -358,7 +360,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, "$past(");
iterateAndNextNull(nodep->exprp());
if (nodep->ticksp()) {
puts(",");
puts(", ");
iterateAndNextNull(nodep->ticksp());
}
puts(")");
@ -482,7 +484,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, "$_ATTROF(");
iterateAndNextNull(nodep->fromp());
if (nodep->dimp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->dimp());
}
puts(")");
@ -654,13 +656,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
iterateChildren(nodep);
// Not v3fatalSrc so we keep processing
nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
if (!m_suppressUnknown) {
nodep->v3error(
"Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
}
}
public:
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
explicit EmitVBaseVisitor(AstSenTree* domainp = nullptr)
: m_sensesp{domainp} {}
explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp)
: m_suppressUnknown{suppressUnknown}
, m_sensesp{domainp} {}
virtual ~EmitVBaseVisitor() override {}
};
@ -679,8 +685,9 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
virtual void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); }
public:
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false,
bool suppressVarSemi = false) {
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressVarSemi,
bool suppressUnknown)
: EmitVBaseVisitor{suppressUnknown, nullptr} {
m_ofp = ofp;
m_trackText = trackText;
m_suppressVarSemi = suppressVarSemi;
@ -704,7 +711,8 @@ class EmitVStreamVisitor : public EmitVBaseVisitor {
public:
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
: m_os(os) { // Need () or GCC 4.8 false warning
: EmitVBaseVisitor{false, nullptr}
, m_os(os) { // Need () or GCC 4.8 false warning
iterate(nodep);
}
virtual ~EmitVStreamVisitor() override {}
@ -747,9 +755,8 @@ public:
, m_prefix{prefix}
, m_flWidth{flWidth} {
m_column = 0;
m_prefixFl
= v3Global.rootp()
->fileline(); // NETLIST's fileline instead of nullptr to avoid nullptr checks
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to
// avoid nullptr checks
}
virtual ~EmitVPrefixedFormatter() override {
if (m_column) puts("\n");
@ -780,7 +787,7 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
public:
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor{domainp}
: EmitVBaseVisitor{false, domainp}
, m_formatter{os, prefix, flWidth} {
if (user3mark) { AstUser3InUse::check(); }
iterate(nodep);
@ -807,7 +814,14 @@ void V3EmitV::emitvFiles() {
V3OutVFile of(vfilep->name());
of.puts("// DESCR"
"IPTION: Verilator generated Verilog\n");
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true);
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true, false);
}
}
}
void V3EmitV::debugEmitV(const string& stage) {
UINFO(2, __FUNCTION__ << ": " << endl);
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__" + stage + ".v";
V3OutVFile of(filename);
EmitVFileVisitor visitor(v3Global.rootp(), &of, true, false, true);
}

View File

@ -31,6 +31,7 @@ public:
static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
int flWidth, AstSenTree* domainp, bool user3mark);
static void emitvFiles();
static void debugEmitV(const string& stage);
};
#endif // Guard

View File

@ -94,7 +94,7 @@ private:
void fixCloneLvalue(AstNode* nodep) {
// In AstSel transforms, we call clone() on VarRefs that were lvalues,
// but are now being used on the RHS of the assignment
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->lvalue(false);
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->access(VAccess::READ);
// Iterate
if (nodep->op1p()) fixCloneLvalue(nodep->op1p());
if (nodep->op2p()) fixCloneLvalue(nodep->op2p());

View File

@ -220,7 +220,7 @@ private:
if (nodep->varScopep()->varp()->isSc()) {
clearSimple("SystemC sig"); // Don't want to eliminate the VL_ASSIGN_SI's
}
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
if (m_lhsVarRef) clearSimple(">1 lhs varRefs");
m_lhsVarRef = nodep;
} else {
@ -448,7 +448,7 @@ private:
vvertexp->setIsClock();
// For SYNCASYNCNET
varscp->user2(true);
} else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) {
} else if (m_activep && m_activep->hasClocked() && !nodep->access().isWrite()) {
if (varscp->user2()) {
if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep);
} else {
@ -457,7 +457,7 @@ private:
}
// We use weight of one; if we ref the var more than once, when we simplify,
// the weight will increase
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1);
} else {
new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1);
@ -525,10 +525,7 @@ private:
public:
// CONSTRUCTORS
explicit GateVisitor(AstNode* nodep) {
AstNode::user1ClearTree();
iterate(nodep);
}
explicit GateVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~GateVisitor() override {
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
@ -845,7 +842,7 @@ private:
// It's possible we substitute into something that will be reduced more later,
// however, as we never delete the top Always/initial statement, all should be well.
m_didReplace = true;
UASSERT_OBJ(!nodep->lvalue(), nodep,
UASSERT_OBJ(!nodep->access().isWrite(), nodep,
"Can't replace lvalue assignments with const var");
AstNode* substp = m_replaceTreep->cloneTree(false);
UASSERT_OBJ(
@ -859,7 +856,8 @@ private:
// to throw warnings that point to a PIN rather than where the pin us used.
if (VN_IS(substp, VarRef)) substp->fileline(nodep->fileline());
// Make the substp an rvalue like nodep. This facilitates the hashing in dedupe.
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef)) varrefp->lvalue(false);
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef))
varrefp->access(VAccess::READ);
hashReplace(nodep, substp);
nodep->replaceWith(substp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
@ -1514,7 +1512,7 @@ private:
UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl);
UINFO(9, " to - " << m_clk_vsp << endl);
AstNode* rhsp = assignp->rhsp();
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false));
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, VAccess::READ));
while (V3GraphEdge* edgep = lvertexp->inBeginp()) {
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}

View File

@ -67,9 +67,9 @@ private:
m_topModp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
m_scopetopp->addVarp(newvscp);
AstAssign* asninitp
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
new AstVarRef(vscp->fileline(), vscp, false));
AstAssign* asninitp = new AstAssign(
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
m_scopetopp->addFinalClkp(asninitp);
//
vscp->user2p(newvscp);
@ -98,7 +98,7 @@ private:
UINFO(8, " VarActReplace " << nodep << endl);
// Replace with the new variable
AstVarScope* newvscp = genInpClk(vscp);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
nodep->replaceWith(newrefp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
@ -186,7 +186,7 @@ private:
UINFO(8, " VarAct " << nodep << endl);
vscp->user1(true);
}
if (m_assignp && nodep->lvalue() && vscp->user1()) {
if (m_assignp && nodep->access().isWrite() && vscp->user1()) {
// Variable was previously used as a clock, and is now being set
// Thus a unordered generated clock...
UINFO(8, " VarSetAct " << nodep << endl);

View File

@ -35,6 +35,12 @@ AstNetlist* V3Global::makeNetlist() {
return newp;
}
void V3Global::clear() {
#ifdef VL_LEAK_CHECK
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = nullptr);
#endif
}
void V3Global::shutdown() {
VL_DO_CLEAR(delete m_hierPlanp, m_hierPlanp = nullptr); // delete nullptr is safe
}

View File

@ -119,6 +119,7 @@ public:
UASSERT(!m_rootp, "call once");
m_rootp = makeNetlist();
}
void clear();
void shutdown(); // Release allocated resorces
// ACCESSORS (general)
AstNetlist* rootp() const { return m_rootp; }

View File

@ -80,6 +80,7 @@
#include "V3Error.h"
#include "V3File.h"
#include "V3HierBlock.h"
#include "V3Os.h"
#include "V3String.h"
#include "V3Stats.h"
@ -88,13 +89,18 @@ static string V3HierCommandArgsFileName(const string& prefix, bool forCMake) {
+ (forCMake ? "_hierCMakeArgs.f" : "_hierMkArgs.f");
}
static void V3HierWriteCommonInputs(std::ostream* of, bool forCMake) {
static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of, bool forCMake) {
string topModuleFile;
if (hblockp) topModuleFile = hblockp->vFileIfNecessary();
if (!forCMake) {
if (!topModuleFile.empty()) *of << topModuleFile << "\n";
const V3StringList& vFiles = v3Global.opt.vFiles();
for (const string& i : vFiles) *of << i << "\n";
}
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
for (const string& i : libraryFiles) *of << "-v " << i << "\n";
for (const string& i : libraryFiles) {
if (V3Os::filenameRealPath(i) != topModuleFile) *of << "-v " << i << "\n";
}
}
//######################################################################
@ -194,6 +200,15 @@ string V3HierBlock::hierGenerated(bool withDir) const {
return hierWrapper(withDir) + ' ' + hierMk(withDir);
}
string V3HierBlock::vFileIfNecessary() const {
const string filename = V3Os::filenameRealPath(m_modp->fileline()->filename());
for (const string& v : v3Global.opt.vFiles()) {
// Already listed in vFiles, so no need to add the file.
if (filename == V3Os::filenameRealPath(v)) return "";
}
return filename;
}
void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
std::unique_ptr<std::ofstream> of(V3File::new_ofstream(commandArgsFileName(forCMake)));
*of << "--cc\n";
@ -203,9 +218,9 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
child != m_children.end(); ++child) {
*of << v3Global.opt.makeDir() << "/" << (*child)->hierWrapper(true) << "\n";
}
*of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n";
}
*of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n";
V3HierWriteCommonInputs(of.get(), forCMake);
V3HierWriteCommonInputs(this, of.get(), forCMake);
const V3StringList& commandOpts = commandArgs(false);
for (const string& opt : commandOpts) *of << opt << "\n";
*of << hierBlockArgs().front() << "\n";
@ -213,6 +228,9 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
++child) {
*of << (*child)->hierBlockArgs().front() << "\n";
}
// Hierarchical blocks should not use multi-threading,
// but needs to be thread safe when top is multi-threaded.
if (v3Global.opt.threads() > 0) { *of << "--threads 1\n"; }
*of << v3Global.opt.allArgsStringForHierBlock(false) << "\n";
}
@ -394,7 +412,7 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const {
*of << it->second->hierWrapper(true) << "\n";
}
}
V3HierWriteCommonInputs(of.get(), forCMake);
V3HierWriteCommonInputs(nullptr, of.get(), forCMake);
if (!forCMake) {
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
for (const string& i : cppFiles) *of << i << "\n";
@ -411,6 +429,9 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const {
*of << "--protect-lib " << v3Global.opt.protectLib() << "\n";
*of << "--protect-key " << v3Global.opt.protectKeyDefaulted() << "\n";
}
if (v3Global.opt.threads() > 0) {
*of << "--threads " << cvtToStr(v3Global.opt.threads()) << "\n";
}
*of << (v3Global.opt.systemC() ? "--sc" : "--cc") << "\n";
*of << v3Global.opt.allArgsStringForHierBlock(true) << "\n";
}

View File

@ -85,6 +85,8 @@ public:
string hierMk(bool withDir) const;
string hierLib(bool withDir) const;
string hierGenerated(bool withDir) const;
// Returns the original HDL file if it is not included in v3Global.opt.vFiles().
string vFileIfNecessary() const;
// Write command line argumuents to .f file for this hierarchical block
void writeCommandArgsFile(bool forCMake) const;
string commandArgsFileName(bool forCMake) const;

View File

@ -313,9 +313,9 @@ private:
UASSERT_OBJ(exprconstp || exprvarrefp, nodep,
"Unknown interconnect type; pinReconnectSimple should have cleared up");
if (exprconstp) {
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
exprconstp->cloneTree(true)));
m_modp->addStmtp(new AstAssignW(
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
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
@ -323,20 +323,22 @@ private:
UINFO(9, "public pin assign: " << exprvarrefp << endl);
UASSERT_OBJ(!nodep->isNonOutput(), nodep, "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)));
nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::WRITE),
new AstVarRef(nodep->fileline(), nodep, VAccess::READ)));
} else if (nodep->isSigPublic() && VN_IS(nodep->dtypep(), UnpackArrayDType)) {
// Public variable at this end and it is an unpacked array. We need to assign
// instead of aliased, because otherwise it will pass V3Slice and invalid
// code will be emitted.
UINFO(9, "assign to public and unpacked: " << nodep << endl);
m_modp->addStmtp(new AstAssignW(
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::WRITE),
new AstVarRef(nodep->fileline(), nodep, VAccess::READ)));
} else if (nodep->isIfaceRef()) {
m_modp->addStmtp(new AstAssignVarScope(
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::READ)));
AstNode* nodebp = exprvarrefp->varp();
nodep->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep->fileline());
@ -344,8 +346,8 @@ private:
// 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)));
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::READ)));
AstNode* nodebp = exprvarrefp->varp();
nodep->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep->fileline());

View File

@ -76,17 +76,17 @@ private:
if (nodep->modVarp()->isInoutish()) {
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
} else if (nodep->modVarp()->isWritable()) {
AstNode* rhsp
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
AstNode* rhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
m_cellp->name(), VAccess::READ);
AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
m_cellp->addNextHere(assp);
} else if (nodep->modVarp()->isNonOutput()) {
// Don't bother moving constants now,
// we'll be pushing the const down to the cell soon enough.
AstNode* assp = new AstAssignW(
exprp->fileline(),
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
exprp);
AstNode* assp = new AstAssignW(exprp->fileline(),
new AstVarXRef(exprp->fileline(), nodep->modVarp(),
m_cellp->name(), VAccess::WRITE),
exprp);
m_cellp->addNextHere(assp);
if (debug() >= 9) assp->dumpTree(cout, " _new: ");
} else if (nodep->modVarp()->isIfaceRef()
@ -96,8 +96,8 @@ private:
IfaceRefDType))) {
// 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);
AstNode* lhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
m_cellp->name(), VAccess::READ);
const AstVarRef* refp = VN_CAST(exprp, VarRef);
const AstVarXRef* xrefp = VN_CAST(exprp, VarXRef);
UASSERT_OBJ(refp || xrefp, exprp,
@ -379,8 +379,9 @@ private:
}
string index = AstNode::encodeNumber(constp->toSInt());
AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef);
AstVarXRef* newp = new AstVarXRef(
nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", true);
AstVarXRef* newp = new AstVarXRef(nodep->fileline(),
varrefp->name() + "__BRA__" + index + "__KET__",
"", VAccess::WRITE);
newp->dtypep(nodep->modVarp()->dtypep());
newp->packagep(varrefp->packagep());
arrselp->addNextHere(newp);
@ -438,7 +439,8 @@ private:
}
if (!varrefp) { newp->exprp()->v3error("Unexpected connection to arrayed port"); }
string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__";
AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", true);
AstVarXRef* newVarXRefp
= new AstVarXRef(nodep->fileline(), newname, "", VAccess::WRITE);
newVarXRefp->varp(newp->modVarp());
newp->exprp()->unlinkFrBack()->deleteTree();
newp->exprp(newVarXRefp);
@ -553,18 +555,19 @@ public:
" direct one-to-one connection (without any expression)");
} else if (pinVarp->isWritable()) {
// See also V3Inst
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, VAccess::READ);
UINFO(5, "pinRecon width " << pinVarp->width() << " >? " << rhsp->width() << " >? "
<< pinexprp->width() << endl);
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true));
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, VAccess::WRITE));
AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp);
} else {
// V3 width should have range/extended to make the widths correct
assignp = new AstAssignW(pinp->fileline(),
new AstVarRef(pinp->fileline(), newvarp, true), pinexprp);
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, false));
new AstVarRef(pinp->fileline(), newvarp, VAccess::WRITE),
pinexprp);
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, VAccess::READ));
}
if (assignp) cellp->addNextHere(assignp);
// if (debug()) { pinp->dumpTree(cout, "- out:"); }

View File

@ -48,7 +48,7 @@ public:
private:
static Singleton& s() {
static Singleton s_s;
static Singleton s_s; // LCOV_EXCL_BR_LINE
return s_s;
}
};

View File

@ -300,7 +300,7 @@ private:
//
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
m_sideEffect = true; // $sscanf etc may have RHS vars that are lvalues
m_lifep->complexAssign(vscp);
} else {

View File

@ -58,7 +58,7 @@ private:
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (AstVarScope* newvscp = reinterpret_cast<AstVarScope*>(vscp->user4p())) {
UINFO(9, " Replace " << nodep << " to " << newvscp << endl);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@ -284,7 +284,7 @@ private:
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
LifeLocation loc(m_execMTaskp, ++m_sequence);
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
m_writes[vscp].insert(loc);
} else {
m_reads[vscp].insert(loc);

View File

@ -1128,6 +1128,7 @@ class LinkDotFindVisitor : public AstNVisitor {
AstVar* newp
= new AstVar(nodep->fileline(), AstVarType(AstVarType::GPARAM),
nodep->name(), nodep);
newp->combineType(nodep);
string svalue = v3Global.opt.parameter(nodep->name());
if (AstNode* valuep
= AstConst::parseParamLiteral(nodep->fileline(), svalue)) {
@ -1960,8 +1961,18 @@ private:
m_ds.m_dotp = nodep; // Always, not just at start
m_ds.m_dotPos = DP_SCOPE;
// m_ds.m_dotText communicates the cell prefix between stages
if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) {
if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "this") {
VSymEnt* classSymp = m_ds.m_dotSymp;
do {
classSymp = classSymp->fallbackp();
} while (classSymp && !VN_IS(classSymp->nodep(), Class));
m_ds.m_dotSymp = classSymp;
if (!classSymp) {
nodep->v3error("'this' used outside class");
m_ds.m_dotErr = true;
}
} else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) {
// m_ds.m_dotText communicates the cell prefix between stages
// if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in
// dotted reference"); m_ds.m_dotErr=true; }
m_ds.m_dotPos = DP_PACKAGE;
@ -2018,21 +2029,14 @@ private:
// Generally resolved during Primay, but might be at param time under AstUnlinkedRef
UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep,
"ParseRefs should no longer exist");
if (nodep->name() == "this") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: this");
} else if (nodep->name() == "super") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
}
if (nodep->name() == "super") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); }
DotStates lastStates = m_ds;
bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
if (start) {
m_ds.init(m_curSymp);
// Note m_ds.m_dot remains nullptr; this is a reference not under a dot
}
if (nodep->name() == "this") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: this");
m_ds.m_dotErr = true;
} else if (nodep->name() == "super") {
if (nodep->name() == "super") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
m_ds.m_dotErr = true;
}
@ -2132,7 +2136,7 @@ private:
m_ds.m_dotPos = DP_SCOPE;
UINFO(9, " cell -> iface varref " << foundp->nodep() << endl);
AstNode* newp
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false);
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, VAccess::READ);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(cellp->modp(), NotFoundModule)) {
@ -2150,7 +2154,7 @@ private:
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);
AstNode* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (allowVar) {
@ -2158,7 +2162,7 @@ private:
if (m_ds.m_dotText != "") {
AstVarXRef* refp
= new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText,
false); // lvalue'ness computed later
VAccess::READ); // lvalue'ness computed later
refp->varp(varp);
if (varp->attrSplitVar()) {
refp->v3warn(
@ -2188,8 +2192,9 @@ private:
newp = refp;
}
} else {
AstVarRef* refp = new AstVarRef(nodep->fileline(), varp,
false); // lvalue'ness computed later
AstVarRef* refp
= new AstVarRef(nodep->fileline(), varp,
VAccess::READ); // lvalue'ness computed later
refp->packagep(foundp->packagep());
newp = refp;
}
@ -2224,7 +2229,7 @@ private:
m_ds.m_dotPos = DP_SCOPE;
ok = true;
AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp);
AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false);
AstVarRef* refp = new AstVarRef(varp->fileline(), varp, VAccess::READ);
nodep->replaceWith(refp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
@ -2274,7 +2279,8 @@ private:
if (checkImplicit) {
// Create if implicit, and also if error (so only complain once)
// Else if a scope is allowed, making a signal won't help error cascade
AstVarRef* newp = new AstVarRef(nodep->fileline(), nodep->name(), false);
AstVarRef* newp
= new AstVarRef(nodep->fileline(), nodep->name(), VAccess::READ);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err);
@ -2293,7 +2299,7 @@ private:
UINFO(9, " linkVarRef se" << cvtToHex(m_curSymp) << " n=" << nodep << endl);
UASSERT_OBJ(m_curSymp, nodep, "nullptr lookup symbol table");
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : nullptr) {
if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr) {
nodep->varp(varp);
// Generally set by parse, but might be an import
nodep->packagep(foundp->packagep());
@ -2333,7 +2339,7 @@ private:
okSymp); // Maybe nullptr
if (!m_statep->forScopeCreation()) {
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : nullptr;
AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr;
nodep->varp(varp);
UINFO(7, " Resolved " << nodep << endl); // Also prints varp
if (!nodep->varp()) {
@ -2349,7 +2355,7 @@ private:
if (!m_statep->forPrearray() && !m_statep->forScopeCreation()) {
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
AstVarRef* newrefp
= new AstVarRef(nodep->fileline(), nodep->varp(), nodep->lvalue());
= new AstVarRef(nodep->fileline(), nodep->varp(), nodep->access());
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@ -2373,7 +2379,7 @@ private:
nodep->varp(vscp->varp());
nodep->varScopep(vscp);
UINFO(7, " Resolved " << nodep << endl); // Also prints taskp
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->lvalue());
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->access());
nodep->replaceWith(newvscp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
UINFO(9, " new " << newvscp << endl); // Also prints taskp

View File

@ -199,30 +199,33 @@ private:
// Define what operation will we be doing
AstNode* operp;
if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) {
operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp);
operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp);
} else {
operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp);
operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp);
}
if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) {
// PreAdd/PreSub operations
// Immediately after declaration - increment it by one
m_insStmtp->addHereThisAsNext(new AstAssign(fl, new AstVarRef(fl, varp, true), operp));
m_insStmtp->addHereThisAsNext(
new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE), operp));
// Immediately after incrementing - assign it to the original variable
m_insStmtp->addHereThisAsNext(new AstAssign(
fl, new AstVarRef(fl, varrefp->varp(), true), new AstVarRef(fl, varp, false)));
m_insStmtp->addHereThisAsNext(
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), VAccess::WRITE),
new AstVarRef(fl, varp, VAccess::READ)));
} else {
// PostAdd/PostSub operations
// assign the original variable to the temporary one
m_insStmtp->addHereThisAsNext(new AstAssign(
fl, new AstVarRef(fl, varp, true), new AstVarRef(fl, varrefp->varp(), false)));
m_insStmtp->addHereThisAsNext(
new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE),
new AstVarRef(fl, varrefp->varp(), VAccess::READ)));
// Increment the original variable by one
m_insStmtp->addHereThisAsNext(
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), true), operp));
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), VAccess::WRITE), operp));
}
// Replace the node with the temporary
nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, true));
nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, VAccess::WRITE));
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstPreAdd* nodep) override { prepost_visit(nodep); }

View File

@ -153,15 +153,15 @@ private:
nodep->findSigned32DType());
varp->usedLoopIdx(true);
m_modp->addStmtp(varp);
AstNode* initsp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, true), countp);
AstNode* initsp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), countp);
AstNode* decp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE),
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::READ),
new AstConst(nodep->fileline(), 1)));
AstNode* zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);
AstNode* condp
= new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), zerosp);
AstNode* condp = new AstGtS(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, VAccess::READ), zerosp);
AstNode* bodysp = nodep->bodysp();
if (bodysp) bodysp->unlinkFrBackWithNext();
AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp);
@ -213,7 +213,7 @@ private:
// Set output variable to return value
nodep->addPrev(new AstAssign(
nodep->fileline(),
new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), true),
new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), VAccess::WRITE),
nodep->lhsp()->unlinkFrBackWithNext()));
}
// Jump to the end of the function call

View File

@ -45,9 +45,9 @@ private:
// Result handing
virtual void visit(AstNodeVarRef* nodep) override {
// VarRef: LValue its reference
if (m_setRefLvalue) nodep->lvalue(true);
if (m_setRefLvalue) nodep->access(VAccess::WRITE);
if (nodep->varp()) {
if (nodep->lvalue() && !m_ftaskp && nodep->varp()->isReadOnly()) {
if (nodep->access().isWrite() && !m_ftaskp && nodep->varp()->isReadOnly()) {
nodep->v3warn(ASSIGNIN,
"Assigning to input/const variable: " << nodep->prettyNameQ());
}
@ -60,7 +60,7 @@ private:
if (nodep->modVarp() && nodep->modVarp()->isWritable()) {
// When the varref's were created, we didn't know the I/O state
// Now that we do, and it's from a output, we know it's a lvalue
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateChildren(nodep);
m_setRefLvalue = false;
} else {
@ -70,7 +70,7 @@ private:
virtual void visit(AstNodeAssign* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
iterateAndNextNull(nodep->rhsp());
@ -79,7 +79,7 @@ private:
virtual void visit(AstFOpen* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
m_setRefLvalue = false;
iterateAndNextNull(nodep->filenamep());
@ -89,7 +89,7 @@ private:
virtual void visit(AstFOpenMcd* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
m_setRefLvalue = false;
iterateAndNextNull(nodep->filenamep());
@ -98,14 +98,14 @@ private:
virtual void visit(AstFClose* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
}
}
virtual void visit(AstFError* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
iterateAndNextNull(nodep->strp());
}
@ -113,21 +113,21 @@ private:
virtual void visit(AstFFlush* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
}
}
virtual void visit(AstFGetC* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
}
}
virtual void visit(AstFGetS* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
iterateAndNextNull(nodep->strgp());
}
@ -135,7 +135,7 @@ private:
virtual void visit(AstFRead* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->memp());
iterateAndNextNull(nodep->filep());
}
@ -143,7 +143,7 @@ private:
virtual void visit(AstFScanF* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
iterateAndNextNull(nodep->exprsp());
}
@ -151,14 +151,14 @@ private:
virtual void visit(AstFUngetC* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
}
}
virtual void visit(AstSScanF* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->exprsp());
}
}
@ -170,7 +170,7 @@ private:
virtual void visit(AstReadMem* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->memp());
m_setRefLvalue = false;
iterateAndNextNull(nodep->filenamep());
@ -183,14 +183,14 @@ private:
{
m_setRefLvalue = false;
iterateAndNextNull(nodep->searchp());
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->outp());
}
}
virtual void visit(AstSFormat* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
iterateAndNextNull(nodep->fmtp());
@ -202,7 +202,7 @@ private:
m_setRefLvalue = false;
iterateAndNextNull(nodep->lhsp());
iterateAndNextNull(nodep->rhsp());
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->thsp());
}
}
@ -260,7 +260,7 @@ private:
if (const AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO()) {
if (portp->isWritable()) {
m_setRefLvalue = true;
m_setRefLvalue = VAccess::WRITE;
iterate(pinp);
m_setRefLvalue = false;
} else {

View File

@ -233,9 +233,10 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
varp->trace(false);
}
AstPin* pinp
= new AstPin(oldvarp->fileline(), 0, varp->name(),
new AstVarRef(varp->fileline(), varp, oldvarp->isWritable()));
AstPin* pinp = new AstPin(
oldvarp->fileline(), 0, varp->name(),
new AstVarRef(varp->fileline(), varp,
oldvarp->isWritable() ? VAccess::WRITE : VAccess::READ));
// Skip length and width comp; we know it's a direct assignment
pinp->modVarp(oldvarp);
cellp->addPinsp(pinp);

View File

@ -226,9 +226,9 @@ private:
} else if (VN_IS(m_modp, Class)) {
// 2. Class member init become initials (as might call functions)
// later move into class constructor
nodep->addNextHere(
new AstInitial(fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
nodep->valuep()->unlinkFrBack())));
nodep->addNextHere(new AstInitial(
fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), VAccess::WRITE),
nodep->valuep()->unlinkFrBack())));
} else if (!m_ftaskp && nodep->isNonOutput()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Default value on module input: "
<< nodep->prettyNameQ());
@ -239,11 +239,13 @@ private:
FileLine* newfl = new FileLine(fl);
newfl->warnOff(V3ErrorCode::PROCASSWIRE, true);
nodep->addNextHere(new AstInitial(
newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true),
nodep->valuep()->unlinkFrBack())));
newfl,
new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), VAccess::WRITE),
nodep->valuep()->unlinkFrBack())));
} // 4. Under blocks, it's an initial value to be under an assign
else {
nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
nodep->addNextHere(new AstAssign(fl,
new AstVarRef(fl, nodep->name(), VAccess::WRITE),
nodep->valuep()->unlinkFrBack()));
}
}
@ -333,7 +335,8 @@ private:
// lvalue is true, because we know we have a verilator public_flat_rw
// but someday we may be more general
bool lvalue = m_varp->isSigUserRWPublic();
nodep->addStmtp(new AstVarRef(nodep->fileline(), m_varp, lvalue));
nodep->addStmtp(
new AstVarRef(nodep->fileline(), m_varp, lvalue ? VAccess::WRITE : VAccess::READ));
}
}
@ -445,7 +448,8 @@ private:
new AstConst(fl, dimension));
AstNode* stmtsp = varp;
// Assign left-dimension into the loop var:
stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp));
stmtsp->addNext(
new AstAssign(fl, new AstVarRef(fl, varp->name(), VAccess::WRITE), leftp));
// This will turn into a constant bool for static arrays
AstNode* notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0));
// This will turn into a bool constant, indicating whether
@ -454,14 +458,15 @@ private:
AstNode* comparep = new AstCond(
fl, countupp->cloneTree(true),
// Left increments up to right
new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)),
new AstLte(fl, new AstVarRef(fl, varp->name(), VAccess::READ),
rightp->cloneTree(true)),
// Left decrements down to right
new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp));
new AstGte(fl, new AstVarRef(fl, varp->name(), VAccess::READ), rightp));
// This will reduce to comparep for static arrays
AstNode* condp = new AstAnd(fl, notemptyp, comparep);
AstNode* incp = new AstAssign(
fl, new AstVarRef(fl, varp->name(), true),
new AstAdd(fl, new AstVarRef(fl, varp->name(), false),
fl, new AstVarRef(fl, varp->name(), VAccess::WRITE),
new AstAdd(fl, new AstVarRef(fl, varp->name(), VAccess::READ),
new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1))));
stmtsp->addNext(new AstWhile(fl, condp, newp, incp));
newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true);

View File

@ -183,9 +183,10 @@ private:
}
addwherep->addNext(newvarp);
sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, false));
sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, VAccess::READ));
AstAssignW* assignp = new AstAssignW(
sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, true), sensp);
sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, VAccess::WRITE),
sensp);
addwherep->addNext(assignp);
}
} else { // Old V1995 sensitivity list; we'll probably mostly ignore
@ -490,7 +491,8 @@ private:
varoutp = varp;
// Tie off
m_modp->addStmtp(new AstAssignW(
varp->fileline(), new AstVarRef(varp->fileline(), varp, true),
varp->fileline(),
new AstVarRef(varp->fileline(), varp, VAccess::WRITE),
new AstConst(varp->fileline(), AstConst::LogicFalse())));
} else {
varp->v3error("Only inputs and outputs are allowed in udp modules");

View File

@ -166,7 +166,7 @@ private:
for (; nodep; nodep = nodep->nextp()) {
if (VN_IS(nodep, NodeAssign)) {
if (AstVarRef* varrefp = VN_CAST(VN_CAST(nodep, NodeAssign)->lhsp(), VarRef)) {
UASSERT_OBJ(varrefp->lvalue(), varrefp, "LHS assignment not lvalue");
UASSERT_OBJ(varrefp->access().isWrite(), varrefp, "LHS assignment not lvalue");
if (!varrefp->varp()->user4p()) {
UINFO(4, " FuncAsn " << varrefp << endl);
varrefp->varp()->user4p(varrefp);

View File

@ -80,7 +80,7 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (!m_mergeable) return;
// Clear if it's an LValue referencing a marked variable
if (nodep->lvalue() && nodep->varp()->user1()) {
if (nodep->access().isWrite() && nodep->varp()->user1()) {
clearMergeable(nodep, "might modify condition");
}
}

View File

@ -1267,7 +1267,7 @@ V3Number& V3Number::opXor(const V3Number& lhs, const V3Number& rhs) {
setBit(bit, 1);
} else if (lhs.bitIs0(bit) && rhs.bitIs1(bit)) {
setBit(bit, 1);
} else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) {
} else if (lhs.bitIsXZ(bit) || rhs.bitIsXZ(bit)) {
setBit(bit, 'x');
}
// else zero

View File

@ -431,15 +431,6 @@ string V3Options::allArgsStringForHierBlock(bool forTop) const {
//######################################################################
// File searching
bool V3Options::fileStatDir(const string& filename) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
struct stat sstat; // Stat information
int err = stat(filename.c_str(), &sstat);
if (err != 0) return false;
if (!S_ISDIR(sstat.st_mode)) return false;
return true;
}
bool V3Options::fileStatNormal(const string& filename) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
struct stat sstat; // Stat information
@ -513,7 +504,7 @@ string V3Options::filePathCheckOneDir(const string& modname, const string& dirna
int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) const {
if (opt == "Mdir" || opt == "clk" || opt == "f" || opt == "j" || opt == "l2-name"
|| opt == "mod-prefix" || opt == "prefix" || opt == "protect-lib" || opt == "protect-key"
|| opt == "top-module" || opt == "v") {
|| opt == "threads" || opt == "top-module" || opt == "v") {
return 2;
}
if (opt == "build" || (!forTop && (opt == "cc" || opt == "exe" || opt == "sc"))
@ -651,9 +642,9 @@ string V3Options::getenvSYSTEMC_ARCH() {
struct utsname uts;
uname(&uts);
string sysname = VString::downcase(uts.sysname); // aka 'uname -s'
if (VString::wildmatch(sysname.c_str(), "*solaris*")) {
if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*solaris*"))) {
var = "gccsparcOS5";
} else if (VString::wildmatch(sysname.c_str(), "*cygwin*")) {
} else if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*cygwin*"))) {
var = "cygwin";
} else {
var = "linux";
@ -1013,6 +1004,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
m_debugCheck = flag;
} else if (onoff(sw, "-debug-collision", flag /*ref*/)) { // Undocumented
m_debugCollision = flag;
} else if (onoff(sw, "-debug-emitv", flag /*ref*/)) { // Undocumented
m_debugEmitV = flag;
} else if (onoff(sw, "-debug-exit-parse", flag /*ref*/)) { // Undocumented
m_debugExitParse = flag;
} else if (onoff(sw, "-debug-exit-uvm", flag /*ref*/)) { // Undocumented
@ -1594,6 +1587,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
string oline;
// cppcheck-suppress StlMissingComparison
char lastch = ' ';
bool space_begin = true; // At beginning or leading spaces only
for (string::const_iterator pos = line.begin(); pos != line.end(); lastch = *pos++) {
if (inCmt) {
if (*pos == '*' && *(pos + 1) == '/') {
@ -1603,11 +1597,15 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
} else if (*pos == '/' && *(pos + 1) == '/'
&& (pos == line.begin() || isspace(lastch))) { // But allow /file//path
break; // Ignore to EOL
} else if (*pos == '#' && space_begin) { // Only # at [spaced] begin of line
break; // Ignore to EOL
} else if (*pos == '/' && *(pos + 1) == '*') {
inCmt = true;
space_begin = false;
// cppcheck-suppress StlMissingComparison
++pos;
} else {
if (!isspace(*pos)) space_begin = false;
oline += *pos;
}
}

View File

@ -265,6 +265,7 @@ private:
bool m_coverageUser = false; // main switch: --coverage-func
bool m_debugCheck = false; // main switch: --debug-check
bool m_debugCollision = false; // main switch: --debug-collision
bool m_debugEmitV = false; // main switch: --debug-emitv
bool m_debugExitParse = false; // main switch: --debug-exit-parse
bool m_debugExitUvm = false; // main switch: --debug-exit-uvm
bool m_debugLeak = true; // main switch: --debug-leak
@ -469,6 +470,7 @@ public:
bool coverageUser() const { return m_coverageUser; }
bool debugCheck() const { return m_debugCheck; }
bool debugCollision() const { return m_debugCollision; }
bool debugEmitV() const { return m_debugEmitV; }
bool debugExitParse() const { return m_debugExitParse; }
bool debugExitUvm() const { return m_debugExitUvm; }
bool debugLeak() const { return m_debugLeak; }
@ -669,7 +671,6 @@ public:
const string& errmsg);
void filePathLookedMsg(FileLine* fl, const string& modname);
V3LangCode fileLanguage(const string& filename);
static bool fileStatDir(const string& filename);
static bool fileStatNormal(const string& filename);
static void fileNfsFlush(const string& filename);

View File

@ -1026,7 +1026,8 @@ private:
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
if (m_inSenTree) {
// Add CLOCK dependency... This is a root of the tree we'll trace
UASSERT_OBJ(!nodep->lvalue(), nodep, "How can a sensitivity be setting a var?");
UASSERT_OBJ(!nodep->access().isWrite(), nodep,
"How can a sensitivity be setting a var?");
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD);
varVxp->isClock(true);
new OrderEdge(&m_graph, varVxp, m_activeSenVxp, WEIGHT_MEDIUM);
@ -1036,7 +1037,7 @@ private:
// We don't want to add extra edges if the logic block has many usages of same var
bool gen = false;
bool con = false;
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
gen = !(varscp->user4() & VU_GEN);
} else {
con = !(varscp->user4() & VU_CON);

View File

@ -535,7 +535,7 @@ private:
nodep->addNext(new AstInitial(
nodep->fileline(),
new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
nodep->valuep()->cloneTree(true))));
if (m_ftaskp) {
// We put the initial in wrong place under a function. We

View File

@ -83,7 +83,7 @@ AstNode* V3ParseGrammar::argWrapList(AstNode* nodep) {
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) {
return new AstAssignW(
fileline, new AstVarRef(fileline, name, true),
fileline, new AstVarRef(fileline, name, VAccess::WRITE),
new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0")));
}

View File

@ -595,11 +595,11 @@ string V3PreLex::cleanDbgStrg(const string& in) {
}
void V3PreLex::unused() {
if (0) {
if (VL_UNCOVERABLE(false)) { // LCOV_EXCL_START
// Prevent unused warnings
yy_top_state();
yyerror((char*)"");
}
} // LCOV_EXCL_STOP
}
/*###################################################################

View File

@ -26,6 +26,7 @@
#include "V3PreShell.h"
#include "V3String.h"
#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <stack>
@ -540,10 +541,7 @@ void V3PreProcImp::unputString(const string& strg) {
}
void V3PreProcImp::unputDefrefString(const string& strg) {
int multiline = 0;
for (size_t i = 0; i < strg.length(); i++) {
if (strg[i] == '\n') multiline++;
}
int multiline = std::count(strg.begin(), strg.end(), '\n');
unputString(strg);
// A define that inserts multiple newlines are really attributed to one source line,
// so temporarily don't increment lineno.
@ -1320,7 +1318,7 @@ int V3PreProcImp::getStateToken() {
// multiline "..." without \ escapes.
// The spec is silent about this either way; simulators vary
string::size_type pos;
while ((pos = out.find('\n')) != string::npos) out.replace(pos, 1, " ");
std::replace(out.begin(), out.end(), '\n', ' ');
unputString(string("\"") + out + "\"");
statePop();
goto next_tok;
@ -1403,7 +1401,10 @@ int V3PreProcImp::getStateToken() {
if (m_off) {
goto next_tok;
} else {
return VP_TEXT;
// We want final text of `name, but that would cause
// recursion, so use a special character to get it through
unputDefrefString(string("`\032") + name);
goto next_tok;
}
} else {
string params = defParams(name);

View File

@ -58,7 +58,7 @@ private:
}
virtual void visit(AstVarRef* nodep) override {
// it's LHS var is used so need a deep temporary
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
nodep->varp()->user4(true);
} else {
if (nodep->varp()->user4()) {
@ -173,11 +173,11 @@ private:
AstVar* varp = getBlockTemp(nodep);
if (noSubst) varp->noSubst(true); // Do not remove varrefs to this in V3Const
// Replace node tree with reference to var
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, false);
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
linker.relink(newp);
// Put assignment before the referencing statement
AstAssign* assp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, true), nodep);
AstAssign* assp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep);
insertBeforeStmt(assp);
if (debug() > 8) assp->dumpTree(cout, "deepou:");
nodep->user1(true); // Don't add another assignment

View File

@ -82,7 +82,7 @@ private:
FileLine* fl = nodep->fileline();
// Need to know the existence of clk before createSvFile()
m_hasClk = checkIfClockExists(nodep);
createSvFile(fl);
createSvFile(fl, nodep);
createCppFile(fl);
iterateChildren(nodep);
@ -124,7 +124,7 @@ private:
addComment(txtp, fl, "Evaluates the secret module's final process");
}
void createSvFile(FileLine* fl) {
void createSvFile(FileLine* fl, AstNodeModule* modp) {
// Comments
AstTextBlock* txtp = new AstTextBlock(fl);
addComment(txtp, fl, "Wrapper module for DPI protected library");
@ -135,18 +135,28 @@ private:
"See instructions in your simulator for how"
" to use DPI libraries\n");
bool timescaleShown = false;
if (v3Global.opt.hierChild() && !modp->timeunit().isNone()) {
// Emit timescale for hierarhical verilation
timescaleShown = true;
txtp->addText(fl, string("`timescale ") + modp->timeunit().ascii() + "/"
+ v3Global.rootp()->timeprecision().ascii() + "\n\n");
}
// Module declaration
m_modPortsp = new AstTextBlock(fl, "module " + m_libName + " (\n", false, true);
txtp->addNodep(m_modPortsp);
txtp->addText(fl, ");\n\n");
// Timescale
addComment(txtp, fl,
"Precision of submodule"
" (commented out to avoid requiring timescale on all modules)");
addComment(txtp, fl, string("timeunit ") + v3Global.rootp()->timeunit().ascii() + ";");
addComment(txtp, fl,
string("timeprecision ") + v3Global.rootp()->timeprecision().ascii() + ";\n");
if (!timescaleShown) {
addComment(txtp, fl,
"Precision of submodule"
" (commented out to avoid requiring timescale on all modules)");
addComment(txtp, fl, string("timeunit ") + v3Global.rootp()->timeunit().ascii() + ";");
addComment(txtp, fl,
string("timeprecision ") + v3Global.rootp()->timeprecision().ascii()
+ ";\n");
}
// DPI declarations
hashComment(txtp, fl);

View File

@ -99,13 +99,13 @@ private:
FileLine* fl = bodyp->fileline();
AstVar* itp = findCreateVarTemp(fl, m_mgCfuncp);
AstNode* initp = new AstAssign(fl, new AstVarRef(fl, itp, true),
AstNode* initp = new AstAssign(fl, new AstVarRef(fl, itp, VAccess::WRITE),
new AstConst(fl, m_mgIndexLo));
AstNode* condp
= new AstLte(fl, new AstVarRef(fl, itp, false), new AstConst(fl, m_mgIndexHi));
AstNode* condp = new AstLte(fl, new AstVarRef(fl, itp, VAccess::READ),
new AstConst(fl, m_mgIndexHi));
AstNode* incp = new AstAssign(
fl, new AstVarRef(fl, itp, true),
new AstAdd(fl, new AstConst(fl, 1), new AstVarRef(fl, itp, false)));
fl, new AstVarRef(fl, itp, VAccess::WRITE),
new AstAdd(fl, new AstConst(fl, 1), new AstVarRef(fl, itp, VAccess::READ)));
AstWhile* whilep = new AstWhile(fl, condp, nullptr, incp);
initp->addNext(whilep);
bodyp->replaceWith(initp);
@ -113,11 +113,11 @@ private:
// Replace constant index with new loop index
AstNode* lbitp = m_mgSelLp->bitp();
lbitp->replaceWith(new AstVarRef(fl, itp, false));
lbitp->replaceWith(new AstVarRef(fl, itp, VAccess::READ));
VL_DO_DANGLING(lbitp->deleteTree(), lbitp);
if (m_mgSelRp) { // else constant and no replace
AstNode* rbitp = m_mgSelRp->bitp();
rbitp->replaceWith(new AstVarRef(fl, itp, false));
rbitp->replaceWith(new AstVarRef(fl, itp, VAccess::READ));
VL_DO_DANGLING(rbitp->deleteTree(), lbitp);
}
if (debug() >= 9) initp->dumpTree(cout, "-new: ");

View File

@ -401,7 +401,7 @@ private:
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), UnpackArrayDType)
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), StructDType))
clearOptimizable(nodep, "Array references/not basic");
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
if (m_inDlyAssign) {
if (!(vscp->user1() & VU_LVDLY)) {
vscp->user1(vscp->user1() | VU_LVDLY);
@ -433,7 +433,7 @@ private:
}
}
if (!m_checkOnly && optimizable()) { // simulating
UASSERT_OBJ(!nodep->lvalue(), nodep,
UASSERT_OBJ(!nodep->access().isWrite(), nodep,
"LHS varref should be handled in AstAssign visitor.");
{
// Return simulation value - copy by reference instead of value for speed

View File

@ -383,7 +383,7 @@ protected:
SplitVarStdVertex* vstdp = reinterpret_cast<SplitVarStdVertex*>(vscp->user1p());
// SPEEDUP: We add duplicate edges, that should be fixed
if (m_inDly && nodep->lvalue()) {
if (m_inDly && nodep->access().isWrite()) {
UINFO(4, " VARREFDLY: " << nodep << endl);
// Delayed variable is different from non-delayed variable
if (!vscp->user2p()) {
@ -398,7 +398,7 @@ protected:
new SplitLVEdge(&m_graph, vpostp, vxp);
}
} else { // Nondelayed assignment
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
// Non-delay; need to maintain existing ordering
// with all consumers of the signal
UINFO(4, " VARREFLV: " << nodep << endl);

View File

@ -49,7 +49,7 @@ private:
// METHODS
virtual void visit(AstVarRef* nodep) override {
if (nodep->lvalue() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) {
if (nodep->access().isWrite() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) {
m_splitVscp = nodep->varScopep();
}
}
@ -76,7 +76,7 @@ private:
// METHODS
virtual void visit(AstVarRef* nodep) override {
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
if (nodep->varScopep() == m_splitVscp) {
UINFO(6, " CL VAR " << nodep << endl);
m_matches = true;
@ -183,10 +183,7 @@ private:
public:
// CONSTRUCTORS
explicit SplitAsVisitor(AstNetlist* nodep) {
AstNode::user1ClearTree(); // user1p() used on entire tree
iterate(nodep);
}
explicit SplitAsVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~SplitAsVisitor() override {
V3Stats::addStat("Optimizations, isolate_assignments blocks", m_statSplits);
}

View File

@ -239,7 +239,7 @@ class UnpackRef {
int m_index; // for ArraySel
int m_msb; // for SliceSel
int m_lsb; // for SliceSel
bool m_lvalue;
VAccess m_access;
bool m_ftask; // true if the reference is in function/task. false if in module.
public:
UnpackRef(AstNode* stmtp, AstVarRef* nodep, bool ftask)
@ -248,23 +248,24 @@ public:
, m_index{-1}
, m_msb{0}
, m_lsb{1}
, m_lvalue{nodep->lvalue()}
, m_access{nodep->access()}
, m_ftask{ftask} {}
UnpackRef(AstNode* stmtp, AstArraySel* nodep, int idx, bool lvalue, bool ftask)
UnpackRef(AstNode* stmtp, AstArraySel* nodep, int idx, const VAccess& access, bool ftask)
: m_contextp{stmtp}
, m_nodep{nodep}
, m_index{idx}
, m_msb{0}
, m_lsb{1}
, m_lvalue{lvalue}
, m_access{access}
, m_ftask{ftask} {}
UnpackRef(AstNode* stmtp, AstSliceSel* nodep, int msb, int lsb, bool lvalue, bool ftask)
UnpackRef(AstNode* stmtp, AstSliceSel* nodep, int msb, int lsb, const VAccess& access,
bool ftask)
: m_contextp{stmtp}
, m_nodep{nodep}
, m_index{msb == lsb ? msb : -1} // Equivalent to ArraySel
, m_msb{msb}
, m_lsb{lsb}
, m_lvalue{lvalue}
, m_access{access}
, m_ftask{ftask} {}
AstNode* nodep() const { return m_nodep; }
bool isSingleRef() const {
@ -275,7 +276,7 @@ public:
return m_index;
}
AstNode* context() const { return m_contextp; }
bool lvalue() const { return m_lvalue; }
VAccess access() const { return m_access; }
bool ftask() const { return m_ftask; }
bool operator<(const UnpackRef& other) const {
return AstNodeComparator()(m_nodep, other.m_nodep);
@ -308,11 +309,11 @@ public:
}
// Register the location where a variable is used.
bool tryAdd(AstNode* context, AstVarRef* refp, AstArraySel* selp, int idx, bool ftask) {
return addCore(refp, UnpackRef(context, selp, idx, refp->lvalue(), ftask));
return addCore(refp, UnpackRef(context, selp, idx, refp->access(), ftask));
}
bool tryAdd(AstNode* context, AstVarRef* refp, AstSliceSel* selp, int msb, int lsb,
bool ftask) {
return addCore(refp, UnpackRef(context, selp, msb, lsb, refp->lvalue(), ftask));
return addCore(refp, UnpackRef(context, selp, msb, lsb, refp->access(), ftask));
}
bool tryAdd(AstNode* context, AstVarRef* refp, bool ftask) {
return addCore(refp, UnpackRef(context, refp, ftask));
@ -434,8 +435,8 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
m_refsForPackedSplit[m_modp].add(varp);
return varp;
}
AstVarRef* newVarRef(FileLine* fl, AstVar* varp, bool lvalue) {
AstVarRef* refp = new AstVarRef(fl, varp, lvalue);
AstVarRef* newVarRef(FileLine* fl, AstVar* varp, const VAccess& access) {
AstVarRef* refp = new AstVarRef(fl, varp, access);
UASSERT_OBJ(m_modp, refp, "Must not nullptr");
m_refsForPackedSplit[m_modp].add(refp);
return refp;
@ -617,9 +618,11 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
= (context && VN_IS(context, NodeFTaskRef)) || (assignp && VN_IS(assignp, Assign));
for (int i = 0; i <= dtypep->msb() - dtypep->lsb(); ++i) {
AstNode* lhsp = newVarRef(nodep->fileline(), vars.at(start_idx + i), lvalue);
AstNode* rhsp = new AstArraySel(nodep->fileline(),
newVarRef(nodep->fileline(), varp, !lvalue), i);
AstNode* lhsp = newVarRef(nodep->fileline(), vars.at(start_idx + i),
lvalue ? VAccess::WRITE : VAccess::READ);
AstNode* rhsp = new AstArraySel(
nodep->fileline(),
newVarRef(nodep->fileline(), varp, !lvalue ? VAccess::WRITE : VAccess::READ), i);
AstNode* refp = lhsp;
UINFO(9, "Creating assign idx:" << i << " + " << start_idx << "\n");
if (!lvalue) std::swap(lhsp, rhsp);
@ -643,16 +646,18 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
UASSERT_OBJ(!m_contextp, m_contextp, "must be null");
setContextAndIterate(newassignp, refp);
}
return newVarRef(nodep->fileline(), varp, lvalue);
return newVarRef(nodep->fileline(), varp, lvalue ? VAccess::WRITE : VAccess::READ);
}
void connectPort(AstVar* varp, std::vector<AstVar*>& vars, AstNode* insertp) {
UASSERT_OBJ(varp->isIO(), varp, "must be port");
insertp = insertp ? toInsertPoint(insertp) : nullptr;
const bool lvalue = varp->direction().isWritable();
for (size_t i = 0; i < vars.size(); ++i) {
AstNode* nodes[]
= {new AstArraySel(varp->fileline(), newVarRef(varp->fileline(), varp, lvalue), i),
newVarRef(varp->fileline(), vars.at(i), !lvalue)};
AstNode* nodes[] = {
new AstArraySel(
varp->fileline(),
newVarRef(varp->fileline(), varp, lvalue ? VAccess::WRITE : VAccess::READ), i),
newVarRef(varp->fileline(), vars.at(i), !lvalue ? VAccess::WRITE : VAccess::READ)};
AstNode* lhsp = nodes[lvalue ? 0 : 1];
AstNode* rhsp = nodes[lvalue ? 1 : 0];
AstNodeAssign* assignp = newAssign(varp->fileline(), lhsp, rhsp, varp);
@ -702,7 +707,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
AstNode* newp = nullptr;
if (sit->isSingleRef()) {
newp = newVarRef(sit->nodep()->fileline(), vars.at(sit->index()),
sit->lvalue());
sit->access());
} else {
AstVarRef* refp = VN_CAST(sit->nodep(), VarRef);
AstUnpackArrayDType* adtypep;
@ -718,7 +723,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
lsb = adtypep->lsb();
}
AstVarRef* newrefp = createTempVar(sit->context(), refp, adtypep, varp->name(),
vars, lsb, refp->lvalue(), sit->ftask());
vars, lsb, refp->access(), sit->ftask());
newp = newrefp;
refp->varp()->addNextHere(newrefp->varp());
UINFO(3,
@ -891,9 +896,9 @@ public:
}
explicit PackedVarRef(AstVar* varp)
: m_basicp{varp->dtypep()->basicp()} {}
void append(const PackedVarRefEntry& e, bool lvalue) {
void append(const PackedVarRefEntry& e, const VAccess& access) {
UASSERT(!m_dedupDone, "cannot add after dedup()");
if (lvalue)
if (access.isWrite())
m_lhs.push_back(e);
else
m_rhs.push_back(e);
@ -981,7 +986,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
"variable in package must have been dropped beforehand.");
const AstBasicDType* basicp = refit->second.basicp();
refit->second.append(PackedVarRefEntry(nodep, basicp->lsb(), varp->width()),
nodep->lvalue());
nodep->access());
UINFO(5, varp->prettyName()
<< " Entire bit of [" << basicp->lsb() << ":+" << varp->width() << "] \n");
}
@ -1005,7 +1010,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
refit->second.append(
PackedVarRefEntry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(),
consts[1]->toUInt()),
vrefp->lvalue());
vrefp->access());
UINFO(5, varp->prettyName()
<< " [" << consts[0]->toSInt() << ":+" << consts[1]->toSInt()
<< "] lsb:" << refit->second.basicp()->lsb() << "\n");
@ -1028,8 +1033,8 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
// Extract necessary bit range from a newly created variable to meet ref
static AstNode* extractBits(const PackedVarRefEntry& ref, const SplitNewVar& var,
bool lvalue) {
AstVarRef* refp = new AstVarRef(ref.nodep()->fileline(), var.varp(), lvalue);
const VAccess access) {
AstVarRef* refp = new AstVarRef(ref.nodep()->fileline(), var.varp(), access);
if (ref.lsb() <= var.lsb() && var.msb() <= ref.msb()) { // Use the entire bits
return refp;
} else { // Use slice
@ -1052,10 +1057,12 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
}
const bool in = portp->isReadOnly();
for (size_t i = 0; i < vars.size(); ++i) {
AstNode* rhsp
= new AstSel(portp->fileline(), new AstVarRef(portp->fileline(), portp, !in),
vars[i].lsb(), vars[i].bitwidth());
AstNode* lhsp = new AstVarRef(portp->fileline(), vars[i].varp(), in);
AstNode* rhsp = new AstSel(
portp->fileline(),
new AstVarRef(portp->fileline(), portp, !in ? VAccess::WRITE : VAccess::READ),
vars[i].lsb(), vars[i].bitwidth());
AstNode* lhsp = new AstVarRef(portp->fileline(), vars[i].varp(),
in ? VAccess::WRITE : VAccess::READ);
if (!in) std::swap(lhsp, rhsp);
AstNodeAssign* assignp = newAssign(portp->fileline(), lhsp, rhsp, portp);
if (insertp) {
@ -1121,12 +1128,12 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
if (AstSenItem* senitemp = refit->backSenItemp()) {
AstNode* oldsenrefp = senitemp->sensp();
oldsenrefp->replaceWith(
new AstVarRef(senitemp->fileline(), varit->varp(), false));
new AstVarRef(senitemp->fileline(), varit->varp(), VAccess::READ));
VL_DO_DANGLING(oldsenrefp->deleteTree(), oldsenrefp);
prevp = senitemp;
inSentitivityList = true;
} else {
prevp = extractBits(*refit, *varit, lvalue);
prevp = extractBits(*refit, *varit, lvalue ? VAccess::WRITE : VAccess::READ);
}
for (int residue = refit->msb() - varit->msb(); residue > 0;
residue -= varit->bitwidth()) {
@ -1135,10 +1142,11 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
if (AstSenItem* senitemp = VN_CAST(prevp, SenItem)) {
prevp = new AstSenItem(
senitemp->fileline(), senitemp->edgeType(),
new AstVarRef(senitemp->fileline(), varit->varp(), false));
new AstVarRef(senitemp->fileline(), varit->varp(), VAccess::READ));
senitemp->addNextHere(prevp);
} else {
AstNode* bitsp = extractBits(*refit, *varit, lvalue);
AstNode* bitsp
= extractBits(*refit, *varit, lvalue ? VAccess::WRITE : VAccess::READ);
prevp = new AstConcat(refit->nodep()->fileline(), bitsp, prevp);
}
}
@ -1177,15 +1185,16 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
connectPortAndVar(vars, varp, nullptr);
} else if (varp->isTrace()) {
// Let's reuse the original variable for tracing
AstNode* rhsp
= new AstVarRef(vars.front().varp()->fileline(), vars.front().varp(), false);
AstNode* rhsp = new AstVarRef(vars.front().varp()->fileline(), vars.front().varp(),
VAccess::READ);
for (size_t i = 1; i < vars.size(); ++i) {
rhsp = new AstConcat(varp->fileline(),
new AstVarRef(varp->fileline(), vars[i].varp(), false),
rhsp);
rhsp = new AstConcat(
varp->fileline(),
new AstVarRef(varp->fileline(), vars[i].varp(), VAccess::READ), rhsp);
}
varp->addNextHere(newAssign(
varp->fileline(), new AstVarRef(varp->fileline(), varp, true), rhsp, varp));
varp->addNextHere(newAssign(varp->fileline(),
new AstVarRef(varp->fileline(), varp, VAccess::WRITE),
rhsp, varp));
} else { // the original variable is not used anymore.
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
}

View File

@ -306,7 +306,7 @@ private:
iterate(nodep->rhsp());
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
AstConst* constp = VN_CAST(nodep->rhsp(), Const);
if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->lvalue() && constp) {
if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->access().isWrite() && constp) {
// Nicely formed lvalues handled in NodeAssign
// Other lvalues handled as unknown mess in AstVarRef
int word = constp->toUInt();
@ -329,14 +329,14 @@ private:
}
virtual void visit(AstVarRef* nodep) override {
// Any variable
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
m_assignStep++;
nodep->varp()->user2(m_assignStep);
UINFO(9, " ASSIGNstep u2=" << nodep->varp()->user2() << " " << nodep << endl);
}
if (isSubstVar(nodep->varp())) {
SubstVarEntry* entryp = getEntryp(nodep);
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
UINFO(8, " ASSIGNcpx " << nodep << endl);
entryp->assignComplex();
} else if (AstNode* substp = entryp->substWhole(nodep)) {
@ -365,11 +365,7 @@ private:
public:
// CONSTRUCTORS
explicit SubstVisitor(AstNode* nodep) {
AstNode::user1ClearTree(); // user1p() used on entire tree
AstNode::user2ClearTree(); // user2p() used on entire tree
iterate(nodep);
}
explicit SubstVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~SubstVisitor() override {
V3Stats::addStat("Optimizations, Substituted temps", m_statSubsts);
for (SubstVarEntry* ip : m_entryps) {

View File

@ -108,6 +108,7 @@ public:
void operator delete(void* objp, size_t size) {}
#endif
void fallbackp(VSymEnt* entp) { m_fallbackp = entp; }
VSymEnt* fallbackp() const { return m_fallbackp; }
void parentp(VSymEnt* entp) { m_parentp = entp; }
VSymEnt* parentp() const { return m_parentp; }
void packagep(AstNodeModule* entp) { m_packagep = entp; }

View File

@ -154,7 +154,7 @@ public:
// Called by TableSimulateVisitor on each unique varref encountered
UINFO(9, " SimVARREF " << nodep << endl);
AstVarScope* vscp = nodep->varScopep();
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
m_outWidth += nodep->varp()->dtypeSkipRefp()->widthTotalBytes();
m_outVarps.push_back(vscp);
} else {
@ -255,7 +255,7 @@ private:
// First var in inVars becomes the LSB of the concat
AstNode* concatp = nullptr;
for (AstVarScope* invscp : m_inVarps) {
AstVarRef* refp = new AstVarRef(nodep->fileline(), invscp, false);
AstVarRef* refp = new AstVarRef(nodep->fileline(), invscp, VAccess::READ);
if (concatp) {
concatp = new AstConcat(nodep->fileline(), refp, concatp);
} else {
@ -263,8 +263,9 @@ private:
}
}
AstNode* stmtsp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), indexVscp, true), concatp);
AstNode* stmtsp
= new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), indexVscp, VAccess::WRITE), concatp);
return stmtsp;
}
@ -372,10 +373,11 @@ private:
// Set each output from array ref into our table
int outnum = 0;
for (AstVarScope* outvscp : m_outVarps) {
AstNode* alhsp = new AstVarRef(nodep->fileline(), outvscp, true);
AstNode* alhsp = new AstVarRef(nodep->fileline(), outvscp, VAccess::WRITE);
AstNode* arhsp = new AstArraySel(
nodep->fileline(), new AstVarRef(nodep->fileline(), m_tableVarps[outnum], false),
new AstVarRef(nodep->fileline(), indexVscp, false));
nodep->fileline(),
new AstVarRef(nodep->fileline(), m_tableVarps[outnum], VAccess::READ),
new AstVarRef(nodep->fileline(), indexVscp, VAccess::READ));
AstNode* outasnp
= (m_assignDly
? static_cast<AstNode*>(new AstAssignDly(nodep->fileline(), alhsp, arhsp))
@ -389,9 +391,10 @@ private:
outsetp = new AstIf(
nodep->fileline(),
new AstAnd(nodep->fileline(),
new AstArraySel(nodep->fileline(),
new AstVarRef(nodep->fileline(), chgVscp, false),
new AstVarRef(nodep->fileline(), indexVscp, false)),
new AstArraySel(
nodep->fileline(),
new AstVarRef(nodep->fileline(), chgVscp, VAccess::READ),
new AstVarRef(nodep->fileline(), indexVscp, VAccess::READ)),
new AstConst(nodep->fileline(), outputChgMask)),
outsetp, nullptr);
}

View File

@ -448,9 +448,9 @@ private:
AstVarScope* tempvscp
= createVarScope(portp, namePrefix + "__" + portp->shortName());
portp->user2p(tempvscp);
AstAssign* assp
= new AstAssign(pinp->fileline(), pinp,
new AstVarRef(tempvscp->fileline(), tempvscp, false));
AstAssign* assp = new AstAssign(
pinp->fileline(), pinp,
new AstVarRef(tempvscp->fileline(), tempvscp, VAccess::READ));
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ,
true); // Ok if in <= block
// Put assignment BEHIND of all other statements
@ -461,7 +461,8 @@ private:
= createVarScope(portp, namePrefix + "__" + portp->shortName());
portp->user2p(inVscp);
AstAssign* assp = new AstAssign(
pinp->fileline(), new AstVarRef(inVscp->fileline(), inVscp, true), pinp);
pinp->fileline(),
new AstVarRef(inVscp->fileline(), inVscp, VAccess::WRITE), pinp);
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ,
true); // Ok if in <= block
// Put assignment in FRONT of all other statements
@ -571,10 +572,10 @@ private:
AstVarScope* newvscp
= createVarScope(portp, namePrefix + "__" + portp->shortName());
portp->user2p(newvscp);
pinp->replaceWith(new AstVarRef(newvscp->fileline(), newvscp, true));
AstAssign* assp
= new AstAssign(pinp->fileline(), pinp,
new AstVarRef(newvscp->fileline(), newvscp, false));
pinp->replaceWith(new AstVarRef(newvscp->fileline(), newvscp, VAccess::WRITE));
AstAssign* assp = new AstAssign(
pinp->fileline(), pinp,
new AstVarRef(newvscp->fileline(), newvscp, VAccess::READ));
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ,
true); // Ok if in <= block
// Put assignment BEHIND of all other statements
@ -608,7 +609,7 @@ private:
ccallp->addArgsp(exprp);
}
if (outvscp) ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true));
if (outvscp) ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, VAccess::WRITE));
if (debug() >= 9) beginp->dumpTreeAndNext(cout, "-nitask: ");
return beginp;
@ -661,7 +662,7 @@ private:
bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, frstmt);
if (useSetWSvlv) {
AstNode* linesp = new AstText(portp->fileline(), frstmt);
linesp->addNext(new AstVarRef(portp->fileline(), portvscp, true));
linesp->addNext(new AstVarRef(portp->fileline(), portvscp, VAccess::WRITE));
linesp->addNext(new AstText(portp->fileline(), "," + frName + ");"));
return new AstCStmt(portp->fileline(), linesp);
}
@ -675,7 +676,7 @@ private:
}
}
AstNode* newp = new AstAssign(
portp->fileline(), new AstVarRef(portp->fileline(), portvscp, true),
portp->fileline(), new AstVarRef(portp->fileline(), portvscp, VAccess::WRITE),
new AstSel(portp->fileline(), new AstCMath(portp->fileline(), frstmt, cwidth, false),
0, portp->width()));
return newp;
@ -741,7 +742,8 @@ private:
outvscp->varp()->protect(false);
portp->protect(false);
AstVarRef* refp
= new AstVarRef(portp->fileline(), outvscp, portp->isWritable());
= new AstVarRef(portp->fileline(), outvscp,
portp->isWritable() ? VAccess::WRITE : VAccess::READ);
argnodesp = argnodesp->addNextNull(refp);
if (portp->isNonOutput()) {
@ -765,7 +767,8 @@ private:
AstVarScope* outvscp = createFuncVar(dpip, portp->name() + "__Vcvt", portp);
// No information exposure; is already visible in import/export func template
outvscp->varp()->protect(false);
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable());
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp,
portp->isWritable() ? VAccess::WRITE : VAccess::READ);
argnodesp = argnodesp->addNextNull(refp);
}
@ -1134,8 +1137,8 @@ private:
// Return statement
if (rtnvscp && nodep->taskPublic()) {
cfuncp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
cfuncp->addFinalsp(new AstCReturn(
rtnvscp->fileline(), new AstVarRef(rtnvscp->fileline(), rtnvscp, VAccess::READ)));
}
// Replace variable refs
// Iteration requires a back, so put under temporary node
@ -1245,7 +1248,7 @@ private:
visitp = insertBeforeStmt(nodep, beginp);
} else if (!nodep->isStatement()) {
UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function");
AstVarRef* outrefp = new AstVarRef(nodep->fileline(), outvscp, false);
AstVarRef* outrefp = new AstVarRef(nodep->fileline(), outvscp, VAccess::READ);
nodep->replaceWith(outrefp);
// Insert new statements
visitp = insertBeforeStmt(nodep, beginp);
@ -1371,7 +1374,6 @@ public:
// CONSTRUCTORS
TaskVisitor(AstNetlist* nodep, TaskStateVisitor* statep)
: m_statep{statep} {
AstNode::user1ClearTree();
iterate(nodep);
}
virtual ~TaskVisitor() override {}

View File

@ -419,13 +419,13 @@ private:
graphSimplify(false);
}
AstNode* selectActivity(FileLine* flp, uint32_t acode, bool lvalue) {
return new AstArraySel(flp, new AstVarRef(flp, m_activityVscp, lvalue), acode);
AstNode* selectActivity(FileLine* flp, uint32_t acode, const VAccess& access) {
return new AstArraySel(flp, new AstVarRef(flp, m_activityVscp, access), acode);
}
void addActivitySetter(AstNode* insertp, uint32_t code) {
FileLine* const fl = insertp->fileline();
AstAssign* const setterp = new AstAssign(fl, selectActivity(fl, code, true),
AstAssign* const setterp = new AstAssign(fl, selectActivity(fl, code, VAccess::WRITE),
new AstConst(fl, AstConst::LogicTrue()));
if (AstCCall* const callp = VN_CAST(insertp, CCall)) {
callp->addNextHere(setterp);
@ -638,7 +638,7 @@ private:
condp = new AstConst(flp, 1); // Always true, will be folded later
} else {
for (const uint32_t actCode : actSet) {
AstNode* const selp = selectActivity(flp, actCode, false);
AstNode* const selp = selectActivity(flp, actCode, VAccess::READ);
condp = condp ? new AstOr(flp, condp, selp) : selp;
}
}
@ -651,7 +651,7 @@ private:
// Add TraceInc node
AstTraceDecl* const declp = vtxp->nodep();
AstTraceInc* const incp = new AstTraceInc(declp->fileline(), declp, false);
AstTraceInc* const incp = new AstTraceInc(declp->fileline(), declp, VAccess::READ);
ifp->addIfsp(incp);
subStmts += EmitCBaseCounterVisitor(incp).count();
@ -686,7 +686,7 @@ private:
// Clear fine grained activity flags
for (uint32_t i = 0; i < m_activityNumber; ++i) {
AstNode* const clrp = new AstAssign(fl, selectActivity(fl, i, true),
AstNode* const clrp = new AstAssign(fl, selectActivity(fl, i, VAccess::WRITE),
new AstConst(fl, AstConst::LogicFalse()));
cleanupFuncp->addStmtsp(clrp);
}
@ -845,7 +845,7 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (m_tracep) {
UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?");
UASSERT_OBJ(!nodep->lvalue(), nodep, "Lvalue in trace? Should be const.");
UASSERT_OBJ(!nodep->access().isWrite(), nodep, "Lvalue in trace? Should be const.");
V3GraphVertex* varVtxp = nodep->varScopep()->user1u().toGraphVertex();
if (!varVtxp) {
varVtxp = new TraceVarVertex(&m_graph, nodep->varScopep());
@ -857,7 +857,7 @@ private:
|| nodep->varp()->isSigPublic()) { // Or ones user can change
new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1);
}
} else if (m_funcp && m_finding && nodep->lvalue()) {
} else if (m_funcp && m_finding && nodep->access().isWrite()) {
UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?");
V3GraphVertex* const funcVtxp = getCFuncVertexp(m_funcp);
V3GraphVertex* const varVtxp = nodep->varScopep()->user1u().toGraphVertex();

View File

@ -201,7 +201,7 @@ private:
if (nodep->valuep()) {
m_traValuep = nodep->valuep()->cloneTree(true);
} else {
m_traValuep = new AstVarRef(nodep->fileline(), nodep, false);
m_traValuep = new AstVarRef(nodep->fileline(), nodep, VAccess::READ);
}
// Recurse into data type of the signal; the visitors will call addTraceDecl()
iterate(varp->dtypep()->skipRefToEnump());

View File

@ -168,7 +168,7 @@ private:
for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) {
TristateVertex* vvertexp = dynamic_cast<TristateVertex*>(edgep->fromp());
if (const AstVarRef* refp = VN_CAST(vvertexp->nodep(), VarRef)) {
if (refp->lvalue()
if (refp->access().isWrite()
// Doesn't hurt to not check if already set, but by doing so when we
// print out the debug messages, we'll see this node at level 0 instead.
&& !vvertexp->isTristate()) {
@ -276,12 +276,12 @@ class TristatePinVisitor : public TristateBaseVisitor {
bool m_lvalue; // Flip to be an LVALUE
// VISITORS
virtual void visit(AstVarRef* nodep) override {
if (m_lvalue && !nodep->lvalue()) {
if (m_lvalue && !nodep->access().isWrite()) {
UINFO(9, " Flip-to-LValue " << nodep << endl);
nodep->lvalue(true);
} else if (!m_lvalue && nodep->lvalue()) {
nodep->access(VAccess::WRITE);
} else if (!m_lvalue && nodep->access().isWrite()) {
UINFO(9, " Flip-to-RValue " << nodep << endl);
nodep->lvalue(false);
nodep->access(VAccess::READ);
// Mark the ex-output as tristated
UINFO(9, " setTristate-subpin " << nodep->varp() << endl);
m_tgraph.setTristate(nodep->varp());
@ -489,7 +489,7 @@ class TristateVisitor : public TristateBaseVisitor {
UINFO(8, " Adding driver to var " << varp << endl);
AstConst* constp = new AstConst(varp->fileline(), AstConst::WidthedValue(),
varp->width(), 0);
AstVarRef* varrefp = new AstVarRef(varp->fileline(), varp, true);
AstVarRef* varrefp = new AstVarRef(varp->fileline(), varp, VAccess::WRITE);
AstNode* newp = new AstAssignW(varp->fileline(), varrefp, constp);
UINFO(9, " newoev " << newp << endl);
varrefp->user1p(new AstConst(varp->fileline(), AstConst::WidthedValue(),
@ -577,24 +577,25 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->addStmtp(newenp);
AstNode* enassp = new AstAssignW(
refp->fileline(), new AstVarRef(refp->fileline(), newenp, true), getEnp(refp));
refp->fileline(), new AstVarRef(refp->fileline(), newenp, VAccess::WRITE),
getEnp(refp));
UINFO(9, " newass " << enassp << endl);
nodep->addStmtp(enassp);
// now append this driver to the driver logic.
AstNode* ref1p = new AstVarRef(refp->fileline(), newlhsp, false);
AstNode* ref2p = new AstVarRef(refp->fileline(), newenp, false);
AstNode* ref1p = new AstVarRef(refp->fileline(), newlhsp, VAccess::READ);
AstNode* ref2p = new AstVarRef(refp->fileline(), newenp, VAccess::READ);
AstNode* andp = new AstAnd(refp->fileline(), ref1p, ref2p);
// or this to the others
orp = (!orp) ? andp : new AstOr(refp->fileline(), orp, andp);
if (envarp) {
AstNode* ref3p = new AstVarRef(refp->fileline(), newenp, false);
AstNode* ref3p = new AstVarRef(refp->fileline(), newenp, VAccess::READ);
enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p);
}
AstNode* tmp = new AstNot(newenp->fileline(),
new AstVarRef(newenp->fileline(), newenp, false));
AstNode* tmp = new AstNot(
newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, VAccess::READ));
undrivenp = ((!undrivenp) ? tmp : new AstAnd(refp->fileline(), tmp, undrivenp));
}
if (!undrivenp) { // No drivers on the bus
@ -621,11 +622,12 @@ class TristateVisitor : public TristateBaseVisitor {
}
if (envarp) {
nodep->addStmtp(new AstAssignW(
enp->fileline(), new AstVarRef(envarp->fileline(), envarp, true), enp));
enp->fileline(), new AstVarRef(envarp->fileline(), envarp, VAccess::WRITE),
enp));
}
// __out (child) or <in> (parent) = drive-value expression
AstNode* assp = new AstAssignW(lhsp->fileline(),
new AstVarRef(lhsp->fileline(), lhsp, true), orp);
AstNode* assp = new AstAssignW(
lhsp->fileline(), new AstVarRef(lhsp->fileline(), lhsp, VAccess::WRITE), orp);
assp->user2(U2_BOTH); // Don't process further; already resolved
if (debug() >= 9) assp->dumpTree(cout, "-lhsp-eqn: ");
nodep->addStmtp(assp);
@ -647,7 +649,7 @@ class TristateVisitor : public TristateBaseVisitor {
// due to the pinReconnectSimple call in visit AstPin.
// We can ignore the output override by making a temporary
AstVar* varp = getCreateUnconnVarp(nodep, nodep->dtypep());
AstNode* newp = new AstVarRef(nodep->fileline(), varp, true);
AstNode* newp = new AstVarRef(nodep->fileline(), varp, VAccess::WRITE);
UINFO(9, " const->" << newp << endl);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@ -945,10 +947,12 @@ class TristateVisitor : public TristateBaseVisitor {
->num(); // visit(AstConst) already split into en/ones
const V3Number& oneIfEnOne = constp->num();
AstVar* envarp = getCreateEnVarp(varrefp->varp());
AstNode* newp = new AstLogAnd(
fl, new AstEq(fl, new AstConst(fl, oneIfEn), new AstVarRef(fl, envarp, false)),
// Keep the caseeq if there are X's present
new AstEqCase(fl, new AstConst(fl, oneIfEnOne), varrefp));
AstNode* newp
= new AstLogAnd(fl,
new AstEq(fl, new AstConst(fl, oneIfEn),
new AstVarRef(fl, envarp, VAccess::READ)),
// Keep the caseeq if there are X's present
new AstEqCase(fl, new AstConst(fl, oneIfEnOne), varrefp));
if (neq) newp = new AstLogNot(fl, newp);
UINFO(9, " newceq " << newp << endl);
if (debug() >= 9) nodep->dumpTree(cout, "-caseeq-old: ");
@ -992,7 +996,7 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->v3warn(E_UNSUPPORTED, "Unsupported pullup/down (weak driver) construct.");
} else {
if (m_graphing) {
varrefp->lvalue(true);
varrefp->access(VAccess::WRITE);
m_logicp = nodep;
m_tgraph.setTristate(nodep);
associateLogic(nodep, varrefp->varp());
@ -1004,7 +1008,7 @@ class TristateVisitor : public TristateBaseVisitor {
// current limitation of this implementation is that a pullup/down
// gets applied to all bits of a bus and a bus cannot have drivers
// in opposite directions on individual pins.
varrefp->lvalue(true);
varrefp->access(VAccess::WRITE);
m_tgraph.didProcess(nodep);
m_tgraph.didProcess(varrefp->varp());
setPullDirection(varrefp->varp(), nodep);
@ -1082,7 +1086,9 @@ class TristateVisitor : public TristateBaseVisitor {
AstVar* ucVarp = getCreateUnconnVarp(nodep, nodep->modVarp()->dtypep());
nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp,
// We converted, so use declaration output state
nodep->modVarp()->declDirection().isWritable()));
nodep->modVarp()->declDirection().isWritable()
? VAccess::WRITE
: VAccess::READ));
m_tgraph.setTristate(ucVarp);
// We don't need a driver on the wire; the lack of one will default to tristate
} else if (inDeclProcessing) { // Not an input that was a converted tristate
@ -1103,15 +1109,16 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->name() + "__en" + cvtToStr(m_unique++),
VFlagBitPacked(), enModVarp->width());
UINFO(9, " newenv " << enVarp << endl);
AstPin* enpinp = new AstPin(nodep->fileline(), nodep->pinNum(),
enModVarp->name(), // should be {var}"__en"
new AstVarRef(nodep->fileline(), enVarp, true));
AstPin* enpinp
= new AstPin(nodep->fileline(), nodep->pinNum(),
enModVarp->name(), // should be {var}"__en"
new AstVarRef(nodep->fileline(), enVarp, VAccess::WRITE));
enpinp->modVarp(enModVarp);
UINFO(9, " newpin " << enpinp << endl);
enpinp->user2(U2_BOTH); // don't iterate the pin later
nodep->addNextHere(enpinp);
m_modp->addStmtp(enVarp);
enrefp = new AstVarRef(nodep->fileline(), enVarp, false);
enrefp = new AstVarRef(nodep->fileline(), enVarp, VAccess::READ);
UINFO(9, " newvrf " << enrefp << endl);
if (debug() >= 9) enpinp->dumpTree(cout, "-pin-ena: ");
}
@ -1215,7 +1222,7 @@ class TristateVisitor : public TristateBaseVisitor {
virtual void visit(AstVarRef* nodep) override {
UINFO(9, dbgState() << nodep << endl);
if (m_graphing) {
if (nodep->lvalue()) {
if (nodep->access().isWrite()) {
associateLogic(nodep, nodep->varp());
} else {
associateLogic(nodep->varp(), nodep);
@ -1226,11 +1233,11 @@ class TristateVisitor : public TristateBaseVisitor {
// Detect all var lhs drivers and adds them to the
// VarMap so that after the walk through the module we can expand
// any tristate logic on the driver.
if (nodep->lvalue() && m_tgraph.isTristate(nodep->varp())) {
if (nodep->access().isWrite() && m_tgraph.isTristate(nodep->varp())) {
UINFO(9, " Ref-to-lvalue " << nodep << endl);
m_tgraph.didProcess(nodep);
mapInsertLhsVarRef(nodep);
} else if (!nodep->lvalue()
} else if (!nodep->access().isWrite()
// Not already processed, nor varref from visit(AstPin) creation
&& !nodep->user1p()
// Reference to another tristate variable
@ -1240,7 +1247,7 @@ class TristateVisitor : public TristateBaseVisitor {
// Then propagate the enable from the original variable
UINFO(9, " Ref-to-tri " << nodep << endl);
AstVar* enVarp = getCreateEnVarp(nodep->varp());
nodep->user1p(new AstVarRef(nodep->fileline(), enVarp, false));
nodep->user1p(new AstVarRef(nodep->fileline(), enVarp, VAccess::READ));
}
if (m_alhs) {} // NOP; user1() already passed down from assignment
}
@ -1254,9 +1261,9 @@ class TristateVisitor : public TristateBaseVisitor {
if (nodep->user2() & U2_GRAPHING) return; // Already processed
nodep->user2(U2_GRAPHING);
if (nodep->isPulldown() || nodep->isPullup()) {
AstNode* newp
= new AstPull(nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
nodep->isPullup());
AstNode* newp = new AstPull(
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
nodep->isPullup());
UINFO(9, " newpul " << newp << endl);
nodep->addNextHere(newp);
// We'll iterate on the new AstPull later

View File

@ -318,7 +318,7 @@ private:
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
UndrivenVarEntry* entryp = getEntryp(varrefp->varp(), usr);
int lsb = constp->toUInt();
if (m_inBBox || varrefp->lvalue()) {
if (m_inBBox || varrefp->access().isWrite()) {
// Don't warn if already driven earlier as "a=0; if(a) a=1;" is fine.
if (usr == 2 && m_alwaysCombp
&& entryp->isUsedNotDrivenBit(lsb, nodep->width())) {
@ -327,7 +327,7 @@ private:
}
entryp->drivenBit(lsb, nodep->width());
}
if (m_inBBox || !varrefp->lvalue()) entryp->usedBit(lsb, nodep->width());
if (m_inBBox || !varrefp->access().isWrite()) entryp->usedBit(lsb, nodep->width());
}
} else {
// else other varrefs handled as unknown mess in AstVarRef
@ -336,7 +336,7 @@ private:
}
virtual void visit(AstNodeVarRef* nodep) override {
// Any variable
if (nodep->lvalue()
if (nodep->access().isWrite()
&& !VN_IS(nodep, VarXRef)) { // Ignore interface variables and similar ugly items
if (m_inProcAssign && !nodep->varp()->varType().isProcAssignable()
&& !nodep->varp()->isDeclTyped() //
@ -355,16 +355,16 @@ private:
}
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
UndrivenVarEntry* entryp = getEntryp(nodep->varp(), usr);
bool fdrv = nodep->lvalue()
bool fdrv = nodep->access().isWrite()
&& nodep->varp()->attrFileDescr(); // FD's are also being read from
if (m_inBBox || nodep->lvalue()) {
if (m_inBBox || nodep->access().isWrite()) {
if (usr == 2 && m_alwaysCombp && entryp->isUsedNotDrivenAny()) {
UINFO(9, " Full bus. Entryp=" << cvtToHex(entryp) << endl);
warnAlwCombOrder(nodep);
}
entryp->drivenWhole();
}
if (m_inBBox || !nodep->lvalue() || fdrv) entryp->usedWhole();
if (m_inBBox || !nodep->access().isWrite() || fdrv) entryp->usedWhole();
}
}

View File

@ -118,14 +118,14 @@ private:
m_modp->addStmtp(varp);
AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace
prep->replaceWith(new AstVarRef(fl, varp, true));
AstIf* newp
= new AstIf(fl, condp,
(needDly ? static_cast<AstNode*>(
new AstAssignDly(fl, prep, new AstVarRef(fl, varp, false)))
: static_cast<AstNode*>(
new AstAssign(fl, prep, new AstVarRef(fl, varp, false)))),
nullptr);
prep->replaceWith(new AstVarRef(fl, varp, VAccess::WRITE));
AstIf* newp = new AstIf(
fl, condp,
(needDly ? static_cast<AstNode*>(
new AstAssignDly(fl, prep, new AstVarRef(fl, varp, VAccess::READ)))
: static_cast<AstNode*>(
new AstAssign(fl, prep, new AstVarRef(fl, varp, VAccess::READ)))),
nullptr);
newp->branchPred(VBranchPred::BP_LIKELY);
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
abovep->addNextStmt(newp, abovep);
@ -281,12 +281,13 @@ private:
++m_statUnkVars;
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false);
AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, VAccess::READ);
replaceHandle.relink(newref1p); // Replace const with varref
AstInitial* newinitp = new AstInitial(
nodep->fileline(),
new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), newvarp, true),
nodep->fileline(),
new AstVarRef(nodep->fileline(), newvarp, VAccess::WRITE),
new AstOr(
nodep->fileline(), new AstConst(nodep->fileline(), numb1),
new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), numbx),
@ -312,7 +313,7 @@ private:
AstNode* basefromp = AstArraySel::baseFromp(nodep);
bool lvalue = false;
if (const AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) {
lvalue = varrefp->lvalue();
lvalue = varrefp->access().isWrite();
}
// Find range of dtype we are selecting from
// Similar code in V3Const::warnSelect
@ -360,7 +361,7 @@ private:
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
bool lvalue = false;
if (const AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) {
lvalue = varrefp->lvalue();
lvalue = varrefp->access().isWrite();
} else if (VN_IS(basefromp, Const)) {
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
} else {

View File

@ -445,13 +445,13 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
&& nodep->lvalue()) {
&& nodep->access().isWrite()) {
UINFO(8, " Itervar assigned to: " << nodep << endl);
m_varAssignHit = true;
}
if (m_varModeReplace && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
&& !nodep->lvalue()) {
&& !nodep->access().isWrite()) {
AstNode* newconstp = m_varValuep->cloneTree(false);
nodep->replaceWith(newconstp);
pushDeletep(nodep);

View File

@ -128,6 +128,11 @@ public:
return m_dtypep;
}
AstNodeDType* dtypeNullp() const { return m_dtypep; }
AstNodeDType* dtypeNullSkipRefp() const {
AstNodeDType* dtp = dtypeNullp();
if (dtp) dtp = dtp->skipRefp();
return dtp;
}
AstNodeDType* dtypeOverridep(AstNodeDType* defaultp) const {
if (m_stage == PRELIM) v3fatalSrc("Parent dtype should be a final-stage action");
return m_dtypep ? m_dtypep : defaultp;
@ -478,7 +483,7 @@ private:
// signed: Unsigned (11.8.1)
// width: LHS + RHS
if (m_vup->prelim()) {
AstNodeDType* vdtypep = m_vup->dtypeNullp();
AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp();
if (vdtypep
&& (VN_IS(vdtypep, AssocArrayDType) //
|| VN_IS(vdtypep, DynArrayDType) //
@ -602,7 +607,7 @@ private:
// LHS, RHS is self-determined
// width: value(LHS) * width(RHS)
if (m_vup->prelim()) {
AstNodeDType* vdtypep = m_vup->dtypeNullp();
AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp();
if (vdtypep
&& (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType)
|| VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) {
@ -1096,6 +1101,14 @@ private:
}
}
virtual void visit(AstImplication* nodep) override {
if (m_vup->prelim()) {
iterateCheckBool(nodep, "LHS", nodep->lhsp(), BOTH);
iterateCheckBool(nodep, "RHS", nodep->rhsp(), BOTH);
nodep->dtypeSetLogicBool();
}
}
virtual void visit(AstRand* nodep) override {
if (m_vup->prelim()) {
nodep->dtypeSetSigned32(); // Says the spec
@ -1110,6 +1123,8 @@ private:
if (m_vup->prelim()) {
nodep->dtypeSetUInt32(); // Says the spec
AstNodeDType* expDTypep = nodep->findUInt32DType();
userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p());
userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p());
iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, expDTypep, EXTEND_EXP);
iterateCheck(nodep, "RHS", nodep->rhsp(), SELF, FINAL, expDTypep, EXTEND_EXP);
}
@ -1356,7 +1371,7 @@ private:
AstVar* varp
= dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType(), msbdim);
AstNode* dimp = nodep->dimp()->unlinkFrBack();
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp);
nodep->replaceWith(newp);
@ -1805,13 +1820,13 @@ private:
// nodep->varp()->dumpTree(cout, " forvar "); }
// Note genvar's are also entered as integers
nodep->dtypeFrom(nodep->varp());
if (VN_IS(nodep->backp(), NodeAssign) && nodep->lvalue()) { // On LHS
if (VN_IS(nodep->backp(), NodeAssign) && nodep->access().isWrite()) { // On LHS
UASSERT_OBJ(nodep->dtypep(), nodep, "LHS var should be dtype completed");
}
// if (debug() >= 9) nodep->dumpTree(cout, " VRout ");
if (nodep->lvalue() && nodep->varp()->direction() == VDirection::CONSTREF) {
if (nodep->access().isWrite() && nodep->varp()->direction() == VDirection::CONSTREF) {
nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ());
} else if (nodep->lvalue() && nodep->varp()->isConst() && !m_paramsOnly
} else if (nodep->access().isWrite() && nodep->varp()->isConst() && !m_paramsOnly
&& (!m_ftaskp || !m_ftaskp->isConstructor()) && !VN_IS(m_procedurep, Initial)) {
// Too loose, but need to allow our generated first assignment
// Move this to a property of the AstInitial block
@ -2311,7 +2326,7 @@ private:
}
int selwidth = V3Number::log2b(msbdim) + 1; // Width to address a bit
AstVar* varp = enumVarp(adtypep, attrType, (1ULL << selwidth) - 1);
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
AstNode* newp = new AstArraySel(
nodep->fileline(), varrefp,
@ -2358,7 +2373,7 @@ private:
newp->didWidth(true);
} else if (nodep->name() == "delete") { // function void delete([input integer index])
methodOkArguments(nodep, 0, 1);
methodCallLValueRecurse(nodep, nodep->fromp(), true);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
if (!nodep->pinsp()) {
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"clear", nullptr);
@ -2387,13 +2402,13 @@ private:
VL_DANGLING(index_exprp); // May have been edited
return VN_CAST(nodep->pinsp(), Arg)->exprp();
}
void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, bool lvalue) {
void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, const VAccess& access) {
if (AstNodeVarRef* varrefp = VN_CAST(childp, NodeVarRef)) {
if (lvalue) varrefp->lvalue(true);
varrefp->access(access);
} else if (AstMemberSel* ichildp = VN_CAST(childp, MemberSel)) {
methodCallLValueRecurse(nodep, ichildp->fromp(), lvalue);
methodCallLValueRecurse(nodep, ichildp->fromp(), access);
} else if (AstNodeSel* ichildp = VN_CAST(childp, NodeSel)) {
methodCallLValueRecurse(nodep, ichildp->fromp(), lvalue);
methodCallLValueRecurse(nodep, ichildp->fromp(), access);
} else {
UINFO(1, " Related node: " << childp << endl);
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-variable on LHS of built-in method '"
@ -2404,7 +2419,7 @@ private:
AstCMethodHard* newp = nullptr;
if (nodep->name() == "at") { // Created internally for []
methodOkArguments(nodep, 1, 1);
methodCallLValueRecurse(nodep, nodep->fromp(), true);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at",
nullptr);
newp->dtypeFrom(adtypep->subDTypep());
@ -2419,7 +2434,7 @@ private:
newp->protect(false);
} else if (nodep->name() == "delete") { // function void delete()
methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), true);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear",
nullptr);
newp->makeStatement();
@ -2437,7 +2452,7 @@ private:
AstCMethodHard* newp = nullptr;
if (nodep->name() == "at") { // Created internally for []
methodOkArguments(nodep, 1, 1);
methodCallLValueRecurse(nodep, nodep->fromp(), true);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at",
nullptr);
newp->dtypeFrom(adtypep->subDTypep());
@ -2453,7 +2468,7 @@ private:
newp->protect(false);
} else if (nodep->name() == "delete") { // function void delete([input integer index])
methodOkArguments(nodep, 0, 1);
methodCallLValueRecurse(nodep, nodep->fromp(), true);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
if (!nodep->pinsp()) {
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"clear", nullptr);
@ -2480,7 +2495,7 @@ private:
}
} else if (nodep->name() == "insert") {
methodOkArguments(nodep, 2, 2);
methodCallLValueRecurse(nodep, nodep->fromp(), true);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
AstNode* index_exprp = methodCallQueueIndexExpr(nodep);
AstArg* argp = VN_CAST(nodep->pinsp()->nextp(), Arg);
iterateCheckTyped(nodep, "insert value", argp->exprp(), adtypep->subDTypep(), BOTH);
@ -2501,7 +2516,7 @@ private:
}
} else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") {
methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), true);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), nullptr);
newp->dtypeFrom(adtypep->subDTypep());
@ -2510,7 +2525,7 @@ private:
if (!nodep->firstAbovep()) { newp->makeStatement(); }
} else if (nodep->name() == "push_back" || nodep->name() == "push_front") {
methodOkArguments(nodep, 1, 1);
methodCallLValueRecurse(nodep, nodep->fromp(), true);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
AstArg* argp = VN_CAST(nodep->pinsp(), Arg);
iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2539,6 +2554,7 @@ private:
UASSERT_OBJ(first_classp, nodep, "Unlinked");
for (AstClass* classp = first_classp; classp;) {
if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) {
userIterate(ftaskp, nullptr);
nodep->taskp(ftaskp);
nodep->dtypeFrom(ftaskp);
if (VN_IS(ftaskp, Task)) nodep->makeStatement();
@ -2672,10 +2688,10 @@ private:
AstNodeVarRef* fromp = VN_CAST(nodep->fromp()->unlinkFrBack(), VarRef);
AstNode* rhsp = arg0p->exprp()->unlinkFrBack();
AstNode* thsp = arg1p->exprp()->unlinkFrBack();
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), fromp->varp(), false);
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), fromp->varp(), VAccess::READ);
AstNode* newp = new AstAssign(nodep->fileline(), fromp,
new AstPutcN(nodep->fileline(), varrefp, rhsp, thsp));
fromp->lvalue(true);
fromp->access(VAccess::WRITE);
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (nodep->name() == "getc") {
@ -2725,7 +2741,7 @@ private:
virtual void visit(AstNew* nodep) override {
if (nodep->didWidthAndSet()) return;
AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullp(), ClassRefDType);
AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType);
if (!refp) { // e.g. int a = new;
nodep->v3error("new() not expected in this context");
return;
@ -2751,7 +2767,7 @@ private:
}
virtual void visit(AstNewCopy* nodep) override {
if (nodep->didWidthAndSet()) return;
AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullp(), ClassRefDType);
AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType);
if (!refp) { // e.g. int a = new;
nodep->v3error("new() not expected in this context");
return;
@ -2766,7 +2782,7 @@ private:
}
virtual void visit(AstNewDynamic* nodep) override {
if (nodep->didWidthAndSet()) return;
AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullp(), DynArrayDType);
AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullSkipRefp(), DynArrayDType);
if (!adtypep) { // e.g. int a = new;
nodep->v3error(
"dynamic new() not expected in this context (data type must be dynamic array)");
@ -5082,7 +5098,7 @@ private:
AstNode* newp = new AstAssign(
nodep->fileline(), fromp,
new AstSFormatF(nodep->fileline(), format, false, argp->exprp()->unlinkFrBack()));
fromp->lvalue(true);
fromp->access(VAccess::WRITE);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}

View File

@ -280,7 +280,7 @@ private:
"Unsupported: String array operation on non-variable");
}
AstNode* newp;
if (varrefp && varrefp->lvalue()) {
if (varrefp && varrefp->access().isWrite()) {
newp = new AstGetcRefN(nodep->fileline(), fromp, rhsp);
} else {
newp = new AstGetcN(nodep->fileline(), fromp, rhsp);

View File

@ -106,6 +106,7 @@ static void reportStatsIfEnabled() {
V3Stats::statsFinalAll(v3Global.rootp());
V3Stats::statsReport();
}
if (v3Global.opt.debugEmitV()) V3EmitV::debugEmitV("final");
}
static void process() {
@ -363,6 +364,7 @@ static void process() {
V3ActiveTop::activeTopAll(v3Global.rootp());
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder");
if (v3Global.opt.debugEmitV()) V3EmitV::debugEmitV("preorder");
// Order the code; form SBLOCKs and BLOCKCALLs
V3Order::orderAll(v3Global.rootp());
@ -547,9 +549,9 @@ static void verilate(const string& argString) {
}
// Undocumented debugging - cannot be a switch as then command line
// would mismatch forcing non-identicalness when we set it
if (!V3Os::getenvStr("VERILATOR_DEBUG_SKIP_IDENTICAL", "").empty()) {
if (!V3Os::getenvStr("VERILATOR_DEBUG_SKIP_IDENTICAL", "").empty()) { // LCOV_EXCL_START
v3fatalSrc("VERILATOR_DEBUG_SKIP_IDENTICAL w/ --skip-identical: Changes found\n");
}
} // LCOV_EXCL_STOP
//--FRONTEND------------------
@ -621,10 +623,8 @@ static void verilate(const string& argString) {
// Final writing shouldn't throw warnings, but...
V3Error::abortIfWarnings();
#ifdef VL_LEAK_CHECKS
// Cleanup memory for valgrind leak analysis
v3Global.clear();
#endif
FileLine::deleteAllRemaining();
}

View File

@ -110,6 +110,20 @@ public:
return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true));
}
}
AstNode* createTypedef(FileLine* fl, const string& name, AstNode* attrsp, AstNodeDType* basep,
AstNodeRange* rangep) {
AstNode* nodep = new AstTypedef(fl, name, attrsp, VFlagChildDType(),
GRAMMARP->createArray(basep, rangep, false));
SYMP->reinsert(nodep);
PARSEP->tagNodep(nodep);
return nodep;
}
AstNode* createTypedefFwd(FileLine* fl, const string& name) {
AstNode* nodep = new AstTypedefFwd(fl, name);
SYMP->reinsert(nodep);
PARSEP->tagNodep(nodep);
return nodep;
}
void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) {
endLabel(fl, nodep->prettyName(), endnamep);
}
@ -1932,7 +1946,7 @@ list_of_tf_variable_identifiers<nodep>: // ==IEEE: list_of_tf_variable_identifie
tf_variable_identifier<varp>: // IEEE: part of list_of_tf_variable_identifiers
id variable_dimensionListE sigAttrListE exprEqE
{ $$ = VARDONEA($<fl>1,*$1, $2, $3);
if ($4) $$->addNext(new AstAssign($4->fileline(), new AstVarRef($<fl>1, *$1, true), $4)); }
if ($4) $$->addNext(new AstAssign($4->fileline(), new AstVarRef($<fl>1, *$1, VAccess::WRITE), $4)); }
;
variable_declExpr<nodep>: // IEEE: part of variable_decl_assignment - rhs of expr
@ -2151,21 +2165,45 @@ implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
//UNSUP ;
type_declaration<nodep>: // ==IEEE: type_declaration
// // Use idAny, as we can redeclare a typedef on an existing typedef
yTYPEDEF data_type idAny variable_dimensionListE dtypeAttrListE ';'
/**/ { $$ = new AstTypedef($<fl>3, *$3, $5, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
SYMP->reinsert($$); PARSEP->tagNodep($$); }
| yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); }
// Data_type expanded
yTYPEDEF data_typeNoRef
/*cont*/ idAny variable_dimensionListE dtypeAttrListE ';'
{ AstNodeDType* dtp = $2;
$$ = GRAMMARP->createTypedef($<fl>3, *$3, $5, dtp, $4); }
| yTYPEDEF packageClassScope idType packed_dimensionListE
/*cont*/ idAny variable_dimensionListE dtypeAttrListE ';'
{ AstRefDType* refp = new AstRefDType($<fl>3, *$3, $2, nullptr);
AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true);
$$ = GRAMMARP->createTypedef($<fl>5, *$5, $7, dtp, $6); }
| yTYPEDEF packageClassScope idType parameter_value_assignmentClass packed_dimensionListE
/*cont*/ idAny variable_dimensionListE dtypeAttrListE ';'
{ AstRefDType* refp = new AstRefDType($<fl>3, *$3, $2, $4);
AstNodeDType* dtp = GRAMMARP->createArray(refp, $5, true);
$$ = GRAMMARP->createTypedef($<fl>6, *$6, $8, dtp, $7); }
| yTYPEDEF idType packed_dimensionListE
/*cont*/ idAny variable_dimensionListE dtypeAttrListE ';'
{ AstRefDType* refp = new AstRefDType($<fl>2, *$2, nullptr, nullptr);
AstNodeDType* dtp = GRAMMARP->createArray(refp, $3, true);
$$ = GRAMMARP->createTypedef($<fl>4, *$4, $6, dtp, $5); }
| yTYPEDEF idType parameter_value_assignmentClass packed_dimensionListE
/*cont*/ idAny variable_dimensionListE dtypeAttrListE ';'
{ AstRefDType* refp = new AstRefDType($<fl>2, *$2, nullptr, $3);
AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true);
$$ = GRAMMARP->createTypedef($<fl>5, *$5, $7, dtp, $6); }
// //
| yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';'
{ $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); }
// // Allow redeclaring same typedef again
// // Alternative is use of idAny below, but this will cause conflicts with ablve
| yTYPEDEF idType ';' { $$ = GRAMMARP->createTypedefFwd($<fl>2, *$2); }
// // Combines into above "data_type id" rule
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
//UNSUP // Below should be idAny to allow duplicate forward defs; need to expand
// // data_type to exclude IDs, or add id__SEMI rule
| yTYPEDEF id ';' { $$ = nullptr; $$ = new AstTypedefFwd($<fl>2, *$2); SYMP->reinsert($$); PARSEP->tagNodep($$); }
| yTYPEDEF yENUM idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($<fl>3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); }
| yTYPEDEF ySTRUCT idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($<fl>3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); }
| yTYPEDEF yUNION idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($<fl>3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); }
| yTYPEDEF yCLASS idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($<fl>3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); }
| yTYPEDEF yINTERFACE yCLASS idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($<fl>4, *$4); SYMP->reinsert($$); PARSEP->tagNodep($$); }
| yTYPEDEF id ';' { $$ = GRAMMARP->createTypedefFwd($<fl>2, *$2); }
| yTYPEDEF yENUM idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
| yTYPEDEF ySTRUCT idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
| yTYPEDEF yUNION idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
| yTYPEDEF yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>3, *$3); }
| yTYPEDEF yINTERFACE yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($<fl>4, *$4); }
;
dtypeAttrListE<nodep>:
@ -2432,7 +2470,8 @@ loop_generate_construct<nodep>: // ==IEEE: loop_generate_construct
genvar_initialization<nodep>: // ==IEEE: genvar_initialization
varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); }
| yGENVAR genvar_identifierDecl '=' constExpr { $$ = $2; $2->addNext(new AstAssign($3,new AstVarRef($2->fileline(),$2,true), $4)); }
| yGENVAR genvar_identifierDecl '=' constExpr
{ $$ = $2; $2->addNext(new AstAssign($3, new AstVarRef($2->fileline(), $2, VAccess::WRITE), $4)); }
;
genvar_iteration<nodep>: // ==IEEE: genvar_iteration
@ -2542,7 +2581,7 @@ netSigList<varp>: // IEEE: list_of_port_identifiers
netSig<varp>: // IEEE: net_decl_assignment - one element from list_of_port_identifiers
netId sigAttrListE { $$ = VARDONEA($<fl>1,*$1, nullptr, $2); }
| netId sigAttrListE '=' expr { $$ = VARDONEA($<fl>1,*$1, nullptr, $2);
$$->addNext(new AstAssignW($3, new AstVarRef($<fl>1, *$1, true), $4)); }
$$->addNext(new AstAssignW($3, new AstVarRef($<fl>1, *$1, VAccess::WRITE), $4)); }
| netId variable_dimensionList sigAttrListE { $$ = VARDONEA($<fl>1,*$1, $2, $3); }
;
@ -3386,12 +3425,12 @@ for_initializationItem<nodep>: // IEEE: variable_assignment + for_variable_decl
data_type idAny/*new*/ '=' expr
{ VARRESET_NONLIST(VAR); VARDTYPE($1);
$$ = VARDONEA($<fl>2,*$2,nullptr,nullptr);
$$->addNext(new AstAssign($3, new AstVarRef($<fl>2, *$2, true), $4));}
$$->addNext(new AstAssign($3, new AstVarRef($<fl>2, *$2, VAccess::WRITE), $4)); }
// // IEEE-2012:
| yVAR data_type idAny/*new*/ '=' expr
{ VARRESET_NONLIST(VAR); VARDTYPE($2);
$$ = VARDONEA($<fl>3,*$3,nullptr,nullptr);
$$->addNext(new AstAssign($4, new AstVarRef($<fl>3, *$3, true), $5));}
$$->addNext(new AstAssign($4, new AstVarRef($<fl>3, *$3, VAccess::WRITE), $5)); }
// // IEEE: variable_assignment
// // UNSUP variable_lvalue below
| varRefBase '=' expr { $$ = new AstAssign($2, $1, $3); }
@ -4860,7 +4899,7 @@ idArrayedForeach<nodep>: // IEEE: id + select (under foreach expression)
// VarRef without any dots or vectorizaion
varRefBase<varrefp>:
id { $$ = new AstVarRef($<fl>1,*$1,false);}
id { $$ = new AstVarRef($<fl>1, *$1, VAccess::READ); }
;
// yaSTRING shouldn't be used directly, instead via an abstraction below
@ -5267,7 +5306,7 @@ pexpr<nodep>: // IEEE: property_expr (The name pexpr is important as regexps j
//UNSUP: This rule has been super-specialized to what is supported now
//UNSUP remove below
expr yP_ORMINUSGT pexpr { $$ = new AstLogOr($2, new AstLogNot($2, $1), $3); }
//UNSUP expr yP_OREQGT pexpr { $$ = new AstLogOr($2, new AstLogNot($2, new AstPast($2, $1, nullptr)), $3); } // This handles disable iff in the past time step incorrectly
| expr yP_OREQGT pexpr { $$ = new AstImplication($2, $1, $3); }
| expr { $$ = $1; }
//UNSUP remove above, use below:
//
@ -6177,9 +6216,9 @@ dist_list<nodep>: // ==IEEE: dist_list
;
dist_item<nodep>: // ==IEEE: dist_item + dist_weight
value_range { $$ = $1; }
| value_range yP_COLONEQ expr { $$ = $1; BBUNSUP($1, "Unsupported: dist :="); }
| value_range yP_COLONDIV expr { $$ = $1; BBUNSUP($1, "Unsupported: dist :/"); }
value_range { $$ = $1; /* Same as := 1 */ }
| value_range yP_COLONEQ expr { $$ = $1; nullptr; /*UNSUP-no-UVM*/ }
| value_range yP_COLONDIV expr { $$ = $1; nullptr; /*UNSUP-no-UVM*/ }
;
//UNSUPextern_constraint_declaration: // ==IEEE: extern_constraint_declaration

View File

@ -2079,6 +2079,7 @@ sub files_identical {
&& !/^-node:/
&& !/^dot [^\n]+\n/
&& !/^In file: .*\/sc_.*:\d+/
&& !/^libgcov.*/
} @l1;
@l1 = map {
s/(Internal Error: [^\n]+\.cpp):[0-9]+:/$1:#:/;
@ -2318,6 +2319,21 @@ sub write_wholefile {
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename,";
print $fh $contents;
$fh->close;
delete $_File_Contents_Cache{$filename};
}
sub file_sed {
my $self = (ref $_[0]? shift : $Self);
my $infilename = shift;
my $outfilename = shift;
my $editcb = shift;
my $contents = $self->file_contents($infilename);
{
$_ = $contents;
$editcb->($contents);
$contents = $_;
}
$self->write_wholefile($outfilename, $contents);
}
#######################################################################

View File

@ -1,5 +1,5 @@
+librescan +libext+.v
+librescan +notimingchecks +libext+.v
-y t
+incdir+t
+incdir+../include

View File

@ -1,18 +1,34 @@
-Info: t/t_assert_comp_bad.v:10:7: User compile-time info
-Info: t/t_assert_comp_bad.v:10:7:
: ... In instance t
10 | $info("User compile-time info");
10 | $info;
| ^~~~~
%Warning-USERWARN: t/t_assert_comp_bad.v:11:7: User compile-time warning
-Info: t/t_assert_comp_bad.v:11:7: User compile-time info
: ... In instance t
11 | $info("User compile-time info");
| ^~~~~
%Warning-USERWARN: t/t_assert_comp_bad.v:12:7:
: ... In instance t
11 | $warning("User compile-time warning");
12 | $warning;
| ^~~~~~~~
... Use "/* verilator lint_off USERWARN */" and lint_on around source to disable this message.
%Warning-USERWARN: t/t_assert_comp_bad.v:12:7: 1
%Warning-USERWARN: t/t_assert_comp_bad.v:13:7: User compile-time warning
: ... In instance t
12 | $warning(1);
13 | $warning("User compile-time warning");
| ^~~~~~~~
%Warning-USERERROR: t/t_assert_comp_bad.v:13:7: User compile-time error
%Warning-USERWARN: t/t_assert_comp_bad.v:14:7: 1
: ... In instance t
14 | $warning(1);
| ^~~~~~~~
%Warning-USERERROR: t/t_assert_comp_bad.v:15:7:
: ... In instance t
13 | $error("User compile-time error");
15 | $error;
| ^~~~~~
%Warning-USERERROR: t/t_assert_comp_bad.v:16:7: User compile-time error
: ... In instance t
16 | $error("User compile-time error");
| ^~~~~~
%Warning-USERFATAL: t/t_assert_comp_bad.v:17:7:
: ... In instance t
17 | $fatal;
| ^~~~~~
%Error: Exiting due to

View File

@ -7,10 +7,14 @@
module t (/*AUTOARG*/);
if (1) begin
$info;
$info("User compile-time info");
$warning;
$warning("User compile-time warning");
$warning(1); // Check can convert arguments to format
$error;
$error("User compile-time error");
$fatal;
end
endmodule

View File

@ -14,11 +14,15 @@ module t (/*AUTOARG*/
Test test (/*AUTOINST*/
// Inputs
.clk (clk));
.clk(clk),
.cyc(cyc));
always @ (posedge clk) begin
if (cyc!=0) begin
cyc <= cyc + 1;
`ifdef TEST_VERBOSE
$display("cyc=%0d", cyc);
`endif
if (cyc==10) begin
$write("*-* All Finished *-*\n");
$finish;
@ -30,7 +34,8 @@ endmodule
module Test
(
input clk
input clk,
input integer cyc
);
`ifdef FAIL_ASSERT_1
@ -38,8 +43,35 @@ module Test
@(posedge clk)
1 |-> 0
) else $display("[%0t] wrong implication", $time);
assert property (
@(posedge clk)
1 |=> 0
) else $display("[%0t] wrong implication", $time);
assert property (
@(posedge clk)
cyc%3==1 |=> cyc%3==1
) else $display("[%0t] wrong implication (step)", $time);
assert property (
@(posedge clk)
cyc%3==1 |=> cyc%3==0
) else $display("[%0t] wrong implication (step)", $time);
assert property (
@(posedge clk) disable iff (cyc == 3)
(cyc == 4) |=> 0
) else $display("[%0t] wrong implication (disable)", $time);
assert property (
@(posedge clk) disable iff (cyc == 6)
(cyc == 4) |=> 0
) else $display("[%0t] wrong implication (disable)", $time);
`endif
// Test |->
assert property (
@(posedge clk)
1 |-> 1
@ -55,4 +87,44 @@ module Test
0 |-> 1
);
// Test |=>
assert property (
@(posedge clk)
1 |=> 1
);
assert property (
@(posedge clk)
0 |=> 0
);
assert property (
@(posedge clk)
0 |=> 1
);
// Test correct handling of time step in |=>
assert property (
@(posedge clk)
cyc%3==1 |=> cyc%3==2
);
// Test correct handling of disable iff
assert property (
@(posedge clk) disable iff (cyc < 3)
1 |=> cyc > 3
);
// Test correct handling of disable iff in current cycle
assert property (
@(posedge clk) disable iff (cyc == 4)
(cyc == 4) |=> 0
);
// Test correct handling of disable iff in previous cycle
assert property (
@(posedge clk) disable iff (cyc == 5)
(cyc == 4) |=> 0
);
endmodule

View File

@ -1,15 +1,3 @@
%Error-UNSUPPORTED: t/t_class_extends_this.v:13:11: Unsupported: this
13 | if (this.value != 1) $stop;
| ^~~~
%Error: t/t_class_extends_this.v:13:11: Can't find definition of scope/variable: 'this'
13 | if (this.value != 1) $stop;
| ^~~~
%Error-UNSUPPORTED: t/t_class_extends_this.v:21:11: Unsupported: this
21 | if (this.value != 2) $stop;
| ^~~~
%Error: t/t_class_extends_this.v:21:11: Can't find definition of scope/variable: 'this'
21 | if (this.value != 2) $stop;
| ^~~~
%Error-UNSUPPORTED: t/t_class_extends_this.v:22:11: Unsupported: super
22 | if (super.value != 1) $stop;
| ^~~~~
@ -28,12 +16,6 @@
%Error: t/t_class_extends_this.v:24:7: Can't find definition of scope/variable: 'super'
24 | super.value = 10;
| ^~~~~
%Error-UNSUPPORTED: t/t_class_extends_this.v:25:7: Unsupported: this
25 | this.value = 20;
| ^~~~
%Error: t/t_class_extends_this.v:25:7: Can't find definition of scope/variable: 'this'
25 | this.value = 20;
| ^~~~
%Error-UNSUPPORTED: t/t_class_extends_this.v:26:11: Unsupported: super
26 | if (super.value != 10) $stop;
| ^~~~~

View File

@ -13,6 +13,8 @@ class Cls;
protected int m_prot = B;
endclass
const Cls mod_c = new;
initial begin
Cls c;
if (c.A != 10) $stop;
@ -21,6 +23,8 @@ endclass
c.m_loc = 10;
if (c.m_loc != 10) $stop;
if (c.m_prot != 20) $stop;
//
if (mod_c.A != 10) $stop;
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -8,7 +8,7 @@ class ClsNoArg;
const int imembera; // Ok for new() to assign to a const
function new();
imembera = 5;
endfunction
endfunction : new
endclass
class ClsArg;

View File

@ -0,0 +1,21 @@
#!/usr/bin/env 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,40 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
//TODO sub #(.WIDTH(1)) w1;
//TODO sub #(.WIDTH(2)) w2;
//TODO sub #(.WIDTH(3)) w3;
//TODO sub #(.WIDTH(4)) w4;
sub #(.WIDTH(5)) w5;
always @ (posedge clk) begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module sub ();
parameter WIDTH=5; // WIDTH >= 5 fails. WIDTH <= 4 passes
typedef struct packed {
logic [WIDTH-1:0] data;
} [15:0] w_t;
class WrReqQ;
w_t w;
endclass
initial begin
if ($bits(w_t) != WIDTH * 16) $stop;
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2020 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.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,34 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 Rafal Kapuscik
// SPDX-License-Identifier: CC0-1.0
//
class foo;
bit [3:0] addr;
function void set (bit [3:0] addr);
begin : body
this.addr = addr;
end : body
endfunction
endclass
module t(/*AUTOARG*/
// Inputs
clk
);
input clk;
foo bar;
foo baz;
initial begin
bar = new();
baz = new();
bar.set(4);
`ifdef TEST_VERBOSE
$display(bar.addr);
$display(baz.addr);
`endif
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

Some files were not shown because too many files have changed in this diff Show More