Merge from master for release.

This commit is contained in:
Wilson Snyder 2020-11-14 09:58:28 -05:00
commit 78e7758022
278 changed files with 5837 additions and 2174 deletions

32
Changes
View File

@ -2,6 +2,38 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.104 2020-11-14
*** Support queue and associative array 'with' statements. (#2616)
*** Support queue slicing (#2326).
*** Support associative array pattern assignments and defaults.
*** Support static methods and typedefs in classes (#2615). [Krzysztof Bieganski]
**** Report error on typedef referencing self (#2539). [Cody Piersall]
**** With --debug, turn off address space layout randomization.
**** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett]
**** Fix cast width propagation (#2597). [flex-liu]
**** Fix return from callValueCbs (#2589) (#2605). [Marlon James]
**** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick]
**** Fix fault when $fgets, $sscanf, etc used with string (#2604). [Yutetsu TAKATSUKASA]
**** Fix WIFEXITED missing from MinGW/MSYS2 (#2609). [Jean Berniolles]
**** Fix queue poping wrong value when otherwise unused (#2512). [nanduraj1]
**** Fix arrays of modport interfaces (#2614). [Thierry Tambe]
**** Fix split_var internal error (#2640) (#2641). [Yutetsu TAKATSUKASA]
* Verilator 4.102 2020-10-15

View File

@ -66,4 +66,5 @@ ci/
/csrc/
obj_dir.*
TAGS
gmon.out
.*~

View File

@ -442,11 +442,11 @@ cppcheck: $(CPPCHECK_DEP)
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
CLANGTIDY = clang-tidy
CLANGTIDY_FLAGS = -config=''
CLANGTIDY_FLAGS = -config='' -checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables'
CLANGTIDY_DEP = $(subst .h,.h.tidy,$(CPPCHECK_H)) \
$(subst .cpp,.cpp.tidy,$(CPPCHECK_CPP))
clangtidy: $(CLANGTIDY_DEP)
clang-tidy: $(CLANGTIDY_DEP)
%.cpp.tidy: %.cpp
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@
%.h.tidy: %.h
@ -462,11 +462,12 @@ analyzer-include:
CLANGFORMAT = clang-format
CLANGFORMAT_FLAGS = -i
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c*
clang-format:
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
ftp: info

View File

@ -76,7 +76,8 @@ if ($opt_gdbbt && !gdb_works()) {
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
if ($opt_gdb) {
# Generic GDB interactive
run (($ENV{VERILATOR_GDB}||"gdb")
run (aslr_off()
.($ENV{VERILATOR_GDB}||"gdb")
." ".verilator_bin()
# Note, uncomment to set breakpoints before running:
# ." -ex 'break main'"
@ -91,16 +92,22 @@ if ($opt_gdb) {
." -ex 'bt'");
} elsif ($opt_rr) {
# Record with rr
run ("rr record ".verilator_bin()
run (aslr_off()
."rr record ".verilator_bin()
." ".join(' ', @quoted_sw));
} elsif ($opt_gdbbt && $Debug) {
# Run under GDB to get gdbbt
run ("gdb"
run (aslr_off()
."gdb"
." ".verilator_bin()
." --batch --quiet --return-child-result"
." -ex \"run ".join(' ', @quoted_sw)."\""
." -ex 'set width 0'"
." -ex 'bt' -ex 'quit'");
} elsif ($Debug) {
# Debug
run(aslr_off()
.verilator_bin()." ".join(' ',@quoted_sw));
} else {
# Normal, non gdb
run(verilator_bin()." ".join(' ',@quoted_sw));
@ -165,6 +172,15 @@ sub gdb_works {
return $status==0;
}
sub aslr_off {
my $ok = `setarch --addr-no-randomize echo ok 2>/dev/null` || "";
if ($ok =~ /ok/) {
return "setarch --addr-no-randomize ";
} else {
return "";
}
}
sub run {
# Run command, check errors
my $command = shift;
@ -4075,9 +4091,10 @@ is ignored, only a single trace file may be active at once.
$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and
$dumplimit/$dumpportlimit are currently ignored.
=item $finish, $stop
=item $exit, $finish, $stop
The rarely used optional parameter to $finish and $stop is ignored.
The rarely used optional parameter to $finish and $stop is ignored. $exit
is aliased to $finish.
=item $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets,
$fscanf, $fwrite, $fscanf, $sscanf

View File

@ -9,22 +9,6 @@ use Pod::Usage;
use strict;
use vars qw($Debug);
#======================================================================
# Old version 1 dump nodes with no dtypep's
our %Ver1_Non_Dtyped = map {$_ => 1} qw(
ACTIVE ALWAYS ALWAYSPOST ALWAYSPUBLIC ATTROF BEGIN BREAK CASE CASEITEM
CCALL CELL CELLINLINE CFILE CFUNC CHANGEDET CLOCKING COMMENT CONTINUE
COVERDECL COVERINC COVERTOGGLE CRETURN CSTMT DEFPARAM DISABLE DISPLAY DOT
DPIEXPORT FCLOSE FFLUSH FINAL FINISH FOPEN GENCASE GENERATE GENFOR GENIF
IF IMPLICIT INITARRAY INITIAL JUMPGO JUMPLABEL MODULE NETLIST
NOTFOUNDMODULE PACKAGE PACKAGEIMPORT PARSEREF PIN PORT PRAGMA PRIMITIVE
PSLASSERT PSLCOVER PSLDEFCLOCK PULL RANGE READMEM REPEAT RETURN SCCTOR
SCDTOR SCHDR SCIMP SCIMPHDR SCINT SCOPE SELBIT SELEXTRACT SELMINUS
SELPLUS SENGATE SENITEM SENTREE SFORMAT SFORMATF STOP SYSIGNORE SYSTEMT
TASK TASKREF TEXT TOPSCOPE TYPEDEFFWD TYPETABLE UCSTMT UDPTABLE
UDPTABLELINE UNTILSTABLE VASSERT WHILE );
#======================================================================
# main
@ -133,8 +117,6 @@ sub filter {
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
if ($verCvt) {
next if $line =~ /^ NETLIST/;
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
# # Below Ver1_Non_Dtyped may replace above further
if ($line =~ /: ([A-Z]+) /) {
my $type = $1;
next if $type =~ 'DTYPE';
@ -147,14 +129,7 @@ sub filter {
}
next;
}
if ($Ver1_Non_Dtyped{$type}) {
$line =~ s! w[0-9]+!!g;
}
}
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
}
print $f2 $line;
}

View File

@ -198,14 +198,18 @@ sub report {
}
print "\nStatistics:\n";
print " min log(p2e) = $min_p2e from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict}, elapsed $Mtasks{$min_mtask}{elapsed})\n";
print " max log(p2e) = $max_p2e from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict}, elapsed $Mtasks{$max_mtask}{elapsed})\n";
printf " min log(p2e) = %0.3f", $min_p2e;
print " from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict},";
print " elapsed $Mtasks{$min_mtask}{elapsed})\n";
printf " max log(p2e) = %0.3f", $max_p2e;
print " from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict},";
print " elapsed $Mtasks{$max_mtask}{elapsed})\n";
my $stddev = stddev(\@p2e_ratios);
my $mean = mean(\@p2e_ratios);
print " mean = " . ($mean) . "\n";
print " stddev = " . ($stddev) . "\n";
print " e ^ stddev = " . exp($stddev). "\n";
printf " mean = %0.3f\n", $mean;
printf " stddev = %0.3f\n", $stddev;
printf " e ^ stddev = %0.3f\n", exp($stddev);
print "\n";
if ($nthreads > $ncpus) {

View File

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

View File

@ -27,13 +27,16 @@ James Hutchinson
Jamey Hicks
James Pallister
Jan Van Winkel
Jean Berniolles
Jeremy Bennett
John Coiner
John Demme
Josh Redford
Julien Margetts
Kaleb Barrett
Kanad Kanhere
Kevin Kiningham
Krzysztof Bieganski
Kuba Ober
Ludwig Rogiers
Lukasz Dalek
@ -41,6 +44,7 @@ Maarten De Braekeleer
Maciej Sobkowski
Marco Widmer
Markus Krause
Marlon James
Marshal Qiao
Matthew Ballance
Michael Killough

View File

@ -556,7 +556,7 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, W
return owp;
}
}
return 0;
return owp;
}
return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp);
}
@ -1079,7 +1079,17 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
WData qowp[VL_WQ_WORDS_E];
VL_SET_WQ(qowp, 0ULL);
WDataOutP owp = qowp;
if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP);
if (obits == -1) { // string
owp = nullptr;
if (VL_UNCOVERABLE(fmt != 's')) {
VL_FATAL_MT(
__FILE__, __LINE__, "",
"Internal: format other than %s is passed to string"); // LCOV_EXCL_LINE
}
} else if (obits > VL_QUADSIZE) {
owp = va_arg(ap, WDataOutP);
}
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
switch (fmt) {
case 'c': {
@ -1093,11 +1103,13 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, nullptr);
if (!tmp[0]) goto done;
int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lsb = 0;
for (int i = 0; i < obits && lpos >= 0; --lpos) {
_vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]);
lsb += 8;
if (owp) {
int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lsb = 0;
for (int i = 0; i < obits && lpos >= 0; --lpos) {
_vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]);
lsb += 8;
}
}
break;
}
@ -1194,6 +1206,9 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
if (!inIgnore) ++got;
// Reload data if non-wide (if wide, we put it in the right place directly)
if (obits == 0) { // Due to inIgnore
} else if (obits == -1) { // string
std::string* p = va_arg(ap, std::string*);
*p = tmp;
} else if (obits <= VL_BYTESIZE) {
CData* p = va_arg(ap, CData*);
*p = owp[0];
@ -1252,36 +1267,44 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp)
for (; i < bytes; ++i) { *op++ = 0; }
}
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
static IData getLine(std::string& str, IData fpi, size_t maxLen) VL_MT_SAFE {
str.clear();
// While threadsafe, each thread can only access different file handles
FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0;
// The string needs to be padded with 0's in unused spaces in front of
// any read data. This means we can't know in what location the first
// character will finally live, so we need to copy. Yuk.
IData bytes = VL_BYTES_I(obits);
char buffer[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
// We don't use fgets, as we must read \0s.
while (str.size() < maxLen) {
const int c = getc(fp); // getc() is threadsafe
if (c == EOF) break;
str.push_back(c);
if (c == '\n') break;
}
return str.size();
}
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
std::string str;
const IData bytes = VL_BYTES_I(obits);
IData got = getLine(str, fpi, bytes);
if (VL_UNLIKELY(str.empty())) return 0;
// V3Emit has static check that bytes < VL_TO_STRING_MAX_WORDS, but be safe
if (VL_UNCOVERABLE(bytes > VL_TO_STRING_MAX_WORDS * VL_EDATASIZE)) {
if (VL_UNCOVERABLE(bytes < str.size())) {
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: fgets buffer overrun"); // LCOV_EXCL_LINE
}
// We don't use fgets, as we must read \0s.
IData got = 0;
char* cp = buffer;
while (got < bytes) {
int c = getc(fp); // getc() is threadsafe
if (c == EOF) break;
*cp++ = c;
got++;
if (c == '\n') break;
}
_VL_STRING_TO_VINT(obits, destp, got, buffer);
_VL_STRING_TO_VINT(obits, destp, got, str.data());
return got;
}
// declared in verilated_heavy.h
IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE {
return getLine(dest, fpi, std::numeric_limits<size_t>::max());
}
IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
// We ignore lhs/fpi - IEEE says "most recent error" so probably good enough
IData ret = errno;

View File

@ -90,7 +90,7 @@ public:
class VerilatedCovImp : VerilatedCovImpBase {
private:
// TYPES
typedef std::map<std::string, int> ValueIndexMap;
typedef std::map<const std::string, int> ValueIndexMap;
typedef std::map<int, std::string> IndexValueMap;
typedef std::deque<VerilatedCovImpItem*> ItemList;
@ -350,7 +350,7 @@ public:
os << "# SystemC::Coverage-3\n";
// Build list of events; totalize if collapsing hierarchy
typedef std::map<std::string, std::pair<std::string, vluint64_t>> EventMap;
typedef std::map<const std::string, std::pair<std::string, vluint64_t>> EventMap;
EventMap eventCounts;
for (const auto& itemp : m_items) {
std::string name;

View File

@ -26,9 +26,11 @@
#include "verilated.h"
#include <algorithm>
#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
//===================================================================
@ -41,6 +43,17 @@ extern std::string VL_TO_STRING(QData lhs);
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
extern std::string VL_TO_STRING_W(int words, WDataInP obj);
//===================================================================
// Shuffle RNG
class VlURNG {
public:
typedef size_t result_type;
static constexpr size_t min() { return 0; }
static constexpr size_t max() { return 1ULL << 31; }
size_t operator()() { return VL_MASK_I(31) & VL_RANDOM_I(32); }
};
//===================================================================
// Readmem/Writemem operation classes
@ -73,6 +86,333 @@ public:
void print(QData addr, bool addrstamp, const void* valuep);
};
//===================================================================
// Verilog queue and dynamic array container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
// For dynamic arrays it is always zero
template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
private:
// TYPES
typedef std::deque<T_Value> Deque;
public:
typedef typename Deque::const_iterator const_iterator;
private:
// MEMBERS
Deque m_deque; // State of the assoc array
T_Value m_defaultValue; // Default value
public:
// CONSTRUCTORS
VlQueue() {
// m_defaultValue isn't defaulted. Caller's constructor must do it.
}
~VlQueue() {}
// Standard copy constructor works. Verilog: assoca = assocb
// Also must allow conversion from a different T_MaxSize queue
template <size_t U_MaxSize = 0> VlQueue operator=(const VlQueue<T_Value, U_MaxSize>& rhs) {
m_deque = rhs.privateDeque();
if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1);
return *this;
}
static VlQueue cons(const T_Value& lhs) {
VlQueue out;
out.push_back(lhs);
return out;
}
static VlQueue cons(const T_Value& lhs, const T_Value& rhs) {
VlQueue out;
out.push_back(rhs);
out.push_back(lhs);
return out;
}
static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) {
VlQueue out = lhs;
out.push_front(rhs);
return out;
}
static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) {
VlQueue out = rhs;
out.push_back(lhs);
return out;
}
static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) {
VlQueue out = rhs;
for (const auto& i : lhs.m_deque) out.push_back(i);
return out;
}
// METHODS
T_Value& atDefault() { return m_defaultValue; }
const Deque& privateDeque() const { return m_deque; }
// Size. Verilog: function int size(), or int num()
int size() const { return m_deque.size(); }
// Clear array. Verilog: function void delete([input index])
void clear() { m_deque.clear(); }
void erase(vlsint32_t index) {
if (VL_LIKELY(index >= 0 && index < m_deque.size()))
m_deque.erase(m_deque.begin() + index);
}
// Dynamic array new[] becomes a renew()
void renew(size_t size) {
clear();
m_deque.resize(size, atDefault());
}
// Dynamic array new[]() becomes a renew_copy()
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
if (size == 0) {
clear();
} else {
*this = rhs;
m_deque.resize(size, atDefault());
}
}
// function void q.push_front(value)
void push_front(const T_Value& value) {
m_deque.push_front(value);
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back();
}
// function void q.push_back(value)
void push_back(const T_Value& value) {
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value);
}
// function value_t q.pop_front();
T_Value pop_front() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.front();
m_deque.pop_front();
return v;
}
// function value_t q.pop_back();
T_Value pop_back() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.back();
m_deque.pop_back();
return v;
}
// Setting. Verilog: assoc[index] = v
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(vlsint32_t index) {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
} else {
return m_deque[index];
}
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(vlsint32_t index) const {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
return atDefault();
} else {
return m_deque[index];
}
}
// function void q.insert(index, value);
void insert(vlsint32_t index, const T_Value& value) {
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
m_deque.insert(m_deque.begin() + index, value);
}
// Return slice q[lsb:msb]
VlQueue slice(vlsint32_t lsb, vlsint32_t msb) const {
VlQueue out;
if (VL_UNLIKELY(lsb < 0)) lsb = 0;
if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1;
if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1;
for (vlsint32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
return out;
}
// For save/restore
const_iterator begin() const { return m_deque.begin(); }
const_iterator end() const { return m_deque.end(); }
// Methods
void sort() { std::sort(m_deque.begin(), m_deque.end()); }
template <typename Func> void sort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.begin(), m_deque.end(),
[=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); });
}
void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
template <typename Func> void rsort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.rbegin(), m_deque.rend(),
[=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); });
}
void reverse() { std::reverse(m_deque.begin(), m_deque.end()); }
void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG()); }
VlQueue unique() const {
VlQueue out;
std::set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(i);
}
}
return out;
}
VlQueue<IData> unique_index() const {
VlQueue<IData> out;
IData index = 0;
std::set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(index);
}
++index;
}
return out;
}
template <typename Func> VlQueue find(Func with_func) const {
VlQueue out;
for (const auto& i : m_deque)
if (with_func(i)) out.push_back(i);
return out;
}
template <typename Func> VlQueue<IData> find_index(Func with_func) const {
VlQueue<IData> out;
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(i)) out.push_back(index);
++index;
}
return out;
}
template <typename Func> VlQueue find_first(Func with_func) const {
const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func);
if (it == m_deque.end()) return VlQueue{};
return VlQueue::cons(*it);
}
template <typename Func> VlQueue<IData> find_first_index(Func with_func) const {
const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func);
if (it == m_deque.end()) return VlQueue<IData>{};
return VlQueue<IData>::cons(std::distance(m_deque.begin(), it));
}
template <typename Func> VlQueue find_last(Func with_func) const {
const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func);
if (it == m_deque.rend()) return VlQueue{};
return VlQueue::cons(*it);
}
template <typename Func> VlQueue<IData> find_last_index(Func with_func) const {
const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func);
if (it == m_deque.rend()) return VlQueue<IData>{};
// Return index must be relative to beginning
return VlQueue<IData>::cons(m_deque.size() - 1 - std::distance(m_deque.rbegin(), it));
}
// Reduction operators
VlQueue min() const {
if (m_deque.empty()) return VlQueue();
const auto it = std::min_element(m_deque.begin(), m_deque.end());
return VlQueue::cons(*it);
}
VlQueue max() const {
if (m_deque.empty()) return VlQueue();
const auto it = std::max_element(m_deque.begin(), m_deque.end());
return VlQueue::cons(*it);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out += i;
return out;
}
template <typename Func> T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out += with_func(i);
return out;
}
T_Value r_product() const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{*it};
++it;
for (; it != m_deque.end(); ++it) out *= *it;
return out;
}
template <typename Func> T_Value r_product(Func with_func) const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{with_func(*it)};
++it;
for (; it != m_deque.end(); ++it) out *= with_func(*it);
return out;
}
T_Value r_and() const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{*it};
++it;
for (; it != m_deque.end(); ++it) out &= *it;
return out;
}
template <typename Func> T_Value r_and(Func with_func) const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin();
T_Value out{with_func(*it)};
++it;
for (; it != m_deque.end(); ++it) out &= with_func(*it);
return out;
}
T_Value r_or() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out |= i;
return out;
}
template <typename Func> T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out |= with_func(i);
return out;
}
T_Value r_xor() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out ^= i;
return out;
}
template <typename Func> T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_deque) out ^= with_func(i);
return out;
}
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
if (m_deque.empty()) return "'{}"; // No trailing space
std::string out = "'{";
std::string comma;
for (const auto& i : m_deque) {
out += comma + VL_TO_STRING(i);
comma = ", ";
}
return out + "} ";
}
};
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
return obj.to_string();
}
//===================================================================
// Verilog array container
// Similar to std::array<WData, N>, but lighter weight, only methods needed
@ -196,12 +536,176 @@ public:
return it->second;
}
}
// Setting as a chained operation
VlAssocArray& set(const T_Key& index, const T_Value& value) {
at(index) = value;
return *this;
}
VlAssocArray& setDefault(const T_Value& value) {
atDefault() = value;
return *this;
}
// For save/restore
const_iterator begin() const { return m_map.begin(); }
const_iterator end() const { return m_map.end(); }
// Methods
VlQueue<T_Value> unique() const {
VlQueue<T_Value> out;
std::set<T_Value> saw;
for (const auto& i : m_map) {
auto it = saw.find(i.second);
if (it == saw.end()) {
saw.insert(it, i.second);
out.push_back(i.second);
}
}
return out;
}
VlQueue<T_Key> unique_index() const {
VlQueue<T_Key> out;
std::set<T_Key> saw;
for (const auto& i : m_map) {
auto it = saw.find(i.second);
if (it == saw.end()) {
saw.insert(it, i.second);
out.push_back(i.first);
}
}
return out;
}
template <typename Func> VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out;
for (const auto& i : m_map)
if (with_func(i.second)) out.push_back(i.second);
return out;
}
template <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
VlQueue<T_Key> out;
for (const auto& i : m_map)
if (with_func(i.second)) out.push_back(i.first);
return out;
}
template <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
}
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
}
// Reduction operators
VlQueue<T_Value> min() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::min_element(
m_map.begin(), m_map.end(),
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return a.second < b.second;
});
return VlQueue<T_Value>::cons(it->second);
}
VlQueue<T_Value> max() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
m_map.begin(), m_map.end(),
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return a.second < b.second;
});
return VlQueue<T_Value>::cons(it->second);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out += i.second;
return out;
}
template <typename Func> T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out += with_func(i.second);
return out;
}
T_Value r_product() const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{it->second};
++it;
for (; it != m_map.end(); ++it) out *= it->second;
return out;
}
template <typename Func> T_Value r_product(Func with_func) const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{with_func(it->second)};
++it;
for (; it != m_map.end(); ++it) out *= with_func(it->second);
return out;
}
T_Value r_and() const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{it->second};
++it;
for (; it != m_map.end(); ++it) out &= it->second;
return out;
}
template <typename Func> T_Value r_and(Func with_func) const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.begin();
T_Value out{with_func(it->second)};
++it;
for (; it != m_map.end(); ++it) out &= with_func(it->second);
return out;
}
T_Value r_or() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out |= i.second;
return out;
}
template <typename Func> T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out |= with_func(i.second);
return out;
}
T_Value r_xor() const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out ^= i.second;
return out;
}
template <typename Func> T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator
for (const auto& i : m_map) out ^= with_func(i.second);
return out;
}
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
if (m_map.empty()) return "'{}"; // No trailing space
std::string out = "'{";
std::string comma;
for (const auto& i : m_map) {
@ -245,133 +749,6 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
}
}
//===================================================================
// Verilog queue and dynamic array container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
// For dynamic arrays it is always zero
template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
private:
// TYPES
typedef std::deque<T_Value> Deque;
public:
typedef typename Deque::const_iterator const_iterator;
private:
// MEMBERS
Deque m_deque; // State of the assoc array
T_Value m_defaultValue; // Default value
public:
// CONSTRUCTORS
VlQueue() {
// m_defaultValue isn't defaulted. Caller's constructor must do it.
}
~VlQueue() {}
// Standard copy constructor works. Verilog: assoca = assocb
// METHODS
T_Value& atDefault() { return m_defaultValue; }
// Size. Verilog: function int size(), or int num()
int size() const { return m_deque.size(); }
// Clear array. Verilog: function void delete([input index])
void clear() { m_deque.clear(); }
void erase(size_t index) {
if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index);
}
// Dynamic array new[] becomes a renew()
void renew(size_t size) {
clear();
m_deque.resize(size, atDefault());
}
// Dynamic array new[]() becomes a renew_copy()
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
if (size == 0) {
clear();
} else {
*this = rhs;
m_deque.resize(size, atDefault());
}
}
// function void q.push_front(value)
void push_front(const T_Value& value) {
m_deque.push_front(value);
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back();
}
// function void q.push_back(value)
void push_back(const T_Value& value) {
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value);
}
// function value_t q.pop_front();
T_Value pop_front() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.front();
m_deque.pop_front();
return v;
}
// function value_t q.pop_back();
T_Value pop_back() {
if (m_deque.empty()) return m_defaultValue;
T_Value v = m_deque.back();
m_deque.pop_back();
return v;
}
// Setting. Verilog: assoc[index] = v
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(size_t index) {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) {
s_throwAway = atDefault();
return s_throwAway;
} else {
return m_deque[index];
}
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(size_t index) const {
static T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index >= m_deque.size())) {
return atDefault();
} else {
return m_deque[index];
}
}
// function void q.insert(index, value);
void insert(size_t index, const T_Value& value) {
if (VL_UNLIKELY(index >= m_deque.size())) return;
m_deque[index] = value;
}
// For save/restore
const_iterator begin() const { return m_deque.begin(); }
const_iterator end() const { return m_deque.end(); }
// Dumping. Verilog: str = $sformatf("%p", assoc)
std::string to_string() const {
std::string out = "'{";
std::string comma;
for (const auto& i : m_deque) {
out += comma + VL_TO_STRING(i);
comma = ", ";
}
return out + "} ";
}
};
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
return obj.to_string();
}
//===================================================================
// Verilog class reference container
// There are no multithreaded locks on this; the base variable must
@ -477,17 +854,17 @@ extern std::string VL_SUBSTR_N(const std::string& lhs, IData rhs, IData ths) VL_
inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool ignoreCase) VL_PURE {
// SystemVerilog does not allow a string variable to contain '\0'.
// So C functions such as strcmp() can correctly compare strings.
int result;
if (ignoreCase) {
result = VL_STRCASECMP(lhs.c_str(), rhs.c_str());
return VL_STRCASECMP(lhs.c_str(), rhs.c_str());
} else {
result = std::strcmp(lhs.c_str(), rhs.c_str());
return std::strcmp(lhs.c_str(), rhs.c_str());
}
return result;
}
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
extern IData VL_FGETS_NI(std::string& dest, IData fpi);
//======================================================================
// Dumping

View File

@ -98,10 +98,8 @@ VlThreadPool::VlThreadPool(int nThreads, bool profiling)
}
VlThreadPool::~VlThreadPool() {
for (int i = 0; i < m_workers.size(); ++i) {
// Each ~WorkerThread will wait for its thread to exit.
delete m_workers[i];
}
// Each ~WorkerThread will wait for its thread to exit.
for (auto& i : m_workers) delete i;
if (VL_UNLIKELY(m_profiling)) tearDownProfilingClientThread();
}

View File

@ -19,6 +19,7 @@
// clang-format off
#ifndef VL_CPPCHECK
#ifndef VL_DERIVED_T
# error "This file should be included in trace format implementations"
#endif
@ -641,3 +642,5 @@ inline static void cvtQDataToStr(char* dstp, QData value) {
}
#define cvtEDataToStr cvtIDataToStr
#endif // VL_CPPCHECK

View File

@ -76,7 +76,7 @@ private:
std::vector<char> m_suffixes; ///< VCD line end string codes + metadata
const char* m_suffixesp; ///< Pointer to first element of above
typedef std::map<std::string, std::string> NameMap;
typedef std::map<const std::string, const std::string> NameMap;
NameMap* m_namemapp = nullptr; ///< List of names for the header
void bufferResize(vluint64_t minsize);

View File

@ -96,7 +96,7 @@ public:
virtual vluint32_t type() const { return 0; }
virtual vluint32_t size() const { return 0; }
virtual const VerilatedRange* rangep() const { return nullptr; }
virtual vpiHandle dovpi_scan() { return 0; }
virtual vpiHandle dovpi_scan() { return nullptr; }
};
typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data*);
@ -187,7 +187,7 @@ public:
nextp->iterationInc();
return ((nextp)->castVpiHandle());
}
return 0; // End of list - only one deep
return nullptr; // End of list - only one deep
}
};
@ -312,14 +312,14 @@ public:
m_it = varsp->begin();
m_started = true;
} else if (VL_UNLIKELY(m_it == varsp->end())) {
return 0;
return nullptr;
} else {
++m_it;
}
if (m_it == varsp->end()) return 0;
if (m_it == varsp->end()) return nullptr;
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))->castVpiHandle());
}
return 0; // End of list - only one deep
return nullptr; // End of list - only one deep
}
};
@ -346,7 +346,7 @@ public:
}
virtual vpiHandle dovpi_scan() override {
vpiHandle result;
if (m_done) return 0;
if (m_done) return nullptr;
result = vpi_handle_by_index(m_handle, m_iteration);
iterationInc();
return result;
@ -387,7 +387,7 @@ public:
}
virtual vluint32_t type() const override { return vpiIterator; }
virtual vpiHandle dovpi_scan() override {
if (m_it == m_vec->end()) return 0;
if (m_it == m_vec->end()) return nullptr;
const VerilatedScope* modp = *m_it++;
return (new VerilatedVpioModule(modp))->castVpiHandle();
}
@ -477,7 +477,8 @@ public:
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
bool called = false;
for (auto it = cbObjList.begin(); it != cbObjList.end();) {
const auto end = cbObjList.end(); // prevent looping over newly added elements
for (auto it = cbObjList.begin(); it != end;) {
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
continue;
@ -489,12 +490,14 @@ public:
}
return called;
}
static void callValueCbs() VL_MT_UNSAFE_ONE {
static bool callValueCbs() VL_MT_UNSAFE_ONE {
assertOneCheck();
VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange];
bool called = false;
typedef std::set<VerilatedVpioVar*> VpioVarSet;
VpioVarSet update; // set of objects to update after callbacks
for (auto it = cbObjList.begin(); it != cbObjList.end();) {
const auto end = cbObjList.end(); // prevent looping over newly added elements
for (auto it = cbObjList.begin(); it != end;) {
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
continue;
@ -512,10 +515,12 @@ public:
update.insert(varop);
vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value);
(vop->cb_rtnp())(vop->cb_datap());
called = true;
}
}
}
for (const auto& ip : update) { memcpy(ip->prevDatap(), ip->varDatap(), ip->entSize()); }
return called;
}
static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info
@ -599,7 +604,7 @@ VL_THREAD_LOCAL vluint8_t* VerilatedVpio::t_freeHead = nullptr;
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callTimedCbs(); }
void VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callValueCbs(); }
bool VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::callValueCbs(); }
bool VerilatedVpi::callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
return VerilatedVpiImp::callCbs(reason);
@ -1048,10 +1053,10 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
}
}
PLI_INT32 vpi_remove_cb(vpiHandle object) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", object););
PLI_INT32 vpi_remove_cb(vpiHandle cb_obj) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", cb_obj););
VerilatedVpiImp::assertOneCheck();
VerilatedVpioCb* vop = VerilatedVpioCb::castp(object);
VerilatedVpioCb* vop = VerilatedVpioCb::castp(cb_obj);
_VL_VPI_ERROR_RESET();
if (VL_UNLIKELY(!vop)) return 0;
if (vop->cb_datap()->reason == cbAfterDelay) {
@ -1065,7 +1070,7 @@ PLI_INT32 vpi_remove_cb(vpiHandle object) {
void vpi_get_cb_info(vpiHandle /*object*/, p_cb_data /*cb_data_p*/) { _VL_VPI_UNIMP(); }
vpiHandle vpi_register_systf(p_vpi_systf_data /*systf_data_p*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
void vpi_get_systf_info(vpiHandle /*object*/, p_vpi_systf_data /*systf_data_p*/) {
_VL_VPI_UNIMP();
@ -1131,24 +1136,24 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
VerilatedVpioVar* varop = VerilatedVpioVar::castp(object);
_VL_VPI_ERROR_RESET();
if (VL_LIKELY(varop)) {
if (varop->varp()->dims() < 2) return 0;
if (varop->varp()->dims() < 2) return nullptr;
if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) {
if (VL_UNLIKELY(indx > varop->varp()->unpacked().left()
|| indx < varop->varp()->unpacked().right()))
return 0;
return nullptr;
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->unpacked().right()))
->castVpiHandle();
}
if (VL_UNLIKELY(indx < varop->varp()->unpacked().left()
|| indx > varop->varp()->unpacked().right()))
return 0;
return nullptr;
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
indx - varop->varp()->unpacked().left()))
->castVpiHandle();
}
_VL_VPI_INTERNAL(__FILE__, __LINE__, "%s : can't resolve handle", VL_FUNC);
return 0;
return nullptr;
}
// for traversing relationships
@ -1160,56 +1165,56 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
switch (type) {
case vpiLeftRange: {
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
case vpiRightRange: {
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
case vpiIndex: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioConst(vop->index()))->castVpiHandle();
}
case vpiScope: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle();
}
case vpiParent: {
VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle();
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type));
return 0;
return nullptr;
}
}
vpiHandle vpi_handle_multi(PLI_INT32 /*type*/, vpiHandle /*refHandle1*/, vpiHandle /*refHandle2*/,
...) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
@ -1219,8 +1224,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
switch (type) {
case vpiMemoryWord: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims() < 2) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
if (vop->varp()->dims() < 2) return nullptr;
if (vop->varp()->dims() > 2) {
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC,
@ -1231,8 +1236,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
}
case vpiRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (vop->varp()->dims() < 2) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
if (vop->varp()->dims() < 2) return nullptr;
// Unsupported is multidim list
if (vop->varp()->dims() > 2) {
_VL_VPI_WARNING(__FILE__, __LINE__,
@ -1244,7 +1249,7 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
}
case vpiReg: {
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
if (VL_UNLIKELY(!vop)) return 0;
if (VL_UNLIKELY(!vop)) return nullptr;
return ((new VerilatedVpioVarIter(vop->scopep()))->castVpiHandle());
}
case vpiModule: {
@ -1252,13 +1257,13 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap();
const VerilatedScope* mod = vop ? vop->scopep() : nullptr;
const auto it = vlstd::as_const(map)->find(const_cast<VerilatedScope*>(mod));
if (it == map->end()) return 0;
if (it == map->end()) return nullptr;
return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle());
}
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
return 0;
return nullptr;
}
}
vpiHandle vpi_scan(vpiHandle object) {
@ -1342,7 +1347,7 @@ PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) {
default:
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
return 0;
return nullptr;
}
}
@ -1639,7 +1644,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
_VL_VPI_ERROR_RESET();
if (VL_UNLIKELY(!valuep)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer");
return 0;
return nullptr;
}
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
VL_DEBUG_IF_PLI(
@ -1652,9 +1657,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
"Ignoring vpi_put_value to signal marked read-only,"
" use public_flat_rw instead: %s",
vop->fullname());
return 0;
return nullptr;
}
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return 0;
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return nullptr;
if (valuep->format == vpiVectorVal) {
if (VL_UNLIKELY(!valuep->value.vector)) return nullptr;
if (vop->varp()->vltype() == VLVT_UINT8) {
@ -1755,7 +1760,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
VL_FUNC, valuep->value.str,
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
return 0;
return nullptr;
}
if (success > 1) {
_VL_VPI_WARNING(__FILE__, __LINE__,
@ -1844,11 +1849,11 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
} else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiParameter: %s",
VL_FUNC, vop->fullname());
return 0;
return nullptr;
} else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiConstant: %s",
VL_FUNC, vop->fullname());
return 0;
return nullptr;
}
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object);
return nullptr;
@ -1910,7 +1915,7 @@ PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
PLI_BYTE8* vpi_mcd_name(PLI_UINT32 /*mcd*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8* formatp, ...) {
@ -2020,7 +2025,7 @@ PLI_INT32 vpi_put_data(PLI_INT32 /*id*/, PLI_BYTE8* /*dataLoc*/, PLI_INT32 /*num
}
void* vpi_get_userdata(vpiHandle /*obj*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}
PLI_INT32 vpi_put_userdata(vpiHandle /*obj*/, void* /*userdata*/) {
_VL_VPI_UNIMP();
@ -2051,5 +2056,5 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,
PLI_INT32* /*index_array*/) {
_VL_VPI_UNIMP();
return 0;
return nullptr;
}

View File

@ -40,7 +40,7 @@ public:
static void callTimedCbs() VL_MT_UNSAFE_ONE;
/// Call value based callbacks
/// Users should call this from their main loops
static void callValueCbs() VL_MT_UNSAFE_ONE;
static bool callValueCbs() VL_MT_UNSAFE_ONE;
/// Call callbacks of arbitrary types
/// Users can call this from their application code
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE;

View File

@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add axiom-athdl`;
exec('atsim',@ARGV);
exec('atsim', @ARGV);
#######################################################################
__END__
@ -22,7 +22,7 @@ invoke_atsim - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_atsim {ncv arguments}
invoke_atsim {arguments}
=head1 DESCRIPTION

View File

@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add cds-ius`;
exec('iccr',@ARGV);
exec('iccr', @ARGV);
#######################################################################
__END__
@ -22,7 +22,7 @@ invoke_iccr - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_iccr {ncv arguments}
invoke_iccr {arguments}
=head1 DESCRIPTION

View File

@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add cds-ius/latest`;
exec('ncverilog',@ARGV);
exec('ncverilog', @ARGV);
#######################################################################
__END__
@ -22,7 +22,7 @@ invoke_ncverilog - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_ncverilog {ncv arguments}
invoke_ncverilog {arguments}
=head1 DESCRIPTION

View File

@ -9,7 +9,7 @@ use strict;
# main
eval `modulecmd perl add synopsys-sim/latest`;
exec('vcs',@ARGV);
exec('vcs', @ARGV);
#######################################################################
__END__
@ -22,7 +22,7 @@ invoke_vcs - Invoke tool under "modules" command
=head1 SYNOPSIS
invoke_vcs {ncv arguments}
invoke_vcs {arguments}
=head1 DESCRIPTION

View File

@ -394,6 +394,7 @@ void AstNode::setOp4p(AstNode* newp) {
void AstNode::addOp1p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp1p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op1p) {
op1p(newp);
} else {
@ -403,6 +404,7 @@ void AstNode::addOp1p(AstNode* newp) {
void AstNode::addOp2p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp2p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op2p) {
op2p(newp);
} else {
@ -412,6 +414,7 @@ void AstNode::addOp2p(AstNode* newp) {
void AstNode::addOp3p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp3p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op3p) {
op3p(newp);
} else {
@ -421,6 +424,7 @@ void AstNode::addOp3p(AstNode* newp) {
void AstNode::addOp4p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp4p");
UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node"););
if (!m_op4p) {
op4p(newp);
} else {
@ -1113,7 +1117,7 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep
}
}
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, bool doCheck) {
// Not const function as calls checkTree
if (doDump) {
{ // Write log & close
@ -1131,7 +1135,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
}
}
}
if (v3Global.opt.debugCheck() || v3Global.opt.dumpTree()) {
if (doCheck && (v3Global.opt.debugCheck() || v3Global.opt.dumpTree())) {
// Error check
checkTree();
// Broken isn't part of check tree because it can munge iterp's
@ -1261,6 +1265,9 @@ AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
AstNodeDType* AstNode::findVoidDType() const {
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
}
AstNodeDType* AstNode::findQueueIndexDType() const {
return v3Global.rootp()->typeTablep()->findQueueIndexDType(fileline());
}
//######################################################################
// AstNVisitor

View File

@ -125,10 +125,22 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
class VAccess {
public:
enum en : uint8_t { READ, WRITE };
enum en : uint8_t {
READ, // Read/Consumed, variable not changed
WRITE, // Written/Updated, variable might be updated, but not consumed
// // so variable might be removable if not consumed elsewhere
READWRITE, // Read/Consumed and written/updated, variable both set and
// // also consumed, cannot remove usage of variable.
// // For non-simple data types only e.g. no tristates/delayed vars.
NOCHANGE // No change to previous state, used only in V3LinkLValue
};
enum en m_e;
const char* ascii() const {
static const char* const names[] = {"RD", "WR"};
static const char* const names[] = {"RD", "WR", "RW", "--"};
return names[m_e];
}
const char* arrow() const {
static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"};
return names[m_e];
}
inline VAccess()
@ -139,9 +151,13 @@ public:
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; }
VAccess invert() const {
return (m_e == READWRITE) ? VAccess(m_e) : (m_e == WRITE ? VAccess(READ) : VAccess(WRITE));
}
bool isReadOnly() const { return m_e == READ; } // False with READWRITE
bool isReadOrRW() const { return m_e == READ || m_e == READWRITE; }
bool isWriteOrRW() const { return m_e == WRITE || m_e == READWRITE; }
bool isRW() const { return m_e == READWRITE; } // False with READWRITE
};
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; }
@ -1254,7 +1270,10 @@ public:
/// along with all children and next(s). This is often better to use
/// than an immediate deleteTree, as any pointers into this node will
/// persist for the lifetime of the visitor
void pushDeletep(AstNode* nodep) { m_deleteps.push_back(nodep); }
void pushDeletep(AstNode* nodep) {
UASSERT_STATIC(nodep, "Cannot delete nullptr node");
m_deleteps.push_back(nodep);
}
/// Call deleteTree on all previously pushDeletep()'ed nodes
void doDeletes();
@ -1731,6 +1750,7 @@ public:
AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); }
AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); }
AstNodeDType* findVoidDType() const;
AstNodeDType* findQueueIndexDType() const;
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,
@ -1801,7 +1821,8 @@ public:
void dumpTreeGdb(); // For GDB only
void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = " ",
int maxDepth = 0) const;
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true);
void dumpTreeFile(const string& filename, bool append = false, bool doDump = true,
bool doCheck = true);
static void dumpTreeFileGdb(const char* filenamep = nullptr);
// METHODS - queries
@ -2439,13 +2460,18 @@ public:
const char* charIQWN() const {
return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I");
}
string cType(const string& name, bool forFunc, bool isRef) const;
private:
class CTypeRecursed;
CTypeRecursed cTypeRecurse(bool compound) const;
};
class AstNodeUOrStructDType : public AstNodeDType {
// A struct or union; common handling
private:
// TYPES
typedef std::map<string, AstMemberDType*> MemberNameMap;
typedef std::map<const string, AstMemberDType*> MemberNameMap;
// MEMBERS
string m_name; // Name from upper typedef, if any
bool m_packed;

View File

@ -312,107 +312,22 @@ string AstVar::verilogKwd() const {
}
}
class AstVar::VlArgTypeRecursed {
public:
bool m_isRef; // Is it a reference?
string m_type; // The base type, e.g.: "Foo_t"s
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
string render(const string& name) const {
string out;
out += m_type;
out += " ";
out += m_isRef ? "(&" + name + ")" : name;
out += m_dims;
return out;
}
};
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc) const {
UASSERT_OBJ(!forReturn, this,
"Internal data is never passed as return, but as first argument");
string ostatic;
if (isStatic() && namespc.empty()) ostatic = "static ";
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false);
bool isRef = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const ";
string oname;
if (named) {
if (!namespc.empty()) oname += namespc + "::";
oname += VIdProtect::protectIf(name(), protect());
}
return ostatic + info.render(oname);
}
AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool compound) const {
VlArgTypeRecursed info;
info.m_isRef
= isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
dtypep = dtypep->skipRefp();
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true);
const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
if (compound) {
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
}
const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound);
info.m_type = sub.m_type;
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
info.m_type = "float";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) {
info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) {
if (compound) {
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else {
info.m_type += "WData" + bitvec; // []'s added later
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
}
}
} else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
}
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; }
return info;
return ostatic + dtypep()->cType(oname, forFunc, isRef);
}
string AstVar::vlEnumType() const {
@ -638,6 +553,92 @@ string AstVar::mtasksString() const {
return os.str();
}
class AstNodeDType::CTypeRecursed {
public:
string m_type; // The base type, e.g.: "Foo_t"s
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
string render(const string& name, bool isRef) const {
string out;
out += m_type;
if (name != "") out += " ";
out += isRef ? "(&" + name + ")" : name;
out += m_dims;
return out;
}
};
string AstNodeDType::cType(const string& name, bool forFunc, bool isRef) const {
CTypeRecursed info = cTypeRecurse(false);
return info.render(name, isRef);
}
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
CTypeRecursed info;
const AstNodeDType* dtypep = this->skipRefp();
if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
if (compound) {
v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
}
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
info.m_type = sub.m_type;
info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
info.m_type = "float";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {
info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) {
info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) {
if (compound) {
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else {
info.m_type += "WData" + bitvec; // []'s added later
info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
}
}
} else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
}
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
return info;
}
AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
// dimension passed from AstArraySel::dimension
// Dimension 0 means the VAR itself, 1 is the closest SEL to the AstVar,
@ -845,9 +846,7 @@ bool AstSenTree::hasCombo() const {
void AstTypeTable::clearCache() {
// When we mass-change widthMin in V3WidthCommit, we need to correct the table.
// Just clear out the maps; the search functions will be used to rebuild the map
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
m_basicps[i] = nullptr;
}
for (auto& itr : m_basicps) itr = nullptr;
m_detailedMap.clear();
// Clear generic()'s so dead detection will work
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
@ -874,6 +873,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
return m_voidp;
}
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
addTypesp(newp);
m_queueIndexp = newp;
}
return m_queueIndexp;
}
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
if (m_basicps[kwd]) return m_basicps[kwd];
//
@ -1082,6 +1090,7 @@ void AstCell::dump(std::ostream& str) const {
void AstCellInline::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << origModName();
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
}
const char* AstClassPackage::broken() const {
BROKEN_BASE_RTN(AstNodeModule::broken());
@ -1166,12 +1175,12 @@ void AstInitArray::dump(std::ostream& str) const {
this->AstNode::dump(str);
int n = 0;
const AstInitArray::KeyItemMap& mapr = map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
for (const auto& itr : mapr) {
if (n++ > 5) {
str << " ...";
break;
}
str << " [" << it->first << "]=" << (void*)it->second;
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
}
}
void AstJumpGo::dump(std::ostream& str) const {
@ -1363,6 +1372,10 @@ void AstPackageImport::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> " << packagep();
}
void AstPatMember::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isDefault()) str << " [DEFAULT]";
}
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstSel::dump(std::ostream& str) const {
this->AstNodeTriop::dump(str);
@ -1392,8 +1405,8 @@ void AstTypeTable::dump(std::ostream& str) const {
}
{
const DetailedMap& mapr = m_detailedMap;
for (DetailedMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
AstBasicDType* dtypep = it->second;
for (const auto& itr : mapr) {
AstBasicDType* dtypep = itr.second;
str << endl; // Newline from caller, so newline first
str << "\t\tdetailed -> ";
dtypep->dump(str);
@ -1403,7 +1416,7 @@ void AstTypeTable::dump(std::ostream& str) const {
}
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "[assoc-" << (void*)keyDTypep() << "]";
str << "[assoc-" << reinterpret_cast<const void*>(keyDTypep()) << "]";
}
string AstAssocArrayDType::prettyDTypeName() const {
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
@ -1443,12 +1456,8 @@ void AstVarScope::dump(std::ostream& str) const {
void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstVarXRef::dump(std::ostream& str) const {
this->AstNodeVarRef::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (access().isWrite()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
}
if (packagep()) str << " pkg=" << nodeAddr(packagep());
str << " " << access().arrow() << " ";
str << ".=" << dotted() << " ";
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
if (varScopep()) {
@ -1461,12 +1470,8 @@ void AstVarXRef::dump(std::ostream& str) const {
}
void AstVarRef::dump(std::ostream& str) const {
this->AstNodeVarRef::dump(str);
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (access().isWrite()) {
str << " [LV] => ";
} else {
str << " [RV] <- ";
}
if (packagep()) str << " pkg=" << nodeAddr(packagep());
str << " " << access().arrow() << " ";
if (varScopep()) {
varScopep()->dump(str);
} else if (varp()) {
@ -1499,6 +1504,12 @@ void AstVar::dump(std::ostream& str) const {
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
str << " " << varType();
}
void AstScope::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [abovep=" << reinterpret_cast<const void*>(aboveScopep()) << "]";
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
}
void AstSenTree::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isMulti()) str << " [MULTI]";

View File

@ -300,7 +300,7 @@ public:
class AstClass : public AstNodeModule {
// TYPES
typedef std::map<string, AstNode*> MemberNameMap;
typedef std::map<const string, AstNode*> MemberNameMap;
// MEMBERS
MemberNameMap m_members; // Members or method children
AstClassPackage* m_packagep = nullptr; // Class package this is under
@ -1100,6 +1100,12 @@ public:
refDTypep(nullptr);
dtypep(nullptr); // V3Width will resolve
}
AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp)
: ASTGEN_SUPER(fl) {
setNOp2p(boundp);
refDTypep(dtp);
dtypep(dtp);
}
ASTNODE_NODE_FUNCS(QueueDType)
virtual const char* broken() const override {
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
@ -2182,11 +2188,6 @@ public:
void addConsumingMTaskId(int id) { m_mtaskIds.insert(id); }
const MTaskIdSet& mtaskIds() const { return m_mtaskIds; }
string mtasksString() const;
private:
class VlArgTypeRecursed;
VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool compound) const;
};
class AstDefParam : public AstNode {
@ -2247,6 +2248,7 @@ public:
virtual bool maybePointedTo() const override { return true; }
virtual string name() const override { return m_name; } // * = Scope name
virtual void name(const string& name) override { m_name = name; }
virtual void dump(std::ostream& str) const override;
string nameDotless() const;
string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); }
AstNodeModule* modp() const { return m_modp; }
@ -2365,7 +2367,7 @@ public:
}
}
virtual int instrCount() const override {
return widthInstrs() * (access().isWrite() ? 1 : instrCountLd());
return widthInstrs() * (access().isReadOrRW() ? instrCountLd() : 1);
}
virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
@ -2970,7 +2972,7 @@ public:
virtual V3Hash sameHash() const override { return V3Hash(m_classOrPackagep); }
virtual void dump(std::ostream& str = std::cout) const override;
virtual string name() const override { return m_name; } // * = Var name
AstNode* classOrPackagep() const { return m_classOrPackagep; }
AstNodeModule* classOrPackagep() const { return VN_CAST(m_classOrPackagep, NodeModule); }
AstPackage* packagep() const { return VN_CAST(classOrPackagep(), Package); }
void classOrPackagep(AstNode* nodep) { m_classOrPackagep = nodep; }
AstPin* paramsp() const { return VN_CAST(op4p(), Pin); }
@ -3076,19 +3078,72 @@ public:
void cname(const string& cname) { m_cname = cname; }
};
class AstWith : public AstNodeStmt {
class AstWithParse : public AstNodeStmt {
// In early parse, FUNC(index) WITH equation-using-index
// Replaced with AstWith
// Parents: math|stmt
// Children: funcref, math
public:
AstWith(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* argsp)
AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp)
: ASTGEN_SUPER(fl) {
statement(stmt);
setOp1p(funcrefp);
addNOp2p(argsp);
addNOp2p(exprp);
}
ASTNODE_NODE_FUNCS(With)
ASTNODE_NODE_FUNCS(WithParse)
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
//
AstNode* funcrefp() const { return op1p(); }
AstNode* exprp() const { return op2p(); }
};
class AstLambdaArgRef : public AstNodeMath {
// Lambda argument usage
// These are not AstVarRefs because we need to be able to delete/clone lambdas during
// optimizations and AstVar's are painful to remove.
private:
string m_name; // Name of variable
public:
AstLambdaArgRef(FileLine* fl, const string& name)
: ASTGEN_SUPER(fl)
, m_name{name} {}
ASTNODE_NODE_FUNCS(LambdaArgRef)
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
virtual string emitVerilog() override { return name(); }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual bool hasDType() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
virtual string name() const override { return m_name; } // * = Var name
virtual void name(const string& name) override { m_name = name; }
};
class AstWith : public AstNodeStmt {
// Used as argument to method, then to AstCMethodHard
// dtypep() contains the with lambda's return dtype
// Parents: funcref (similar to AstArg)
// Children: VAR that declares the index variable
// Children: math (equation establishing the with)
public:
AstWith(FileLine* fl, AstLambdaArgRef* argrefp, AstNode* exprp)
: ASTGEN_SUPER(fl) {
addOp1p(argrefp);
addNOp2p(exprp);
}
ASTNODE_NODE_FUNCS(With)
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
virtual bool hasDType() const override { return true; }
virtual const char* broken() const override {
BROKEN_RTN(!argrefp()); // varp needed to know lambda's arg dtype
return nullptr;
}
//
AstLambdaArgRef* argrefp() const { return VN_CAST(op1p(), LambdaArgRef); }
AstNode* exprp() const { return op2p(); }
};
//######################################################################
@ -4604,6 +4659,93 @@ public:
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstConsAssoc : public AstNodeMath {
// Construct an assoc array and return object, '{}
// Parents: math
// Children: expression (elements or other queues)
public:
AstConsAssoc(FileLine* fl, AstNode* defaultp)
: ASTGEN_SUPER(fl) {
setNOp1p(defaultp);
}
ASTNODE_NODE_FUNCS(ConsAssoc)
virtual string emitVerilog() override { return "'{}"; }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* defaultp() const { return op1p(); }
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstSetAssoc : public AstNodeMath {
// Set an assoc array element and return object, '{}
// Parents: math
// Children: expression (elements or other queues)
public:
AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep)
: ASTGEN_SUPER(fl) {
setOp1p(lhsp);
setNOp2p(keyp);
setOp3p(valuep);
}
ASTNODE_NODE_FUNCS(SetAssoc)
virtual string emitVerilog() override { return "'{}"; }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* lhsp() const { return op1p(); }
AstNode* keyp() const { return op2p(); }
AstNode* valuep() const { return op3p(); }
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstConsDynArray : public AstNodeMath {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// Parents: math
// Children: expression (elements or other queues)
public:
AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
: ASTGEN_SUPER(fl) {
setNOp1p(lhsp);
setNOp2p(rhsp);
}
ASTNODE_NODE_FUNCS(ConsDynArray)
virtual string emitVerilog() override { return "'{%l, %r}"; }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* lhsp() const { return op1p(); } // op1 = expression
AstNode* rhsp() const { return op2p(); } // op2 = expression
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstConsQueue : public AstNodeMath {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// Parents: math
// Children: expression (elements or other queues)
public:
AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
: ASTGEN_SUPER(fl) {
setNOp1p(lhsp);
setNOp2p(rhsp);
}
ASTNODE_NODE_FUNCS(ConsQueue)
virtual string emitVerilog() override { return "'{%l, %r}"; }
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { return true; }
virtual int instrCount() const override { return widthInstrs(); }
AstNode* lhsp() const { return op1p(); } // op1 = expression
AstNode* rhsp() const { return op2p(); } // op2 = expression
virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; }
};
class AstBegin : public AstNodeBlock {
// A Begin/end named block, only exists shortly after parsing until linking
// Parents: statement
@ -5812,12 +5954,17 @@ public:
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
AstNode* lhsp() const { return op1p(); }
void lhsp(AstNode* nodep) { setOp1p(nodep); }
virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* childDTypep() const { return VN_CAST(op2p(), NodeDType); }
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
};
class AstCastDynamic : public AstNodeBiop {
// Verilog $cast used as a function
// Task usage of $cast is converted during parse to assert($cast(...))
// Parents: MATH
// Children: MATH
public:
AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: ASTGEN_SUPER(fl, lhsp, rhsp) {}
@ -7895,7 +8042,10 @@ public:
V3ERROR_NA;
}
virtual string emitVerilog() override { return "%f$fgets(%l,%r)"; }
virtual string emitC() override { return "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; }
virtual string emitC() override {
return strgp()->dtypep()->basicp()->isString() ? "VL_FGETS_NI(%li, %ri)"
: "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)";
}
virtual bool cleanOut() const override { return false; }
virtual bool cleanLhs() const override { return true; }
virtual bool cleanRhs() const override { return true; }
@ -8238,6 +8388,7 @@ public:
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
virtual int instrCount() const override { return widthInstrs() * 2; }
virtual void dump(std::ostream& str = std::cout) const override;
// op1 = expression to assign or another AstPattern (list if replicated)
AstNode* lhssp() const { return op1p(); }
AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text)
@ -8913,6 +9064,7 @@ class AstTypeTable : public AstNode {
// Container for hash of standard data types
// Children: NODEDTYPEs
AstVoidDType* m_voidp = nullptr;
AstQueueDType* m_queueIndexp = nullptr;
AstBasicDType* m_basicps[AstBasicDTypeKwd::_ENUM_MAX];
//
typedef std::map<VBasicTypeKey, AstBasicDType*> DetailedMap;
@ -8927,6 +9079,7 @@ public:
AstNodeDType* typesp() const { return VN_CAST(op1p(), NodeDType); } // op1 = List of dtypes
void addTypesp(AstNodeDType* nodep) { addOp1p(nodep); }
AstVoidDType* findVoidDType(FileLine* fl);
AstQueueDType* findQueueIndexDType(FileLine* fl);
AstBasicDType* findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd);
AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width, int widthMin,
VSigning numeric);

View File

@ -69,6 +69,11 @@ private:
// METHODS
VL_DEBUG_FUNC; // Declare debug()
string dot(const string& a, const string& b) {
if (a == "") return b;
return a + "__DOT__" + b;
}
// VISITORS
virtual void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_modp);
@ -81,7 +86,7 @@ private:
UINFO(8, " " << nodep << endl);
// Rename it
if (m_unnamedScope != "") {
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
UINFO(8, " rename to " << nodep->name() << endl);
m_statep->userMarkChanged(nodep);
}
@ -103,8 +108,8 @@ private:
virtual void visit(AstBegin* nodep) override {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep << endl);
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
{
UINFO(8, "nname " << m_namedScope << endl);
if (nodep->name() != "") { // Else unneeded unnamed block
@ -114,18 +119,8 @@ private:
while ((pos = dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + strlen("__DOT__"));
if (nodep->name() != "") {
if (m_namedScope == "") {
m_namedScope = ident;
} else {
m_namedScope = m_namedScope + "__DOT__" + ident;
}
}
if (m_unnamedScope == "") {
m_unnamedScope = ident;
} else {
m_unnamedScope = m_unnamedScope + "__DOT__" + ident;
}
if (nodep->name() != "") m_namedScope = dot(m_namedScope, ident);
m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(
@ -138,31 +133,29 @@ private:
// Remap var names and replace lower Begins
iterateAndNextNull(nodep->stmtsp());
UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier");
}
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
// Cleanup
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
} else {
addsp = stmtsp;
// Cleanup
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
} else {
addsp = stmtsp;
}
}
if (addsp) {
nodep->replaceWith(addsp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
if (addsp) {
nodep->replaceWith(addsp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstVar* nodep) override {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
@ -176,7 +169,7 @@ private:
virtual void visit(AstTypedef* nodep) override {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_unnamedScope, nodep->name()));
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
@ -193,7 +186,7 @@ private:
if (m_namedScope != "") {
m_statep->userMarkChanged(nodep);
// Rename it
nodep->name(m_namedScope + "__DOT__" + nodep->name());
nodep->name(dot(m_namedScope, nodep->name()));
UINFO(8, " rename to " << nodep->name() << endl);
// Move to module
nodep->unlinkFrBack();

View File

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

View File

@ -41,7 +41,7 @@ private:
// MEMBERS
AstNodeModule* m_modInsertp; // Current module to insert AstCUse under
typedef std::pair<VUseType, string> UseString;
std::map<UseString, AstCUse*> m_didUse; // What we already used
std::map<const UseString, AstCUse*> m_didUse; // What we already used
// NODE STATE
// Entire netlist:
@ -148,7 +148,7 @@ class CUseVisitor : public AstNVisitor {
funcp->isStatic(false);
funcp->protect(false);
AstNode* exprp = new AstCMath(nodep->fileline(),
"std::string(\"`{\") + to_string_middle() + \"}\"", 0);
R"(std::string("'{") + to_string_middle() + "}")", 0);
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp));
nodep->addStmtp(funcp);
@ -162,23 +162,25 @@ class CUseVisitor : public AstNVisitor {
funcp->addStmtsp(new AstCStmt(nodep->fileline(), "std::string out;\n"));
std::string comma;
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
if (VN_IS(itemp, Var)) {
string stmt = "out += \"";
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + ";
if (itemp->isWide()) {
stmt += "VL_TO_STRING_W(";
stmt += cvtToStr(itemp->widthWords());
stmt += ", ";
} else {
stmt += "VL_TO_STRING(";
if (auto* varp = VN_CAST(itemp, Var)) {
if (!varp->isParam()) {
string stmt = "out += \"";
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
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
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
stmt += itemp->nameProtect();
stmt += ");\n";
nodep->user1(true); // So what we extend dumps this
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
}
if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) {

View File

@ -486,7 +486,7 @@ private:
public:
// CONSTRUCTORS
explicit CaseVisitor(AstNetlist* nodep) {
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = nullptr;
for (auto& itr : m_valueItem) itr = nullptr;
iterate(nodep);
}
virtual ~CaseVisitor() override {

View File

@ -73,7 +73,7 @@ private:
ensureLower32Cast(castp);
nodep->user1(1); // Now must be of known size
}
int castSize(AstNode* nodep) {
static int castSize(AstNode* nodep) {
if (nodep->isQuad()) {
return VL_QUADSIZE;
} else if (nodep->width() <= 8) {
@ -154,7 +154,7 @@ private:
}
}
virtual void visit(AstVarRef* nodep) override {
if (nodep->access().isRead() && !VN_IS(nodep->backp(), CCast)
if (nodep->access().isReadOnly() && !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

View File

@ -311,13 +311,12 @@ private:
}
}
string spaces(int level) {
static string spaces(int level) {
string out;
while (level--) out += " ";
return out;
} // LCOV_EXCL_LINE
string pad(unsigned column, const string& in) {
static string pad(unsigned column, const string& in) {
string out = in;
while (out.length() < column) out += ' ';
return out;
@ -588,15 +587,15 @@ private:
// Convert list of senses into one sense node
AstSenTree* senoutp = nullptr;
bool senedited = false;
for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) {
for (const auto& itr : senouts) {
if (!senoutp) {
senoutp = *it;
senoutp = itr;
} else {
if (!senedited) {
senedited = true;
senoutp = senoutp->cloneTree(true);
}
senoutp->addSensesp((*it)->sensesp()->cloneTree(true));
senoutp->addSensesp(itr->sensesp()->cloneTree(true));
}
}
// If multiple domains need to do complicated optimizations
@ -661,7 +660,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->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
if (m_inDly) {
varvertexp->fromFlop(true);

View File

@ -35,6 +35,8 @@ private:
AstUser1InUse m_inuser1;
string m_prefix; // String prefix to add to name based on hier
AstScope* m_classScopep = nullptr; // Package moving scopes into
AstScope* m_packageScopep = nullptr; // Class package scope
AstNodeFTask* m_ftaskp = nullptr; // Current task
typedef std::vector<std::pair<AstNode*, AstScope*>> MoveVector;
MoveVector m_moves;
@ -76,12 +78,14 @@ private:
packagep->addStmtp(scopep);
// Iterate
VL_RESTORER(m_prefix);
VL_RESTORER(m_classScopep);
VL_RESTORER(m_packageScopep);
{
m_classScopep = classScopep;
m_packageScopep = scopep;
m_prefix = nodep->name() + "__02e"; // .
iterateChildren(nodep);
}
m_classScopep = nullptr;
}
virtual void visit(AstPackage* nodep) override {
VL_RESTORER(m_prefix);
@ -94,11 +98,28 @@ private:
virtual void visit(AstVar* nodep) override {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
// TODO move class statics only
// if (m_classScopep) {
// m_moves.push_back(make_pair(nodep, m_classScopep));
//}
// TODO move class statics too
if (m_ftaskp && m_ftaskp->lifetime().isStatic()) {
m_moves.push_back(make_pair(nodep, m_packageScopep));
}
}
virtual void visit(AstVarScope* nodep) override {
iterateChildren(nodep);
nodep->varp()->user1p(nodep);
}
virtual void visit(AstNodeFTask* nodep) override {
VL_RESTORER(m_ftaskp);
{
m_ftaskp = nodep;
iterateChildren(nodep);
if (nodep->lifetime().isStatic()) {
m_moves.push_back(make_pair(nodep, m_packageScopep));
}
}
}
virtual void visit(AstCFunc* nodep) override {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
@ -116,8 +137,13 @@ public:
// CONSTRUCTORS
explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ClassVisitor() override {
for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) {
it->second->addVarp(it->first->unlinkFrBack());
for (auto moved : m_moves) {
if (VN_IS(moved.first, NodeFTask)) {
moved.second->addActivep(moved.first->unlinkFrBack());
} else if (VN_IS(moved.first, Var)) {
AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope);
moved.second->addVarp(scopep->unlinkFrBack());
}
}
}
};

View File

@ -285,6 +285,11 @@ private:
ensureCleanAndNext(nodep->pinsp());
setClean(nodep, true);
}
virtual void visit(AstWith* nodep) override {
iterateChildren(nodep);
ensureCleanAndNext(nodep->exprp());
setClean(nodep, true);
}
virtual void visit(AstIntfRef* nodep) override {
iterateChildren(nodep);
setClean(nodep, true); // generates a string, so not relevant

View File

@ -177,7 +177,7 @@ private:
VDouble0 m_statCombs; // Statistic tracking
CombineState m_state = STATE_IDLE; // Major state
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current function
AstCFunc* m_cfuncp = nullptr; // Current function
CombCallVisitor m_call; // Tracking of function call users
int m_modNFuncs = 0; // Number of functions made
#ifdef VL_COMBINE_STATEMENTS
@ -203,8 +203,8 @@ private:
}
#endif
void walkEmptyFuncs() {
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
AstNode* node1p = it->second;
for (const auto& itr : m_hashed) {
AstNode* node1p = itr.second;
AstCFunc* oldfuncp = VN_CAST(node1p, CFunc);
if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) {
UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " "
@ -330,7 +330,7 @@ private:
AstNode* last2p) { // Final node in linked list, maybe null if all statements
// to be grabbed
// Make new function
string oldname = m_funcp->name();
string oldname = m_cfuncp->name();
string::size_type pos;
if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos);
if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos);
@ -423,7 +423,8 @@ private:
m_modp = nullptr;
}
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
VL_RESTORER(m_cfuncp);
m_cfuncp = nodep;
if (!nodep->dontCombine()) {
if (m_state == STATE_HASH) {
hashStatement(nodep); // Hash the entire function - it might be identical
@ -434,18 +435,17 @@ private:
}
#endif
}
m_funcp = nullptr;
}
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
}
if (m_state == STATE_HASH && m_funcp) {
if (m_state == STATE_HASH && m_cfuncp) {
hashStatement(nodep);
}
#ifdef VL_COMBINE_STATEMENTS
else if (m_state == STATE_DUP && m_funcp) {
else if (m_state == STATE_DUP && m_cfuncp) {
walkDupCodeStart(nodep);
}
#endif

View File

@ -33,7 +33,7 @@
// cache of resolved entities. Entities stored in this container need an update
// function that takes a reference of this type to join multiple entities into one.
template <typename T> class V3ConfigWildcardResolver {
typedef std::map<string, T> Map;
typedef std::map<const string, T> Map;
Map m_mapWildcard; // Wildcard strings to entities
Map m_mapResolved; // Resolved strings to converged entities
@ -282,15 +282,9 @@ public:
}
void update(const V3ConfigFile& file) {
// Copy in all Attributes
for (LineAttrMap::const_iterator it = file.m_lineAttrs.begin();
it != file.m_lineAttrs.end(); ++it) {
m_lineAttrs[it->first] |= it->second;
}
for (const auto& itr : file.m_lineAttrs) { m_lineAttrs[itr.first] |= itr.second; }
// Copy in all ignores
for (IgnLines::const_iterator it = file.m_ignLines.begin(); it != file.m_ignLines.end();
++it) {
m_ignLines.insert(*it);
}
for (const auto& ignLine : file.m_ignLines) m_ignLines.insert(ignLine);
// Update the iterator after the list has changed
m_lastIgnore.it = m_ignLines.begin();
m_waivers.reserve(m_waivers.size() + file.m_waivers.size());
@ -338,9 +332,9 @@ public:
}
}
bool waive(V3ErrorCode code, const string& match) {
for (Waivers::const_iterator it = m_waivers.begin(); it != m_waivers.end(); ++it) {
if (((it->first == code) || (it->first == V3ErrorCode::I_LINT))
&& VString::wildmatch(match, it->second)) {
for (const auto& itr : m_waivers) {
if (((itr.first == code) || (itr.first == V3ErrorCode::I_LINT))
&& VString::wildmatch(match, itr.second)) {
return true;
}
}

View File

@ -314,7 +314,7 @@ private:
// It was an expression, then got constified. In reality, the WordSel
// must be wrapped in a Cond, that will be false.
return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef)
&& !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isWrite()
&& VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isReadOnly()
&& (static_cast<int>(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt())
>= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords()));
}
@ -1297,17 +1297,21 @@ private:
virtual void visit(AstCFunc* nodep) override {
// No ASSIGNW removals under funcs, we've long eliminated INITIALs
// (We should perhaps rename the assignw's to just assigns)
m_wremove = false;
iterateChildren(nodep);
m_wremove = true;
VL_RESTORER(m_wremove);
{
m_wremove = false;
iterateChildren(nodep);
}
}
virtual void visit(AstScope* nodep) override {
// No ASSIGNW removals under scope, we've long eliminated INITIALs
m_scopep = nodep;
m_wremove = false;
iterateChildren(nodep);
m_wremove = true;
m_scopep = nullptr;
VL_RESTORER(m_wremove);
VL_RESTORER(m_scopep);
{
m_wremove = false;
m_scopep = nodep;
iterateChildren(nodep);
}
}
void swapSides(AstNodeBiCom* nodep) {
@ -1605,7 +1609,7 @@ private:
// if (debug()) valuep->dumpTree(cout, " visitvaref: ");
iterateAndNextNull(nodep->varp()->valuep()); // May change nodep->varp()->valuep()
AstNode* valuep = nodep->varp()->valuep();
if (!nodep->access().isWrite()
if (nodep->access().isReadOnly()
&& ((!m_params // Can reduce constant wires into equations
&& m_doNConst
&& v3Global.opt.oConst()
@ -1937,7 +1941,8 @@ private:
ifp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep));
nodep->replaceWith(ifp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
} else if (false // Disabled, as vpm assertions are faster
// without due to short-circuiting
&& operandIfIf(nodep)) {
UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl);
AstNodeIf* lowerIfp = VN_CAST(nodep->ifsp(), NodeIf);

View File

@ -188,15 +188,15 @@ private:
const LinenoSet& lines = m_handleLines[state.m_handle];
int first = 0;
int last = 0;
for (LinenoSet::iterator it = lines.begin(); it != lines.end(); ++it) {
for (int linen : lines) {
if (!first) {
first = last = *it;
} else if (*it == last + 1) {
first = last = linen;
} else if (linen == last + 1) {
++last;
} else {
if (!out.empty()) out += ",";
out += linesFirstLast(first, last);
first = last = *it;
first = last = linen;
}
}
if (first) {

View File

@ -367,14 +367,13 @@ private:
void deadCheckClasses() {
for (bool retry = true; retry;) {
retry = false;
for (std::vector<AstClass*>::iterator it = m_classesp.begin(); it != m_classesp.end();
++it) {
if (AstClass* nodep = *it) { // nullptr if deleted earlier
for (auto& itr : m_classesp) {
if (AstClass* nodep = itr) { // nullptr if deleted earlier
if (nodep->user1() == 0) {
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
if (nodep->packagep()) nodep->packagep()->user1Inc(-1);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
*it = nullptr;
itr = nullptr;
retry = true;
}
}

View File

@ -95,10 +95,10 @@ private:
bool m_inDly = false; // True in delayed assignments
bool m_inLoop = false; // True in for loops
bool m_inInitial = false; // True in initial blocks
typedef std::map<std::pair<AstNodeModule*, string>, AstVar*> VarMap;
typedef std::map<const std::pair<AstNodeModule*, string>, AstVar*> VarMap;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
typedef std::map<AstVarScope*, int> ScopeVecMap;
typedef std::map<const AstVarScope*, int> ScopeVecMap;
ScopeVecMap m_scopeVecMap; // Next var number for each scope
// METHODS
@ -358,9 +358,11 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) override {
m_cfuncp = nodep;
iterateChildren(nodep);
m_cfuncp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
virtual void visit(AstActive* nodep) override {
m_activep = nodep;
@ -408,10 +410,11 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (!nodep->user2Inc()) { // Not done yet
if (m_inDly && nodep->access().isWrite()) {
if (m_inDly && nodep->access().isWriteOrRW()) {
UINFO(4, "AssignDlyVar: " << nodep << endl);
markVarUsage(nodep->varScopep(), VU_DLY);
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
UASSERT_OBJ(!nodep->access().isRW(), nodep, "<= on read+write method");
if (!m_activep->hasClocked()) {
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
"have converted in V3Active");
@ -456,7 +459,7 @@ private:
newrefp->user2(true); // No reason to do it again
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (!m_inDly && nodep->access().isWrite()) {
} else if (!m_inDly && nodep->access().isWriteOrRW()) {
// UINFO(9, "NBA " << nodep << endl);
if (!m_inInitial) {
UINFO(4, "AssignNDlyVar: " << nodep << endl);

View File

@ -40,7 +40,7 @@ private:
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current block
AstCFunc* m_cfuncp = nullptr; // Current block
AstNode* m_stmtp = nullptr; // Current statement
int m_depth = 0; // How deep in an expression
int m_maxdepth = 0; // Maximum depth in an expression
@ -61,8 +61,8 @@ private:
// bitmask instead of widths....)
// See t_func_crc for an example test that requires this
VFlagLogicPacked(), nodep->width());
UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function");
m_funcp->addInitsp(varp);
UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function");
m_cfuncp->addInitsp(varp);
// Replace node tree with reference to var
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
nodep->replaceWith(newp);
@ -81,23 +81,27 @@ private:
VL_RESTORER(m_modp);
{
m_modp = nodep;
m_funcp = nullptr;
m_cfuncp = nullptr;
iterateChildren(nodep);
}
}
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
m_funcp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
}
}
void visitStmt(AstNodeStmt* nodep) {
m_depth = 0;
m_maxdepth = 0;
m_stmtp = nodep;
iterateChildren(nodep);
m_stmtp = nullptr;
VL_RESTORER(m_stmtp);
{
m_stmtp = nodep;
m_depth = 0;
m_maxdepth = 0;
iterateChildren(nodep);
}
}
virtual void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
@ -128,10 +132,10 @@ private:
// Marking of non-static functions (because they might need "this")
// (Here instead of new visitor after V3Descope just to avoid another visitor)
void needNonStaticFunc(AstNode* nodep) {
UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function");
if (m_funcp->isStatic().trueUnknown()) {
UASSERT_OBJ(m_cfuncp, nodep, "Non-static accessor not under a function");
if (m_cfuncp->isStatic().trueUnknown()) {
UINFO(5, "Mark non-public due to " << nodep << endl);
m_funcp->isStatic(false);
m_cfuncp->isStatic(false);
}
}
virtual void visit(AstUCFunc* nodep) override {

View File

@ -38,7 +38,7 @@ private:
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current function
AstCFunc* m_cfuncp = nullptr; // Current function
int m_depth = 0; // How deep in an expression
int m_deepNum = 0; // How many functions made
@ -49,11 +49,11 @@ private:
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
// Create function
string name = m_funcp->name() + "__deep" + cvtToStr(++m_deepNum);
string name = m_cfuncp->name() + "__deep" + cvtToStr(++m_deepNum);
AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, nullptr);
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->symProlog(true);
funcp->slow(m_funcp->slow());
funcp->slow(m_cfuncp->slow());
funcp->addStmtsp(nodep);
m_modp->addStmtp(funcp);
// Call it at the point where the body was removed from
@ -78,10 +78,10 @@ private:
virtual void visit(AstCFunc* nodep) override {
// We recurse into this.
VL_RESTORER(m_depth);
VL_RESTORER(m_funcp);
VL_RESTORER(m_cfuncp);
{
m_depth = 0;
m_funcp = nodep;
m_cfuncp = nodep;
iterateChildren(nodep);
}
}

View File

@ -268,6 +268,8 @@ private:
// nodep->funcp()->scopep(nullptr);
}
virtual void visit(AstCFunc* nodep) override {
VL_RESTORER(m_needThis);
VL_RESTORER(m_allowThis);
if (!nodep->user1()) {
m_needThis = false;
m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static

View File

@ -23,6 +23,7 @@
#include "V3EmitCBase.h"
#include "V3Number.h"
#include "V3PartitionGraph.h"
#include "V3Task.h"
#include "V3TSP.h"
#include <algorithm>
@ -156,6 +157,7 @@ public:
}
void emitParams(AstNodeModule* modp, bool init, bool* firstp, string& sectionr) {
bool anyi = false;
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) {
if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) {
@ -172,12 +174,15 @@ public:
}
} else if (varp->isString()) {
if (init) {
emitCtorSep(firstp);
puts(protect("var_" + varp->name()) + " (");
puts("const std::string ");
puts(prefixNameProtect(modp) + "::" + protect("var_" + varp->name())
+ "(");
iterateAndNextNull(varp->valuep());
puts(")");
puts(");\n");
anyi = true;
} else {
puts("const std::string " + protect("var_" + varp->name()) + ";\n");
puts("static const std::string " + protect("var_" + varp->name())
+ ";\n");
}
} else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output
// putsDecoration("// enum ..... "+varp->nameProtect()
@ -187,10 +192,12 @@ public:
->isOpaque()) { // Can't put out e.g. doubles
} else {
if (init) {
emitCtorSep(firstp);
puts(protect("var_" + varp->name()) + " (");
puts(varp->isQuad() ? "const QData " : "const IData ");
puts(prefixNameProtect(modp) + "::" + protect("var_" + varp->name())
+ "(");
iterateAndNextNull(varp->valuep());
puts(")");
puts(");\n");
anyi = true;
} else {
// enum
puts(varp->isQuad() ? "enum _QData" : "enum _IData");
@ -198,13 +205,14 @@ public:
iterateAndNextNull(varp->valuep());
puts("};\n");
// var
puts(varp->isQuad() ? "const QData " : "const IData ");
puts(varp->isQuad() ? "static const QData " : "static const IData ");
puts(protect("var_" + varp->name()) + ";\n");
}
}
}
}
}
if (anyi) puts("\n");
}
struct CmpName {
@ -418,6 +426,18 @@ public:
UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep,
"Statement of non-void data type");
}
virtual void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); }
virtual void visit(AstWith* nodep) override {
// With uses a C++11 lambda
putbs("[=](");
if (auto* argrefp = nodep->argrefp()) {
putbs(argrefp->dtypep()->cType(nodep->argrefp()->nameProtect(), false, false));
}
// Probably fragile, V3Task may need to convert to a AstCReturn
puts(") { return ");
iterateAndNextNull(nodep->exprp());
puts("; }\n");
}
virtual void visit(AstIntfRef* nodep) override {
putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), nodep->protect()));
}
@ -1225,7 +1245,6 @@ public:
nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName());
}
public:
EmitCStmts() {
m_suppressSemi = false;
m_wideTempRefp = nullptr;
@ -1275,8 +1294,8 @@ public:
// Returns the number of elements in set_a that don't appear in set_b
static int diffs(const MTaskIdSet& set_a, const MTaskIdSet& set_b) {
int diffs = 0;
for (MTaskIdSet::iterator it = set_a.begin(); it != set_a.end(); ++it) {
if (set_b.find(*it) == set_b.end()) ++diffs;
for (int i : set_a) {
if (set_b.find(i) == set_b.end()) ++diffs;
}
return diffs;
}
@ -1568,6 +1587,55 @@ class EmitCImp : EmitCStmts {
}
}
virtual void visit(AstConsAssoc* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
puts("()");
if (nodep->defaultp()) {
putbs(".setDefault(");
iterateAndNextNull(nodep->defaultp());
puts(")");
}
}
virtual void visit(AstSetAssoc* nodep) override {
iterateAndNextNull(nodep->lhsp());
putbs(".set(");
iterateAndNextNull(nodep->keyp());
puts(", ");
putbs("");
iterateAndNextNull(nodep->valuep());
puts(")");
}
virtual void visit(AstConsDynArray* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
} else {
puts("::cons(");
iterateAndNextNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
putbs("");
}
iterateAndNextNull(nodep->rhsp());
puts(")");
}
}
virtual void visit(AstConsQueue* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
} else {
puts("::cons(");
iterateAndNextNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
putbs("");
}
iterateAndNextNull(nodep->rhsp());
puts(")");
}
}
virtual void visit(AstChangeDet* nodep) override { //
m_blkChangeDetVec.push_back(nodep);
}
@ -1656,19 +1724,16 @@ class EmitCImp : EmitCStmts {
} else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (initarp->defaultp()) {
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi=0;");
puts(" for (; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("; ++__Vi) {\n");
emitSetVarConstant(varp->nameProtect() + "[__Vi]",
VN_CAST(initarp->defaultp(), Const));
puts("}}\n");
puts("}\n");
}
const AstInitArray::KeyItemMap& mapr = initarp->map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end();
++it) {
AstNode* valuep = it->second->valuep();
emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(it->first) + "]",
for (const auto& itr : mapr) {
AstNode* valuep = itr.second->valuep();
emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(itr.first) + "]",
VN_CAST(valuep, Const));
}
} else {
@ -1704,12 +1769,11 @@ class EmitCImp : EmitCStmts {
UASSERT_OBJ(adtypep->msb() >= adtypep->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(depth);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
string pre = ("{ int " + ivar + "=" + cvtToStr(0) + ";" + " for (; " + ivar + "<"
string pre = ("for (int " + ivar + "=" + cvtToStr(0) + "; " + ivar + "<"
+ cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n");
string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1,
suffix + "[" + ivar + "]");
string post = "}}\n";
string post = "}\n";
return below.empty() ? "" : pre + below + post;
} else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) {
// String's constructor deals with it
@ -1839,6 +1903,16 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
puts(");\n");
} else {
// strings and other fundamental c types
if (nodep->isFuncLocal() && nodep->isString()) {
const string name = nodep->name();
const string suffix = V3Task::dpiTemporaryVarSuffix();
// string temporary variable for DPI-C needs to be static because c_str() will be
// passed to C code and the lifetime of the variable must be long enough. See also
// Issue 2622.
const bool beStatic = name.size() >= suffix.size()
&& name.substr(name.size() - suffix.size()) == suffix;
if (beStatic) puts("static VL_THREAD_LOCAL ");
}
puts(nodep->vlArgType(true, false, false, prefixIfImp));
puts(";\n");
}
@ -2161,7 +2235,12 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
}
emitDispState.pushFormat(pfmt);
if (!ignore) {
emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin()));
if (argp->dtypep()->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
// string in SystemVerilog is std::string in C++ which is not POD
emitDispState.pushArg(' ', nullptr, "-1");
} else {
emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin()));
}
emitDispState.pushArg(fmtLetter, argp, "");
} else {
emitDispState.pushArg(fmtLetter, nullptr, "");
@ -2272,7 +2351,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, const str
//######################################################################
// Internal EmitC
void EmitCImp::emitCoverageDecl(AstNodeModule* modp) {
void EmitCImp::emitCoverageDecl(AstNodeModule*) {
if (v3Global.opt.coverage()) {
ofp()->putsPrivate(true);
putsDecoration("// Coverage\n");
@ -2319,6 +2398,9 @@ void EmitCImp::emitMTaskVertexCtors(bool* firstp) {
void EmitCImp::emitCtorImp(AstNodeModule* modp) {
puts("\n");
bool first = true;
string section;
emitParams(modp, true, &first, section /*ref*/);
if (VN_IS(modp, Class)) {
modp->v3fatalSrc("constructors should be AstCFuncs instead");
} else if (optSystemC() && modp->isTop()) {
@ -2329,8 +2411,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
}
emitVarCtors(&first);
if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first);
string section("");
emitParams(modp, true, &first, section /*ref*/);
puts(" {\n");
emitCellCtors(modp);
emitSensitives();
@ -2397,7 +2478,7 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
splitSizeInc(10);
}
void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
void EmitCImp::emitCoverageImp(AstNodeModule*) {
if (v3Global.opt.coverage()) {
puts("\n// Coverage\n");
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this function
@ -2499,10 +2580,8 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)',
// so declare in sep block
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";");
puts(" for (; " + ivar + "<" + cvtToStr(arrayp->elementsConst()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0));
puts("; " + ivar + "<" + cvtToStr(arrayp->elementsConst()));
puts("; ++" + ivar + ") {\n");
elementp = arrayp->subDTypep()->skipRefp();
}
@ -2513,14 +2592,14 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
&& !(basicp && basicp->keyword() == AstBasicDTypeKwd::STRING)) {
int vecnum = vects++;
string ivar = string("__Vi") + cvtToStr(vecnum);
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";");
puts(" for (; " + ivar + "<" + cvtToStr(elementp->widthWords()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0));
puts("; " + ivar + "<" + cvtToStr(elementp->widthWords()));
puts("; ++" + ivar + ") {\n");
}
puts("os" + op + varp->nameProtect());
for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]");
puts(";\n");
for (int v = 0; v < vects; ++v) puts("}}\n");
for (int v = 0; v < vects; ++v) puts("}\n");
}
}
}
@ -2588,16 +2667,14 @@ void EmitCImp::emitSensitives() {
UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp,
"Should have swapped msb & lsb earlier.");
string ivar = string("__Vi") + cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb())
+ ";");
puts(" for (; " + ivar + "<=" + cvtToStr(arrayp->msb()));
puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb()));
puts("; " + ivar + "<=" + cvtToStr(arrayp->msb()));
puts("; ++" + ivar + ") {\n");
}
puts("sensitive << " + varp->nameProtect());
for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]");
puts(";\n");
for (int v = 0; v < vects; ++v) puts("}}\n");
for (int v = 0; v < vects; ++v) puts("}\n");
}
}
}
@ -2824,8 +2901,8 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) {
if (!v3Global.opt.mtasks()) {
// Plain old serial mode. Sort by size, from small to large,
// to optimize for both packing and small offsets in code.
for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
for (VarVec::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) {
for (const auto& itr : vmap) {
for (VarVec::const_iterator jt = itr.second.begin(); jt != itr.second.end(); ++jt) {
sortedp->push_back(*jt);
}
}
@ -2833,7 +2910,7 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) {
}
// MacroTask mode. Sort by MTask-affinity group first, size second.
typedef std::map<MTaskIdSet, VarSortMap> MTaskVarSortMap;
typedef std::map<const MTaskIdSet, VarSortMap> MTaskVarSortMap;
MTaskVarSortMap m2v;
for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
int size_class = it->first;
@ -2954,7 +3031,7 @@ void EmitCImp::emitMTaskState() {
puts("bool __Vm_even_cycle;\n");
}
void EmitCImp::emitIntTop(AstNodeModule* modp) {
void EmitCImp::emitIntTop(AstNodeModule*) {
// Always have this first; gcc has short circuiting if #ifdef is first in a file
ofp()->putsGuard();
puts("\n");
@ -3150,13 +3227,13 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("\n// INTERNAL METHODS\n");
if (modp->isTop()) {
ofp()->putsPrivate(true); // private:
ofp()->putsPrivate(false); // public: as accessed by another VL_MODULE
puts("static void " + protect("_eval_initial_loop") + "(" + EmitCBaseVisitor::symClassVar()
+ ");\n");
if (v3Global.needTraceDumper()) {
if (!optSystemC()) puts("void _traceDump();");
puts("void _traceDumpOpen();");
puts("void _traceDumpClose();");
if (!optSystemC()) puts("void _traceDump();\n");
puts("void _traceDumpOpen();\n");
puts("void _traceDumpClose();\n");
}
}
@ -3331,7 +3408,7 @@ class EmitCTrace : EmitCStmts {
AstUser1InUse m_inuser1;
// MEMBERS
AstCFunc* m_funcp = nullptr; // Function we're in now
AstCFunc* m_cfuncp = nullptr; // Function we're in now
bool m_slow; // Making slow file
int m_enumNum = 0; // Enumeration number (whole netlist)
int m_baseCode = -1; // Code of first AstTraceInc in this function
@ -3663,8 +3740,9 @@ class EmitCTrace : EmitCStmts {
virtual void visit(AstNodeModule* nodep) override { iterateChildren(nodep); }
virtual void visit(AstCFunc* nodep) override {
if (nodep->slow() != m_slow) return;
VL_RESTORER(m_cfuncp);
if (nodep->funcType().isTrace()) { // TRACE_*
m_funcp = nodep;
m_cfuncp = nodep;
if (splitNeeded()) {
// Splitting file, so using parallel build.
@ -3734,7 +3812,6 @@ class EmitCTrace : EmitCStmts {
}
puts("}\n");
}
m_funcp = nullptr;
}
virtual void visit(AstTraceDecl* nodep) override {
int enumNum = emitTraceDeclDType(nodep->dtypep());

View File

@ -71,8 +71,8 @@ class CMakeEmitter {
// Swap all backslashes for forward slashes, because of Windows
static string deslash(const string& s) {
std::string res = s;
for (string::iterator it = res.begin(); it != res.end(); ++it) {
if (*it == '\\') *it = '/';
for (char& c : res) {
if (c == '\\') c = '/';
}
return res;
}
@ -150,37 +150,37 @@ class CMakeEmitter {
}
}
global.push_back("${VERILATOR_ROOT}/include/verilated.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated.cpp");
if (v3Global.dpi()) { //
global.push_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp");
}
if (v3Global.opt.vpi()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp");
}
if (v3Global.opt.savable()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_save.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_save.cpp");
}
if (v3Global.opt.coverage()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_cov.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_cov.cpp");
}
if (v3Global.opt.trace()) {
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase()
+ "_c.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase()
+ "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3warn(E_UNSUPPORTED,
"Unsupported: This trace format is not supported in SystemC, "
"use VCD format.");
}
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang()
+ ".cpp");
global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang()
+ ".cpp");
}
}
if (v3Global.opt.mtasks()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
}
if (!v3Global.opt.protectLib().empty()) {
global.push_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp");
global.emplace_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp");
}
*of << "# Global classes, need linked once per executable\n";
@ -243,9 +243,9 @@ class CMakeEmitter {
*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) {
for (const auto& itr : *planp) {
*of << " "
<< deslash(v3Global.opt.makeDir() + "/" + it->second->hierWrapper(true));
<< deslash(v3Global.opt.makeDir() + "/" + itr.second->hierWrapper(true));
}
*of << " " << deslash(cmake_list(v3Global.opt.vFiles()));
*of << " VERILATOR_ARGS ";

View File

@ -50,11 +50,11 @@ class EmitCSyms : EmitCBaseVisitor {
};
struct ScopeFuncData {
AstScopeName* m_scopep;
AstCFunc* m_funcp;
AstCFunc* m_cfuncp;
AstNodeModule* m_modp;
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
: m_scopep{scopep}
, m_funcp{funcp}
, m_cfuncp{funcp}
, m_modp{modp} {}
};
struct ScopeVarData {
@ -71,13 +71,13 @@ class EmitCSyms : EmitCBaseVisitor {
, m_modp{modp}
, m_scopep{scopep} {}
};
typedef std::map<string, ScopeFuncData> ScopeFuncs;
typedef std::map<string, ScopeVarData> ScopeVars;
typedef std::map<string, ScopeData> ScopeNames;
typedef std::map<const string, ScopeFuncData> ScopeFuncs;
typedef std::map<const string, ScopeVarData> ScopeVars;
typedef std::map<const string, ScopeData> ScopeNames;
typedef std::pair<AstScope*, AstNodeModule*> ScopeModPair;
typedef std::pair<AstNodeModule*, AstVar*> ModVarPair;
typedef std::vector<string> ScopeNameList;
typedef std::map<string, ScopeNameList> ScopeNameHierarchy;
typedef std::map<const string, ScopeNameList> ScopeNameHierarchy;
struct CmpName {
inline bool operator()(const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
return lhsp.first->name() < rhsp.first->name();
@ -94,7 +94,7 @@ class EmitCSyms : EmitCBaseVisitor {
};
// STATE
AstCFunc* m_funcp = nullptr; // Current function
AstCFunc* m_cfuncp = nullptr; // Current function
AstNodeModule* m_modp = nullptr; // Current module
std::vector<ScopeModPair> m_scopes; // Every scope by module
std::vector<AstCFunc*> m_dpis; // DPI functions
@ -296,7 +296,7 @@ class EmitCSyms : EmitCBaseVisitor {
if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible
nameCheck(nodep);
m_scopes.push_back(make_pair(nodep, m_modp));
m_scopes.emplace_back(make_pair(nodep, m_modp));
if (v3Global.opt.vpi() && !nodep->isTop()) {
string name_dedot = AstNode::dedotName(nodep->shortName());
@ -316,9 +316,9 @@ class EmitCSyms : EmitCBaseVisitor {
name, ScopeData(name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER")));
}
if (nodep->dpiExport()) {
UASSERT_OBJ(m_funcp, nodep, "ScopeName not under DPI function");
UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function");
m_scopeFuncs.insert(
make_pair(name + " " + m_funcp->name(), ScopeFuncData(nodep, m_funcp, m_modp)));
make_pair(name + " " + m_cfuncp->name(), ScopeFuncData(nodep, m_cfuncp, m_modp)));
} else {
if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) {
m_scopeNames.insert(
@ -331,7 +331,7 @@ class EmitCSyms : EmitCBaseVisitor {
virtual void visit(AstVar* nodep) override {
nameCheck(nodep);
iterateChildren(nodep);
if (nodep->isSigUserRdPublic()) { m_modVars.push_back(make_pair(m_modp, nodep)); }
if (nodep->isSigUserRdPublic()) { m_modVars.emplace_back(make_pair(m_modp, nodep)); }
}
virtual void visit(AstCoverDecl* nodep) override {
// Assign numbers to all bins, so we know how big of an array to use
@ -342,9 +342,11 @@ class EmitCSyms : EmitCBaseVisitor {
virtual void visit(AstCFunc* nodep) override {
nameCheck(nodep);
if (nodep->dpiImport() || nodep->dpiExportWrapper()) m_dpis.push_back(nodep);
m_funcp = nodep;
iterateChildren(nodep);
m_funcp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
//---------------------------------------
@ -395,17 +397,15 @@ void EmitCSyms::emitSymHdr() {
if (v3Global.dpi()) {
puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n");
std::map<string, int> types; // Remove duplicates and sort
for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
AstCFunc* funcp = it->second.m_funcp;
std::map<const string, int> types; // Remove duplicates and sort
for (const auto& itr : m_scopeFuncs) {
AstCFunc* funcp = itr.second.m_cfuncp;
if (funcp->dpiExport()) {
string cbtype = protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t");
types["typedef void (*" + cbtype + ") (" + cFuncArgs(funcp) + ");\n"] = 1;
}
}
for (std::map<string, int>::iterator it = types.begin(); it != types.end(); ++it) {
puts(it->first);
}
for (const auto& i : types) puts(i.first);
}
puts("\n// SYMS CLASS\n");
@ -432,9 +432,9 @@ void EmitCSyms::emitSymHdr() {
puts("bool __Vm_didInit;\n");
puts("\n// SUBCELL STATE\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
if (VN_IS(modp, Class)) continue;
if (modp->isTop()) {
ofp()->printf("%-30s ", (prefixNameProtect(modp) + "*").c_str());
@ -455,8 +455,8 @@ void EmitCSyms::emitSymHdr() {
if (!m_scopeNames.empty()) { // Scope names
puts("\n// SCOPE NAMES\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
puts("VerilatedScope " + protect("__Vscope_" + it->second.m_symName) + ";\n");
for (const auto& itr : m_scopeNames) {
puts("VerilatedScope " + protect("__Vscope_" + itr.second.m_symName) + ";\n");
}
}
@ -469,9 +469,9 @@ void EmitCSyms::emitSymHdr() {
puts(symClassName() + "(" + topClassName() + "* topp, const char* namep);\n");
puts(string("~") + symClassName() + "() {}\n");
for (std::map<int, bool>::iterator it = m_usesVfinal.begin(); it != m_usesVfinal.end(); ++it) {
puts("void " + symClassName() + "_" + cvtToStr(it->first) + "(");
if (it->second) {
for (const auto& i : m_usesVfinal) {
puts("void " + symClassName() + "_" + cvtToStr(i.first) + "(");
if (i.second) {
puts("int __Vfinal");
} else {
puts(topClassName() + "* topp");
@ -619,9 +619,9 @@ void EmitCSyms::emitSymImp() {
puts(" , __Vm_didInit(false)\n");
puts(" // Setup submodule names\n");
char comma = ',';
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
if (modp->isTop()) {
} else {
puts(string(" ") + comma + " " + protect(scopep->nameDotless()));
@ -638,9 +638,9 @@ void EmitCSyms::emitSymImp() {
puts("// Pointer to top level\n");
puts("TOPp = topp;\n");
puts("// Setup each module's pointers to their submodules\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
if (!modp->isTop()) {
checkSplit(false);
string arrow = scopep->name();
@ -656,9 +656,9 @@ void EmitCSyms::emitSymImp() {
puts("// Setup each module's pointer back to symbol table (for public functions)\n");
puts("TOPp->" + protect("__Vconfigure") + "(this, true);\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
if (!modp->isTop()) {
checkSplit(false);
// first is used by AstCoverDecl's call to __vlCoverInsert
@ -723,7 +723,7 @@ void EmitCSyms::emitSymImp() {
m_ofpBase->puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n");
for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
AstScopeName* scopep = it->second.m_scopep;
AstCFunc* funcp = it->second.m_funcp;
AstCFunc* funcp = it->second.m_cfuncp;
AstNodeModule* modp = it->second.m_modp;
if (funcp->dpiExport()) {
checkSplit(true);

View File

@ -281,7 +281,6 @@ public:
of.putsHeader();
}
public:
explicit EmitMk() {
emitClassMake();
emitOverallMake();
@ -363,10 +362,7 @@ class EmitMkHierVerilation {
of.puts(v3Global.opt.prefix()
+ ".mk: $(VM_HIER_INPUT_FILES) $(VM_HIER_VERILOG_LIBS) ");
of.puts(V3Os::filenameNonDir(argsFile) + " ");
for (V3HierBlockPlan::const_iterator it = m_planp->begin(); it != m_planp->end();
++it) {
of.puts(it->second->hierWrapper(true) + " ");
}
for (const auto& itr : *m_planp) of.puts(itr.second->hierWrapper(true) + " ");
of.puts("\n");
emitLaunchVerilator(of, argsFile);
}

View File

@ -490,14 +490,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(")");
}
virtual void visit(AstInitArray* nodep) override {
putfs(nodep, "`{");
putfs(nodep, "'{");
int comma = 0;
const AstInitArray::KeyItemMap& mapr = nodep->map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
for (const auto& itr : mapr) {
if (comma++) putbs(", ");
puts(cvtToStr(it->first));
puts(cvtToStr(itr.first));
puts(":");
AstNode* valuep = it->second->valuep();
AstNode* valuep = itr.second->valuep();
iterate(valuep);
}
puts("}");

View File

@ -172,9 +172,8 @@ inline void V3FileDependImp::writeDepend(const string& filename) {
inline std::vector<string> V3FileDependImp::getAllDeps() const {
std::vector<string> r;
for (std::set<DependFile>::const_iterator iter = m_filenameList.begin();
iter != m_filenameList.end(); ++iter) {
if (!iter->target() && iter->exists()) { r.push_back(iter->filename()); }
for (const auto& itr : m_filenameList) {
if (!itr.target() && itr.exists()) r.push_back(itr.filename());
}
return r;
}
@ -331,7 +330,7 @@ void V3File::createMakeDir() {
// VInFilterImp
class VInFilterImp {
typedef std::map<string, string> FileContentsMap;
typedef std::map<const string, string> FileContentsMap;
typedef VInFilter::StrList StrList;
FileContentsMap m_contentsMap; // Cache of file contents
@ -587,12 +586,12 @@ protected:
}
return true;
}
size_t listSize(StrList& sl) {
static size_t listSize(StrList& sl) {
size_t out = 0;
for (const string& i : sl) out += i.length();
return out;
}
string listString(StrList& sl) {
static string listString(StrList& sl) {
string out;
for (const string& i : sl) out += i;
return out;
@ -942,8 +941,8 @@ void V3OutCFile::putsGuard() {
UASSERT(!m_guard, "Already called putsGuard in emit file");
m_guard = true;
string var = VString::upcase(string("_") + V3Os::filenameNonDir(filename()) + "_");
for (string::iterator pos = var.begin(); pos != var.end(); ++pos) {
if (!isalnum(*pos)) *pos = '_';
for (char& c : var) {
if (!isalnum(c)) c = '_';
}
puts("\n#ifndef " + var + "\n");
puts("#define " + var + " // guard\n");
@ -954,7 +953,7 @@ void V3OutCFile::putsGuard() {
class VIdProtectImp {
// MEMBERS
typedef std::map<string, string> IdMap;
typedef std::map<const string, string> IdMap;
IdMap m_nameMap; // Map of old name into new name
typedef std::unordered_set<std::string> IdSet;
IdSet m_newIdSet; // Which new names exist
@ -1046,8 +1045,8 @@ public:
"IPTION: Verilator output: XML representation of netlist -->\n");
of.puts("<verilator_id_map>\n");
{
for (IdMap::const_iterator it = m_nameMap.begin(); it != m_nameMap.end(); ++it) {
of.puts("<map from=\"" + it->second + "\" to=\"" + it->first + "\"/>\n");
for (const auto& itr : m_nameMap) {
of.puts("<map from=\"" + itr.second + "\" to=\"" + itr.first + "\"/>\n");
}
}
of.puts("</verilator_id_map>\n");

View File

@ -90,8 +90,8 @@ int VFileContent::debug() {
void VFileContent::pushText(const string& text) {
if (m_lines.size() == 0) {
m_lines.push_back(""); // no such thing as line [0]
m_lines.push_back(""); // start with no leftover
m_lines.emplace_back(""); // no such thing as line [0]
m_lines.emplace_back(""); // start with no leftover
}
// Any leftover text is stored on largest line (might be "")
@ -112,7 +112,7 @@ void VFileContent::pushText(const string& text) {
}
}
// Keep leftover for next time
m_lines.push_back(string(leftover, line_start)); // Might be ""
m_lines.emplace_back(string(leftover, line_start)); // Might be ""
}
string VFileContent::getLine(int lineno) const {

View File

@ -39,7 +39,7 @@ class FileLine;
//! source file (each with its own unique filename number).
class FileLineSingleton {
// TYPES
typedef std::map<string, int> FileNameNumMap;
typedef std::map<const string, int> FileNameNumMap;
// MEMBERS
FileNameNumMap m_namemap; // filenameno for each filename
std::deque<string> m_names; // filename text for each filenameno

View File

@ -220,7 +220,9 @@ private:
if (nodep->varScopep()->varp()->isSc()) {
clearSimple("SystemC sig"); // Don't want to eliminate the VL_ASSIGN_SI's
}
if (nodep->access().isWrite()) {
if (nodep->access().isRW()) {
clearSimple("R/W");
} else if (nodep->access().isWriteOrRW()) {
if (m_lhsVarRef) clearSimple(">1 lhs varRefs");
m_lhsVarRef = nodep;
} else {
@ -448,7 +450,7 @@ private:
vvertexp->setIsClock();
// For SYNCASYNCNET
varscp->user2(true);
} else if (m_activep && m_activep->hasClocked() && !nodep->access().isWrite()) {
} else if (m_activep && m_activep->hasClocked() && nodep->access().isReadOnly()) {
if (varscp->user2()) {
if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep);
} else {
@ -457,9 +459,10 @@ private:
}
// We use weight of one; if we ref the var more than once, when we simplify,
// the weight will increase
if (nodep->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1);
} else {
}
if (nodep->access().isReadOrRW()) {
new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1);
}
}
@ -600,7 +603,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
<< " ob" << vvertexp->outBeginp() << " on"
<< (vvertexp->outBeginp()
? vvertexp->outBeginp()->outNextp()
: 0)
: nullptr)
<< " " << vvertexp->name() << endl);
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;
edgep = edgep->outNextp()) {
@ -842,7 +845,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->access().isWrite(), nodep,
UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
"Can't replace lvalue assignments with const var");
AstNode* substp = m_replaceTreep->cloneTree(false);
UASSERT_OBJ(
@ -937,7 +940,7 @@ private:
public:
GateDedupeHash() {}
~GateDedupeHash() {
virtual ~GateDedupeHash() override {
if (v3Global.opt.debugCheck()) check();
}
@ -963,7 +966,7 @@ public:
}
// Callback from V3Hashed::findDuplicate
bool isSame(AstNode* node1p, AstNode* node2p) {
virtual bool isSame(AstNode* node1p, AstNode* node2p) override {
// Assignment may have been hashReplaced, if so consider non-match (effectively removed)
if (isReplaced(node1p) || isReplaced(node2p)) {
// UINFO(9, "isSame hit on replaced "<<(void*)node1p<<" "<<(void*)node2p<<endl);
@ -999,8 +1002,8 @@ public:
void check() {
m_hashed.check();
for (V3Hashed::HashMmap::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
AstNode* nodep = it->second;
for (const auto& itr : m_hashed) {
AstNode* nodep = itr.second;
AstNode* activep = nodep->user3p();
AstNode* condVarp = nodep->user5p();
if (!isReplaced(nodep)) {
@ -1084,7 +1087,7 @@ private:
public:
// CONSTRUCTORS
GateDedupeVarVisitor() {}
~GateDedupeVarVisitor() {}
virtual ~GateDedupeVarVisitor() override {}
// PUBLIC METHODS
AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
m_assignp = nullptr;
@ -1346,7 +1349,7 @@ private:
}
return VNUser(0);
}
virtual VNUser visit(GateLogicVertex*, VNUser vu) override { //
virtual VNUser visit(GateLogicVertex*, VNUser) override { //
return VNUser(0);
}

View File

@ -111,7 +111,6 @@ private:
m_activep = nullptr;
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) override { iterateChildren(nodep); }
//-----
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
@ -186,7 +185,7 @@ private:
UINFO(8, " VarAct " << nodep << endl);
vscp->user1(true);
}
if (m_assignp && nodep->access().isWrite() && vscp->user1()) {
if (m_assignp && nodep->access().isWriteOrRW() && vscp->user1()) {
// Variable was previously used as a clock, and is now being set
// Thus a unordered generated clock...
UINFO(8, " VarSetAct " << nodep << endl);

View File

@ -335,7 +335,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
// We use a map here, as we don't want to corrupt anything (userp) in the graph,
// and we don't care if this is slow.
std::map<V3GraphVertex*, int> numMap;
std::map<const V3GraphVertex*, int> numMap;
// Print vertices
int n = 0;

View File

@ -143,9 +143,7 @@ private:
}
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(toEdgep->userp());
if (OrigEdgeList* addListp = static_cast<OrigEdgeList*>(addEdgep->userp())) {
for (OrigEdgeList::iterator it = addListp->begin(); it != addListp->end(); ++it) {
oEListp->push_back(*it);
}
for (const auto& itr : *addListp) oEListp->push_back(itr);
addListp->clear(); // Done with it
} else {
oEListp->push_back(addEdgep);
@ -160,8 +158,7 @@ private:
v3fatalSrc("No original edge associated with cutting edge " << breakEdgep << endl);
}
// The breakGraph edge may represent multiple real edges; cut them all
for (OrigEdgeList::iterator it = oEListp->begin(); it != oEListp->end(); ++it) {
V3GraphEdge* origEdgep = *it;
for (const auto& origEdgep : *oEListp) {
origEdgep->cut();
UINFO(8,
" " << why << " " << origEdgep->fromp() << " ->" << origEdgep->top() << endl);

View File

@ -73,8 +73,8 @@ private:
// METHODS
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; }
// bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; }
static bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; }
// static bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; }
void nextStep() { m_step++; }
@ -317,9 +317,8 @@ private:
}
// Foreach input state (NFA inputs of this DFA state)
for (std::set<int>::const_iterator inIt = inputs.begin(); inIt != inputs.end();
++inIt) {
DfaInput input = *inIt;
for (int inIt : inputs) {
DfaInput input = inIt;
UINFO(9, " ===" << ++i << "=======================\n");
UINFO(9, " On input " << cvtToHex(input.toNodep()) << endl);

View File

@ -42,7 +42,7 @@ struct GraphPCNode {
// CONSTRUCTORS
GraphPCNode() {
for (int w = 0; w < GraphWay::NUM_WAYS; w++) m_cp[w] = 0;
for (unsigned int& w : m_cp) w = 0;
}
~GraphPCNode() {}
};

View File

@ -139,8 +139,8 @@ void V3Hashed::erase(iterator it) {
}
void V3Hashed::check() {
for (HashMmap::iterator it = begin(); it != end(); ++it) {
AstNode* nodep = it->second;
for (const auto& itr : *this) {
AstNode* nodep = itr.second;
UASSERT_OBJ(nodep->user4p(), nodep, "V3Hashed check failed, non-hashed node");
}
}
@ -174,21 +174,20 @@ void V3Hashed::dumpFile(const string& filename, bool tree) {
}
*logp << "\n*** STATS:\n" << endl;
*logp << " #InBucket Occurrences\n";
for (std::map<int, int>::iterator it = dist.begin(); it != dist.end(); ++it) {
*logp << " " << std::setw(9) << it->first << " " << std::setw(12) << it->second
<< endl;
for (const auto& i : dist) {
*logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << endl;
}
*logp << "\n*** Dump:\n" << endl;
for (HashMmap::iterator it = begin(); it != end(); ++it) {
if (lasthash != it->first) {
lasthash = it->first;
*logp << " " << it->first << endl;
for (const auto& itr : *this) {
if (lasthash != itr.first) {
lasthash = itr.first;
*logp << " " << itr.first << endl;
}
*logp << "\t" << it->second << endl;
*logp << "\t" << itr.second << endl;
// Dumping the entire tree may make nearly N^2 sized dumps,
// because the nodes under this one may also be in the hash table!
if (tree) it->second->dumpTree(*logp, " ");
if (tree) itr.second->dumpTree(*logp, " ");
}
}

View File

@ -75,8 +75,9 @@ public:
void check(); // Check assertions on structure
// Hash the node, and insert into map. Return iterator to inserted
iterator hashAndInsert(AstNode* nodep);
void hash(AstNode* nodep); // Only hash the node
bool sameNodes(AstNode* node1p, AstNode* node2p); // After hashing, and tell if identical
static void hash(AstNode* nodep); // Only hash the node
// After hashing, and tell if identical
static bool sameNodes(AstNode* node1p, AstNode* node2p);
void erase(iterator it); // Remove node from structures
// Return duplicate in hash, if any, with optional user check for sameness
iterator findDuplicate(AstNode* nodep, V3HashedUserSame* checkp = nullptr);

View File

@ -107,9 +107,8 @@ static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of
V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, bool forGOption) {
StrGParams strParams;
for (V3HierBlock::GParams::const_iterator gparamIt = gparams.begin();
gparamIt != gparams.end(); ++gparamIt) {
if (const AstConst* constp = VN_CAST((*gparamIt)->valuep(), Const)) {
for (const auto& gparam : gparams) {
if (const AstConst* constp = VN_CAST(gparam->valuep(), Const)) {
string s;
// Only constant parameter needs to be set to -G because already checked in
// V3Param.cpp. See also ParamVisitor::checkSupportedParam() in the file.
@ -131,7 +130,7 @@ V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, boo
s = constp->num().ascii(true, true);
s = VString::quoteAny(s, '\'', '\\');
}
strParams.push_back(std::make_pair((*gparamIt)->name(), s));
strParams.push_back(std::make_pair(gparam->name(), s));
}
}
return strParams;
@ -139,9 +138,8 @@ V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, boo
V3HierBlock::~V3HierBlock() {
UASSERT(m_children.empty(), "at least one module must be a leaf");
for (HierBlockSet::const_iterator child = m_children.begin(); child != m_children.end();
++child) {
const bool deleted = (*child)->m_children.erase(this);
for (const auto& hierblockp : m_children) {
const bool deleted = hierblockp->m_children.erase(this);
UASSERT_OBJ(deleted, m_modp, " is not registered");
}
}
@ -214,9 +212,8 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
*of << "--cc\n";
if (!forCMake) {
for (V3HierBlock::HierBlockSet::const_iterator child = m_children.begin();
child != m_children.end(); ++child) {
*of << v3Global.opt.makeDir() << "/" << (*child)->hierWrapper(true) << "\n";
for (const auto& hierblockp : m_children) {
*of << v3Global.opt.makeDir() << "/" << hierblockp->hierWrapper(true) << "\n";
}
*of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n";
}
@ -224,10 +221,7 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
const V3StringList& commandOpts = commandArgs(false);
for (const string& opt : commandOpts) *of << opt << "\n";
*of << hierBlockArgs().front() << "\n";
for (HierBlockSet::const_iterator child = m_children.begin(); child != m_children.end();
++child) {
*of << (*child)->hierBlockArgs().front() << "\n";
}
for (const auto& hierblockp : m_children) *of << hierblockp->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"; }
@ -436,6 +430,6 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const {
*of << v3Global.opt.allArgsStringForHierBlock(true) << "\n";
}
string V3HierBlockPlan::topCommandArgsFileName(bool forCMake) const {
string V3HierBlockPlan::topCommandArgsFileName(bool forCMake) {
return V3HierCommandArgsFileName(v3Global.opt.prefix(), forCMake);
}

View File

@ -122,7 +122,7 @@ public:
// Write command line arguments to .f files for child Verilation run
void writeCommandArgsFiles(bool forCMake) const;
string topCommandArgsFileName(bool forCMake) const;
static string topCommandArgsFileName(bool forCMake);
static void createPlan(AstNetlist* nodep);
};

View File

@ -417,7 +417,7 @@ private:
// Track what scope it was originally under so V3LinkDot can resolve it
string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots());
nodep->inlinedDots(newdots);
for (string tryname = nodep->dotted(); 1;) {
for (string tryname = nodep->dotted(); true;) {
if (m_renamedInterfaces.count(tryname)) {
nodep->dotted(m_cellp->name() + "__DOT__" + nodep->dotted());
break;

View File

@ -141,7 +141,7 @@ class InstDeModVarVisitor : public AstNVisitor {
// Expand all module variables, and save names for later reference
private:
// STATE
typedef std::map<string, AstVar*> VarNameMap;
typedef std::map<const string, AstVar*> VarNameMap;
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
VL_DEBUG_FUNC; // Declare debug()
@ -172,13 +172,11 @@ public:
}
}
void dump() {
for (VarNameMap::iterator it = m_modVarNameMap.begin(); it != m_modVarNameMap.end();
++it) {
cout << "-namemap: " << it->first << " -> " << it->second << endl;
for (const auto& itr : m_modVarNameMap) {
cout << "-namemap: " << itr.first << " -> " << itr.second << endl;
}
}
public:
// CONSTRUCTORS
explicit InstDeModVarVisitor() {}
void main(AstNodeModule* nodep) {
@ -195,8 +193,8 @@ class InstDeVisitor : public AstNVisitor {
// Find all cells with arrays, and convert to non-arrayed
private:
// STATE
AstRange* m_cellRangep
= nullptr; // Range for arrayed instantiations, nullptr for normal instantiations
// Range for arrayed instantiations, nullptr for normal instantiations
AstRange* m_cellRangep = nullptr;
int m_instSelNum = 0; // Current instantiation count 0..N-1
InstDeModVarVisitor m_deModVars; // State of variables for current cell module
@ -278,8 +276,7 @@ private:
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType);
origIfaceRefp->cellp(nullptr);
AstVar* varNewp = ifaceVarp->cloneTree(false);
AstIfaceRefDType* ifaceRefp
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType)->cloneTree(false);
AstIfaceRefDType* ifaceRefp = origIfaceRefp->cloneTree(false);
arrdtype->addNextHere(ifaceRefp);
ifaceRefp->cellp(newp);
ifaceRefp->cellName(newp->name());
@ -378,7 +375,10 @@ private:
return;
}
string index = AstNode::encodeNumber(constp->toSInt());
if (VN_IS(arrselp->lhsp(), SliceSel))
arrselp->lhsp()->v3error("Unsupported: interface slices");
AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef);
UASSERT_OBJ(varrefp, arrselp, "No interface varref under array");
AstVarXRef* newp = new AstVarXRef(nodep->fileline(),
varrefp->name() + "__BRA__" + index + "__KET__",
"", VAccess::WRITE);

View File

@ -241,13 +241,12 @@ private:
UASSERT_OBJ(m_tracingCall || nodep == m_startNodep, nodep,
"AstCFunc not under AstCCall, or not start node");
m_tracingCall = false;
bool saved_inCFunc = m_inCFunc;
m_inCFunc = true;
VL_RESTORER(m_inCFunc);
{
m_inCFunc = true;
VisitBase vb(this, nodep);
iterateChildren(nodep);
}
m_inCFunc = saved_inCFunc;
}
virtual void visit(AstNode* nodep) override {
VisitBase vb(this, nodep);

View File

@ -27,7 +27,7 @@
class V3LanguageWords {
// List of common reserved keywords
private:
typedef std::map<string, string> KeywordMap;
typedef std::map<const string, string> KeywordMap;
struct Singleton {
KeywordMap s_kwdMap; // List of keywords, and what language applies
Singleton() { init(); }

View File

@ -49,7 +49,6 @@ public:
VDouble0 m_statAssnCon; // Statistic tracking
std::vector<AstNode*> m_unlinkps;
public:
// CONSTRUCTORS
LifeState() {}
~LifeState() {
@ -68,35 +67,29 @@ public:
// Structure for each variable encountered
class LifeVarEntry {
AstNodeAssign* m_assignp; // Last assignment to this varscope, nullptr if no longer relevant
AstConst* m_constp; // Known constant value
// Last assignment to this varscope, nullptr if no longer relevant
AstNodeAssign* m_assignp = nullptr;
AstConst* m_constp = nullptr; // Known constant value
// First access was a set (and thus block above may have a set that can be deleted
bool m_setBeforeUse;
// Was ever assigned (and thus above block may not preserve constant propagation)
bool m_everSet;
inline void init(bool setBeforeUse) {
m_assignp = nullptr;
m_constp = nullptr;
m_setBeforeUse = setBeforeUse;
m_everSet = false;
}
bool m_everSet = false;
public:
class SIMPLEASSIGN {};
class COMPLEXASSIGN {};
class CONSUMED {};
LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) {
init(true);
LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp)
: m_setBeforeUse{true} {
simpleAssign(assp);
}
explicit LifeVarEntry(COMPLEXASSIGN) {
init(false);
explicit LifeVarEntry(COMPLEXASSIGN)
: m_setBeforeUse{false} {
complexAssign();
}
explicit LifeVarEntry(CONSUMED) {
init(false);
explicit LifeVarEntry(CONSUMED)
: m_setBeforeUse{false} {
consumed();
}
~LifeVarEntry() {}
@ -300,7 +293,7 @@ private:
//
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (nodep->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
m_sideEffect = true; // $sscanf etc may have RHS vars that are lvalues
m_lifep->complexAssign(vscp);
} else {

View File

@ -99,13 +99,11 @@ public:
// and a sequence number within the mtask:
struct LifeLocation {
const ExecMTask* mtaskp;
uint32_t sequence;
const ExecMTask* mtaskp = nullptr;
uint32_t sequence = 0;
public:
LifeLocation()
: mtaskp{nullptr}
, sequence{0} {}
LifeLocation() {}
LifeLocation(const ExecMTask* mtaskp_, uint32_t sequence_)
: mtaskp{mtaskp_}
, sequence{sequence_} {}
@ -120,9 +118,8 @@ public:
struct LifePostLocation {
LifeLocation loc;
AstAssignPost* nodep;
LifePostLocation()
: nodep{nullptr} {}
AstAssignPost* nodep = nullptr;
LifePostLocation() {}
LifePostLocation(LifeLocation loc_, AstAssignPost* nodep_)
: loc{loc_}
, nodep{nodep_} {}
@ -183,15 +180,14 @@ private:
return true;
}
if (before(assignPostLoc, loc)) return true;
for (std::set<LifeLocation>::iterator it = dlyVarAssigns.begin();
it != dlyVarAssigns.end(); ++it) {
if (!before(loc, *it)) return false;
for (const auto& i : dlyVarAssigns) {
if (!before(loc, i)) return false;
}
return true;
}
void squashAssignposts() {
for (PostLocMap::iterator it = m_assignposts.begin(); it != m_assignposts.end(); ++it) {
LifePostLocation* app = &it->second;
for (auto& itr : m_assignposts) {
LifePostLocation* app = &itr.second;
AstVarRef* lhsp = VN_CAST(app->nodep->lhsp(), VarRef); // original var
AstVarRef* rhsp = VN_CAST(app->nodep->rhsp(), VarRef); // dly var
AstVarScope* dlyVarp = rhsp->varScopep();
@ -284,11 +280,8 @@ private:
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
LifeLocation loc(m_execMTaskp, ++m_sequence);
if (nodep->access().isWrite()) {
m_writes[vscp].insert(loc);
} else {
m_reads[vscp].insert(loc);
}
if (nodep->access().isWriteOrRW()) m_writes[vscp].insert(loc);
if (nodep->access().isReadOrRW()) m_reads[vscp].insert(loc);
}
virtual void visit(AstAssignPre* nodep) override {
// Do not record varrefs within assign pre.

View File

@ -46,6 +46,8 @@
// #8: Insert modport's symbols under IfaceRefDType (after #7)
// ResolveVisitor:
// #9: Resolve general variables, which may point into the interface or modport (after #8)
// LinkResolve:
// #10: Unlink modports, not needed later except for XML/Lint
//*************************************************************************
// TOP
// {name-of-top-modulename}
@ -90,7 +92,9 @@ public:
};
class LinkNodeMatcherVar : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Var); }
virtual bool nodeMatch(const AstNode* nodep) const override {
return VN_IS(nodep, Var) || VN_IS(nodep, LambdaArgRef);
}
};
class LinkNodeMatcherVarIO : public VNodeMatcher {
public:
@ -108,12 +112,6 @@ public:
return varp->isParam();
}
};
class LinkNodeMatcherVarOrScope : public VNodeMatcher {
public:
virtual bool nodeMatch(const AstNode* nodep) const override {
return VN_IS(nodep, Var) || VN_IS(nodep, Scope);
}
};
//######################################################################
// LinkDot state, as a visitor of each AstNode
@ -450,6 +448,8 @@ public:
if (!ifacerefp->ifaceViaCellp()) {
if (!ifacerefp->cellp()) { // Probably a NotFoundModule, or a normal module if
// made mistake
UINFO(1, "Associated cell " << AstNode::prettyNameQ(ifacerefp->cellName())
<< endl);
ifacerefp->v3error("Cannot find file containing interface: "
<< AstNode::prettyNameQ(ifacerefp->ifaceName()));
continue;
@ -719,6 +719,7 @@ class LinkDotFindVisitor : public AstNVisitor {
int m_blockNum = 0; // Begin block number, 0=none seen
bool m_explicitNew = false; // Hit a "new" function
int m_modBlockNum = 0; // Begin block number in module, 0=none seen
int m_modWithNum = 0; // With block number, 0=none seen
// METHODS
static int debug() { return LinkDotState::debug(); }
@ -781,6 +782,7 @@ class LinkDotFindVisitor : public AstNVisitor {
VL_RESTORER(m_paramNum);
VL_RESTORER(m_blockNum);
VL_RESTORER(m_modBlockNum);
VL_RESTORER(m_modWithNum);
if (doit && nodep->user2()) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Identically recursive module (module instantiates "
@ -807,6 +809,7 @@ class LinkDotFindVisitor : public AstNVisitor {
m_paramNum = 0;
m_blockNum = 0;
m_modBlockNum = 0;
m_modWithNum = 0;
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
// Iterate
nodep->user2(true);
@ -842,6 +845,7 @@ class LinkDotFindVisitor : public AstNVisitor {
VL_RESTORER(m_paramNum);
VL_RESTORER(m_blockNum);
VL_RESTORER(m_modBlockNum);
VL_RESTORER(m_modWithNum);
{
UINFO(4, " Link Class: " << nodep << endl);
VSymEnt* upperSymp = m_curSymp;
@ -854,6 +858,7 @@ class LinkDotFindVisitor : public AstNVisitor {
m_paramNum = 0;
m_blockNum = 0;
m_modBlockNum = 0;
m_modWithNum = 0;
m_explicitNew = false;
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
// Iterate
@ -1001,7 +1006,12 @@ class LinkDotFindVisitor : public AstNVisitor {
}
// Create symbol table for the task's vars
string name = string{nodep->isExternProto() ? "extern " : ""} + nodep->name();
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_packagep);
auto pkgp = m_packagep;
// Set the class as package for static class methods
if (nodep->lifetime().isStatic() && VN_IS(m_curSymp->nodep(), Class)) {
pkgp = VN_CAST(m_curSymp->nodep(), Class);
}
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, pkgp);
m_curSymp->fallbackp(oldCurSymp);
// Convert the func's range to the output variable
// This should probably be done in the Parser instead, as then we could
@ -1253,6 +1263,46 @@ class LinkDotFindVisitor : public AstNVisitor {
m_curSymp->exportStarStar(m_statep->symsp());
// No longer needed, but can't delete until any multi-instantiated modules are expanded
}
virtual void visit(AstWithParse* nodep) override {
// Change WITHPARSE(FUNCREF, equation) to FUNCREF(WITH(equation))
auto funcrefp = VN_CAST(nodep->funcrefp(), NodeFTaskRef);
UASSERT_OBJ(funcrefp, nodep, "'with' only can operate on a function/task");
string name = "item";
FileLine* argFl = nodep->fileline();
if (auto argp = VN_CAST(funcrefp->pinsp(), Arg)) {
if (auto parserefp = VN_CAST(argp->exprp(), ParseRef)) {
name = parserefp->name();
argFl = parserefp->fileline();
} else {
argp->v3error("'with' function expects simple variable name");
}
if (argp->nextp())
argp->nextp()->v3error("'with' function expects only up to one argument");
VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp);
}
// Type depends on the method used, let V3Width figure it out later
auto* argrefp = new AstLambdaArgRef(argFl, name);
auto* newp
= new AstWith(nodep->fileline(), argrefp, nodep->exprp()->unlinkFrBackWithNext());
funcrefp->addPinsp(newp);
nodep->replaceWith(funcrefp->unlinkFrBack());
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstWith* nodep) override {
// Symbol table needs nodep->name() as the index variable's name
// Iteration will pickup the AstVar we made under AstWith
VL_RESTORER(m_curSymp);
VSymEnt* const oldCurSymp = m_curSymp;
{
++m_modWithNum;
m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep,
m_packagep);
m_curSymp->fallbackp(oldCurSymp);
UASSERT_OBJ(nodep->argrefp(), nodep, "Missing lambda argref");
// Insert argref's name into symbol table
m_statep->insertSym(m_curSymp, nodep->argrefp()->name(), nodep->argrefp(), nullptr);
}
}
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
@ -1502,6 +1552,11 @@ class LinkDotScopeVisitor : public AstNVisitor {
symp->fallbackp(m_modSymp);
// No recursion, we don't want to pick up variables
}
virtual void visit(AstWith* nodep) override {
VSymEnt* symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr);
symp->fallbackp(m_modSymp);
// No recursion, we don't want to pick up variables
}
virtual void visit(AstAssignAlias* nodep) override {
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
// we'll need to replace it with a VARXREF(aliased_to)
@ -1671,9 +1726,9 @@ public:
};
void LinkDotState::computeIfaceModSyms() {
for (IfaceModSyms::iterator it = m_ifaceModSyms.begin(); it != m_ifaceModSyms.end(); ++it) {
AstIface* nodep = it->first;
VSymEnt* symp = it->second;
for (const auto& itr : m_ifaceModSyms) {
AstIface* nodep = itr.first;
VSymEnt* symp = itr.second;
LinkDotIfaceVisitor(nodep, symp, this);
}
m_ifaceModSyms.clear();
@ -1718,7 +1773,7 @@ private:
VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup
AstDot* m_dotp; // Current dot
bool m_unresolved; // Unresolved, needs help from V3Param
AstNode* m_unlinkedScope; // Unresolved scope, needs corresponding VarXRef
AstNode* m_unlinkedScopep; // Unresolved scope, needs corresponding VarXRef
bool m_dotErr; // Error found in dotted resolution, ignore upwards
string m_dotText; // String of dotted names found in below parseref
DotStates() { init(nullptr); }
@ -1730,7 +1785,7 @@ private:
m_dotErr = false;
m_dotText = "";
m_unresolved = false;
m_unlinkedScope = nullptr;
m_unlinkedScopep = nullptr;
}
string ascii() const {
static const char* const names[] = {"NONE", "PACKAGE", "SCOPE", "FINAL", "MEMBER"};
@ -1781,7 +1836,7 @@ private:
m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*packagep*/);
}
}
AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, bool lvalue) {
AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, VAccess access) {
// Return a variable if possible, auto converting a modport to variable
if (!symp) {
return nullptr;
@ -1790,7 +1845,7 @@ private:
} else if (VN_IS(symp->nodep(), ModportVarRef)) {
AstModportVarRef* snodep = VN_CAST(symp->nodep(), ModportVarRef);
AstVar* varp = snodep->varp();
if (lvalue && snodep->direction().isReadOnly()) {
if (access.isWriteOrRW() && snodep->direction().isReadOnly()) {
nodep->v3error("Attempt to drive input-only modport: " << nodep->prettyNameQ());
} // else other simulators don't warn about reading, and IEEE doesn't say illegal
return varp;
@ -1812,18 +1867,12 @@ private:
m_ds.m_dotErr = true;
}
}
AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep,
AstModport* modportp) {
// Create iface variable, using duplicate var when under same module scope
string varName = ifacep->name() + "__Vmp__" + modportp->name() + "__Viftop"
+ cvtToStr(++m_modportNum);
AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, modportp->fileline(), cellp->name(),
ifacep->name(), modportp->name());
idtypep->cellp(cellp);
AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
varp->isIfaceParent(true);
m_modp->addStmtp(varp);
return varp;
AstVar* findIfaceTopVarp(AstNode* nodep, VSymEnt* parentEntp, const string& name) {
string findName = name + "__Viftop";
VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName);
AstVar* ifaceTopVarp = ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : nullptr;
UASSERT_OBJ(ifaceTopVarp, nodep, "Can't find interface var ref: " << findName);
return ifaceTopVarp;
}
void markAndCheckPinDup(AstNode* nodep, AstNode* refp, const char* whatp) {
if (refp->user5p() && refp->user5p() != nodep) {
@ -1979,11 +2028,11 @@ private:
} else {
m_ds.m_dotPos = DP_SCOPE;
iterateAndNextNull(nodep->lhsp());
// if (debug()>=9) nodep->dumpTree("-dot-lho: ");
// if (debug() >= 9) nodep->dumpTree("-dot-lho: ");
}
if (m_ds.m_unresolved
&& (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
m_ds.m_unlinkedScope = nodep->lhsp();
m_ds.m_unlinkedScopep = nodep->lhsp();
}
if (!m_ds.m_dotErr) { // Once something wrong, give up
// Top 'final' dot RHS is final RHS, else it's a
@ -2066,12 +2115,7 @@ private:
"Bad package link");
AstClassOrPackageRef* cpackagerefp
= VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
packagep = cpackagerefp->packagep();
if (!packagep && cpackagerefp->classOrPackagep()) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Class '::' references: "
<< AstNode::prettyNameQ(cpackagerefp->name()));
}
packagep = cpackagerefp->classOrPackagep();
UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link");
m_ds.m_dotSymp = m_statep->getNodeSym(packagep);
m_ds.m_dotPos = DP_SCOPE;
@ -2123,12 +2167,7 @@ private:
VSymEnt* parentEntp
= cellEntp->parentp(); // Container of the var; probably a module or
// generate begin
string findName = nodep->name() + "__Viftop";
VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName);
AstVar* ifaceRefVarp
= ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : nullptr;
UASSERT_OBJ(ifaceRefVarp, nodep,
"Can't find interface var ref: " << findName);
AstVar* ifaceRefVarp = findIfaceTopVarp(nodep, parentEntp, nodep->name());
//
ok = true;
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
@ -2144,7 +2183,7 @@ private:
<< cellp->modp()->prettyNameQ());
}
}
} else if (AstVar* varp = foundToVarp(foundp, nodep, false)) {
} else if (AstVar* varp = foundToVarp(foundp, nodep, VAccess::READ)) {
AstIfaceRefDType* ifacerefp = LinkDotState::ifaceRefFromArray(varp->subDTypep());
if (ifacerefp) {
UASSERT_OBJ(ifacerefp->ifaceViaCellp(), ifacerefp, "Unlinked interface");
@ -2173,19 +2212,19 @@ private:
varp->attrSplitVar(false);
}
m_ds.m_dotText = "";
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) {
string dotted = refp->dotted();
size_t pos = dotted.find("__BRA__??__KET__");
// Arrays of interfaces all have the same parameters
if (pos != string::npos && varp->isParam()
&& VN_IS(m_ds.m_unlinkedScope, CellArrayRef)) {
&& VN_IS(m_ds.m_unlinkedScopep, CellArrayRef)) {
refp->dotted(dotted.substr(0, pos));
newp = refp;
} else {
newp = new AstUnlinkedRef(nodep->fileline(),
VN_CAST(refp, VarXRef), refp->name(),
m_ds.m_unlinkedScope->unlinkFrBack());
m_ds.m_unlinkedScope = nullptr;
m_ds.m_unlinkedScopep->unlinkFrBack());
m_ds.m_unlinkedScopep = nullptr;
m_ds.m_unresolved = false;
}
} else {
@ -2208,6 +2247,7 @@ private:
// A scope reference into an interface's modport (not
// necessarily at a pin connection)
UINFO(9, "cell-ref-to-modport " << m_ds.m_dotText << " " << nodep << endl);
UINFO(9, "unlinked " << m_ds.m_unlinkedScopep << endl);
UINFO(9, "dotSymp " << m_ds.m_dotSymp << " " << m_ds.m_dotSymp->nodep() << endl);
// Iface was the previously dotted component
if (!m_ds.m_dotSymp || !VN_IS(m_ds.m_dotSymp->nodep(), Cell)
@ -2222,15 +2262,32 @@ private:
} else {
AstCell* cellp = VN_CAST(m_ds.m_dotSymp->nodep(), Cell);
UASSERT_OBJ(cellp, nodep, "Modport not referenced from a cell");
AstIface* ifacep = VN_CAST(cellp->modp(), Iface);
// string cellName = m_ds.m_dotText; // Use cellp->name
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
m_ds.m_dotSymp = m_statep->getNodeSym(modportp);
m_ds.m_dotPos = DP_SCOPE;
VSymEnt* cellEntp = m_statep->getNodeSym(cellp);
UASSERT_OBJ(cellEntp, nodep, "No interface sym entry");
VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a
// module or generate begin
// We drop __BRA__??__KET__ as cells don't have that naming yet
AstVar* ifaceRefVarp = findIfaceTopVarp(nodep, parentEntp, cellp->name());
//
ok = true;
AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp);
AstVarRef* refp = new AstVarRef(varp->fileline(), varp, VAccess::READ);
nodep->replaceWith(refp);
m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name());
m_ds.m_dotSymp = foundp;
m_ds.m_dotPos = DP_SCOPE;
UINFO(9, " cell -> iface varref " << foundp->nodep() << endl);
AstNode* newp
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, VAccess::READ);
auto* cellarrayrefp = VN_CAST(m_ds.m_unlinkedScopep, CellArrayRef);
if (cellarrayrefp) {
// iface[vec].modport became CellArrayRef(iface, lsb)
// Convert back to SelBit(iface, lsb)
UINFO(9, " Array modport to SelBit " << cellarrayrefp << endl);
newp = new AstSelBit(cellarrayrefp->fileline(), newp,
cellarrayrefp->selp()->unlinkFrBack());
newp->user3(true); // Don't process again
VL_DO_DANGLING(cellarrayrefp->unlinkFrBack(), cellarrayrefp);
m_ds.m_unlinkedScopep = nullptr;
}
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
} else if (AstEnumItem* valuep = VN_CAST(foundp->nodep(), EnumItem)) {
@ -2242,6 +2299,14 @@ private:
ok = true;
m_ds.m_dotText = "";
}
} else if (AstLambdaArgRef* argrefp = VN_CAST(foundp->nodep(), LambdaArgRef)) {
if (allowVar) {
AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name());
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
ok = true;
m_ds.m_dotText = "";
}
}
//
if (!ok) {
@ -2406,11 +2471,6 @@ private:
iterateChildren(nodep);
}
}
virtual void visit(AstWith* nodep) override {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements");
nodep->replaceWith(nodep->funcrefp()->unlinkFrBack());
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstVar* nodep) override {
checkNoDot(nodep);
iterateChildren(nodep);
@ -2433,18 +2493,17 @@ private:
if (cpackagerefp->paramsp()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages");
}
UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(),
m_ds.m_dotp->lhsp(), "Bad package link");
nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep());
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
nodep->packagep(cpackagerefp->classOrPackagep());
m_ds.m_dotPos = DP_SCOPE;
m_ds.m_dotp = nullptr;
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) {
AstNodeFTaskRef* newftaskp = nodep->cloneTree(false);
newftaskp->dotted(m_ds.m_dotText);
AstNode* newp = new AstUnlinkedRef(nodep->fileline(), newftaskp, nodep->name(),
m_ds.m_unlinkedScope->unlinkFrBack());
m_ds.m_unlinkedScope = nullptr;
m_ds.m_unlinkedScopep->unlinkFrBack());
m_ds.m_unlinkedScopep = nullptr;
m_ds.m_unresolved = false;
nodep->replaceWith(newp);
return;
@ -2642,9 +2701,6 @@ private:
virtual void visit(AstNodeFTask* nodep) override {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
if (nodep->classMethod() && nodep->lifetime().isStatic()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class method");
}
if (nodep->isExternDef()) {
if (!m_curSymp->findIdFallback("extern " + nodep->name())) {
nodep->v3error("extern not found that declares " + nodep->prettyNameQ());
@ -2664,6 +2720,16 @@ private:
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
m_ftaskp = nullptr;
}
virtual void visit(AstWith* nodep) override {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
VSymEnt* oldCurSymp = m_curSymp;
{
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
iterateChildren(nodep);
}
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
}
virtual void visit(AstClass* nodep) override {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
@ -2674,42 +2740,46 @@ private:
// Until overridden by a SCOPE
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep);
m_modp = nodep;
iterateChildren(nodep);
}
for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) {
if (AstClassExtends* cextp = VN_CAST(itemp, ClassExtends)) {
// Replace abstract reference with hard pointer
// Will need later resolution when deal with parameters
if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted
AstClassOrPackageRef* cpackagerefp
= VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef);
if (!cpackagerefp) {
cextp->v3error("Attempting to extend using a non-class ");
} else {
VSymEnt* foundp = m_curSymp->findIdFallback(cpackagerefp->name());
bool ok = false;
if (foundp) {
if (AstClass* classp = VN_CAST(foundp->nodep(), Class)) {
AstClassRefDType* newp
= new AstClassRefDType{nodep->fileline(), classp};
cextp->childDTypep(newp);
classp->isExtended(true);
nodep->isExtended(true);
VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(),
cpackagerefp);
ok = true;
for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) {
if (AstClassExtends* cextp = VN_CAST(itemp, ClassExtends)) {
// Replace abstract reference with hard pointer
// Will need later resolution when deal with parameters
if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted
AstClassOrPackageRef* cpackagerefp
= VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef);
if (!cpackagerefp) {
cextp->v3error("Attempting to extend using a non-class ");
} else {
VSymEnt* foundp = m_curSymp->findIdFallback(cpackagerefp->name());
bool ok = false;
if (foundp) {
if (AstClass* classp = VN_CAST(foundp->nodep(), Class)) {
UINFO(8, "Import to " << nodep << " from export class " << classp
<< endl);
AstClassRefDType* newp
= new AstClassRefDType{nodep->fileline(), classp};
cextp->childDTypep(newp);
classp->isExtended(true);
nodep->isExtended(true);
VSymEnt* srcp = m_statep->getNodeSym(classp);
m_curSymp->importFromClass(m_statep->symsp(), srcp);
VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(),
cpackagerefp);
ok = true;
}
}
if (!ok) {
string suggest = m_statep->suggestSymFallback(
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
cpackagerefp->v3error(
"Class to extend not found: "
<< cpackagerefp->prettyNameQ() << endl
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
}
}
if (!ok) {
string suggest = m_statep->suggestSymFallback(
m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{});
cpackagerefp->v3error(
"Class to extend not found: "
<< cpackagerefp->prettyNameQ() << endl
<< (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest));
}
}
}
iterateChildren(nodep);
}
// V3Width when determines types needs to find enum values and such
// so add members pointing to appropriate enum values
@ -2736,10 +2806,13 @@ private:
if (cpackagerefp->packagep()) {
nodep->packagep(cpackagerefp->packagep());
} else {
cpackagep->v3warn(E_UNSUPPORTED, "Unsupported: Class '::' reference");
// if (cpackagerefp->paramsp()) {
// nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages");
// }
nodep->packagep(cpackagerefp->classOrPackagep());
if (!VN_IS(nodep->packagep(), Class) && !VN_IS(nodep->packagep(), Package)) {
cpackagerefp->v3error(
"'::' expected to reference a class/package but referenced "
<< nodep->packagep()->prettyTypeName() << endl
<< cpackagerefp->warnMore() + "... Suggest '.' instead of '::'");
}
}
} else {
cpackagep->v3warn(E_UNSUPPORTED,

View File

@ -35,7 +35,7 @@ private:
// NODE STATE
// STATE
bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside
// METHODS
@ -45,9 +45,9 @@ private:
// Result handing
virtual void visit(AstNodeVarRef* nodep) override {
// VarRef: LValue its reference
if (m_setRefLvalue) nodep->access(VAccess::WRITE);
if (m_setRefLvalue != VAccess::NOCHANGE) nodep->access(m_setRefLvalue);
if (nodep->varp()) {
if (nodep->access().isWrite() && !m_ftaskp && nodep->varp()->isReadOnly()) {
if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) {
nodep->v3warn(ASSIGNIN,
"Assigning to input/const variable: " << nodep->prettyNameQ());
}
@ -62,7 +62,7 @@ private:
// Now that we do, and it's from a output, we know it's a lvalue
m_setRefLvalue = VAccess::WRITE;
iterateChildren(nodep);
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
} else {
iterateChildren(nodep);
}
@ -72,7 +72,16 @@ private:
{
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
}
}
virtual void visit(AstCastDynamic* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
}
}
@ -81,7 +90,7 @@ private:
{
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->filenamep());
iterateAndNextNull(nodep->modep());
}
@ -91,7 +100,7 @@ private:
{
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->filep());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->filenamep());
}
}
@ -172,7 +181,7 @@ private:
{
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->memp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->filenamep());
iterateAndNextNull(nodep->lsbp());
iterateAndNextNull(nodep->msbp());
@ -181,7 +190,7 @@ private:
virtual void visit(AstValuePlusArgs* nodep) override {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->searchp());
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->outp());
@ -192,14 +201,14 @@ private:
{
m_setRefLvalue = VAccess::WRITE;
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->fmtp());
}
}
void prepost_visit(AstNodeTriop* nodep) {
VL_RESTORER(m_setRefLvalue);
{
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->lhsp());
iterateAndNextNull(nodep->rhsp());
m_setRefLvalue = VAccess::WRITE;
@ -217,7 +226,7 @@ private:
{
iterateAndNextNull(nodep->lhsp());
// Only set lvalues on the from
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
iterateAndNextNull(nodep->thsp());
}
@ -226,14 +235,14 @@ private:
VL_RESTORER(m_setRefLvalue);
{ // Only set lvalues on the from
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
}
}
virtual void visit(AstCellArrayRef* nodep) override {
VL_RESTORER(m_setRefLvalue);
{ // selp is not an lvalue
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->selp());
}
}
@ -241,7 +250,7 @@ private:
VL_RESTORER(m_setRefLvalue);
{ // Only set lvalues on the from
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
iterateAndNextNull(nodep->rhsp());
iterateAndNextNull(nodep->thsp());
}
@ -262,7 +271,7 @@ private:
if (portp->isWritable()) {
m_setRefLvalue = VAccess::WRITE;
iterate(pinp);
m_setRefLvalue = false;
m_setRefLvalue = VAccess::NOCHANGE;
} else {
iterate(pinp);
}
@ -277,7 +286,7 @@ private:
public:
// CONSTRUCTORS
LinkLValueVisitor(AstNode* nodep, bool start)
LinkLValueVisitor(AstNode* nodep, VAccess start)
: m_setRefLvalue{start} {
iterate(nodep);
}
@ -289,12 +298,12 @@ public:
void V3LinkLValue::linkLValue(AstNetlist* nodep) {
UINFO(4, __FUNCTION__ << ": " << endl);
{ LinkLValueVisitor visitor(nodep, false); } // Destruct before checking
{ LinkLValueVisitor visitor(nodep, VAccess::NOCHANGE); } // Destruct before checking
V3Global::dumpCheckGlobalTree("linklvalue", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}
void V3LinkLValue::linkLValueSet(AstNode* nodep) {
// Called by later link functions when it is known a node needs
// to be converted to a lvalue.
UINFO(9, __FUNCTION__ << ": " << endl);
LinkLValueVisitor visitor(nodep, true);
LinkLValueVisitor visitor(nodep, VAccess::WRITE);
}

View File

@ -89,9 +89,9 @@ void V3LinkLevel::timescaling(const ModVec& mods) {
AstNodeModule* modTimedp = nullptr;
VTimescale unit(VTimescale::NONE);
// Use highest level module as default unit - already sorted in proper order
for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) {
if (!modTimedp && !(*it)->timeunit().isNone()) {
modTimedp = *it;
for (const auto& modp : mods) {
if (!modTimedp && !modp->timeunit().isNone()) {
modTimedp = modp;
unit = modTimedp->timeunit();
break;
}

View File

@ -44,7 +44,7 @@ private:
AstUser2InUse m_inuser2;
// TYPES
typedef std::map<std::pair<void*, string>, AstTypedef*> ImplTypedefMap;
typedef std::map<const std::pair<void*, string>, AstTypedef*> ImplTypedefMap;
typedef std::set<FileLine*> FileLineSet;
// STATE
@ -57,6 +57,7 @@ private:
AstNodeModule* m_modp = nullptr; // Current module
AstNodeFTask* m_ftaskp = nullptr; // Current task
AstNodeDType* m_dtypep = nullptr; // Current data type
VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -104,13 +105,20 @@ private:
// VISITs
virtual void visit(AstNodeFTask* nodep) override {
V3Config::applyFTask(m_modp, nodep);
if (!nodep->user1SetOnce()) { // Process only once.
V3Config::applyFTask(m_modp, nodep);
cleanFileline(nodep);
m_ftaskp = nodep;
iterateChildren(nodep);
m_ftaskp = nullptr;
VL_RESTORER(m_ftaskp);
VL_RESTORER(m_lifetime);
{
m_ftaskp = nodep;
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) {
// Automatic always until we support static
m_lifetime = VLifetime::AUTOMATIC;
}
iterateChildren(nodep);
}
}
}
virtual void visit(AstNodeFTaskRef* nodep) override {
@ -172,6 +180,13 @@ private:
virtual void visit(AstVar* nodep) override {
cleanFileline(nodep);
if (nodep->lifetime().isNone()) {
if (m_ftaskp) {
nodep->lifetime(VLifetime::AUTOMATIC);
} else {
nodep->lifetime(m_lifetime);
}
}
if (nodep->isParam() && !nodep->valuep()
&& nodep->fileline()->language() < V3LangCode::L1800_2009) {
nodep->v3error("Parameter requires default value, or use IEEE 1800-2009 or later.");
@ -223,25 +238,20 @@ private:
FileLine* fl = nodep->valuep()->fileline();
if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) {
// 1. Parameters and function inputs: It's a default to use if not overridden
} 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(), VAccess::WRITE),
nodep->valuep()->unlinkFrBack())));
} else if (!m_ftaskp && nodep->isNonOutput()) {
} else if (!m_ftaskp && !VN_IS(m_modp, Class) && nodep->isNonOutput()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Default value on module input: "
<< nodep->prettyNameQ());
nodep->valuep()->unlinkFrBack()->deleteTree();
} // 3. Under modules, it's an initial value to be loaded at time 0 via an AstInitial
} // 2. Under modules/class, it's an initial value to be loaded at time 0 via an
// AstInitial
else if (m_valueModp) {
// Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it
FileLine* newfl = new FileLine(fl);
newfl->warnOff(V3ErrorCode::PROCASSWIRE, true);
nodep->addNextHere(new AstInitial(
newfl,
new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), VAccess::WRITE),
nodep->valuep()->unlinkFrBack())));
auto* assp
= new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), VAccess::WRITE),
nodep->valuep()->unlinkFrBack());
nodep->addNextHere(new AstInitial(newfl, assp));
} // 4. Under blocks, it's an initial value to be under an assign
else {
nodep->addNextHere(new AstAssign(fl,
@ -482,12 +492,17 @@ private:
V3Config::applyModule(nodep);
VL_RESTORER(m_modp);
VL_RESTORER(m_lifetime);
{
// Module: Create sim table for entire module and iterate
cleanFileline(nodep);
//
m_modp = nodep;
m_valueModp = nodep;
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) {
m_lifetime = VN_IS(nodep, Class) ? VLifetime::AUTOMATIC : VLifetime::STATIC;
}
iterateChildren(nodep);
}
m_valueModp = nodep;

View File

@ -51,7 +51,6 @@ private:
AstClass* m_classp = nullptr; // Class we're inside
AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside
AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion
VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime
int m_senitemCvtNum = 0; // Temporary signal counter
// METHODS
@ -66,23 +65,17 @@ private:
UINFO(8, "MODULE " << nodep << endl);
if (nodep->dead()) return;
VL_RESTORER(m_modp);
VL_RESTORER(m_lifetime);
VL_RESTORER(m_senitemCvtNum);
{
m_modp = nodep;
m_senitemCvtNum = 0;
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) m_lifetime = VLifetime::STATIC;
iterateChildren(nodep);
}
}
virtual void visit(AstClass* nodep) override {
VL_RESTORER(m_classp);
VL_RESTORER(m_lifetime);
{
m_classp = nodep;
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC;
iterateChildren(nodep);
}
}
@ -106,13 +99,6 @@ private:
if (m_classp && nodep->isParam())
nodep->v3warn(E_UNSUPPORTED, "Unsupported: class parameter");
if (m_ftaskp) nodep->funcLocal(true);
if (nodep->lifetime().isNone()) {
if (nodep->isFuncLocal() && nodep->isIO()) {
nodep->lifetime(VLifetime::AUTOMATIC);
} else {
nodep->lifetime(m_lifetime);
}
}
if (nodep->isSigModPublic()) {
nodep->sigModPublic(false); // We're done with this attribute
m_modp->modPublic(true); // Avoid flattening if signals are exposed
@ -136,15 +122,11 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
VLifetime origLifetime = m_lifetime;
{
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC;
m_ftaskp = nodep;
iterateChildren(nodep);
}
m_ftaskp = nullptr;
m_lifetime = origLifetime;
if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); }
}
virtual void visit(AstNodeFTaskRef* nodep) override {
@ -190,27 +172,27 @@ private:
addwherep->addNext(assignp);
}
} else { // Old V1995 sensitivity list; we'll probably mostly ignore
bool did = 1;
bool did = true;
while (did) {
did = 0;
did = false;
if (AstNodeSel* selp = VN_CAST(nodep->sensp(), NodeSel)) {
AstNode* fromp = selp->fromp()->unlinkFrBack();
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
did = true;
}
// NodeSel doesn't include AstSel....
if (AstSel* selp = VN_CAST(nodep->sensp(), Sel)) {
AstNode* fromp = selp->fromp()->unlinkFrBack();
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
did = true;
}
if (AstNodePreSel* selp = VN_CAST(nodep->sensp(), NodePreSel)) {
AstNode* fromp = selp->lhsp()->unlinkFrBack();
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
did = true;
}
}
}
@ -377,7 +359,7 @@ private:
if (!inpercent && c == '%') {
inpercent = true;
} else if (inpercent) {
inpercent = 0;
inpercent = false;
switch (c) {
case '0': // FALLTHRU
case '1': // FALLTHRU
@ -410,7 +392,7 @@ private:
return newFormat;
}
void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) {
static void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) {
if (!filep) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
@ -520,6 +502,16 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstIfaceRefDType* nodep) override {
// LinkDot checked modports, now remove references to them
// Keeping them later caused problems with InstDeArray,
// as it needed to make new modport arrays and such
nodep->modportp(nullptr);
iterateChildren(nodep);
}
// virtual void visit(AstModport* nodep) override { ... }
// We keep Modport's themselves around for XML dump purposes
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:

View File

@ -150,13 +150,15 @@ private:
}
virtual void visit(AstCFunc* nodep) override {
UINFO(4, " CFUNC " << nodep << endl);
m_cfuncp = nodep;
searchFuncStmts(nodep->argsp());
searchFuncStmts(nodep->initsp());
searchFuncStmts(nodep->stmtsp());
searchFuncStmts(nodep->finalsp());
iterateChildren(nodep);
m_cfuncp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
searchFuncStmts(nodep->argsp());
searchFuncStmts(nodep->initsp());
searchFuncStmts(nodep->stmtsp());
searchFuncStmts(nodep->finalsp());
iterateChildren(nodep);
}
}
void searchFuncStmts(AstNode* nodep) {
// Search for basic assignments to allow moving non-blocktemps
@ -166,7 +168,8 @@ 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->access().isWrite(), varrefp, "LHS assignment not lvalue");
UASSERT_OBJ(varrefp->access().isWriteOrRW(), varrefp,
"LHS assignment not lvalue");
if (!varrefp->varp()->user4p()) {
UINFO(4, " FuncAsn " << varrefp << endl);
varrefp->varp()->user4p(varrefp);

View File

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

View File

@ -53,7 +53,7 @@
class V3OptionsImp {
public:
// TYPES
typedef std::map<string, std::set<string>> DirMap; // Directory listing
typedef std::map<const string, std::set<string>> DirMap; // Directory listing
// STATE
std::list<string> m_allArgs; // List of every argument encountered
@ -61,7 +61,7 @@ public:
std::set<string> m_incDirUserSet; // Include directories (for removing duplicates)
std::list<string> m_incDirFallbacks; // Include directories (ordered)
std::set<string> m_incDirFallbackSet; // Include directories (for removing duplicates)
std::map<string, V3LangCode> m_langExts; // Language extension map
std::map<const string, V3LangCode> m_langExts; // Language extension map
std::list<string> m_libExtVs; // Library extensions (ordered)
std::set<string> m_libExtVSet; // Library extensions (for removing duplicates)
DirMap m_dirMap; // Directory listing
@ -346,10 +346,7 @@ void V3Options::checkParameters() {
if (!m_parameters.empty()) {
std::stringstream msg;
msg << "Parameters from the command line were not found in the design:";
for (std::map<string, string>::iterator it = m_parameters.begin();
it != m_parameters.end(); ++it) {
msg << " " << it->first;
}
for (const auto& i : m_parameters) msg << " " << i.first;
v3error(msg.str());
}
}
@ -395,8 +392,7 @@ string V3Options::allArgsString() const {
// Delete some options for Verilation of the hierarchical blocks.
string V3Options::allArgsStringForHierBlock(bool forTop) const {
std::set<string> vFiles;
for (V3StringList::const_iterator it = m_vFiles.begin(); it != m_vFiles.end(); ++it)
vFiles.insert(*it);
for (const auto& vFile : m_vFiles) vFiles.insert(vFile);
string out;
for (std::list<string>::const_iterator it = m_impp->m_allArgs.begin();
it != m_impp->m_allArgs.end(); ++it) {
@ -501,7 +497,7 @@ string V3Options::filePathCheckOneDir(const string& modname, const string& dirna
// 0: Keep the option including its argument
// 1: Delete the option which has no argument
// 2: Delete the option and its argument
int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) const {
int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) {
if (opt == "Mdir" || opt == "clk" || opt == "f" || opt == "j" || opt == "l2-name"
|| opt == "mod-prefix" || opt == "prefix" || opt == "protect-lib" || opt == "protect-key"
|| opt == "threads" || opt == "top-module" || opt == "v") {

View File

@ -201,7 +201,7 @@ typedef std::set<string> V3StringSet;
class V3HierarchicalBlockOption {
public:
// key:parameter name, value:value (as string)
typedef std::map<string, string> ParamStrMap;
typedef std::map<const string, string> ParamStrMap;
private:
string m_origName; // module name
@ -218,7 +218,7 @@ public:
const ParamStrMap params() const { return m_parameters; }
};
typedef std::map<string, V3HierarchicalBlockOption> V3HierBlockOptSet;
typedef std::map<const string, V3HierarchicalBlockOption> V3HierBlockOptSet;
//######################################################################
// V3Options - Command line options
@ -227,7 +227,7 @@ class V3Options {
public:
private:
// TYPES
typedef std::map<string, int> DebugSrcMap;
typedef std::map<const string, int> DebugSrcMap;
// MEMBERS (general options)
V3OptionsImp* m_impp; // Slow hidden options
@ -245,8 +245,8 @@ private:
V3StringList m_forceIncs; // argument: -FI
DebugSrcMap m_debugSrcs; // argument: --debugi-<srcfile>=<level>
DebugSrcMap m_dumpTrees; // argument: --dump-treei-<srcfile>=<level>
std::map<string,string> m_parameters; // Parameters
std::map<string, V3HierarchicalBlockOption> m_hierBlocks; // main switch: --hierarchical-block
std::map<const string, string> m_parameters; // Parameters
std::map<const string, V3HierarchicalBlockOption> m_hierBlocks; // main switch: --hierarchical-block
bool m_preprocOnly = false; // main switch: -E
bool m_makePhony = false; // main switch: -MP
@ -410,13 +410,13 @@ private:
void optimize(int level);
void showVersion(bool verbose);
void coverage(bool flag) { m_coverageLine = m_coverageToggle = m_coverageUser = flag; }
bool onoff(const char* sw, const char* arg, bool& flag);
bool onoffb(const char* sw, const char* arg, VOptionBool& flagr);
bool suffixed(const string& sw, const char* arg);
string parseFileArg(const string& optdir, const string& relfilename);
static bool onoff(const char* sw, const char* arg, bool& flag);
static bool onoffb(const char* sw, const char* arg, VOptionBool& flagr);
static bool suffixed(const string& sw, const char* arg);
static string parseFileArg(const string& optdir, const string& relfilename);
bool parseLangExt(const char* swp, const char* langswp, const V3LangCode& lc);
string filePathCheckOneDir(const string& modname, const string& dirname);
int stripOptionsForChildRun(const string& opt, bool forTop) const;
static int stripOptionsForChildRun(const string& opt, bool forTop);
// CONSTRUCTORS
VL_UNCOPYABLE(V3Options);

View File

@ -36,6 +36,9 @@
// assignments to avoid saving state, thus we prefer
// a <= b ... As the opposite order would
// b <= c ... require the old value of b.
// Add edge consumed_var_POST->logic_vertex
// This prevents a consumer of the "early" value to be
// scheduled after we've changed to the next-cycle value
// For Logic
// Add vertex for this logic
// Add edge logic_sensitive_vertex->logic_vertex
@ -49,6 +52,7 @@
// Add edge logic_sensitive_vertex->logic_vertex
// Add edge logic_consumed_var->logic_vertex (same as if comb)
// Add edge logic_vertex->logic_generated_var (same as if comb)
// Add edge consumed_var_POST->logic_vertex (same as if comb)
//
// For comb logic
// For comb logic
@ -149,9 +153,7 @@ public:
OrderMoveVertex* vertexp); // Mark one vertex as finished, remove from ready list if done
// STATIC MEMBERS (for lookup)
static void clear() {
for (DomScopeMap::iterator it = s_dsMap.begin(); it != s_dsMap.end(); ++it) {
delete it->second;
}
for (const auto& itr : s_dsMap) delete itr.second;
s_dsMap.clear();
}
V3List<OrderMoveVertex*>& readyVertices() { return m_readyVertices; }
@ -213,10 +215,9 @@ public:
return vertexp;
}
public:
// CONSTRUCTORS
OrderUser() {
for (int i = 0; i < WV_MAX; i++) m_vertexp[i] = nullptr;
for (auto& vertexp : m_vertexp) vertexp = nullptr;
}
~OrderUser() {}
};
@ -561,14 +562,15 @@ public:
: m_pomGraphp{pomGraphp}
, m_pomWaitingp{pomWaitingp} {}
// METHODS
OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*,
const AstScope* scopep, const AstSenTree* domainp) {
virtual OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*,
const AstScope* scopep,
const AstSenTree* domainp) override {
OrderMoveVertex* resultp = new OrderMoveVertex(m_pomGraphp, lvertexp);
resultp->domScopep(OrderMoveDomScope::findCreate(domainp, scopep));
resultp->m_pomWaitingE.pushBack(*m_pomWaitingp, resultp);
return resultp;
}
void freeVertexp(OrderMoveVertex* freeMep) {
virtual void freeVertexp(OrderMoveVertex* freeMep) override {
freeMep->m_pomWaitingE.unlink(*m_pomWaitingp, freeMep);
freeMep->unlinkDelete(m_pomGraphp);
}
@ -583,14 +585,18 @@ class OrderMTaskMoveVertexMaker : public ProcessMoveBuildGraph<MTaskMoveVertex>:
public:
explicit OrderMTaskMoveVertexMaker(V3Graph* pomGraphp)
: m_pomGraphp{pomGraphp} {}
MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex* varVertexp,
const AstScope* scopep, const AstSenTree* domainp) {
virtual MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp,
const OrderEitherVertex* varVertexp,
const AstScope* scopep,
const AstSenTree* domainp) override {
// Exclude initial/settle logic from the mtasks graph.
// We'll output time-zero logic separately.
if (domainp->hasInitial() || domainp->hasSettle()) return nullptr;
return new MTaskMoveVertex(m_pomGraphp, lvertexp, varVertexp, scopep, domainp);
}
void freeVertexp(MTaskMoveVertex* freeMep) { freeMep->unlinkDelete(m_pomGraphp); }
virtual void freeVertexp(MTaskMoveVertex* freeMep) override {
freeMep->unlinkDelete(m_pomGraphp);
}
private:
VL_UNCOPYABLE(OrderMTaskMoveVertexMaker);
@ -1026,7 +1032,7 @@ 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->access().isWrite(), nodep,
UASSERT_OBJ(!nodep->access().isWriteOrRW(), nodep,
"How can a sensitivity be setting a var?");
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD);
varVxp->isClock(true);
@ -1037,9 +1043,8 @@ 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->access().isWrite()) {
gen = !(varscp->user4() & VU_GEN);
} else {
if (nodep->access().isWriteOrRW()) gen = !(varscp->user4() & VU_GEN);
if (nodep->access().isReadOrRW()) {
con = !(varscp->user4() & VU_CON);
if ((varscp->user4() & VU_GEN) && !m_inClocked) {
// Dangerous assumption:

View File

@ -49,6 +49,14 @@
# include <direct.h> // mkdir
# include <psapi.h> // GetProcessMemoryInfo
# include <thread>
// These macros taken from gdbsupport/gdb_wait.h in binutils-gdb
# ifndef WIFEXITED
# ifdef __MINGW32__
# define WIFEXITED(w) (((w) & 0xC0000000) == 0)
# else
# define WIFEXITED(w) (((w) & 0377) == 0)
# endif
# endif
#else
# include <sys/time.h>
# include <sys/wait.h> // Needed on FreeBSD for WIFEXITED

View File

@ -68,8 +68,8 @@
class ParameterizedHierBlocks {
typedef std::multimap<string, const V3HierarchicalBlockOption*> HierBlockOptsByOrigName;
typedef HierBlockOptsByOrigName::const_iterator HierMapIt;
typedef std::map<string, AstNodeModule*> HierBlockModMap;
typedef std::map<string, AstConst*> ParamConstMap;
typedef std::map<const string, AstNodeModule*> HierBlockModMap;
typedef std::map<const string, AstConst*> ParamConstMap;
typedef std::map<const V3HierarchicalBlockOption*, ParamConstMap> ParamsMap;
// MEMBERS
@ -119,10 +119,11 @@ class ParameterizedHierBlocks {
public:
ParameterizedHierBlocks(const V3HierBlockOptSet& hierOpts, AstNetlist* nodep) {
for (V3HierBlockOptSet::const_iterator it = hierOpts.begin(); it != hierOpts.end(); ++it) {
m_hierBlockOptsByOrigName.insert(std::make_pair(it->second.origName(), &it->second));
const V3HierarchicalBlockOption::ParamStrMap& params = it->second.params();
ParamConstMap& consts = m_params[&it->second];
for (const auto& hierOpt : hierOpts) {
m_hierBlockOptsByOrigName.insert(
std::make_pair(hierOpt.second.origName(), &hierOpt.second));
const V3HierarchicalBlockOption::ParamStrMap& params = hierOpt.second.params();
ParamConstMap& consts = m_params[&hierOpt.second];
for (V3HierarchicalBlockOption::ParamStrMap::const_iterator pIt = params.begin();
pIt != params.end(); ++pIt) {
AstConst* constp = AstConst::parseParamLiteral(
@ -141,10 +142,7 @@ public:
}
~ParameterizedHierBlocks() {
for (ParamsMap::const_iterator it = m_params.begin(); it != m_params.end(); ++it) {
for (ParamConstMap::const_iterator pIt = it->second.begin(); pIt != it->second.end();
++pIt) {
delete pIt->second;
}
for (const auto& pItr : it->second) { delete pItr.second; }
}
}
AstNodeModule* findByParams(const string& origName, AstPin* firstPinp,
@ -218,17 +216,17 @@ private:
typedef std::deque<std::pair<AstIfaceRefDType*, AstIfaceRefDType*>> IfaceRefRefs;
// STATE
typedef std::map<AstNode*, AstNode*> CloneMap;
typedef std::map<const AstNode*, AstNode*> CloneMap;
struct ModInfo {
AstNodeModule* m_modp; // Module with specified name
CloneMap m_cloneMap; // Map of old-varp -> new cloned varp
explicit ModInfo(AstNodeModule* modp)
: m_modp{modp} {}
};
typedef std::map<string, ModInfo> ModNameMap;
typedef std::map<const string, ModInfo> ModNameMap;
ModNameMap m_modNameMap; // Hash of created module flavors by name
typedef std::map<string, string> LongMap;
typedef std::map<const string, string> LongMap;
LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId = 0;
@ -237,7 +235,7 @@ private:
V3StringSet m_allModuleNames;
typedef std::pair<int, string> ValueMapValue;
typedef std::map<V3Hash, ValueMapValue> ValueMap;
typedef std::map<const V3Hash, ValueMapValue> ValueMap;
ValueMap m_valueMap; // Hash of node hash to (param value, name)
int m_nextValue = 1; // Next value to use in m_valueMap
@ -370,7 +368,7 @@ private:
}
}
void relinkPinsByName(AstPin* startpinp, AstNodeModule* modp) {
std::map<string, AstVar*> nameToPin;
std::map<const string, AstVar*> nameToPin;
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = VN_CAST(stmtp, Var)) {
if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
@ -892,10 +890,13 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
AstIfaceRefDType* pinIrefp = nullptr;
AstNode* exprp = pinp->exprp();
if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
&& VN_IS(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType)) {
pinIrefp = VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType);
AstVar* varp
= (exprp && VN_IS(exprp, VarRef)) ? VN_CAST(exprp, VarRef)->varp() : nullptr;
if (varp && varp->subDTypep() && VN_IS(varp->subDTypep(), IfaceRefDType)) {
pinIrefp = VN_CAST(varp->subDTypep(), IfaceRefDType);
} else if (varp && varp->subDTypep() && arraySubDTypep(varp->subDTypep())
&& VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType)) {
pinIrefp = VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType);
} else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef)
&& VN_CAST(exprp->op1p(), VarRef)->varp()
&& VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()
@ -906,13 +907,6 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
pinIrefp = VN_CAST(
arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()),
IfaceRefDType);
} else if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
&& arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep())
&& VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()),
IfaceRefDType)) {
pinIrefp = VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()),
IfaceRefDType);
}
UINFO(9, " portIfaceRef " << portIrefp << endl);

View File

@ -49,13 +49,9 @@ int V3ParseSym::s_anonNum = 0;
// Parser constructor
V3ParseImp::~V3ParseImp() {
for (std::deque<string*>::iterator it = m_stringps.begin(); it != m_stringps.end(); ++it) {
VL_DO_DANGLING(delete *it, *it);
}
for (auto& itr : m_stringps) VL_DO_DANGLING(delete itr, itr);
m_stringps.clear();
for (std::deque<V3Number*>::iterator it = m_numberps.begin(); it != m_numberps.end(); ++it) {
VL_DO_DANGLING(delete *it, *it);
}
for (auto& itr : m_numberps) VL_DO_DANGLING(delete itr, itr);
m_numberps.clear();
lexDestroy();
parserClear();
@ -252,11 +248,10 @@ void V3ParseImp::preprocDumps(std::ostream& os) {
V3PreShell::dumpDefines(os);
} else {
bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine();
for (std::deque<string>::iterator it = m_ppBuffers.begin(); it != m_ppBuffers.end();
++it) {
for (auto& buf : m_ppBuffers) {
if (noblanks) {
bool blank = true;
for (string::iterator its = it->begin(); its != it->end(); ++its) {
for (string::iterator its = buf.begin(); its != buf.end(); ++its) {
if (!isspace(*its) && *its != '\n') {
blank = false;
break;
@ -264,7 +259,7 @@ void V3ParseImp::preprocDumps(std::ostream& os) {
}
if (blank) continue;
}
os << *it;
os << buf;
}
}
}

View File

@ -37,7 +37,7 @@ public:
// CONSTRUCTORS
V3Lexer()
: V3LexerBase{nullptr} {}
~V3Lexer() {}
~V3Lexer() override {}
// METHODS
void unputString(const char* textp, size_t length) {
// Add characters to input stream in back-to-front order

View File

@ -284,7 +284,7 @@ private:
if (it != m_cp.end()) return it->second;
return 0;
}
uint32_t cost(const V3GraphVertex*) const { return 1; }
static uint32_t cost(const V3GraphVertex*) { return 1; }
void partInitCriticalPaths(bool checkOnly) {
// Set up the FORWARD cp's only. This test only looks in one
// direction, it assumes REVERSE is symmetrical and would be
@ -308,7 +308,7 @@ private:
// Generate a pseudo-random graph
vluint64_t rngState[2] = {0x12345678ULL, 0x9abcdef0ULL};
// Create 50 vertices
for (unsigned i = 0; i < 50; ++i) m_vx[i] = new V3GraphVertex(&m_graph);
for (auto& i : m_vx) i = new V3GraphVertex(&m_graph);
// Create 250 edges at random. Edges must go from
// lower-to-higher index vertices, so we get a DAG.
for (unsigned i = 0; i < 250; ++i) {
@ -328,10 +328,8 @@ private:
// Seed the propagator with every input node;
// This should result in the complete graph getting all CP's assigned.
for (unsigned i = 0; i < 50; ++i) {
if (!m_vx[i]->inBeginp()) {
prop.cpHasIncreased(m_vx[i], 1 /* inclusive CP starts at 1 */);
}
for (const auto& i : m_vx) {
if (!i->inBeginp()) prop.cpHasIncreased(i, 1 /* inclusive CP starts at 1 */);
}
// Run the propagator.
@ -451,7 +449,7 @@ public:
// CONSTRUCTORS
LogicMTask(V3Graph* graphp, MTaskMoveVertex* mtmvVxp)
: AbstractLogicMTask{graphp} {
for (int i = 0; i < GraphWay::NUM_WAYS; ++i) m_critPathCost[i] = 0;
for (unsigned int& i : m_critPathCost) i = 0;
if (mtmvVxp) { // Else null for test
m_vertices.push_back(mtmvVxp);
if (OrderLogicVertex* olvp = mtmvVxp->logicp()) {
@ -726,10 +724,10 @@ class SiblingMC : public MergeCandidate {
private:
LogicMTask* m_ap;
LogicMTask* m_bp;
// CONSTRUCTORS
SiblingMC() = delete;
public:
// CONSTRUCTORS
SiblingMC() = delete;
SiblingMC(LogicMTask* ap, LogicMTask* bp) {
// Assign 'ap' and 'bp' in a canonical order, so we can more easily
// compare pairs of SiblingMCs
@ -745,7 +743,7 @@ public:
// METHODS
LogicMTask* ap() const { return m_ap; }
LogicMTask* bp() const { return m_bp; }
bool mergeWouldCreateCycle() const {
bool mergeWouldCreateCycle() const override {
return (LogicMTask::pathExistsFrom(m_ap, m_bp, nullptr)
|| LogicMTask::pathExistsFrom(m_bp, m_ap, nullptr));
}

View File

@ -108,7 +108,7 @@ public:
class V3PreProcImp : public V3PreProc {
public:
// TYPES
typedef std::map<string, VDefine> DefinesMap;
typedef std::map<const string, VDefine> DefinesMap;
typedef VInFilter::StrList StrList;
// debug() -> see V3PreShellImp::debug; use --debugi-V3PreShell
@ -202,7 +202,7 @@ private:
string commentCleanup(const string& text);
bool commentTokenMatch(string& cmdr, const char* strg);
string trimWhitespace(const string& strg, bool trailing);
static string trimWhitespace(const string& strg, bool trailing);
void unputString(const string& strg);
void unputDefrefString(const string& strg);
@ -238,24 +238,24 @@ private:
public:
// METHODS, called from upper level shell
void openFile(FileLine* fl, VInFilter* filterp, const string& filename);
bool isEof() const { return m_lexp->curStreamp()->m_eof; }
void openFile(FileLine* fl, VInFilter* filterp, const string& filename) override;
bool isEof() const override { return m_lexp->curStreamp()->m_eof; }
void forceEof() { m_lexp->curStreamp()->m_eof = true; }
string getline();
void insertUnreadback(const string& text) { m_lineCmt += text; }
string getline() override;
void insertUnreadback(const string& text) override { m_lineCmt += text; }
void insertUnreadbackAtBol(const string& text);
void addLineComment(int enterExit);
void dumpDefines(std::ostream& os);
void candidateDefines(VSpellCheck* spellerp);
void dumpDefines(std::ostream& os) override;
void candidateDefines(VSpellCheck* spellerp) override;
// METHODS, callbacks
virtual void comment(const string& text); // Comment detected (if keepComments==2)
virtual void include(const string& filename); // Request a include file be processed
virtual void undef(const string& name);
virtual void comment(const string& text) override; // Comment detected (if keepComments==2)
virtual void include(const string& filename) override; // Request a include file be processed
virtual void undef(const string& name) override;
virtual void undefineall();
virtual void define(FileLine* fl, const string& name, const string& value,
const string& params, bool cmdline);
virtual string removeDefines(const string& text); // Remove defines in a text string
const string& params, bool cmdline) override;
virtual string removeDefines(const string& text) override; // Remove defines in a text string
// CONSTRUCTORS
V3PreProcImp() {
@ -274,7 +274,7 @@ public:
m_lexp->m_pedantic = pedantic();
m_lexp->debug(debug() >= 5 ? debug() : 0); // See also V3PreProc::debug() method
}
~V3PreProcImp() {
~V3PreProcImp() override {
if (m_lexp) VL_DO_CLEAR(delete m_lexp, m_lexp = nullptr);
}
};
@ -585,7 +585,7 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) {
string value = defValue(refp->name());
UINFO(4, "defineValue '" << V3PreLex::cleanDbgStrg(value) << "'" << endl);
std::map<string, string> argValueByName;
std::map<const string, string> argValueByName;
{ // Parse argument list into map
unsigned numArgs = 0;
string argName;
@ -764,7 +764,7 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) {
//**********************************************************************
// Parser routines
void V3PreProcImp::openFile(FileLine* fl, VInFilter* filterp, const string& filename) {
void V3PreProcImp::openFile(FileLine*, VInFilter* filterp, const string& filename) {
// Open a new file, possibly overriding the current one which is active.
if (m_incError) return;
V3File::addSrcDepend(filename);
@ -1549,8 +1549,8 @@ int V3PreProcImp::getFinalToken(string& buf) {
}
}
// Track newlines in prep for next token
for (string::iterator cp = buf.begin(); cp != buf.end(); ++cp) {
if (*cp == '\n') {
for (char& c : buf) {
if (c == '\n') {
m_finAtBol = true;
m_finFilelinep->linenoInc();
} else {

View File

@ -58,7 +58,7 @@ private:
}
virtual void visit(AstVarRef* nodep) override {
// it's LHS var is used so need a deep temporary
if (nodep->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
nodep->varp()->user4(true);
} else {
if (nodep->varp()->user4()) {
@ -94,7 +94,7 @@ private:
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_funcp = nullptr; // Current block
AstCFunc* m_cfuncp = nullptr; // Current block
AstNode* m_stmtp = nullptr; // Current statement
AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions
AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions
@ -141,7 +141,7 @@ private:
string newvarname = (string("__Vtemp") + cvtToStr(m_modp->varNumGetInc()));
AstVar* varp
= new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep());
m_funcp->addInitsp(varp);
m_cfuncp->addInitsp(varp);
return varp;
}
@ -189,18 +189,20 @@ private:
VL_RESTORER(m_modp);
{
m_modp = nodep;
m_funcp = nullptr;
m_cfuncp = nullptr;
iterateChildren(nodep);
}
}
virtual void visit(AstCFunc* nodep) override {
m_funcp = nodep;
iterateChildren(nodep);
m_funcp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
void startStatement(AstNode* nodep) {
m_assignLhs = false;
if (m_funcp) m_stmtp = nodep;
if (m_cfuncp) m_stmtp = nodep;
}
virtual void visit(AstWhile* nodep) override {
UINFO(4, " WHILE " << nodep << endl);

View File

@ -142,9 +142,11 @@ private:
// VISITORS
virtual void visit(AstCFunc* nodep) override {
m_cfuncp = nodep;
iterateChildren(nodep);
m_cfuncp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
virtual void visit(AstNodeAssign* nodep) override {
if (!m_cfuncp) return;

View File

@ -65,10 +65,9 @@ private:
VL_DEBUG_FUNC; // Declare debug()
void cleanupVarRefs() {
for (VarRefScopeSet::iterator it = m_varRefScopes.begin(); it != m_varRefScopes.end();
++it) {
AstVarRef* nodep = it->first;
AstScope* scopep = it->second;
for (const auto& itr : m_varRefScopes) {
AstVarRef* nodep = itr.first;
AstScope* scopep = itr.second;
if (nodep->packagep() && !nodep->varp()->isClassMember()) {
const auto it2 = m_packageScopes.find(nodep->packagep());
UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope");
@ -117,7 +116,8 @@ private:
// Now for each child cell, iterate the module this cell points to
for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp = cellnextp->nextp()) {
if (AstCell* cellp = VN_CAST(cellnextp, Cell)) {
VL_RESTORER(m_scopep);
VL_RESTORER(m_scopep); // Protects m_scopep set in called module
// which is "above" in this code, but later in code execution order
VL_RESTORER(m_aboveCellp);
VL_RESTORER(m_aboveScopep);
{
@ -330,9 +330,11 @@ private:
// VISITORS
virtual void visit(AstScope* nodep) override {
// Want to ignore blocks under it
m_scopep = nodep;
iterateChildren(nodep);
m_scopep = nullptr;
VL_RESTORER(m_scopep);
{
m_scopep = nodep;
iterateChildren(nodep);
}
}
virtual void movedDeleteOrIterate(AstNode* nodep) {
@ -377,6 +379,7 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstModportFTaskRef* nodep) override {
// The modport persists only for xml dump
// The crossrefs are dealt with in V3LinkDot
nodep->ftaskp(nullptr);
iterateChildren(nodep);

View File

@ -61,7 +61,7 @@ public:
};
typedef std::deque<AstConst*> ConstDeque;
typedef std::map<AstNodeDType*, ConstDeque> ConstPile;
typedef std::map<const AstNodeDType*, ConstDeque> ConstPile;
class SimulateVisitor : public AstNVisitor {
// Simulate a node tree, returning value of variables
@ -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->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
if (m_inDlyAssign) {
if (!(vscp->user1() & VU_LVDLY)) {
vscp->user1(vscp->user1() | VU_LVDLY);
@ -416,7 +416,8 @@ private:
if (m_checkOnly) varRefCb(nodep);
}
}
} else {
}
if (nodep->access().isReadOrRW()) {
if (!(vscp->user1() & VU_RV)) {
if (!m_params && (vscp->user1() & VU_LV)) {
clearOptimizable(nodep, "Var write & read");
@ -433,7 +434,7 @@ private:
}
}
if (!m_checkOnly && optimizable()) { // simulating
UASSERT_OBJ(!nodep->access().isWrite(), nodep,
UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
"LHS varref should be handled in AstAssign visitor.");
{
// Return simulation value - copy by reference instead of value for speed

View File

@ -291,10 +291,10 @@ private:
if (!m_pliVertexp) {
m_pliVertexp = new SplitPliVertex(&m_graph, nodep); // m_graph.clear() will delete it
}
for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) {
for (const auto& vtxp : m_stmtStackps) {
// Both ways...
new SplitScorebdEdge(&m_graph, *it, m_pliVertexp);
new SplitScorebdEdge(&m_graph, m_pliVertexp, *it);
new SplitScorebdEdge(&m_graph, vtxp, m_pliVertexp);
new SplitScorebdEdge(&m_graph, m_pliVertexp, vtxp);
}
}
void scoreboardPushStmt(AstNode* nodep) {
@ -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->access().isWrite()) {
if (m_inDly && nodep->access().isWriteOrRW()) {
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->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
// Non-delay; need to maintain existing ordering
// with all consumers of the signal
UINFO(4, " VARREFLV: " << nodep << endl);
@ -709,7 +709,7 @@ public:
void go() {
// Create a new always for each color
const ColorSet& colors = m_ifColorp->colors();
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
for (unsigned int color : colors) {
// We don't need to clone m_origAlwaysp->sensesp() here;
// V3Activate already moved it to a parent node.
AstAlways* alwaysp
@ -718,7 +718,7 @@ public:
// We'll strip these out after the blocks are fully cloned.
AstSplitPlaceholder* placeholderp = makePlaceholderp();
alwaysp->addStmtp(placeholderp);
m_addAfter[*color] = placeholderp;
m_addAfter[color] = placeholderp;
m_newBlocksp->push_back(alwaysp);
}
// Scan the body of the always. We'll handle if/else
@ -761,7 +761,7 @@ protected:
typedef std::unordered_map<uint32_t, AstNodeIf*> CloneMap;
CloneMap clones;
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
for (unsigned int color : colors) {
// Clone this if into its set of split blocks
AstSplitPlaceholder* if_placeholderp = makePlaceholderp();
AstSplitPlaceholder* else_placeholderp = makePlaceholderp();
@ -775,9 +775,9 @@ protected:
clonep->unique0Pragma(origp->unique0Pragma());
clonep->priorityPragma(origp->priorityPragma());
}
clones[*color] = clonep;
m_addAfter[*color]->addNextHere(clonep);
m_addAfter[*color] = if_placeholderp;
clones[color] = clonep;
m_addAfter[color]->addNextHere(clonep);
m_addAfter[color] = if_placeholderp;
}
iterateAndNextNull(nodep->ifsp());

View File

@ -49,7 +49,7 @@ private:
// METHODS
virtual void visit(AstVarRef* nodep) override {
if (nodep->access().isWrite() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) {
if (nodep->access().isWriteOrRW() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) {
m_splitVscp = nodep->varScopep();
}
}
@ -76,7 +76,7 @@ private:
// METHODS
virtual void visit(AstVarRef* nodep) override {
if (nodep->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
if (nodep->varScopep() == m_splitVscp) {
UINFO(6, " CL VAR " << nodep << endl);
m_matches = true;

View File

@ -361,9 +361,7 @@ public:
v.iterate(nodep);
}
void visit(AstNVisitor* visitor) {
for (VarSet::iterator it = m_vars.begin(), it_end = m_vars.end(); it != it_end; ++it) {
visitor->iterate(*it);
}
for (const auto& varp : m_vars) visitor->iterate(varp);
for (SelSet::iterator it = m_sels.begin(), it_end = m_sels.end(); it != it_end; ++it) {
// If m_refs includes VarRef from ArraySel, remove it
// because the VarRef would not be visited in SplitPackedVarVisitor::visit(AstSel*).
@ -462,13 +460,17 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
if (nodep->sensesp()) { // When visiting sensitivity list, always is the context
setContextAndIterate(nodep, nodep->sensesp());
}
if (AstNode* bodysp = nodep->bodysp()) iterate(bodysp);
for (AstNode* bodysp = nodep->bodysp(); bodysp; bodysp = bodysp->nextp()) {
iterate(bodysp);
}
};
virtual void visit(AstAlwaysPublic* nodep) override {
if (nodep->sensesp()) { // When visiting sensitivity list, always is the context
setContextAndIterate(nodep, nodep->sensesp());
}
if (AstNode* bodysp = nodep->bodysp()) iterate(bodysp);
for (AstNode* bodysp = nodep->bodysp(); bodysp; bodysp = bodysp->nextp()) {
iterate(bodysp);
}
}
virtual void visit(AstNodeFTaskRef* nodep) override {
VL_RESTORER(m_contextp);
@ -767,7 +769,7 @@ public:
: m_refs{} {
iterate(nodep);
}
~SplitUnpackedVarVisitor() {
~SplitUnpackedVarVisitor() override {
UASSERT(m_refs.empty(), "Don't forget to call split()");
V3Stats::addStat("SplitVar, Split unpacked arrays", m_numSplit);
}
@ -898,10 +900,8 @@ public:
: m_basicp{varp->dtypep()->basicp()} {}
void append(const PackedVarRefEntry& e, const VAccess& access) {
UASSERT(!m_dedupDone, "cannot add after dedup()");
if (access.isWrite())
m_lhs.push_back(e);
else
m_rhs.push_back(e);
if (access.isWriteOrRW()) m_lhs.push_back(e);
if (access.isReadOrRW()) m_rhs.push_back(e);
}
void dedup() {
UASSERT(!m_dedupDone, "dedup() called twice");
@ -918,8 +918,8 @@ public:
std::vector<std::pair<int, bool>> points; // <bit location, is end>
points.reserve(m_lhs.size() * 2 + 2); // 2 points will be added per one PackedVarRefEntry
for (const_iterator it = m_lhs.begin(), itend = m_lhs.end(); it != itend; ++it) {
points.push_back(std::make_pair(it->lsb(), false)); // Start of a region
points.push_back(std::make_pair(it->msb() + 1, true)); // End of a region
points.emplace_back(std::make_pair(it->lsb(), false)); // Start of a region
points.emplace_back(std::make_pair(it->msb() + 1, true)); // End of a region
}
if (skipUnused && !m_rhs.empty()) { // Range to be read must be kept, so add points here
int lsb = m_basicp->msb() + 1;
@ -929,12 +929,12 @@ public:
msb = std::max(msb, m_rhs[i].msb());
}
UASSERT_OBJ(lsb <= msb, m_basicp, "lsb:" << lsb << " msb:" << msb << " are wrong");
points.push_back(std::make_pair(lsb, false));
points.push_back(std::make_pair(msb + 1, true));
points.emplace_back(std::make_pair(lsb, false));
points.emplace_back(std::make_pair(msb + 1, true));
}
if (!skipUnused) { // All bits are necessary
points.push_back(std::make_pair(m_basicp->lsb(), false));
points.push_back(std::make_pair(m_basicp->msb() + 1, true));
points.emplace_back(std::make_pair(m_basicp->lsb(), false));
points.emplace_back(std::make_pair(m_basicp->msb() + 1, true));
}
std::sort(points.begin(), points.end(), SortByFirst());
@ -949,7 +949,7 @@ public:
}
UASSERT(refcount >= 0, "refcounut must not be negative");
if (bitwidth == 0 || refcount == 0) continue; // Vacant region
plan.push_back(SplitNewVar(points[i].first, bitwidth));
plan.emplace_back(SplitNewVar(points[i].first, bitwidth));
}
return plan;
@ -1211,15 +1211,14 @@ public:
, m_numSplit{0} {
// If you want ignore refs and walk the tne entire AST,
// just call iterateChildren(m_modp) and split() for each module
for (SplitVarRefsMap::iterator it = refs.begin(), it_end = refs.end(); it != it_end;
++it) {
m_modp = it->first;
it->second.visit(this);
for (auto& i : refs) {
m_modp = i.first;
i.second.visit(this);
split();
m_modp = nullptr;
}
}
~SplitPackedVarVisitor() {
~SplitPackedVarVisitor() override {
UASSERT(m_refs.empty(), "Forgot to call split()");
V3Stats::addStat("SplitVar, Split packed variables", m_numSplit);
}

View File

@ -34,7 +34,7 @@ class StatsVisitor : public AstNVisitor {
private:
// NODE STATE/TYPES
typedef std::map<string, int> NameMap; // Number of times a name appears
typedef std::map<const string, int> NameMap; // Number of times a name appears
// STATE
string m_stage; // Name of the stage we are scanning
@ -181,10 +181,12 @@ private:
if (!m_tracingCall && !nodep->entryPoint()) return;
m_tracingCall = false;
}
m_cfuncp = nodep;
allNodes(nodep);
iterateChildrenConst(nodep);
m_cfuncp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
allNodes(nodep);
iterateChildrenConst(nodep);
}
}
virtual void visit(AstNode* nodep) override {
allNodes(nodep);
@ -232,10 +234,10 @@ public:
if (count != 0.0) {
if (v3Global.opt.statsVars()) {
NameMap& nameMapr = m_statVarWidthNames.at(i);
for (NameMap::iterator it = nameMapr.begin(); it != nameMapr.end(); ++it) {
for (const auto& itr : nameMapr) {
std::ostringstream os;
os << "Vars, width " << std::setw(5) << std::dec << i << " " << it->first;
V3Stats::addStat(m_stage, os.str(), it->second);
os << "Vars, width " << std::setw(5) << std::dec << i << " " << itr.first;
V3Stats::addStat(m_stage, os.str(), itr.second);
}
} else {
std::ostringstream os;

View File

@ -53,15 +53,15 @@ class StatsReport {
typedef std::multimap<string, V3Statistic*> ByName;
ByName byName;
// * is always first
for (StatColl::iterator it = s_allStats.begin(); it != s_allStats.end(); ++it) {
V3Statistic* repp = &(*it);
for (auto& itr : s_allStats) {
V3Statistic* repp = &itr;
byName.insert(make_pair(repp->name(), repp));
}
// Process duplicates
V3Statistic* lastp = nullptr;
for (ByName::iterator it = byName.begin(); it != byName.end(); ++it) {
V3Statistic* repp = it->second;
for (const auto& itr : byName) {
V3Statistic* repp = itr.second;
if (lastp && lastp->sumit() && lastp->printit() && lastp->name() == repp->name()
&& lastp->stage() == repp->stage()) {
repp->combineWith(lastp);
@ -76,8 +76,8 @@ class StatsReport {
typedef std::multimap<string, const V3Statistic*> ByName;
ByName byName;
// * is always first
for (StatColl::iterator it = s_allStats.begin(); it != s_allStats.end(); ++it) {
const V3Statistic* repp = &(*it);
for (const auto& itr : s_allStats) {
const V3Statistic* repp = &itr;
if (repp->stage() == "*" && repp->printit()) {
if (maxWidth < repp->name().length()) maxWidth = repp->name().length();
byName.insert(make_pair(repp->name(), repp));
@ -87,8 +87,8 @@ class StatsReport {
// Print organized by stage
os << "Global Statistics:\n";
os << endl;
for (ByName::iterator it = byName.begin(); it != byName.end(); ++it) {
const V3Statistic* repp = it->second;
for (const auto& itr : byName) {
const V3Statistic* repp = itr.second;
if (repp->perf()) continue;
os << " " << std::left << std::setw(maxWidth) << repp->name();
repp->dump(os);
@ -99,8 +99,8 @@ class StatsReport {
// Print organized by stage
os << "Performance Statistics:\n";
os << endl;
for (ByName::iterator it = byName.begin(); it != byName.end(); ++it) {
const V3Statistic* repp = it->second;
for (const auto& itr : byName) {
const V3Statistic* repp = itr.second;
if (!repp->perf()) continue;
os << " " << std::left << std::setw(maxWidth) << repp->name();
repp->dump(os);

View File

@ -306,7 +306,7 @@ private:
iterate(nodep->rhsp());
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
AstConst* constp = VN_CAST(nodep->rhsp(), Const);
if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->access().isWrite() && constp) {
if (varrefp && isSubstVar(varrefp->varp()) && varrefp->access().isReadOnly() && 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->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
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->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
UINFO(8, " ASSIGNcpx " << nodep << endl);
entryp->assignComplex();
} else if (AstNode* substp = entryp->substWhole(nodep)) {

View File

@ -411,9 +411,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
// Build the initial graph from the starting state set.
typedef TspGraphTmpl<const TspStateBase*> Graph;
Graph graph;
for (V3TSP::StateVec::const_iterator it = states.begin(); it != states.end(); ++it) {
graph.addVertex(*it);
}
for (const auto& state : states) graph.addVertex(state);
for (V3TSP::StateVec::const_iterator it = states.begin(); it != states.end(); ++it) {
for (V3TSP::StateVec::const_iterator jt = it; jt != states.end(); ++jt) {
if (it == jt) continue;
@ -645,11 +643,11 @@ void V3TSP::selfTestString() {
minGraph.findEulerTour(&result);
std::vector<string> expect;
expect.push_back("0");
expect.push_back("2");
expect.push_back("1");
expect.push_back("2");
expect.push_back("3");
expect.emplace_back("0");
expect.emplace_back("2");
expect.emplace_back("1");
expect.emplace_back("2");
expect.emplace_back("3");
if (VL_UNCOVERABLE(expect != result)) {
for (const string& i : result) cout << i << " ";

View File

@ -154,10 +154,11 @@ public:
// Called by TableSimulateVisitor on each unique varref encountered
UINFO(9, " SimVARREF " << nodep << endl);
AstVarScope* vscp = nodep->varScopep();
if (nodep->access().isWrite()) {
if (nodep->access().isWriteOrRW()) {
m_outWidth += nodep->varp()->dtypeSkipRefp()->widthTotalBytes();
m_outVarps.push_back(vscp);
} else {
}
if (nodep->access().isReadOrRW()) {
// We'll make the table with a separate natural alignment for each
// output var, so always have char, 16 or 32 bit widths, so use widthTotalBytes
m_inWidth += nodep->varp()->width(); // Space for var
@ -199,10 +200,7 @@ private:
// Collapse duplicate tables
chgVscp = findDuplicateTable(chgVscp);
for (std::deque<AstVarScope*>::iterator it = m_tableVarps.begin();
it != m_tableVarps.end(); ++it) {
*it = findDuplicateTable(*it);
}
for (auto& vscp : m_tableVarps) vscp = findDuplicateTable(vscp);
createOutputAssigns(nodep, stmtsp, indexVscp, chgVscp);
@ -222,7 +220,7 @@ private:
void createTableVars(AstNode* nodep) {
// Create table for each output
typedef std::map<string, int> NameCounts;
typedef std::map<const string, int> NameCounts;
NameCounts namecounts;
for (const AstVarScope* outvscp : m_outVarps) {
AstVar* outvarp = outvscp->varp();

View File

@ -104,7 +104,7 @@ private:
// TYPES
typedef std::map<std::pair<AstScope*, AstVar*>, AstVarScope*> VarToScopeMap;
typedef std::map<AstNodeFTask*, AstClass*> FuncToClassMap;
typedef std::map<const AstNodeFTask*, AstClass*> FuncToClassMap;
typedef std::vector<AstInitial*> Initials;
// MEMBERS
VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings
@ -341,7 +341,7 @@ private:
IM_AFTER, // Pointing at last inserted stmt, insert after
IM_WHILE_PRECOND // Pointing to for loop, add to body end
};
typedef std::map<string, std::pair<AstNodeFTask*, string>> DpiNames;
typedef std::map<const string, std::pair<AstNodeFTask*, string>> DpiNames;
// STATE
TaskStateVisitor* m_statep; // Common state between visitors
@ -402,9 +402,9 @@ private:
// Create input variables
AstNode::user2ClearTree();
V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp);
for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) {
AstVar* portp = it->first;
AstArg* argp = it->second;
for (const auto& itr : tconnects) {
AstVar* portp = itr.first;
AstArg* argp = itr.second;
AstNode* pinp = argp->exprp();
portp->unlinkFrBack();
pushDeletep(portp); // Remove it from the clone (not original)
@ -536,9 +536,9 @@ private:
// Convert complicated outputs to temp signals
V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp());
for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) {
AstVar* portp = it->first;
AstNode* pinp = it->second->exprp();
for (const auto& itr : tconnects) {
AstVar* portp = itr.first;
AstNode* pinp = itr.second->exprp();
if (!pinp) {
// Too few arguments in function call
} else {
@ -683,6 +683,7 @@ private:
}
void makeDpiExportWrapper(AstNodeFTask* nodep, AstVar* rtnvarp) {
const char* const tmpSuffixp = V3Task::dpiTemporaryVarSuffix();
AstCFunc* dpip = new AstCFunc(nodep->fileline(), nodep->cname(), m_scopep,
(rtnvarp ? rtnvarp->dpiArgType(true, true) : ""));
dpip->dontCombine(true);
@ -737,7 +738,7 @@ private:
argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true));
args = "";
}
AstVarScope* outvscp = createFuncVar(dpip, portp->name() + "__Vcvt", portp);
AstVarScope* outvscp = createFuncVar(dpip, portp->name() + tmpSuffixp, portp);
// No information exposure; is already visible in import/export func template
outvscp->varp()->protect(false);
portp->protect(false);
@ -764,7 +765,7 @@ private:
argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true));
args = "";
}
AstVarScope* outvscp = createFuncVar(dpip, portp->name() + "__Vcvt", portp);
AstVarScope* outvscp = createFuncVar(dpip, portp->name() + tmpSuffixp, portp);
// No information exposure; is already visible in import/export func template
outvscp->varp()->protect(false);
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp,
@ -789,14 +790,14 @@ private:
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && portp->isWritable() && !portp->isFuncReturn()) {
dpip->addStmtsp(createAssignInternalToDpi(portp, true, "__Vcvt", ""));
dpip->addStmtsp(createAssignInternalToDpi(portp, true, tmpSuffixp, ""));
}
}
}
if (rtnvarp) {
dpip->addStmtsp(createDpiTemp(rtnvarp, ""));
dpip->addStmtsp(createAssignInternalToDpi(rtnvarp, false, "__Vcvt", ""));
dpip->addStmtsp(createAssignInternalToDpi(rtnvarp, false, tmpSuffixp, ""));
string stmt = "return " + rtnvarp->name();
stmt += rtnvarp->basicp()->isDpiPrimitive() ? ";\n" : "[0];\n";
dpip->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
@ -873,6 +874,7 @@ private:
}
void bodyDpiImportFunc(AstNodeFTask* nodep, AstVarScope* rtnvscp, AstCFunc* cfuncp) {
const char* const tmpSuffixp = V3Task::dpiTemporaryVarSuffix();
// Convert input/inout arguments to DPI types
string args;
for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
@ -914,12 +916,12 @@ private:
args += "&";
}
args += portp->name() + "__Vcvt";
args += portp->name() + tmpSuffixp;
cfuncp->addStmtsp(createDpiTemp(portp, "__Vcvt"));
cfuncp->addStmtsp(createDpiTemp(portp, tmpSuffixp));
if (portp->isNonOutput()) {
cfuncp->addStmtsp(
createAssignInternalToDpi(portp, false, "", "__Vcvt"));
createAssignInternalToDpi(portp, false, "", tmpSuffixp));
}
}
}
@ -935,8 +937,8 @@ private:
{ // Call the user function
string stmt;
if (rtnvscp) { // isFunction will no longer work as we unlinked the return var
cfuncp->addStmtsp(createDpiTemp(rtnvscp->varp(), "__Vcvt"));
stmt = rtnvscp->varp()->name() + "__Vcvt";
cfuncp->addStmtsp(createDpiTemp(rtnvscp->varp(), tmpSuffixp));
stmt = rtnvscp->varp()->name() + tmpSuffixp;
stmt += rtnvscp->varp()->basicp()->isDpiPrimitive() ? " = " : "[0] = ";
}
stmt += nodep->cname() + "(" + args + ");\n";
@ -952,7 +954,7 @@ private:
AstVarScope* portvscp = VN_CAST(
portp->user2p(), VarScope); // Remembered when we created it earlier
cfuncp->addStmtsp(
createAssignDpiToInternal(portvscp, portp->name() + "__Vcvt"));
createAssignDpiToInternal(portvscp, portp->name() + tmpSuffixp));
}
}
}
@ -1388,7 +1390,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// Missing pin/expr? We return (pinvar, nullptr)
// Extra pin/expr? We clean it up
typedef std::map<string, int> NameToIndex;
typedef std::map<const string, int> NameToIndex;
NameToIndex nameToIndex;
V3TaskConnects tconnects;
UASSERT_OBJ(nodep->taskp(), nodep, "unlinked");
@ -1577,6 +1579,11 @@ bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& fr
return false;
}
const char* V3Task::dpiTemporaryVarSuffix() {
static const char suffix[] = "__Vcvt";
return suffix;
}
void V3Task::taskAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{

View File

@ -40,6 +40,7 @@ public:
static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix,
const string& toSuffix, const string& frPrefix = "");
static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt);
static const char* dpiTemporaryVarSuffix();
};
#endif // Guard

View File

@ -169,7 +169,7 @@ private:
// STATE
AstNodeModule* m_topModp = nullptr; // Module to add variables to
AstScope* m_topScopep = nullptr; // Scope to add variables to
AstCFunc* m_funcp = nullptr; // C function adding to graph
AstCFunc* m_cfuncp = nullptr; // C function adding to graph
AstTraceDecl* m_tracep = nullptr; // Trace function adding to graph
AstVarScope* m_activityVscp = nullptr; // Activity variable
uint32_t m_activityNumber = 0; // Count of fields in activity variable
@ -741,8 +741,8 @@ private:
// Remove refs to traced values from TraceDecl nodes, these have now moved under
// TraceInc
for (TraceVec::iterator it = traces.begin(); it != traces.end(); ++it) {
AstNode* const valuep = it->second->nodep()->valuep();
for (const auto& i : traces) {
AstNode* const valuep = i.second->nodep()->valuep();
valuep->unlinkFrBack();
valuep->deleteTree();
}
@ -826,9 +826,11 @@ private:
new V3GraphEdge(&m_graph, activityVtxp, funcVtxp, 1);
}
}
m_funcp = nodep;
iterateChildren(nodep);
m_funcp = nullptr;
VL_RESTORER(m_cfuncp);
{
m_cfuncp = nodep;
iterateChildren(nodep);
}
}
virtual void visit(AstTraceDecl* nodep) override {
UINFO(8, " TRACE " << nodep << endl);
@ -836,7 +838,7 @@ private:
V3GraphVertex* const vertexp = new TraceTraceVertex(&m_graph, nodep);
nodep->user1p(vertexp);
UASSERT_OBJ(m_funcp, nodep, "Trace not under func");
UASSERT_OBJ(m_cfuncp, nodep, "Trace not under func");
m_tracep = nodep;
iterateChildren(nodep);
m_tracep = nullptr;
@ -845,7 +847,7 @@ private:
virtual void visit(AstVarRef* nodep) override {
if (m_tracep) {
UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?");
UASSERT_OBJ(!nodep->access().isWrite(), nodep, "Lvalue in trace? Should be const.");
UASSERT_OBJ(nodep->access().isReadOnly(), nodep, "Lvalue in trace? Should be const.");
V3GraphVertex* varVtxp = nodep->varScopep()->user1u().toGraphVertex();
if (!varVtxp) {
varVtxp = new TraceVarVertex(&m_graph, nodep->varScopep());
@ -857,9 +859,9 @@ private:
|| nodep->varp()->isSigPublic()) { // Or ones user can change
new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1);
}
} else if (m_funcp && m_finding && nodep->access().isWrite()) {
} else if (m_cfuncp && m_finding && nodep->access().isWriteOrRW()) {
UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?");
V3GraphVertex* const funcVtxp = getCFuncVertexp(m_funcp);
V3GraphVertex* const funcVtxp = getCFuncVertexp(m_cfuncp);
V3GraphVertex* const varVtxp = nodep->varScopep()->user1u().toGraphVertex();
if (varVtxp) { // else we're not tracing this signal
new V3GraphEdge(&m_graph, funcVtxp, varVtxp, 1);

View File

@ -168,7 +168,7 @@ private:
for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) {
TristateVertex* vvertexp = dynamic_cast<TristateVertex*>(edgep->fromp());
if (const AstVarRef* refp = VN_CAST(vvertexp->nodep(), VarRef)) {
if (refp->access().isWrite()
if (refp->access().isWriteOrRW()
// 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,10 +276,11 @@ class TristatePinVisitor : public TristateBaseVisitor {
bool m_lvalue; // Flip to be an LVALUE
// VISITORS
virtual void visit(AstVarRef* nodep) override {
if (m_lvalue && !nodep->access().isWrite()) {
UASSERT_OBJ(!nodep->access().isRW(), nodep, "Tristate unexpected on R/W access flip");
if (m_lvalue && !nodep->access().isWriteOrRW()) {
UINFO(9, " Flip-to-LValue " << nodep << endl);
nodep->access(VAccess::WRITE);
} else if (!m_lvalue && nodep->access().isWrite()) {
} else if (!m_lvalue && !nodep->access().isReadOnly()) {
UINFO(9, " Flip-to-RValue " << nodep << endl);
nodep->access(VAccess::READ);
// Mark the ex-output as tristated
@ -479,8 +480,7 @@ class TristateVisitor : public TristateBaseVisitor {
// or inouts without high-Z logic and put a 1'bz driver on them and add
// them to the lhs map so they get expanded correctly.
TristateGraph::VarVec vars = m_tgraph.tristateVars();
for (TristateGraph::VarVec::iterator ii = vars.begin(); ii != vars.end(); ++ii) {
AstVar* varp = (*ii);
for (auto varp : vars) {
if (m_tgraph.isTristate(varp)) {
const auto it = m_lhsmap.find(varp);
if (it == m_lhsmap.end()) {
@ -556,8 +556,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstNode* undrivenp = nullptr;
// loop through the lhs drivers to build the driver resolution logic
for (RefVec::iterator ii = refsp->begin(); ii != refsp->end(); ++ii) {
AstVarRef* refp = (*ii);
for (auto refp : *refsp) {
int w = lhsp->width();
// create the new lhs driver for this var
@ -1222,22 +1221,20 @@ class TristateVisitor : public TristateBaseVisitor {
virtual void visit(AstVarRef* nodep) override {
UINFO(9, dbgState() << nodep << endl);
if (m_graphing) {
if (nodep->access().isWrite()) {
associateLogic(nodep, nodep->varp());
} else {
associateLogic(nodep->varp(), nodep);
}
if (nodep->access().isWriteOrRW()) associateLogic(nodep, nodep->varp());
if (nodep->access().isReadOrRW()) associateLogic(nodep->varp(), nodep);
} else {
if (nodep->user2() & U2_NONGRAPH) return; // Processed
nodep->user2(U2_NONGRAPH);
// 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->access().isWrite() && m_tgraph.isTristate(nodep->varp())) {
if (nodep->access().isWriteOrRW() && m_tgraph.isTristate(nodep->varp())) {
UINFO(9, " Ref-to-lvalue " << nodep << endl);
UASSERT_OBJ(!nodep->access().isRW(), nodep, "Tristate unexpected on R/W access");
m_tgraph.didProcess(nodep);
mapInsertLhsVarRef(nodep);
} else if (!nodep->access().isWrite()
} else if (nodep->access().isReadOnly()
// Not already processed, nor varref from visit(AstPin) creation
&& !nodep->user1p()
// Reference to another tristate variable

View File

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

View File

@ -313,7 +313,7 @@ private:
AstNode* basefromp = AstArraySel::baseFromp(nodep);
bool lvalue = false;
if (const AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) {
lvalue = varrefp->access().isWrite();
lvalue = varrefp->access().isWriteOrRW();
}
// Find range of dtype we are selecting from
// Similar code in V3Const::warnSelect
@ -361,7 +361,7 @@ private:
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
bool lvalue = false;
if (const AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) {
lvalue = varrefp->access().isWrite();
lvalue = varrefp->access().isWriteOrRW();
} else if (VN_IS(basefromp, Const)) {
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
} else {

View File

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

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