Merge from master for release.
This commit is contained in:
commit
78e7758022
32
Changes
32
Changes
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -66,4 +66,5 @@ ci/
|
|||
/csrc/
|
||||
obj_dir.*
|
||||
TAGS
|
||||
gmon.out
|
||||
.*~
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
42
src/V3Ast.h
42
src/V3Ast.h
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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]";
|
||||
|
|
|
|||
179
src/V3AstNodes.h
179
src/V3AstNodes.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
177
src/V3EmitC.cpp
177
src/V3EmitC.cpp
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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 ";
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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("}");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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, " ");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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 << " ";
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue