Merge from master for release.
This commit is contained in:
commit
818318ddd5
10
.travis.yml
10
.travis.yml
|
|
@ -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
33
Changes
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
66
src/V3Ast.h
66
src/V3Ast.h
|
|
@ -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;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -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]";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ";
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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:"); }
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public:
|
|||
|
||||
private:
|
||||
static Singleton& s() {
|
||||
static Singleton s_s;
|
||||
static Singleton s_s; // LCOV_EXCL_BR_LINE
|
||||
return s_s;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
/*###################################################################
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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: ");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
+librescan +libext+.v
|
||||
+librescan +notimingchecks +libext+.v
|
||||
-y t
|
||||
+incdir+t
|
||||
+incdir+../include
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
| ^~~~~
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
Loading…
Reference in New Issue