mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 08:33:21 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02cb3d17a2 | ||
|
|
c3cfaf55ed | ||
|
|
3e7013af31 | ||
|
|
f7a5883205 | ||
|
|
5d3482734a | ||
|
|
e8c03650ae | ||
|
|
7eac788306 | ||
|
|
6a58e67699 | ||
|
|
b49be06a5a | ||
|
|
87b2adb6a1 | ||
|
|
5634a18f78 | ||
|
|
b84c9bb4c0 | ||
|
|
6dfce882a1 | ||
|
|
79d33bf1ee | ||
|
|
44eb362a18 | ||
|
|
8664aac225 | ||
|
|
6965e138aa | ||
|
|
fc52fb9093 | ||
|
|
cef7708f38 | ||
|
|
438fb01665 | ||
|
|
67d5b1a11a | ||
|
|
d78941885b | ||
|
|
6e7b07c794 | ||
|
|
9655e287ab | ||
|
|
917ca2bad7 | ||
|
|
c3f5dd7414 | ||
|
|
04c7fd1696 | ||
|
|
152689776d | ||
|
|
778f133118 | ||
|
|
ff5465308b | ||
|
|
602750b1ee | ||
|
|
2a24bb4759 | ||
|
|
7c4259bc0a | ||
|
|
1c2384cb3d | ||
|
|
75881754a9 | ||
|
|
0505816d31 | ||
|
|
48bcf66ac7 | ||
|
|
0145d9d514 | ||
|
|
2ce86eddfa | ||
|
|
b663d1a230 | ||
|
|
5821048df7 | ||
|
|
80284c437e | ||
|
|
2aedc91151 | ||
|
|
c1e8337fc1 | ||
|
|
1858cc8ff1 | ||
|
|
5e6aca59ab | ||
|
|
726e78fdda | ||
|
|
085e8454b8 | ||
|
|
85b05366bc | ||
|
|
e6b0479b80 | ||
|
|
3a53b32a32 | ||
|
|
cf7b5c091a | ||
|
|
51b0963e61 | ||
|
|
0c949ceba2 | ||
|
|
5c070558ae | ||
|
|
0c328b6eaf | ||
|
|
f670eccf8c | ||
|
|
23140aeff0 | ||
|
|
d44426b3f3 | ||
|
|
05ff96bea3 | ||
|
|
77ac9bfcc6 | ||
|
|
34b8ed4cf0 | ||
|
|
95d1272269 | ||
|
|
046c0a7aa1 | ||
|
|
835905bdae | ||
|
|
51d1235cda | ||
|
|
2f21b3385a | ||
|
|
9d0a7d5e70 | ||
|
|
4cec3ff2a0 | ||
|
|
25593c0ee2 | ||
|
|
5d3dd52f13 | ||
|
|
ec36d0d772 | ||
|
|
3d2503f9aa | ||
|
|
4576644591 | ||
|
|
d8df216a8d | ||
|
|
964dcd5b7c | ||
|
|
f62c070d06 | ||
|
|
a56e0a6e89 | ||
|
|
451e961e03 | ||
|
|
cb550e5357 | ||
|
|
829db3eefa | ||
|
|
44f938e507 | ||
|
|
4849c0530b | ||
|
|
f4ed367850 | ||
|
|
d4df94d866 | ||
|
|
5d8019f941 | ||
|
|
48597bebaf | ||
|
|
470859f929 | ||
|
|
77553d23fc | ||
|
|
3b9c8b64f7 | ||
|
|
7e5f562500 | ||
|
|
d4d3ae4dfc | ||
|
|
79b1b07fcd | ||
|
|
e3cf5c07e4 | ||
|
|
8750352495 | ||
|
|
3d8dc2774b | ||
|
|
0a9ae154be | ||
|
|
e25a6334cf | ||
|
|
070bead9f9 | ||
|
|
549921be2e | ||
|
|
7c05033b79 | ||
|
|
215d3614c0 | ||
|
|
1ebf937a6c | ||
|
|
7be343fd7c | ||
|
|
fb2d78520f | ||
|
|
c5da072ff6 | ||
|
|
efbcb094ca | ||
|
|
5033c906fd | ||
|
|
f8ab30d127 | ||
|
|
222ca4b009 | ||
|
|
e3a1954e20 | ||
|
|
4ba2637360 | ||
|
|
6430743b6f | ||
|
|
0c49cca527 | ||
|
|
7a9e79ea79 | ||
|
|
157948c552 | ||
|
|
1a127a479c | ||
|
|
87e4a86fbb | ||
|
|
1c1b95161b | ||
|
|
66d1754d19 | ||
|
|
57a53c014d | ||
|
|
e48a859b86 | ||
|
|
430238a6b4 | ||
|
|
9a4c5509fc | ||
|
|
0765443353 | ||
|
|
d07a6f81e4 | ||
|
|
fac04521db | ||
|
|
d0819f156f | ||
|
|
b77eab3f83 | ||
|
|
30f3774134 | ||
|
|
1899a875a4 | ||
|
|
cc134b38ee | ||
|
|
993115d30a | ||
|
|
c1d35c8622 |
+5
-5
@@ -85,7 +85,7 @@ jobs:
|
||||
# OS X build
|
||||
- {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}}
|
||||
# FreeBSD build
|
||||
- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
|
||||
#- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
|
||||
############################################################################
|
||||
# Jobs in the 'test' stage
|
||||
############################################################################
|
||||
@@ -136,10 +136,10 @@ jobs:
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
# FreeBSD tests
|
||||
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
@@ -2,6 +2,69 @@ 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
|
||||
|
||||
**** Support const object new() assignments.
|
||||
|
||||
**** Support # as a comment in -f files (#2497). [phantom-killua]
|
||||
|
||||
**** Support 'this' (#2585). [Rafal Kapuscik]
|
||||
|
||||
**** Support defines for FST tracing (#2592). [Markus Krause]
|
||||
|
||||
**** Support |=> inside properties (#1292). [Peter Monsson]
|
||||
|
||||
**** Fix timescale with --hierarchical (#2554). [Yutetsu TAKATSUKASA]
|
||||
|
||||
**** Fix cmake build with --hierarchical (#2560). [Yutetsu TAKATSUKASA]
|
||||
|
||||
**** Fix -G dropping public indication (#2561). [Andrew Goessling]
|
||||
|
||||
**** Fix $urandom_range passed variable (#2563). [nanduraj1]
|
||||
|
||||
**** Fix method calls to package class functions (#2565). [Peter Monsson]
|
||||
|
||||
**** Fix class wide member display (#2567). [Nandu Raj P]
|
||||
|
||||
**** Fix hierarchical references inside function (#2267) (#2572). [James Pallister]
|
||||
|
||||
**** Fix flushCall for backward compatibility (#2580). [chenguokai]
|
||||
|
||||
**** Fix preprocessor stringify of undefined macro. [Martin Whitaker]
|
||||
|
||||
|
||||
* Verilator 4.100 2020-09-07
|
||||
|
||||
@@ -27,6 +90,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
**** Add support for assume property. [Peter Monsson]
|
||||
|
||||
**** Add support for |=> inside properties (#1292). [Peter Monsson]
|
||||
|
||||
|
||||
* Verilator 4.040 2020-08-15
|
||||
|
||||
|
||||
@@ -66,4 +66,5 @@ ci/
|
||||
/csrc/
|
||||
obj_dir.*
|
||||
TAGS
|
||||
gmon.out
|
||||
.*~
|
||||
|
||||
+6
-3
@@ -170,6 +170,8 @@ DISTFILES_INC = $(INFOS) .gitignore \
|
||||
test_regress/t/t*/*.v* \
|
||||
test_regress/t/t*/*/*.sv* \
|
||||
test_regress/t/t*/*/*.v* \
|
||||
test_regress/t/t*/*.cpp \
|
||||
test_regress/t/t*/CMakeLists.txt \
|
||||
test_regress/t/*.cpp \
|
||||
test_regress/t/*.h \
|
||||
test_regress/t/*.dat \
|
||||
@@ -440,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
|
||||
@@ -460,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
|
||||
|
||||
|
||||
+22
-5
@@ -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;
|
||||
}
|
||||
|
||||
+17
-6
@@ -156,7 +156,8 @@ sub report {
|
||||
print "\nAnalysis:\n";
|
||||
printf " Total threads = %d\n", $nthreads;
|
||||
printf " Total mtasks = %d\n", scalar(keys %Mtasks);
|
||||
printf " Total cpus used = %d\n", scalar(keys %{$Global{cpus}});
|
||||
my $ncpus = scalar(keys %{$Global{cpus}});
|
||||
printf " Total cpus used = %d\n", $ncpus;
|
||||
printf " Total yields = %d\n", $Global{stats}{yields};
|
||||
printf " Total eval time = %d rdtsc ticks\n", $Global{last_end};
|
||||
printf " Longest mtask time = %d rdtsc ticks\n", $long_mtask_time;
|
||||
@@ -197,15 +198,25 @@ 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) {
|
||||
print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n";
|
||||
print " : See docs on use of numactl.\n";
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub report_graph {
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.100 2020-09-07],
|
||||
AC_INIT([Verilator],[4.104 2020-11-14],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
# When releasing, also update header of Changes file
|
||||
|
||||
@@ -25,20 +25,26 @@ Iztok Jeras
|
||||
James Hanlon
|
||||
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
|
||||
Maarten De Braekeleer
|
||||
Maciej Sobkowski
|
||||
Marco Widmer
|
||||
Markus Krause
|
||||
Marlon James
|
||||
Marshal Qiao
|
||||
Matthew Ballance
|
||||
Michael Killough
|
||||
@@ -52,6 +58,7 @@ Philipp Wagner
|
||||
Pieter Kapsenberg
|
||||
Piotr Binkowski
|
||||
Qingyao Sun
|
||||
Rafal Kapuscik
|
||||
Richard Myers
|
||||
Rupert Swarbrick
|
||||
Sean Cross
|
||||
@@ -65,6 +72,7 @@ Tobias Wölfel
|
||||
Todd Strader
|
||||
Tomasz Gorochowik
|
||||
Tymoteusz Blazejczyk
|
||||
Victor Besyakov
|
||||
Vassilis Papaefstathiou
|
||||
Veripool API Bot
|
||||
Wilson Snyder
|
||||
|
||||
+11
-2
@@ -586,7 +586,7 @@ dealing with. For example a visitor might not implement separate `visit`
|
||||
methods for `AstIf` and `AstGenIf`, but just a single method for the base
|
||||
class:
|
||||
|
||||
void visit (AstNodeIf* nodep)
|
||||
void visit(AstNodeIf* nodep)
|
||||
|
||||
However that method might want to specify additional code if it is called
|
||||
for `AstGenIf`. Verilator does this by providing a `VN_IS` method for each
|
||||
@@ -672,7 +672,7 @@ Set to 1 to indicate that the compilation or execution is intended to fail.
|
||||
For example the following would specify that compilation requires two
|
||||
defines and is expected to fail.
|
||||
|
||||
compile (
|
||||
compile(
|
||||
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
|
||||
fails => 1,
|
||||
);
|
||||
@@ -758,6 +758,15 @@ may be required to setup the system for fuzzing.
|
||||
|
||||
== Debugging
|
||||
|
||||
=== Debug Levels
|
||||
|
||||
The "UINFO" calls in the source indicate a debug level. Messages level 3
|
||||
and below are globally enabled with `--debug`. Higher levels may be
|
||||
controlled with `--debugi <level>`. An individual source file levels may
|
||||
be controlled with `-debugi-<srcfile> <level>`. For example `--debug
|
||||
--debugi 5 --debugi-V3Width 9` will use the debug binary at default debug
|
||||
level 5, with the V3Width.cpp file at level 9.
|
||||
|
||||
=== --debug
|
||||
|
||||
When you run with `--debug` there are two primary output file types placed
|
||||
|
||||
+55
-29
@@ -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);
|
||||
}
|
||||
@@ -913,10 +913,11 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
output += "0123456789abcdef"[charval];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default: { // LCOV_EXCL_START
|
||||
std::string msg = std::string("Unknown _vl_vsformat code: ") + pos[0];
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
break;
|
||||
} // LCOV_EXCL_STOP
|
||||
} // switch
|
||||
}
|
||||
} // switch
|
||||
@@ -1078,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': {
|
||||
@@ -1092,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;
|
||||
}
|
||||
@@ -1182,15 +1195,20 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
default: { // LCOV_EXCL_START
|
||||
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
break;
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
} // switch
|
||||
|
||||
if (!inIgnore) ++got;
|
||||
// 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];
|
||||
@@ -1249,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;
|
||||
@@ -2596,7 +2622,7 @@ vluint32_t VerilatedVarProps::entSize() const {
|
||||
case VLVT_UINT32: size = sizeof(IData); break;
|
||||
case VLVT_UINT64: size = sizeof(QData); break;
|
||||
case VLVT_WDATA: size = VL_WORDS_I(packed().elements()) * sizeof(IData); break;
|
||||
default: size = 0; break;
|
||||
default: size = 0; break; // LCOV_EXCL_LINE
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -499,6 +499,7 @@ public:
|
||||
static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void runFlushCallbacks() VL_MT_SAFE;
|
||||
static void flushCall() VL_MT_SAFE { runFlushCallbacks(); } // Deprecated
|
||||
/// Callbacks to run prior to termination
|
||||
static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
|
||||
@@ -54,6 +54,7 @@ VK_CPPFLAGS_ALWAYS += \
|
||||
-DVM_COVERAGE=$(VM_COVERAGE) \
|
||||
-DVM_SC=$(VM_SC) \
|
||||
-DVM_TRACE=$(VM_TRACE) \
|
||||
-DVM_TRACE_FST=$(VM_TRACE_FST) \
|
||||
$(CFG_CXXFLAGS_NO_UNUSED) \
|
||||
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
|
||||
@@ -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;
|
||||
|
||||
+508
-131
@@ -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
|
||||
|
||||
|
||||
@@ -42,9 +42,10 @@
|
||||
// clang-format on
|
||||
|
||||
// CONSTANTS
|
||||
static const char* const VLTSAVE_HEADER_STR
|
||||
= "verilatorsave01\n"; ///< Value of first bytes of each file
|
||||
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
||||
/// Value of first bytes of each file (must be multiple of 8 bytes)
|
||||
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n";
|
||||
/// Value of last bytes of each file (must be multiple of 8 bytes)
|
||||
static const char* const VLTSAVE_TRAILER_STR = "vltsaved";
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
@@ -64,10 +65,10 @@ VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict da
|
||||
size_t size) VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(readDiffers(datap, size))) {
|
||||
std::string fn = filename();
|
||||
std::string msg
|
||||
= "Can't deserialize save-restore file as was made from different model:" + filename();
|
||||
std::string msg = "Can't deserialize save-restore file as was made from different model: "
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
@@ -88,9 +89,11 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
||||
std::string fn = filename();
|
||||
std::string msg
|
||||
= std::string("Can't deserialize; file has wrong header signature: ") + filename();
|
||||
= std::string(
|
||||
"Can't deserialize; file has wrong header signature, or file not found: ")
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
os.read(Verilated::serialized1Ptr(), Verilated::serialized1Size());
|
||||
os.read(Verilated::serialized2Ptr(), Verilated::serialized2Size());
|
||||
@@ -109,7 +112,7 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ")
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -139,7 +137,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
|
||||
if (VL_UNLIKELY(!fp)) {
|
||||
VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable");
|
||||
// cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr
|
||||
return;
|
||||
return; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// TODO Perhaps merge with verilated_coverage output format, so can
|
||||
|
||||
@@ -22,6 +22,15 @@
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h" // for VerilatedMutex and clang annotations
|
||||
|
||||
#ifndef VL_THREADED
|
||||
// Hitting this likely means verilated_threads.cpp is being compiled when
|
||||
// 'verilator --threads' was not used. 'verilator --threads' sets
|
||||
// VL_THREADED.
|
||||
// Alternatively it is always safe but may harm performance to always
|
||||
// define VL_THREADED for all compiles.
|
||||
#error "verilated_threads.h/cpp expected VL_THREADED (from verilator --threads)"
|
||||
#endif
|
||||
|
||||
#include <condition_variable>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
@@ -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);
|
||||
|
||||
+52
-47
@@ -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;
|
||||
|
||||
@@ -46,14 +46,17 @@ remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
|
||||
exclude_line_regexp(qr/(\bv3fatalSrc\b
|
||||
|\bfatalSrc\b
|
||||
|\bVL_UNCOVERABLE\b
|
||||
|\bVL_UNREACHABLE\b
|
||||
|\bVL_FATAL
|
||||
|\bUASSERT
|
||||
|\bNUM_ASSERT
|
||||
|\bERROR_RSVD_WORD
|
||||
|\bV3ERROR_NA
|
||||
|\bUINFO\b)/x);
|
||||
|
||||
# Exclude for branch coverage only
|
||||
exclude_branch_regexp(qr/(\bdebug\(\)
|
||||
|\bassert\(
|
||||
|\bSELF_CHECK)/x);
|
||||
|
||||
1;
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
|
||||
@@ -81,6 +81,10 @@ prefiles:: config_rev.h
|
||||
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
|
||||
# Human convenience
|
||||
clang-format:
|
||||
$(MAKE) -C .. $@
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_* *.log *.dmp *.vpd core
|
||||
|
||||
+3
-3
@@ -317,12 +317,12 @@ private:
|
||||
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
|
||||
inp->dtypep());
|
||||
m_modp->addStmtp(outvarp);
|
||||
AstNode* assp = new AstAssignDly(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), outvarp, true), inp);
|
||||
AstNode* assp = new AstAssignDly(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
|
||||
alwaysp->addStmtp(assp);
|
||||
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
|
||||
invarp = outvarp;
|
||||
inp = new AstVarRef(nodep->fileline(), invarp, false);
|
||||
inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ);
|
||||
}
|
||||
nodep->replaceWith(inp);
|
||||
}
|
||||
|
||||
+26
-3
@@ -39,6 +39,8 @@ private:
|
||||
AstSenItem* m_senip = nullptr; // Last sensitivity
|
||||
// Reset each always:
|
||||
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
|
||||
// Reset each assertion:
|
||||
AstNode* m_disablep = nullptr; // Last disable
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@@ -58,7 +60,10 @@ private:
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
void clearAssertInfo() { m_senip = nullptr; }
|
||||
void clearAssertInfo() {
|
||||
m_senip = nullptr;
|
||||
m_disablep = nullptr;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
//========== Statements
|
||||
@@ -129,8 +134,25 @@ private:
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq(fl, past,
|
||||
exprp->cloneTree(false)); // new AstVarRef(fl, exprp, true)
|
||||
exprp = new AstEq(fl, past, exprp->cloneTree(false));
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstImplication* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
|
||||
if (m_disablep) { lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); }
|
||||
|
||||
AstNode* past = new AstPast(fl, lhsp, nullptr);
|
||||
past->dtypeFrom(lhsp);
|
||||
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
@@ -145,6 +167,7 @@ private:
|
||||
// Block is the new expression to evaluate
|
||||
AstNode* blockp = nodep->propp()->unlinkFrBack();
|
||||
if (nodep->disablep()) {
|
||||
m_disablep = nodep->disablep()->cloneTree(false);
|
||||
if (VN_IS(nodep->backp(), Cover)) {
|
||||
blockp = new AstAnd(
|
||||
nodep->disablep()->fileline(),
|
||||
|
||||
+12
-4
@@ -58,9 +58,10 @@ std::ostream& operator<<(std::ostream& os, AstType rhs);
|
||||
//######################################################################
|
||||
// Creators
|
||||
|
||||
void AstNode::init() {
|
||||
AstNode::AstNode(AstType t, FileLine* fl)
|
||||
: m_type{t}
|
||||
, m_fileline{fl} {
|
||||
editCountInc();
|
||||
m_fileline = nullptr;
|
||||
m_nextp = nullptr;
|
||||
m_backp = nullptr;
|
||||
m_headtailp = this; // When made, we're a list of only a single element
|
||||
@@ -393,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 {
|
||||
@@ -402,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 {
|
||||
@@ -411,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 {
|
||||
@@ -420,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 {
|
||||
@@ -1112,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
|
||||
@@ -1130,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
|
||||
@@ -1260,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
|
||||
|
||||
+76
-22
@@ -123,6 +123,49 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VAccess {
|
||||
public:
|
||||
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", "RW", "--"};
|
||||
return names[m_e];
|
||||
}
|
||||
const char* arrow() const {
|
||||
static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"};
|
||||
return names[m_e];
|
||||
}
|
||||
inline VAccess()
|
||||
: m_e{READ} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
inline VAccess(en _e)
|
||||
: m_e{_e} {}
|
||||
explicit inline VAccess(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
operator en() const { return m_e; }
|
||||
VAccess invert() const {
|
||||
return (m_e == 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; }
|
||||
inline bool operator==(VAccess::en lhs, const VAccess& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return os << rhs.ascii(); }
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VSigning {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
@@ -1227,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();
|
||||
|
||||
@@ -1422,7 +1468,6 @@ class AstNode {
|
||||
if (nodep) nodep->m_backp = this;
|
||||
}
|
||||
|
||||
void init(); // initialize value of AstNode
|
||||
private:
|
||||
AstNode* cloneTreeIter();
|
||||
AstNode* cloneTreeIterList();
|
||||
@@ -1442,15 +1487,7 @@ public:
|
||||
|
||||
protected:
|
||||
// CONSTRUCTORS
|
||||
AstNode(AstType t)
|
||||
: m_type{t} {
|
||||
init();
|
||||
}
|
||||
AstNode(AstType t, FileLine* fl)
|
||||
: m_type{t} {
|
||||
init();
|
||||
m_fileline = fl;
|
||||
}
|
||||
AstNode(AstType t, FileLine* fl);
|
||||
virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead
|
||||
virtual void cloneRelink() {}
|
||||
void cloneRelinkTree();
|
||||
@@ -1713,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,
|
||||
@@ -1783,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
|
||||
@@ -1889,6 +1928,7 @@ public:
|
||||
: AstNode{t, fl} {}
|
||||
ASTNODE_BASE_FUNCS(NodeMath)
|
||||
// METHODS
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
virtual bool hasDType() const override { return true; }
|
||||
virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV
|
||||
// For documentation on emitC format see EmitCStmts::emitOpName
|
||||
@@ -1911,6 +1951,7 @@ public:
|
||||
// See checkTreeIter also that asserts no children
|
||||
// cppcheck-suppress functionConst
|
||||
void iterateChildren(AstNVisitor& v) {}
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
};
|
||||
|
||||
class AstNodeUniop : public AstNodeMath {
|
||||
@@ -1925,6 +1966,7 @@ public:
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
|
||||
// METHODS
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
// Set out to evaluation of a AstConst'ed lhs
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0;
|
||||
virtual bool cleanLhs() const = 0;
|
||||
@@ -1987,6 +2029,7 @@ public:
|
||||
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
|
||||
void thsp(AstNode* nodep) { return setOp3p(nodep); }
|
||||
// METHODS
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
// Set out to evaluation of a AstConst'ed
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
|
||||
const V3Number& ths)
|
||||
@@ -2142,6 +2185,7 @@ public:
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeProcedure)
|
||||
// METHODS
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
|
||||
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
|
||||
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
|
||||
@@ -2158,8 +2202,11 @@ public:
|
||||
// METHODS
|
||||
bool isStatement() const { return m_statement; } // Really a statement
|
||||
void statement(bool flag) { m_statement = flag; }
|
||||
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
||||
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
||||
virtual void addNextStmt(AstNode* newp,
|
||||
AstNode* belowp) override; // Stop statement searchback here
|
||||
virtual void addBeforeStmt(AstNode* newp,
|
||||
AstNode* belowp) override; // Stop statement searchback here
|
||||
virtual void dump(std::ostream& str = std::cout) const override;
|
||||
};
|
||||
|
||||
class AstNodeAssign : public AstNodeStmt {
|
||||
@@ -2255,7 +2302,7 @@ public:
|
||||
class AstNodeVarRef : public AstNodeMath {
|
||||
// An AstVarRef or AstVarXRef
|
||||
private:
|
||||
bool m_lvalue; // Left hand side assignment
|
||||
VAccess m_access; // Left hand side assignment
|
||||
AstVar* m_varp; // [AfterLink] Pointer to variable itself
|
||||
AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy
|
||||
AstNodeModule* m_packagep = nullptr; // Package hierarchy
|
||||
@@ -2264,28 +2311,29 @@ private:
|
||||
bool m_hierThis = false; // Hiername points to "this" function
|
||||
|
||||
public:
|
||||
AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue)
|
||||
AstNodeVarRef(AstType t, FileLine* fl, const string& name, const VAccess& access)
|
||||
: AstNodeMath{t, fl}
|
||||
, m_lvalue{lvalue}
|
||||
, m_access{access}
|
||||
, m_name{name} {
|
||||
this->varp(nullptr);
|
||||
}
|
||||
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue)
|
||||
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access)
|
||||
: AstNodeMath{t, fl}
|
||||
, m_lvalue{lvalue}
|
||||
, m_access{access}
|
||||
, m_name{name} {
|
||||
// May have varp==nullptr
|
||||
this->varp(varp);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeVarRef)
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
virtual bool hasDType() const override { return true; }
|
||||
virtual const char* broken() const override;
|
||||
virtual int instrCount() const override { return widthInstrs(); }
|
||||
virtual void cloneRelink() override;
|
||||
virtual string name() const override { return m_name; } // * = Var name
|
||||
virtual void name(const string& name) override { m_name = name; }
|
||||
bool lvalue() const { return m_lvalue; }
|
||||
void lvalue(bool lval) { m_lvalue = lval; } // Avoid using this; Set in constructor
|
||||
VAccess access() const { return m_access; }
|
||||
void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
void varp(AstVar* varp);
|
||||
AstVarScope* varScopep() const { return m_varScopep; }
|
||||
@@ -2412,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;
|
||||
@@ -2862,6 +2915,7 @@ public:
|
||||
AstNodeRange(AstType t, FileLine* fl)
|
||||
: AstNode{t, fl} {}
|
||||
ASTNODE_BASE_FUNCS(NodeRange)
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+159
-134
@@ -87,8 +87,10 @@ const char* AstNodeUOrStructDType::broken() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
|
||||
void AstNodeCCall::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (funcp()) {
|
||||
str << " " << funcp()->name() << " => ";
|
||||
funcp()->dump(str);
|
||||
@@ -310,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());
|
||||
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 {
|
||||
@@ -636,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,
|
||||
@@ -843,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()) {
|
||||
@@ -872,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];
|
||||
//
|
||||
@@ -1035,8 +1045,10 @@ void AstNode::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
|
||||
void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
|
||||
void AstAlways::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeProcedure::dump(str);
|
||||
if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]";
|
||||
}
|
||||
|
||||
@@ -1057,8 +1069,12 @@ string AstBasicDType::prettyDTypeName() const {
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
||||
|
||||
void AstCCast::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeUniop::dump(str);
|
||||
str << " sz" << size();
|
||||
}
|
||||
void AstCell::dump(std::ostream& str) const {
|
||||
@@ -1074,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());
|
||||
@@ -1119,15 +1136,15 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const {
|
||||
str << "class:" << name();
|
||||
}
|
||||
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (immediate()) str << " [IMMEDIATE]";
|
||||
}
|
||||
void AstDisplay::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
// str<<" "<<displayType().ascii();
|
||||
}
|
||||
void AstEnumItemRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeMath::dump(str);
|
||||
str << " -> ";
|
||||
if (itemp()) {
|
||||
itemp()->dump(str);
|
||||
@@ -1158,16 +1175,16 @@ 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 {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (labelp()) {
|
||||
labelp()->dump(str);
|
||||
@@ -1176,7 +1193,7 @@ void AstJumpGo::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstJumpLabel::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (blockp()) {
|
||||
blockp()->dump(str);
|
||||
@@ -1185,7 +1202,7 @@ void AstJumpLabel::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstMemberSel::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeMath::dump(str);
|
||||
str << " -> ";
|
||||
if (varp()) {
|
||||
varp()->dump(str);
|
||||
@@ -1194,7 +1211,7 @@ void AstMemberSel::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstMethodCall::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (isStatement()) str << " [STMT]";
|
||||
str << " -> ";
|
||||
if (taskp()) {
|
||||
@@ -1235,27 +1252,30 @@ void AstPin::dump(std::ostream& str) const {
|
||||
if (svImplicit()) str << " [.SV]";
|
||||
}
|
||||
void AstPrintTimeScale::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " " << timeunit();
|
||||
}
|
||||
|
||||
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
||||
void AstTime::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeTermop::dump(str);
|
||||
str << " " << timeunit();
|
||||
}
|
||||
void AstTimeD::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeTermop::dump(str);
|
||||
str << " " << timeunit();
|
||||
}
|
||||
void AstTimeImport::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeUniop::dump(str);
|
||||
str << " " << timeunit();
|
||||
}
|
||||
void AstTypedef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (attrPublic()) str << " [PUBLIC]";
|
||||
}
|
||||
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstRange::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeRange::dump(str);
|
||||
if (littleEndian()) str << " [LITTLE]";
|
||||
}
|
||||
void AstRefDType::dump(std::ostream& str) const {
|
||||
@@ -1352,15 +1372,20 @@ void AstPackageImport::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " -> " << packagep();
|
||||
}
|
||||
void AstSel::dump(std::ostream& str) const {
|
||||
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);
|
||||
if (declRange().ranged()) {
|
||||
str << " decl" << declRange() << "]";
|
||||
if (declElWidth() != 1) str << "/" << declElWidth();
|
||||
}
|
||||
}
|
||||
void AstSliceSel::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeTriop::dump(str);
|
||||
if (declRange().ranged()) str << " decl" << declRange();
|
||||
}
|
||||
void AstMTaskBody::dump(std::ostream& str) const {
|
||||
@@ -1380,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);
|
||||
@@ -1391,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() + "]";
|
||||
@@ -1428,14 +1453,11 @@ void AstVarScope::dump(std::ostream& str) const {
|
||||
str << " ->UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
||||
void AstVarXRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
if (lvalue()) {
|
||||
str << " [LV] => ";
|
||||
} else {
|
||||
str << " [RV] <- ";
|
||||
}
|
||||
this->AstNodeVarRef::dump(str);
|
||||
if (packagep()) str << " pkg=" << nodeAddr(packagep());
|
||||
str << " " << access().arrow() << " ";
|
||||
str << ".=" << dotted() << " ";
|
||||
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
|
||||
if (varScopep()) {
|
||||
@@ -1447,13 +1469,9 @@ void AstVarXRef::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstVarRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
if (lvalue()) {
|
||||
str << " [LV] => ";
|
||||
} else {
|
||||
str << " [RV] <- ";
|
||||
}
|
||||
this->AstNodeVarRef::dump(str);
|
||||
if (packagep()) str << " pkg=" << nodeAddr(packagep());
|
||||
str << " " << access().arrow() << " ";
|
||||
if (varScopep()) {
|
||||
varScopep()->dump(str);
|
||||
} else if (varp()) {
|
||||
@@ -1486,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]";
|
||||
@@ -1522,7 +1546,7 @@ void AstActive::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
|
||||
str << " -> ";
|
||||
if (dotted() != "") { str << ".=" << dotted() << " "; }
|
||||
@@ -1554,7 +1578,7 @@ void AstBegin::dump(std::ostream& str) const {
|
||||
if (implied()) str << " [IMPLIED]";
|
||||
}
|
||||
void AstCoverDecl::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (!page().empty()) str << " page=" << page();
|
||||
if (!linescov().empty()) str << " lc=" << linescov();
|
||||
if (this->dataDeclNullp()) {
|
||||
@@ -1565,7 +1589,7 @@ void AstCoverDecl::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
void AstCoverInc::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (declp()) {
|
||||
declp()->dump(str);
|
||||
@@ -1578,7 +1602,7 @@ void AstFork::dump(std::ostream& str) const {
|
||||
if (!joinType().join()) str << " [" << joinType() << "]";
|
||||
}
|
||||
void AstTraceInc::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (declp()) {
|
||||
declp()->dump(str);
|
||||
@@ -1597,10 +1621,11 @@ void AstNodeText::dump(std::ostream& str) const {
|
||||
str << " \"" << out << "\"";
|
||||
}
|
||||
|
||||
void AstVFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); }
|
||||
|
||||
void AstCFile::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
this->AstNodeFile::dump(str);
|
||||
if (source()) str << " [SRC]";
|
||||
if (slow()) str << " [SLOW]";
|
||||
}
|
||||
|
||||
+218
-27
@@ -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
|
||||
@@ -539,10 +539,13 @@ public:
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
if (!asamep->keyDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep());
|
||||
}
|
||||
virtual bool similarDType(AstNodeDType* samep) const override {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual string prettyDTypeName() const override;
|
||||
@@ -635,10 +638,12 @@ public:
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return subDTypep() == asamep->subDTypep();
|
||||
}
|
||||
virtual bool similarDType(AstNodeDType* samep) const override {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual string prettyDTypeName() const override;
|
||||
@@ -741,10 +746,12 @@ public:
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep());
|
||||
}
|
||||
virtual bool similarDType(AstNodeDType* samep) const override {
|
||||
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual void dumpSmall(std::ostream& str) const override;
|
||||
@@ -1093,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())
|
||||
@@ -1104,10 +1117,12 @@ public:
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstQueueDType* asamep = static_cast<const AstQueueDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep());
|
||||
}
|
||||
virtual bool similarDType(AstNodeDType* samep) const override {
|
||||
const AstQueueDType* asamep = static_cast<const AstQueueDType*>(samep);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual void dumpSmall(std::ostream& str) const override;
|
||||
@@ -1669,7 +1684,7 @@ class AstSel : public AstNodeTriop {
|
||||
// Multiple bit range extraction
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math, constant math
|
||||
// Tempting to have an lvalue() style method here as LHS selects are quite
|
||||
// Tempting to have an access() style method here as LHS selects are quite
|
||||
// different, but that doesn't play well with V3Inst and bidirects which don't know direction
|
||||
private:
|
||||
VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid
|
||||
@@ -2173,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 = false) const;
|
||||
};
|
||||
|
||||
class AstDefParam : public AstNode {
|
||||
@@ -2238,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; }
|
||||
@@ -2319,15 +2330,15 @@ public:
|
||||
class AstVarRef : public AstNodeVarRef {
|
||||
// A reference to a variable (lvalue or rvalue)
|
||||
public:
|
||||
AstVarRef(FileLine* fl, const string& name, bool lvalue)
|
||||
: ASTGEN_SUPER(fl, name, nullptr, lvalue) {}
|
||||
AstVarRef(FileLine* fl, const string& name, const VAccess& access)
|
||||
: ASTGEN_SUPER(fl, name, nullptr, access) {}
|
||||
// This form only allowed post-link because output/wire compression may
|
||||
// lead to deletion of AstVar's
|
||||
AstVarRef(FileLine* fl, AstVar* varp, bool lvalue)
|
||||
: ASTGEN_SUPER(fl, varp->name(), varp, lvalue) {}
|
||||
AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access)
|
||||
: ASTGEN_SUPER(fl, varp->name(), varp, access) {}
|
||||
// This form only allowed post-link (see above)
|
||||
AstVarRef(FileLine* fl, AstVarScope* varscp, bool lvalue)
|
||||
: ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), lvalue) {
|
||||
AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access)
|
||||
: ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), access) {
|
||||
varScopep(varscp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(VarRef)
|
||||
@@ -2340,21 +2351,23 @@ public:
|
||||
}
|
||||
inline bool same(const AstVarRef* samep) const {
|
||||
if (varScopep()) {
|
||||
return (varScopep() == samep->varScopep() && lvalue() == samep->lvalue());
|
||||
return (varScopep() == samep->varScopep() && access() == samep->access());
|
||||
} else {
|
||||
return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name()
|
||||
&& lvalue() == samep->lvalue());
|
||||
&& access() == samep->access());
|
||||
}
|
||||
}
|
||||
inline bool sameNoLvalue(AstVarRef* samep) const {
|
||||
if (varScopep()) {
|
||||
return (varScopep() == samep->varScopep());
|
||||
} else {
|
||||
return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name());
|
||||
return (hiername() == samep->hiername()
|
||||
&& (hiername() != "" || samep->hiername() != "")
|
||||
&& varp()->name() == samep->varp()->name());
|
||||
}
|
||||
}
|
||||
virtual int instrCount() const override {
|
||||
return widthInstrs() * (lvalue() ? 1 : instrCountLd());
|
||||
return widthInstrs() * (access().isReadOrRW() ? instrCountLd() : 1);
|
||||
}
|
||||
virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -2368,11 +2381,11 @@ private:
|
||||
string m_dotted; // Dotted part of scope the name()'ed reference is under or ""
|
||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||
public:
|
||||
AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue)
|
||||
: ASTGEN_SUPER(fl, name, nullptr, lvalue)
|
||||
AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access)
|
||||
: ASTGEN_SUPER(fl, name, nullptr, access)
|
||||
, m_dotted{dotted} {}
|
||||
AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, bool lvalue)
|
||||
: ASTGEN_SUPER(fl, varp->name(), varp, lvalue)
|
||||
AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access)
|
||||
: ASTGEN_SUPER(fl, varp->name(), varp, access)
|
||||
, m_dotted{dotted} {
|
||||
dtypeFrom(varp);
|
||||
}
|
||||
@@ -2959,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); }
|
||||
@@ -3065,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(); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -4593,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
|
||||
@@ -5801,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) {}
|
||||
@@ -7884,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; }
|
||||
@@ -8227,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)
|
||||
@@ -8235,6 +8397,32 @@ public:
|
||||
void isDefault(bool flag) { m_default = flag; }
|
||||
};
|
||||
|
||||
class AstImplication : public AstNodeMath {
|
||||
// Verilog |-> |=>
|
||||
// Parents: math
|
||||
// Children: expression
|
||||
public:
|
||||
AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
setOp1p(lhs);
|
||||
setOp2p(rhs);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Implication)
|
||||
virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); }
|
||||
virtual int instrCount() const override { return widthInstrs(); }
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
AstNode* rhsp() const { return op2p(); }
|
||||
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
|
||||
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
|
||||
AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain
|
||||
void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain
|
||||
virtual V3Hash sameHash() const override { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// Assertions
|
||||
|
||||
@@ -8461,6 +8649,7 @@ public:
|
||||
m_name = name;
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeFile)
|
||||
virtual void dump(std::ostream& str) const override;
|
||||
virtual string name() const override { return m_name; }
|
||||
virtual V3Hash sameHash() const override { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
@@ -8875,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;
|
||||
@@ -8889,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);
|
||||
|
||||
+29
-36
@@ -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();
|
||||
@@ -203,7 +196,7 @@ private:
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) override {
|
||||
UINFO(9, " VARXREF " << nodep << endl);
|
||||
if (m_namedScope != "" && nodep->inlinedDots() == "") {
|
||||
if (m_namedScope != "" && nodep->inlinedDots() == "" && !m_ftaskp) {
|
||||
nodep->inlinedDots(m_namedScope);
|
||||
UINFO(9, " rescope to " << nodep << endl);
|
||||
}
|
||||
|
||||
+1
-1
@@ -275,7 +275,7 @@ private:
|
||||
processAndIterate(nodep);
|
||||
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
|
||||
&& VN_IS(nodep->lhsp(), NodeVarRef)
|
||||
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
|
||||
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
|
||||
nodep, "Assignment LHS is not an lvalue");
|
||||
}
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
|
||||
+4
-3
@@ -111,7 +111,7 @@ void V3CCtors::evalAsserts() {
|
||||
int lastWordWidth = varp->width() % storedWidth;
|
||||
if (lastWordWidth != 0) {
|
||||
// if (signal & CONST(upper_non_clean_mask)) { fail; }
|
||||
AstNode* newp = new AstVarRef(varp->fileline(), varp, false);
|
||||
AstNode* newp = new AstVarRef(varp->fileline(), varp, VAccess::READ);
|
||||
if (varp->isWide()) {
|
||||
newp = new AstWordSel(
|
||||
varp->fileline(), newp,
|
||||
@@ -151,8 +151,9 @@ void V3CCtors::cctorsAll() {
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(np, Var)) {
|
||||
if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) {
|
||||
var_reset.add(new AstCReset(varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, true)));
|
||||
var_reset.add(
|
||||
new AstCReset(varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, VAccess::WRITE)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-12
@@ -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,16 +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 += ":\" + VL_TO_STRING(";
|
||||
stmt += itemp->nameProtect();
|
||||
stmt += ");\n";
|
||||
nodep->user1(true); // So what we extend dumps this
|
||||
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) {
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+4
-4
@@ -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,9 +154,9 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath)
|
||||
&& !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width()
|
||||
&& castSize(nodep) != castSize(nodep->varp())) {
|
||||
if (nodep->access().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
|
||||
// CData x=3; out = (QData)(x<<30);
|
||||
insertCast(nodep, castSize(nodep));
|
||||
|
||||
+6
-7
@@ -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->lvalue()) {
|
||||
if (nodep->access().isWriteOrRW()) {
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
|
||||
if (m_inDly) {
|
||||
varvertexp->fromFlop(true);
|
||||
|
||||
+3
-3
@@ -199,9 +199,9 @@ public:
|
||||
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
|
||||
m_statep->m_scopetopp->addVarp(m_newvscp);
|
||||
|
||||
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
|
||||
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
|
||||
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
|
||||
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, VAccess::READ);
|
||||
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::WRITE);
|
||||
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::READ);
|
||||
}
|
||||
iterate(vscp->dtypep()->skipRefp());
|
||||
m_varEqnp->deleteTree();
|
||||
|
||||
+33
-7
@@ -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
|
||||
|
||||
+16
-13
@@ -79,15 +79,15 @@ private:
|
||||
vscp->user1p(newvscp);
|
||||
m_scopep->addVarp(newvscp);
|
||||
// Add init
|
||||
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
|
||||
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ);
|
||||
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
|
||||
AstNode* newinitp = new AstAssign(
|
||||
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp);
|
||||
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, VAccess::WRITE), fromp);
|
||||
addToInitial(newinitp);
|
||||
// At bottom, assign them
|
||||
AstAssign* finalp
|
||||
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
new AstVarRef(vscp->fileline(), vscp, false));
|
||||
AstAssign* finalp = new AstAssign(vscp->fileline(),
|
||||
new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
|
||||
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
|
||||
m_evalFuncp->addFinalsp(finalp);
|
||||
//
|
||||
UINFO(4, "New Last: " << newvscp << endl);
|
||||
@@ -112,25 +112,28 @@ private:
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
|
||||
new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), lastVscp, false)));
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(
|
||||
nodep->fileline(),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(),
|
||||
VAccess::READ)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstXor(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) {
|
||||
newp = new AstVarRef(nodep->fileline(), clkvscp, false);
|
||||
newp = new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ);
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) {
|
||||
newp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), clkvscp, false));
|
||||
newp = new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ));
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad edge type");
|
||||
}
|
||||
|
||||
+8
-8
@@ -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
|
||||
|
||||
+6
-12
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+32
-23
@@ -314,7 +314,7 @@ private:
|
||||
// It was an expression, then got constified. In reality, the WordSel
|
||||
// must be wrapped in a Cond, that will be false.
|
||||
return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef)
|
||||
&& !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->lvalue()
|
||||
&& VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isReadOnly()
|
||||
&& (static_cast<int>(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt())
|
||||
>= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords()));
|
||||
}
|
||||
@@ -1132,18 +1132,22 @@ private:
|
||||
VFlagLogicPacked(), msb2 - lsb2 + 1);
|
||||
m_modp->addStmtp(temp1p);
|
||||
m_modp->addStmtp(temp2p);
|
||||
AstNodeAssign* asn1ap = VN_CAST(
|
||||
nodep->cloneType(new AstVarRef(sel1p->fileline(), temp1p, true), sel1p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn2ap = VN_CAST(
|
||||
nodep->cloneType(new AstVarRef(sel2p->fileline(), temp2p, true), sel2p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn1bp = VN_CAST(
|
||||
nodep->cloneType(lc1p, new AstVarRef(sel1p->fileline(), temp1p, false)),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn2bp = VN_CAST(
|
||||
nodep->cloneType(lc2p, new AstVarRef(sel2p->fileline(), temp2p, false)),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn1ap
|
||||
= VN_CAST(nodep->cloneType(
|
||||
new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn2ap
|
||||
= VN_CAST(nodep->cloneType(
|
||||
new AstVarRef(sel2p->fileline(), temp2p, VAccess::WRITE), sel2p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn1bp
|
||||
= VN_CAST(nodep->cloneType(
|
||||
lc1p, new AstVarRef(sel1p->fileline(), temp1p, VAccess::READ)),
|
||||
NodeAssign);
|
||||
AstNodeAssign* asn2bp
|
||||
= VN_CAST(nodep->cloneType(
|
||||
lc2p, new AstVarRef(sel2p->fileline(), temp2p, VAccess::READ)),
|
||||
NodeAssign);
|
||||
asn1ap->dtypeFrom(temp1p);
|
||||
asn1bp->dtypeFrom(temp1p);
|
||||
asn2ap->dtypeFrom(temp2p);
|
||||
@@ -1293,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) {
|
||||
@@ -1601,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->lvalue()
|
||||
if (nodep->access().isReadOnly()
|
||||
&& ((!m_params // Can reduce constant wires into equations
|
||||
&& m_doNConst
|
||||
&& v3Global.opt.oConst()
|
||||
@@ -1933,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);
|
||||
|
||||
+9
-8
@@ -130,8 +130,8 @@ private:
|
||||
m_modp->addStmtp(varp);
|
||||
UINFO(5, "New coverage trace: " << varp << endl);
|
||||
AstAssign* assp = new AstAssign(
|
||||
incp->fileline(), new AstVarRef(incp->fileline(), varp, true),
|
||||
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, false),
|
||||
incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE),
|
||||
new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ),
|
||||
new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1)));
|
||||
incp->addNext(assp);
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -288,8 +288,9 @@ private:
|
||||
// This is necessarily an O(n^2) expansion, which is why
|
||||
// we limit coverage to signals with < 256 bits.
|
||||
|
||||
ToggleEnt newvec(string(""), new AstVarRef(nodep->fileline(), nodep, false),
|
||||
new AstVarRef(nodep->fileline(), chgVarp, true));
|
||||
ToggleEnt newvec(string(""),
|
||||
new AstVarRef(nodep->fileline(), nodep, VAccess::READ),
|
||||
new AstVarRef(nodep->fileline(), chgVarp, VAccess::WRITE));
|
||||
toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep, chgVarp);
|
||||
newvec.cleanup();
|
||||
}
|
||||
|
||||
+3
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+35
-27
@@ -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
|
||||
@@ -228,9 +228,10 @@ private:
|
||||
AstVarScope* bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
|
||||
AstAssign* bitassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), dimp);
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
|
||||
dimp);
|
||||
nodep->addNextHere(bitassignp);
|
||||
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
|
||||
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ));
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -247,9 +248,10 @@ private:
|
||||
AstVarScope* bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
|
||||
AstAssign* bitassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), lsbvaluep);
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
|
||||
lsbvaluep);
|
||||
nodep->addNextHere(bitassignp);
|
||||
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
|
||||
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ);
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -263,8 +265,8 @@ private:
|
||||
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
AstVarScope* valvscp
|
||||
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
|
||||
newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
|
||||
valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
|
||||
newlhsp = new AstVarRef(nodep->fileline(), valvscp, VAccess::WRITE);
|
||||
valreadp = new AstVarRef(nodep->fileline(), valvscp, VAccess::READ);
|
||||
}
|
||||
//
|
||||
//=== Setting/not setting boolean: __Vdlyvset__
|
||||
@@ -283,11 +285,11 @@ private:
|
||||
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
|
||||
setinitp = new AstAssignPre(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), setvscp, true),
|
||||
new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
AstAssign* setassignp
|
||||
= new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
|
||||
AstAssign* setassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
|
||||
nodep->addNextHere(setassignp);
|
||||
}
|
||||
if (m_nextDlyp) { // Tell next assigndly it can share the variable
|
||||
@@ -332,9 +334,9 @@ private:
|
||||
UASSERT_OBJ(postLogicp, nodep,
|
||||
"Delayed assignment misoptimized; prev var found w/o associated IF");
|
||||
} else {
|
||||
postLogicp
|
||||
= new AstIf(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, false),
|
||||
nullptr, nullptr);
|
||||
postLogicp = new AstIf(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), setvscp, VAccess::READ),
|
||||
nullptr, nullptr);
|
||||
UINFO(9, " Created " << postLogicp << endl);
|
||||
finalp->addBodysp(postLogicp);
|
||||
finalp->user3p(setvscp); // Remember IF's vset variable
|
||||
@@ -356,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;
|
||||
@@ -406,10 +410,11 @@ private:
|
||||
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (!nodep->user2Inc()) { // Not done yet
|
||||
if (m_inDly && nodep->lvalue()) {
|
||||
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");
|
||||
@@ -429,16 +434,19 @@ private:
|
||||
if (basicp && basicp->isEventValue()) {
|
||||
// Events go to zero on next timestep unless reactivated
|
||||
prep = new AstAssignPre(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicFalse()));
|
||||
} else {
|
||||
prep = new AstAssignPre(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, false));
|
||||
prep = new AstAssignPre(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, VAccess::READ));
|
||||
}
|
||||
AstNodeAssign* postp = new AstAssignPost(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, false));
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::READ));
|
||||
postp->lhsp()->user2(true); // Don't detect this assignment
|
||||
oldvscp->user1p(dlyvscp); // So we can find it later
|
||||
// Make new ACTIVE with identical sensitivity tree
|
||||
@@ -447,11 +455,11 @@ private:
|
||||
newactp->addStmtsp(prep); // Add to FRONT of statements
|
||||
newactp->addStmtsp(postp);
|
||||
}
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
|
||||
newrefp->user2(true); // No reason to do it again
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (!m_inDly && nodep->lvalue()) {
|
||||
} else if (!m_inDly && nodep->access().isWriteOrRW()) {
|
||||
// UINFO(9, "NBA " << nodep << endl);
|
||||
if (!m_inInitial) {
|
||||
UINFO(4, "AssignNDlyVar: " << nodep << endl);
|
||||
|
||||
+24
-20
@@ -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,14 +61,14 @@ 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, false);
|
||||
AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
|
||||
nodep->replaceWith(newp);
|
||||
// Put assignment before the referencing statement
|
||||
AstAssign* assp = new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, true), nodep);
|
||||
AstAssign* assp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep);
|
||||
AstNRelinker linker2;
|
||||
m_stmtp->unlinkFrBack(&linker2);
|
||||
assp->addNext(m_stmtp);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -184,8 +184,9 @@ private:
|
||||
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
AstNode* newp
|
||||
= new AstVarRef(portp->fileline(), portp, portp->isWritable());
|
||||
AstNode* newp = new AstVarRef(portp->fileline(), portp,
|
||||
portp->isWritable() ? VAccess::WRITE
|
||||
: VAccess::READ);
|
||||
argsp = argsp ? argsp->addNextNull(newp) : newp;
|
||||
}
|
||||
}
|
||||
@@ -267,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
|
||||
|
||||
+127
-50
@@ -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());
|
||||
|
||||
+27
-24
@@ -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";
|
||||
@@ -204,15 +204,14 @@ class CMakeEmitter {
|
||||
*of << "# Verilate hierarchical blocks\n";
|
||||
// Sorted hierarchical blocks in order of leaf-first.
|
||||
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
|
||||
const string topTarget = v3Global.opt.protectLib().empty() ? v3Global.opt.prefix()
|
||||
: v3Global.opt.protectLib();
|
||||
*of << "get_target_property(TOP_TARGET_NAME \"${TARGET}\" NAME)\n";
|
||||
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
|
||||
it != hierBlocks.end(); ++it) {
|
||||
const V3HierBlock* hblockp = *it;
|
||||
const V3HierBlock::HierBlockSet& children = hblockp->children();
|
||||
const string prefix = hblockp->hierPrefix();
|
||||
*of << "add_library(" << prefix << " STATIC)\n";
|
||||
*of << "target_link_libraries(" << topTarget << " PRIVATE " << prefix << ")\n";
|
||||
*of << "target_link_libraries(${TOP_TARGET_NAME} PRIVATE " << prefix << ")\n";
|
||||
if (!children.empty()) {
|
||||
*of << "target_link_libraries(" << prefix << " INTERFACE";
|
||||
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
|
||||
@@ -223,14 +222,17 @@ class CMakeEmitter {
|
||||
}
|
||||
*of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE "
|
||||
<< hblockp->modp()->name() << " DIRECTORY "
|
||||
<< deslash("${CMAKE_CURRENT_BINARY_DIR}/" + prefix) << " SOURCES ";
|
||||
<< deslash(v3Global.opt.makeDir() + "/" + prefix) << " SOURCES ";
|
||||
for (V3HierBlock::HierBlockSet::const_iterator child = children.begin();
|
||||
child != children.end(); ++child) {
|
||||
*of << deslash(" ${CMAKE_CURRENT_BINARY_DIR}/" + (*child)->hierWrapper(true));
|
||||
*of << " "
|
||||
<< deslash(v3Global.opt.makeDir() + "/" + (*child)->hierWrapper(true));
|
||||
}
|
||||
*of << " ";
|
||||
const string vFile = hblockp->vFileIfNecessary();
|
||||
if (!vFile.empty()) *of << vFile << " ";
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i);
|
||||
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " ";
|
||||
*of << " VERILATOR_ARGS ";
|
||||
*of << "-f " << deslash(hblockp->commandArgsFileName(true))
|
||||
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked
|
||||
@@ -238,11 +240,12 @@ class CMakeEmitter {
|
||||
<< ")\n";
|
||||
}
|
||||
*of << "\n# Verilate the top module that refers protect-lib wrappers of above\n";
|
||||
*of << "verilate(" << topTarget << " PREFIX " << v3Global.opt.prefix()
|
||||
<< " TOP_MODULE " << v3Global.rootp()->topModulep()->name() << " DIRECTORY "
|
||||
<< deslash("${CMAKE_CURRENT_BINARY_DIR}/" + topTarget + ".dir") << " SOURCES ";
|
||||
for (V3HierBlockPlan::const_iterator it = planp->begin(); it != planp->end(); ++it) {
|
||||
*of << deslash(" ${CMAKE_CURRENT_BINARY_DIR}/" + it->second->hierWrapper(true));
|
||||
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
|
||||
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
|
||||
<< deslash(v3Global.opt.makeDir()) << " SOURCES ";
|
||||
for (const auto& itr : *planp) {
|
||||
*of << " "
|
||||
<< deslash(v3Global.opt.makeDir() + "/" + itr.second->hierWrapper(true));
|
||||
}
|
||||
*of << " " << deslash(cmake_list(v3Global.opt.vFiles()));
|
||||
*of << " VERILATOR_ARGS ";
|
||||
|
||||
+38
-38
@@ -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);
|
||||
|
||||
+5
-5
@@ -65,6 +65,10 @@ public:
|
||||
of.puts("VM_TRACE = ");
|
||||
of.puts(v3Global.opt.trace() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
of.puts("# Tracing output mode in FST format? 0/1 (from --trace-fst)\n");
|
||||
of.puts("VM_TRACE_FST = ");
|
||||
of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n");
|
||||
of.puts("VM_TRACE_THREADS = ");
|
||||
of.puts(cvtToStr(v3Global.opt.trueTraceThreads()));
|
||||
@@ -277,7 +281,6 @@ public:
|
||||
of.putsHeader();
|
||||
}
|
||||
|
||||
public:
|
||||
explicit EmitMk() {
|
||||
emitClassMake();
|
||||
emitOverallMake();
|
||||
@@ -359,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);
|
||||
}
|
||||
|
||||
+43
-29
@@ -31,6 +31,7 @@
|
||||
class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
// MEMBERS
|
||||
bool m_suppressSemi = false;
|
||||
bool m_suppressUnknown = false;
|
||||
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
|
||||
|
||||
// METHODS
|
||||
@@ -51,12 +52,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); }
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
||||
}
|
||||
virtual void visit(AstPort* nodep) override {}
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
putfs(nodep, nodep->isFunction() ? "function" : "task");
|
||||
puts(" ");
|
||||
@@ -212,14 +214,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
|
||||
AstNode* exprsp) {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
if (fileOrStrgp) {
|
||||
iterateAndNextNull(fileOrStrgp);
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
}
|
||||
putsQuoted(text);
|
||||
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
|
||||
puts(",");
|
||||
puts(", ");
|
||||
iterateAndNextNull(expp);
|
||||
}
|
||||
puts(");\n");
|
||||
@@ -247,7 +249,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->filenamep());
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->modep());
|
||||
puts(");\n");
|
||||
}
|
||||
@@ -259,13 +261,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
virtual void visit(AstFClose* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
if (nodep->filep()) iterateAndNextNull(nodep->filep());
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFFlush* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
if (nodep->filep()) iterateAndNextNull(nodep->filep());
|
||||
puts(");\n");
|
||||
}
|
||||
@@ -282,16 +284,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
virtual void visit(AstNodeReadWriteMem* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
if (nodep->memp()) iterateAndNextNull(nodep->memp());
|
||||
if (nodep->lsbp()) {
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
}
|
||||
if (nodep->msbp()) {
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->msbp());
|
||||
}
|
||||
puts(");\n");
|
||||
@@ -302,7 +304,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
virtual void visit(AstSysIgnore* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
puts(");\n");
|
||||
}
|
||||
@@ -358,7 +360,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
putfs(nodep, "$past(");
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
if (nodep->ticksp()) {
|
||||
puts(",");
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->ticksp());
|
||||
}
|
||||
puts(")");
|
||||
@@ -482,20 +484,20 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
putfs(nodep, "$_ATTROF(");
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
if (nodep->dimp()) {
|
||||
putbs(",");
|
||||
putbs(", ");
|
||||
iterateAndNextNull(nodep->dimp());
|
||||
}
|
||||
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("}");
|
||||
@@ -654,13 +656,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
|
||||
iterateChildren(nodep);
|
||||
// Not v3fatalSrc so we keep processing
|
||||
nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
|
||||
if (!m_suppressUnknown) {
|
||||
nodep->v3error(
|
||||
"Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
||||
explicit EmitVBaseVisitor(AstSenTree* domainp = nullptr)
|
||||
: m_sensesp{domainp} {}
|
||||
explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp)
|
||||
: m_suppressUnknown{suppressUnknown}
|
||||
, m_sensesp{domainp} {}
|
||||
virtual ~EmitVBaseVisitor() override {}
|
||||
};
|
||||
|
||||
@@ -679,8 +685,9 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
|
||||
virtual void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); }
|
||||
|
||||
public:
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false,
|
||||
bool suppressVarSemi = false) {
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressVarSemi,
|
||||
bool suppressUnknown)
|
||||
: EmitVBaseVisitor{suppressUnknown, nullptr} {
|
||||
m_ofp = ofp;
|
||||
m_trackText = trackText;
|
||||
m_suppressVarSemi = suppressVarSemi;
|
||||
@@ -704,7 +711,8 @@ class EmitVStreamVisitor : public EmitVBaseVisitor {
|
||||
|
||||
public:
|
||||
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
|
||||
: m_os(os) { // Need () or GCC 4.8 false warning
|
||||
: EmitVBaseVisitor{false, nullptr}
|
||||
, m_os(os) { // Need () or GCC 4.8 false warning
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~EmitVStreamVisitor() override {}
|
||||
@@ -747,9 +755,8 @@ public:
|
||||
, m_prefix{prefix}
|
||||
, m_flWidth{flWidth} {
|
||||
m_column = 0;
|
||||
m_prefixFl
|
||||
= v3Global.rootp()
|
||||
->fileline(); // NETLIST's fileline instead of nullptr to avoid nullptr checks
|
||||
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to
|
||||
// avoid nullptr checks
|
||||
}
|
||||
virtual ~EmitVPrefixedFormatter() override {
|
||||
if (m_column) puts("\n");
|
||||
@@ -780,7 +787,7 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
|
||||
public:
|
||||
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
|
||||
AstSenTree* domainp, bool user3mark)
|
||||
: EmitVBaseVisitor{domainp}
|
||||
: EmitVBaseVisitor{false, domainp}
|
||||
, m_formatter{os, prefix, flWidth} {
|
||||
if (user3mark) { AstUser3InUse::check(); }
|
||||
iterate(nodep);
|
||||
@@ -807,7 +814,14 @@ void V3EmitV::emitvFiles() {
|
||||
V3OutVFile of(vfilep->name());
|
||||
of.puts("// DESCR"
|
||||
"IPTION: Verilator generated Verilog\n");
|
||||
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true);
|
||||
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3EmitV::debugEmitV(const string& stage) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__" + stage + ".v";
|
||||
V3OutVFile of(filename);
|
||||
EmitVFileVisitor visitor(v3Global.rootp(), &of, true, false, true);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
|
||||
int flWidth, AstSenTree* domainp, bool user3mark);
|
||||
static void emitvFiles();
|
||||
static void debugEmitV(const string& stage);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ private:
|
||||
void fixCloneLvalue(AstNode* nodep) {
|
||||
// In AstSel transforms, we call clone() on VarRefs that were lvalues,
|
||||
// but are now being used on the RHS of the assignment
|
||||
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->lvalue(false);
|
||||
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->access(VAccess::READ);
|
||||
// Iterate
|
||||
if (nodep->op1p()) fixCloneLvalue(nodep->op1p());
|
||||
if (nodep->op2p()) fixCloneLvalue(nodep->op2p());
|
||||
|
||||
+10
-11
@@ -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");
|
||||
|
||||
+3
-3
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+19
-18
@@ -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->lvalue()) {
|
||||
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->lvalue()) {
|
||||
} 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->lvalue()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -525,10 +528,7 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit GateVisitor(AstNode* nodep) {
|
||||
AstNode::user1ClearTree();
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit GateVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~GateVisitor() override {
|
||||
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
|
||||
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
|
||||
@@ -603,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()) {
|
||||
@@ -845,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->lvalue(), nodep,
|
||||
UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
|
||||
"Can't replace lvalue assignments with const var");
|
||||
AstNode* substp = m_replaceTreep->cloneTree(false);
|
||||
UASSERT_OBJ(
|
||||
@@ -859,7 +859,8 @@ private:
|
||||
// to throw warnings that point to a PIN rather than where the pin us used.
|
||||
if (VN_IS(substp, VarRef)) substp->fileline(nodep->fileline());
|
||||
// Make the substp an rvalue like nodep. This facilitates the hashing in dedupe.
|
||||
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef)) varrefp->lvalue(false);
|
||||
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef))
|
||||
varrefp->access(VAccess::READ);
|
||||
hashReplace(nodep, substp);
|
||||
nodep->replaceWith(substp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
@@ -939,7 +940,7 @@ private:
|
||||
|
||||
public:
|
||||
GateDedupeHash() {}
|
||||
~GateDedupeHash() {
|
||||
virtual ~GateDedupeHash() override {
|
||||
if (v3Global.opt.debugCheck()) check();
|
||||
}
|
||||
|
||||
@@ -965,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);
|
||||
@@ -1001,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)) {
|
||||
@@ -1086,7 +1087,7 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
GateDedupeVarVisitor() {}
|
||||
~GateDedupeVarVisitor() {}
|
||||
virtual ~GateDedupeVarVisitor() override {}
|
||||
// PUBLIC METHODS
|
||||
AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
|
||||
m_assignp = nullptr;
|
||||
@@ -1348,7 +1349,7 @@ private:
|
||||
}
|
||||
return VNUser(0);
|
||||
}
|
||||
virtual VNUser visit(GateLogicVertex*, VNUser vu) override { //
|
||||
virtual VNUser visit(GateLogicVertex*, VNUser) override { //
|
||||
return VNUser(0);
|
||||
}
|
||||
|
||||
@@ -1514,7 +1515,7 @@ private:
|
||||
UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl);
|
||||
UINFO(9, " to - " << m_clk_vsp << endl);
|
||||
AstNode* rhsp = assignp->rhsp();
|
||||
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false));
|
||||
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, VAccess::READ));
|
||||
while (V3GraphEdge* edgep = lvertexp->inBeginp()) {
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
}
|
||||
|
||||
+5
-6
@@ -67,9 +67,9 @@ private:
|
||||
m_topModp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
|
||||
m_scopetopp->addVarp(newvscp);
|
||||
AstAssign* asninitp
|
||||
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
new AstVarRef(vscp->fileline(), vscp, false));
|
||||
AstAssign* asninitp = new AstAssign(
|
||||
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
|
||||
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
|
||||
m_scopetopp->addFinalClkp(asninitp);
|
||||
//
|
||||
vscp->user2p(newvscp);
|
||||
@@ -98,7 +98,7 @@ private:
|
||||
UINFO(8, " VarActReplace " << nodep << endl);
|
||||
// Replace with the new variable
|
||||
AstVarScope* newvscp = genInpClk(vscp);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
@@ -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->lvalue() && 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);
|
||||
|
||||
@@ -35,6 +35,12 @@ AstNetlist* V3Global::makeNetlist() {
|
||||
return newp;
|
||||
}
|
||||
|
||||
void V3Global::clear() {
|
||||
#ifdef VL_LEAK_CHECK
|
||||
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void V3Global::shutdown() {
|
||||
VL_DO_CLEAR(delete m_hierPlanp, m_hierPlanp = nullptr); // delete nullptr is safe
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ public:
|
||||
UASSERT(!m_rootp, "call once");
|
||||
m_rootp = makeNetlist();
|
||||
}
|
||||
void clear();
|
||||
void shutdown(); // Release allocated resorces
|
||||
// ACCESSORS (general)
|
||||
AstNetlist* rootp() const { return m_rootp; }
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+2
-5
@@ -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);
|
||||
|
||||
+4
-5
@@ -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() {}
|
||||
};
|
||||
|
||||
+10
-11
@@ -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, " ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -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);
|
||||
|
||||
+35
-20
@@ -80,6 +80,7 @@
|
||||
#include "V3Error.h"
|
||||
#include "V3File.h"
|
||||
#include "V3HierBlock.h"
|
||||
#include "V3Os.h"
|
||||
#include "V3String.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
@@ -88,22 +89,26 @@ static string V3HierCommandArgsFileName(const string& prefix, bool forCMake) {
|
||||
+ (forCMake ? "_hierCMakeArgs.f" : "_hierMkArgs.f");
|
||||
}
|
||||
|
||||
static void V3HierWriteCommonInputs(std::ostream* of, bool forCMake) {
|
||||
static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of, bool forCMake) {
|
||||
string topModuleFile;
|
||||
if (hblockp) topModuleFile = hblockp->vFileIfNecessary();
|
||||
if (!forCMake) {
|
||||
if (!topModuleFile.empty()) *of << topModuleFile << "\n";
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles) *of << i << "\n";
|
||||
}
|
||||
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
|
||||
for (const string& i : libraryFiles) *of << "-v " << i << "\n";
|
||||
for (const string& i : libraryFiles) {
|
||||
if (V3Os::filenameRealPath(i) != topModuleFile) *of << "-v " << i << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
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.
|
||||
@@ -125,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;
|
||||
@@ -133,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");
|
||||
}
|
||||
}
|
||||
@@ -194,25 +198,33 @@ string V3HierBlock::hierGenerated(bool withDir) const {
|
||||
return hierWrapper(withDir) + ' ' + hierMk(withDir);
|
||||
}
|
||||
|
||||
string V3HierBlock::vFileIfNecessary() const {
|
||||
const string filename = V3Os::filenameRealPath(m_modp->fileline()->filename());
|
||||
for (const string& v : v3Global.opt.vFiles()) {
|
||||
// Already listed in vFiles, so no need to add the file.
|
||||
if (filename == V3Os::filenameRealPath(v)) return "";
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
|
||||
std::unique_ptr<std::ofstream> of(V3File::new_ofstream(commandArgsFileName(forCMake)));
|
||||
*of << "--cc\n";
|
||||
|
||||
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";
|
||||
}
|
||||
*of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n";
|
||||
V3HierWriteCommonInputs(of.get(), forCMake);
|
||||
V3HierWriteCommonInputs(this, of.get(), forCMake);
|
||||
const V3StringList& commandOpts = commandArgs(false);
|
||||
for (const string& opt : commandOpts) *of << opt << "\n";
|
||||
*of << hierBlockArgs().front() << "\n";
|
||||
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"; }
|
||||
*of << v3Global.opt.allArgsStringForHierBlock(false) << "\n";
|
||||
}
|
||||
|
||||
@@ -394,7 +406,7 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const {
|
||||
*of << it->second->hierWrapper(true) << "\n";
|
||||
}
|
||||
}
|
||||
V3HierWriteCommonInputs(of.get(), forCMake);
|
||||
V3HierWriteCommonInputs(nullptr, of.get(), forCMake);
|
||||
if (!forCMake) {
|
||||
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
|
||||
for (const string& i : cppFiles) *of << i << "\n";
|
||||
@@ -411,10 +423,13 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const {
|
||||
*of << "--protect-lib " << v3Global.opt.protectLib() << "\n";
|
||||
*of << "--protect-key " << v3Global.opt.protectKeyDefaulted() << "\n";
|
||||
}
|
||||
if (v3Global.opt.threads() > 0) {
|
||||
*of << "--threads " << cvtToStr(v3Global.opt.threads()) << "\n";
|
||||
}
|
||||
*of << (v3Global.opt.systemC() ? "--sc" : "--cc") << "\n";
|
||||
*of << v3Global.opt.allArgsStringForHierBlock(true) << "\n";
|
||||
}
|
||||
|
||||
string V3HierBlockPlan::topCommandArgsFileName(bool forCMake) const {
|
||||
string V3HierBlockPlan::topCommandArgsFileName(bool forCMake) {
|
||||
return V3HierCommandArgsFileName(v3Global.opt.prefix(), forCMake);
|
||||
}
|
||||
|
||||
+3
-1
@@ -85,6 +85,8 @@ public:
|
||||
string hierMk(bool withDir) const;
|
||||
string hierLib(bool withDir) const;
|
||||
string hierGenerated(bool withDir) const;
|
||||
// Returns the original HDL file if it is not included in v3Global.opt.vFiles().
|
||||
string vFileIfNecessary() const;
|
||||
// Write command line argumuents to .f file for this hierarchical block
|
||||
void writeCommandArgsFile(bool forCMake) const;
|
||||
string commandArgsFileName(bool forCMake) const;
|
||||
@@ -120,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);
|
||||
};
|
||||
|
||||
+14
-12
@@ -313,9 +313,9 @@ private:
|
||||
UASSERT_OBJ(exprconstp || exprvarrefp, nodep,
|
||||
"Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||
if (exprconstp) {
|
||||
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
exprconstp->cloneTree(true)));
|
||||
m_modp->addStmtp(new AstAssignW(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
|
||||
exprconstp->cloneTree(true)));
|
||||
} else if (nodep->user3()) {
|
||||
// Public variable at the lower module end - we need to make sure we propagate
|
||||
// the logic changes up and down; if we aliased, we might
|
||||
@@ -323,20 +323,22 @@ private:
|
||||
UINFO(9, "public pin assign: " << exprvarrefp << endl);
|
||||
UASSERT_OBJ(!nodep->isNonOutput(), nodep, "Outputs only - inputs use AssignAlias");
|
||||
m_modp->addStmtp(new AstAssignW(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), nodep, VAccess::READ)));
|
||||
} else if (nodep->isSigPublic() && VN_IS(nodep->dtypep(), UnpackArrayDType)) {
|
||||
// Public variable at this end and it is an unpacked array. We need to assign
|
||||
// instead of aliased, because otherwise it will pass V3Slice and invalid
|
||||
// code will be emitted.
|
||||
UINFO(9, "assign to public and unpacked: " << nodep << endl);
|
||||
m_modp->addStmtp(new AstAssignW(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), nodep, VAccess::READ)));
|
||||
} else if (nodep->isIfaceRef()) {
|
||||
m_modp->addStmtp(new AstAssignVarScope(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::READ)));
|
||||
AstNode* nodebp = exprvarrefp->varp();
|
||||
nodep->fileline()->modifyStateInherit(nodebp->fileline());
|
||||
nodebp->fileline()->modifyStateInherit(nodep->fileline());
|
||||
@@ -344,8 +346,8 @@ private:
|
||||
// Do to inlining child's variable now within the same
|
||||
// module, so a AstVarRef not AstVarXRef below
|
||||
m_modp->addStmtp(new AstAssignAlias(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::READ)));
|
||||
AstNode* nodebp = exprvarrefp->varp();
|
||||
nodep->fileline()->modifyStateInherit(nodebp->fileline());
|
||||
nodebp->fileline()->modifyStateInherit(nodep->fileline());
|
||||
@@ -415,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;
|
||||
|
||||
+27
-24
@@ -76,17 +76,17 @@ private:
|
||||
if (nodep->modVarp()->isInoutish()) {
|
||||
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
|
||||
} else if (nodep->modVarp()->isWritable()) {
|
||||
AstNode* rhsp
|
||||
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
|
||||
AstNode* rhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
|
||||
m_cellp->name(), VAccess::READ);
|
||||
AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
|
||||
m_cellp->addNextHere(assp);
|
||||
} else if (nodep->modVarp()->isNonOutput()) {
|
||||
// Don't bother moving constants now,
|
||||
// we'll be pushing the const down to the cell soon enough.
|
||||
AstNode* assp = new AstAssignW(
|
||||
exprp->fileline(),
|
||||
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
|
||||
exprp);
|
||||
AstNode* assp = new AstAssignW(exprp->fileline(),
|
||||
new AstVarXRef(exprp->fileline(), nodep->modVarp(),
|
||||
m_cellp->name(), VAccess::WRITE),
|
||||
exprp);
|
||||
m_cellp->addNextHere(assp);
|
||||
if (debug() >= 9) assp->dumpTree(cout, " _new: ");
|
||||
} else if (nodep->modVarp()->isIfaceRef()
|
||||
@@ -96,8 +96,8 @@ private:
|
||||
IfaceRefDType))) {
|
||||
// Create an AstAssignVarScope for Vars to Cells so we can
|
||||
// link with their scope later
|
||||
AstNode* lhsp
|
||||
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
|
||||
AstNode* lhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
|
||||
m_cellp->name(), VAccess::READ);
|
||||
const AstVarRef* refp = VN_CAST(exprp, VarRef);
|
||||
const AstVarXRef* xrefp = VN_CAST(exprp, VarXRef);
|
||||
UASSERT_OBJ(refp || xrefp, exprp,
|
||||
@@ -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,9 +375,13 @@ 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);
|
||||
AstVarXRef* newp = new AstVarXRef(
|
||||
nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", true);
|
||||
UASSERT_OBJ(varrefp, arrselp, "No interface varref under array");
|
||||
AstVarXRef* newp = new AstVarXRef(nodep->fileline(),
|
||||
varrefp->name() + "__BRA__" + index + "__KET__",
|
||||
"", VAccess::WRITE);
|
||||
newp->dtypep(nodep->modVarp()->dtypep());
|
||||
newp->packagep(varrefp->packagep());
|
||||
arrselp->addNextHere(newp);
|
||||
@@ -438,7 +439,8 @@ private:
|
||||
}
|
||||
if (!varrefp) { newp->exprp()->v3error("Unexpected connection to arrayed port"); }
|
||||
string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__";
|
||||
AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", true);
|
||||
AstVarXRef* newVarXRefp
|
||||
= new AstVarXRef(nodep->fileline(), newname, "", VAccess::WRITE);
|
||||
newVarXRefp->varp(newp->modVarp());
|
||||
newp->exprp()->unlinkFrBack()->deleteTree();
|
||||
newp->exprp(newVarXRefp);
|
||||
@@ -553,18 +555,19 @@ public:
|
||||
" direct one-to-one connection (without any expression)");
|
||||
} else if (pinVarp->isWritable()) {
|
||||
// See also V3Inst
|
||||
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
|
||||
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, VAccess::READ);
|
||||
UINFO(5, "pinRecon width " << pinVarp->width() << " >? " << rhsp->width() << " >? "
|
||||
<< pinexprp->width() << endl);
|
||||
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
|
||||
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true));
|
||||
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, VAccess::WRITE));
|
||||
AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
|
||||
assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp);
|
||||
} else {
|
||||
// V3 width should have range/extended to make the widths correct
|
||||
assignp = new AstAssignW(pinp->fileline(),
|
||||
new AstVarRef(pinp->fileline(), newvarp, true), pinexprp);
|
||||
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, false));
|
||||
new AstVarRef(pinp->fileline(), newvarp, VAccess::WRITE),
|
||||
pinexprp);
|
||||
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, VAccess::READ));
|
||||
}
|
||||
if (assignp) cellp->addNextHere(assignp);
|
||||
// if (debug()) { pinp->dumpTree(cout, "- out:"); }
|
||||
|
||||
@@ -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(); }
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
private:
|
||||
static Singleton& s() {
|
||||
static Singleton s_s;
|
||||
static Singleton s_s; // LCOV_EXCL_BR_LINE
|
||||
return s_s;
|
||||
}
|
||||
};
|
||||
|
||||
+11
-18
@@ -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->lvalue()) {
|
||||
if (nodep->access().isWriteOrRW()) {
|
||||
m_sideEffect = true; // $sscanf etc may have RHS vars that are lvalues
|
||||
m_lifep->complexAssign(vscp);
|
||||
} else {
|
||||
|
||||
+12
-19
@@ -58,7 +58,7 @@ private:
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
if (AstVarScope* newvscp = reinterpret_cast<AstVarScope*>(vscp->user4p())) {
|
||||
UINFO(9, " Replace " << nodep << " to " << newvscp << endl);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
@@ -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->lvalue()) {
|
||||
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.
|
||||
|
||||
+204
-125
@@ -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
|
||||
@@ -1128,6 +1138,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
AstVar* newp
|
||||
= new AstVar(nodep->fileline(), AstVarType(AstVarType::GPARAM),
|
||||
nodep->name(), nodep);
|
||||
newp->combineType(nodep);
|
||||
string svalue = v3Global.opt.parameter(nodep->name());
|
||||
if (AstNode* valuep
|
||||
= AstConst::parseParamLiteral(nodep->fileline(), svalue)) {
|
||||
@@ -1252,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); }
|
||||
|
||||
@@ -1501,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)
|
||||
@@ -1670,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();
|
||||
@@ -1717,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); }
|
||||
@@ -1729,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"};
|
||||
@@ -1780,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;
|
||||
@@ -1789,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;
|
||||
@@ -1811,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) {
|
||||
@@ -1960,19 +2010,29 @@ private:
|
||||
m_ds.m_dotp = nodep; // Always, not just at start
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
|
||||
// m_ds.m_dotText communicates the cell prefix between stages
|
||||
if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) {
|
||||
if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "this") {
|
||||
VSymEnt* classSymp = m_ds.m_dotSymp;
|
||||
do {
|
||||
classSymp = classSymp->fallbackp();
|
||||
} while (classSymp && !VN_IS(classSymp->nodep(), Class));
|
||||
m_ds.m_dotSymp = classSymp;
|
||||
if (!classSymp) {
|
||||
nodep->v3error("'this' used outside class");
|
||||
m_ds.m_dotErr = true;
|
||||
}
|
||||
} else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) {
|
||||
// m_ds.m_dotText communicates the cell prefix between stages
|
||||
// if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in
|
||||
// dotted reference"); m_ds.m_dotErr=true; }
|
||||
m_ds.m_dotPos = DP_PACKAGE;
|
||||
} 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
|
||||
@@ -2018,21 +2078,14 @@ private:
|
||||
// Generally resolved during Primay, but might be at param time under AstUnlinkedRef
|
||||
UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep,
|
||||
"ParseRefs should no longer exist");
|
||||
if (nodep->name() == "this") {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: this");
|
||||
} else if (nodep->name() == "super") {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
|
||||
}
|
||||
if (nodep->name() == "super") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); }
|
||||
DotStates lastStates = m_ds;
|
||||
bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
|
||||
if (start) {
|
||||
m_ds.init(m_curSymp);
|
||||
// Note m_ds.m_dot remains nullptr; this is a reference not under a dot
|
||||
}
|
||||
if (nodep->name() == "this") {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: this");
|
||||
m_ds.m_dotErr = true;
|
||||
} else if (nodep->name() == "super") {
|
||||
if (nodep->name() == "super") {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
|
||||
m_ds.m_dotErr = true;
|
||||
}
|
||||
@@ -2062,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;
|
||||
@@ -2119,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());
|
||||
@@ -2132,7 +2175,7 @@ private:
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
UINFO(9, " cell -> iface varref " << foundp->nodep() << endl);
|
||||
AstNode* newp
|
||||
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false);
|
||||
= new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, VAccess::READ);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (VN_IS(cellp->modp(), NotFoundModule)) {
|
||||
@@ -2140,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");
|
||||
@@ -2150,7 +2193,7 @@ private:
|
||||
m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp());
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
ok = true;
|
||||
AstNode* newp = new AstVarRef(nodep->fileline(), varp, false);
|
||||
AstNode* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (allowVar) {
|
||||
@@ -2158,7 +2201,7 @@ private:
|
||||
if (m_ds.m_dotText != "") {
|
||||
AstVarXRef* refp
|
||||
= new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText,
|
||||
false); // lvalue'ness computed later
|
||||
VAccess::READ); // lvalue'ness computed later
|
||||
refp->varp(varp);
|
||||
if (varp->attrSplitVar()) {
|
||||
refp->v3warn(
|
||||
@@ -2169,27 +2212,28 @@ 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 {
|
||||
newp = refp;
|
||||
}
|
||||
} else {
|
||||
AstVarRef* refp = new AstVarRef(nodep->fileline(), varp,
|
||||
false); // lvalue'ness computed later
|
||||
AstVarRef* refp
|
||||
= new AstVarRef(nodep->fileline(), varp,
|
||||
VAccess::READ); // lvalue'ness computed later
|
||||
refp->packagep(foundp->packagep());
|
||||
newp = refp;
|
||||
}
|
||||
@@ -2203,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)
|
||||
@@ -2217,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, false);
|
||||
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)) {
|
||||
@@ -2237,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) {
|
||||
@@ -2274,7 +2344,8 @@ private:
|
||||
if (checkImplicit) {
|
||||
// Create if implicit, and also if error (so only complain once)
|
||||
// Else if a scope is allowed, making a signal won't help error cascade
|
||||
AstVarRef* newp = new AstVarRef(nodep->fileline(), nodep->name(), false);
|
||||
AstVarRef* newp
|
||||
= new AstVarRef(nodep->fileline(), nodep->name(), VAccess::READ);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err);
|
||||
@@ -2293,7 +2364,7 @@ private:
|
||||
UINFO(9, " linkVarRef se" << cvtToHex(m_curSymp) << " n=" << nodep << endl);
|
||||
UASSERT_OBJ(m_curSymp, nodep, "nullptr lookup symbol table");
|
||||
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
|
||||
if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : nullptr) {
|
||||
if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr) {
|
||||
nodep->varp(varp);
|
||||
// Generally set by parse, but might be an import
|
||||
nodep->packagep(foundp->packagep());
|
||||
@@ -2333,7 +2404,7 @@ private:
|
||||
okSymp); // Maybe nullptr
|
||||
if (!m_statep->forScopeCreation()) {
|
||||
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
|
||||
AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : nullptr;
|
||||
AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr;
|
||||
nodep->varp(varp);
|
||||
UINFO(7, " Resolved " << nodep << endl); // Also prints varp
|
||||
if (!nodep->varp()) {
|
||||
@@ -2349,7 +2420,7 @@ private:
|
||||
if (!m_statep->forPrearray() && !m_statep->forScopeCreation()) {
|
||||
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
|
||||
AstVarRef* newrefp
|
||||
= new AstVarRef(nodep->fileline(), nodep->varp(), nodep->lvalue());
|
||||
= new AstVarRef(nodep->fileline(), nodep->varp(), nodep->access());
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
@@ -2373,7 +2444,7 @@ private:
|
||||
nodep->varp(vscp->varp());
|
||||
nodep->varScopep(vscp);
|
||||
UINFO(7, " Resolved " << nodep << endl); // Also prints taskp
|
||||
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->lvalue());
|
||||
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->access());
|
||||
nodep->replaceWith(newvscp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
UINFO(9, " new " << newvscp << endl); // Also prints taskp
|
||||
@@ -2400,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);
|
||||
@@ -2427,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;
|
||||
@@ -2636,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());
|
||||
@@ -2658,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);
|
||||
@@ -2668,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
|
||||
@@ -2730,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,
|
||||
|
||||
+12
-9
@@ -199,30 +199,33 @@ private:
|
||||
// Define what operation will we be doing
|
||||
AstNode* operp;
|
||||
if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) {
|
||||
operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp);
|
||||
operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp);
|
||||
} else {
|
||||
operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp);
|
||||
operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp);
|
||||
}
|
||||
|
||||
if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) {
|
||||
// PreAdd/PreSub operations
|
||||
// Immediately after declaration - increment it by one
|
||||
m_insStmtp->addHereThisAsNext(new AstAssign(fl, new AstVarRef(fl, varp, true), operp));
|
||||
m_insStmtp->addHereThisAsNext(
|
||||
new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE), operp));
|
||||
// Immediately after incrementing - assign it to the original variable
|
||||
m_insStmtp->addHereThisAsNext(new AstAssign(
|
||||
fl, new AstVarRef(fl, varrefp->varp(), true), new AstVarRef(fl, varp, false)));
|
||||
m_insStmtp->addHereThisAsNext(
|
||||
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), VAccess::WRITE),
|
||||
new AstVarRef(fl, varp, VAccess::READ)));
|
||||
} else {
|
||||
// PostAdd/PostSub operations
|
||||
// assign the original variable to the temporary one
|
||||
m_insStmtp->addHereThisAsNext(new AstAssign(
|
||||
fl, new AstVarRef(fl, varp, true), new AstVarRef(fl, varrefp->varp(), false)));
|
||||
m_insStmtp->addHereThisAsNext(
|
||||
new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE),
|
||||
new AstVarRef(fl, varrefp->varp(), VAccess::READ)));
|
||||
// Increment the original variable by one
|
||||
m_insStmtp->addHereThisAsNext(
|
||||
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), true), operp));
|
||||
new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), VAccess::WRITE), operp));
|
||||
}
|
||||
|
||||
// Replace the node with the temporary
|
||||
nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, true));
|
||||
nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, VAccess::WRITE));
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstPreAdd* nodep) override { prepost_visit(nodep); }
|
||||
|
||||
+7
-7
@@ -153,15 +153,15 @@ private:
|
||||
nodep->findSigned32DType());
|
||||
varp->usedLoopIdx(true);
|
||||
m_modp->addStmtp(varp);
|
||||
AstNode* initsp = new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, true), countp);
|
||||
AstNode* initsp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), countp);
|
||||
AstNode* decp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE),
|
||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::READ),
|
||||
new AstConst(nodep->fileline(), 1)));
|
||||
AstNode* zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);
|
||||
AstNode* condp
|
||||
= new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), zerosp);
|
||||
AstNode* condp = new AstGtS(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, VAccess::READ), zerosp);
|
||||
AstNode* bodysp = nodep->bodysp();
|
||||
if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp);
|
||||
@@ -213,7 +213,7 @@ private:
|
||||
// Set output variable to return value
|
||||
nodep->addPrev(new AstAssign(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), true),
|
||||
new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), VAccess::WRITE),
|
||||
nodep->lhsp()->unlinkFrBackWithNext()));
|
||||
}
|
||||
// Jump to the end of the function call
|
||||
|
||||
+46
-37
@@ -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->lvalue(true);
|
||||
if (m_setRefLvalue != VAccess::NOCHANGE) nodep->access(m_setRefLvalue);
|
||||
if (nodep->varp()) {
|
||||
if (nodep->lvalue() && !m_ftaskp && nodep->varp()->isReadOnly()) {
|
||||
if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) {
|
||||
nodep->v3warn(ASSIGNIN,
|
||||
"Assigning to input/const variable: " << nodep->prettyNameQ());
|
||||
}
|
||||
@@ -60,9 +60,9 @@ private:
|
||||
if (nodep->modVarp() && nodep->modVarp()->isWritable()) {
|
||||
// When the varref's were created, we didn't know the I/O state
|
||||
// Now that we do, and it's from a output, we know it's a lvalue
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateChildren(nodep);
|
||||
m_setRefLvalue = false;
|
||||
m_setRefLvalue = VAccess::NOCHANGE;
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
@@ -70,18 +70,27 @@ private:
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
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());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFOpen* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = false;
|
||||
m_setRefLvalue = VAccess::NOCHANGE;
|
||||
iterateAndNextNull(nodep->filenamep());
|
||||
iterateAndNextNull(nodep->modep());
|
||||
}
|
||||
@@ -89,23 +98,23 @@ private:
|
||||
virtual void visit(AstFOpenMcd* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
m_setRefLvalue = false;
|
||||
m_setRefLvalue = VAccess::NOCHANGE;
|
||||
iterateAndNextNull(nodep->filenamep());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFClose* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFError* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextNull(nodep->strp());
|
||||
}
|
||||
@@ -113,21 +122,21 @@ private:
|
||||
virtual void visit(AstFFlush* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFGetC* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFGetS* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextNull(nodep->strgp());
|
||||
}
|
||||
@@ -135,7 +144,7 @@ private:
|
||||
virtual void visit(AstFRead* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->memp());
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
@@ -143,7 +152,7 @@ private:
|
||||
virtual void visit(AstFScanF* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
}
|
||||
@@ -151,14 +160,14 @@ private:
|
||||
virtual void visit(AstFUngetC* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->filep());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSScanF* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->exprsp());
|
||||
}
|
||||
}
|
||||
@@ -170,9 +179,9 @@ private:
|
||||
virtual void visit(AstReadMem* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->memp());
|
||||
m_setRefLvalue = false;
|
||||
m_setRefLvalue = VAccess::NOCHANGE;
|
||||
iterateAndNextNull(nodep->filenamep());
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
iterateAndNextNull(nodep->msbp());
|
||||
@@ -181,28 +190,28 @@ private:
|
||||
virtual void visit(AstValuePlusArgs* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = false;
|
||||
m_setRefLvalue = VAccess::NOCHANGE;
|
||||
iterateAndNextNull(nodep->searchp());
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->outp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSFormat* nodep) override {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
m_setRefLvalue = false;
|
||||
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 = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterateAndNextNull(nodep->thsp());
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -260,9 +269,9 @@ private:
|
||||
if (const AstVar* portp = VN_CAST(stmtp, Var)) {
|
||||
if (portp->isIO()) {
|
||||
if (portp->isWritable()) {
|
||||
m_setRefLvalue = true;
|
||||
m_setRefLvalue = VAccess::WRITE;
|
||||
iterate(pinp);
|
||||
m_setRefLvalue = false;
|
||||
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);
|
||||
}
|
||||
|
||||
+7
-6
@@ -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;
|
||||
}
|
||||
@@ -233,9 +233,10 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
||||
varp->trace(false);
|
||||
}
|
||||
|
||||
AstPin* pinp
|
||||
= new AstPin(oldvarp->fileline(), 0, varp->name(),
|
||||
new AstVarRef(varp->fileline(), varp, oldvarp->isWritable()));
|
||||
AstPin* pinp = new AstPin(
|
||||
oldvarp->fileline(), 0, varp->name(),
|
||||
new AstVarRef(varp->fileline(), varp,
|
||||
oldvarp->isWritable() ? VAccess::WRITE : VAccess::READ));
|
||||
// Skip length and width comp; we know it's a direct assignment
|
||||
pinp->modVarp(oldvarp);
|
||||
cellp->addPinsp(pinp);
|
||||
|
||||
+44
-24
@@ -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,27 +238,24 @@ 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(), true),
|
||||
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(), true),
|
||||
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, new AstVarRef(fl, nodep->name(), true),
|
||||
nodep->addNextHere(new AstAssign(fl,
|
||||
new AstVarRef(fl, nodep->name(), VAccess::WRITE),
|
||||
nodep->valuep()->unlinkFrBack()));
|
||||
}
|
||||
}
|
||||
@@ -333,7 +345,8 @@ private:
|
||||
// lvalue is true, because we know we have a verilator public_flat_rw
|
||||
// but someday we may be more general
|
||||
bool lvalue = m_varp->isSigUserRWPublic();
|
||||
nodep->addStmtp(new AstVarRef(nodep->fileline(), m_varp, lvalue));
|
||||
nodep->addStmtp(
|
||||
new AstVarRef(nodep->fileline(), m_varp, lvalue ? VAccess::WRITE : VAccess::READ));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +458,8 @@ private:
|
||||
new AstConst(fl, dimension));
|
||||
AstNode* stmtsp = varp;
|
||||
// Assign left-dimension into the loop var:
|
||||
stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp));
|
||||
stmtsp->addNext(
|
||||
new AstAssign(fl, new AstVarRef(fl, varp->name(), VAccess::WRITE), leftp));
|
||||
// This will turn into a constant bool for static arrays
|
||||
AstNode* notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0));
|
||||
// This will turn into a bool constant, indicating whether
|
||||
@@ -454,14 +468,15 @@ private:
|
||||
AstNode* comparep = new AstCond(
|
||||
fl, countupp->cloneTree(true),
|
||||
// Left increments up to right
|
||||
new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)),
|
||||
new AstLte(fl, new AstVarRef(fl, varp->name(), VAccess::READ),
|
||||
rightp->cloneTree(true)),
|
||||
// Left decrements down to right
|
||||
new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp));
|
||||
new AstGte(fl, new AstVarRef(fl, varp->name(), VAccess::READ), rightp));
|
||||
// This will reduce to comparep for static arrays
|
||||
AstNode* condp = new AstAnd(fl, notemptyp, comparep);
|
||||
AstNode* incp = new AstAssign(
|
||||
fl, new AstVarRef(fl, varp->name(), true),
|
||||
new AstAdd(fl, new AstVarRef(fl, varp->name(), false),
|
||||
fl, new AstVarRef(fl, varp->name(), VAccess::WRITE),
|
||||
new AstAdd(fl, new AstVarRef(fl, varp->name(), VAccess::READ),
|
||||
new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1))));
|
||||
stmtsp->addNext(new AstWhile(fl, condp, newp, incp));
|
||||
newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true);
|
||||
@@ -477,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;
|
||||
|
||||
+22
-28
@@ -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 {
|
||||
@@ -183,33 +165,34 @@ private:
|
||||
}
|
||||
addwherep->addNext(newvarp);
|
||||
|
||||
sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, false));
|
||||
sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, VAccess::READ));
|
||||
AstAssignW* assignp = new AstAssignW(
|
||||
sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, true), sensp);
|
||||
sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, VAccess::WRITE),
|
||||
sensp);
|
||||
addwherep->addNext(assignp);
|
||||
}
|
||||
} else { // Old V1995 sensitivity list; we'll probably mostly ignore
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,7 +359,7 @@ private:
|
||||
if (!inpercent && c == '%') {
|
||||
inpercent = true;
|
||||
} else if (inpercent) {
|
||||
inpercent = 0;
|
||||
inpercent = false;
|
||||
switch (c) {
|
||||
case '0': // FALLTHRU
|
||||
case '1': // FALLTHRU
|
||||
@@ -409,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");
|
||||
@@ -490,7 +473,8 @@ private:
|
||||
varoutp = varp;
|
||||
// Tie off
|
||||
m_modp->addStmtp(new AstAssignW(
|
||||
varp->fileline(), new AstVarRef(varp->fileline(), varp, true),
|
||||
varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, VAccess::WRITE),
|
||||
new AstConst(varp->fileline(), AstConst::LogicFalse())));
|
||||
} else {
|
||||
varp->v3error("Only inputs and outputs are allowed in udp modules");
|
||||
@@ -518,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:
|
||||
|
||||
+11
-8
@@ -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->lvalue(), 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);
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ private:
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
if (!m_mergeable) return;
|
||||
// Clear if it's an LValue referencing a marked variable
|
||||
if (nodep->lvalue() && nodep->varp()->user1()) {
|
||||
if (nodep->access().isWriteOrRW() && nodep->varp()->user1()) {
|
||||
clearMergeable(nodep, "might modify condition");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1267,7 +1267,7 @@ V3Number& V3Number::opXor(const V3Number& lhs, const V3Number& rhs) {
|
||||
setBit(bit, 1);
|
||||
} else if (lhs.bitIs0(bit) && rhs.bitIs1(bit)) {
|
||||
setBit(bit, 1);
|
||||
} else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) {
|
||||
} else if (lhs.bitIsXZ(bit) || rhs.bitIsXZ(bit)) {
|
||||
setBit(bit, 'x');
|
||||
}
|
||||
// else zero
|
||||
|
||||
+15
-21
@@ -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) {
|
||||
@@ -431,15 +427,6 @@ string V3Options::allArgsStringForHierBlock(bool forTop) const {
|
||||
//######################################################################
|
||||
// File searching
|
||||
|
||||
bool V3Options::fileStatDir(const string& filename) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
struct stat sstat; // Stat information
|
||||
int err = stat(filename.c_str(), &sstat);
|
||||
if (err != 0) return false;
|
||||
if (!S_ISDIR(sstat.st_mode)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool V3Options::fileStatNormal(const string& filename) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
struct stat sstat; // Stat information
|
||||
@@ -510,10 +497,10 @@ 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 == "top-module" || opt == "v") {
|
||||
|| opt == "threads" || opt == "top-module" || opt == "v") {
|
||||
return 2;
|
||||
}
|
||||
if (opt == "build" || (!forTop && (opt == "cc" || opt == "exe" || opt == "sc"))
|
||||
@@ -651,9 +638,9 @@ string V3Options::getenvSYSTEMC_ARCH() {
|
||||
struct utsname uts;
|
||||
uname(&uts);
|
||||
string sysname = VString::downcase(uts.sysname); // aka 'uname -s'
|
||||
if (VString::wildmatch(sysname.c_str(), "*solaris*")) {
|
||||
if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*solaris*"))) {
|
||||
var = "gccsparcOS5";
|
||||
} else if (VString::wildmatch(sysname.c_str(), "*cygwin*")) {
|
||||
} else if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*cygwin*"))) {
|
||||
var = "cygwin";
|
||||
} else {
|
||||
var = "linux";
|
||||
@@ -1013,6 +1000,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
m_debugCheck = flag;
|
||||
} else if (onoff(sw, "-debug-collision", flag /*ref*/)) { // Undocumented
|
||||
m_debugCollision = flag;
|
||||
} else if (onoff(sw, "-debug-emitv", flag /*ref*/)) { // Undocumented
|
||||
m_debugEmitV = flag;
|
||||
} else if (onoff(sw, "-debug-exit-parse", flag /*ref*/)) { // Undocumented
|
||||
m_debugExitParse = flag;
|
||||
} else if (onoff(sw, "-debug-exit-uvm", flag /*ref*/)) { // Undocumented
|
||||
@@ -1594,6 +1583,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
|
||||
string oline;
|
||||
// cppcheck-suppress StlMissingComparison
|
||||
char lastch = ' ';
|
||||
bool space_begin = true; // At beginning or leading spaces only
|
||||
for (string::const_iterator pos = line.begin(); pos != line.end(); lastch = *pos++) {
|
||||
if (inCmt) {
|
||||
if (*pos == '*' && *(pos + 1) == '/') {
|
||||
@@ -1603,11 +1593,15 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
|
||||
} else if (*pos == '/' && *(pos + 1) == '/'
|
||||
&& (pos == line.begin() || isspace(lastch))) { // But allow /file//path
|
||||
break; // Ignore to EOL
|
||||
} else if (*pos == '#' && space_begin) { // Only # at [spaced] begin of line
|
||||
break; // Ignore to EOL
|
||||
} else if (*pos == '/' && *(pos + 1) == '*') {
|
||||
inCmt = true;
|
||||
space_begin = false;
|
||||
// cppcheck-suppress StlMissingComparison
|
||||
++pos;
|
||||
} else {
|
||||
if (!isspace(*pos)) space_begin = false;
|
||||
oline += *pos;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-11
@@ -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
|
||||
@@ -265,6 +265,7 @@ private:
|
||||
bool m_coverageUser = false; // main switch: --coverage-func
|
||||
bool m_debugCheck = false; // main switch: --debug-check
|
||||
bool m_debugCollision = false; // main switch: --debug-collision
|
||||
bool m_debugEmitV = false; // main switch: --debug-emitv
|
||||
bool m_debugExitParse = false; // main switch: --debug-exit-parse
|
||||
bool m_debugExitUvm = false; // main switch: --debug-exit-uvm
|
||||
bool m_debugLeak = true; // main switch: --debug-leak
|
||||
@@ -409,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);
|
||||
@@ -469,6 +470,7 @@ public:
|
||||
bool coverageUser() const { return m_coverageUser; }
|
||||
bool debugCheck() const { return m_debugCheck; }
|
||||
bool debugCollision() const { return m_debugCollision; }
|
||||
bool debugEmitV() const { return m_debugEmitV; }
|
||||
bool debugExitParse() const { return m_debugExitParse; }
|
||||
bool debugExitUvm() const { return m_debugExitUvm; }
|
||||
bool debugLeak() const { return m_debugLeak; }
|
||||
@@ -669,7 +671,6 @@ public:
|
||||
const string& errmsg);
|
||||
void filePathLookedMsg(FileLine* fl, const string& modname);
|
||||
V3LangCode fileLanguage(const string& filename);
|
||||
static bool fileStatDir(const string& filename);
|
||||
static bool fileStatNormal(const string& filename);
|
||||
static void fileNfsFlush(const string& filename);
|
||||
|
||||
|
||||
+21
-15
@@ -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,8 @@ private:
|
||||
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
|
||||
if (m_inSenTree) {
|
||||
// Add CLOCK dependency... This is a root of the tree we'll trace
|
||||
UASSERT_OBJ(!nodep->lvalue(), nodep, "How can a sensitivity be setting a var?");
|
||||
UASSERT_OBJ(!nodep->access().isWriteOrRW(), nodep,
|
||||
"How can a sensitivity be setting a var?");
|
||||
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD);
|
||||
varVxp->isClock(true);
|
||||
new OrderEdge(&m_graph, varVxp, m_activeSenVxp, WEIGHT_MEDIUM);
|
||||
@@ -1036,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->lvalue()) {
|
||||
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
|
||||
|
||||
+21
-27
@@ -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()) {
|
||||
@@ -535,7 +533,7 @@ private:
|
||||
nodep->addNext(new AstInitial(
|
||||
nodep->fileline(),
|
||||
new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE),
|
||||
nodep->valuep()->cloneTree(true))));
|
||||
if (m_ftaskp) {
|
||||
// We put the initial in wrong place under a function. We
|
||||
@@ -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);
|
||||
|
||||
@@ -83,7 +83,7 @@ AstNode* V3ParseGrammar::argWrapList(AstNode* nodep) {
|
||||
|
||||
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) {
|
||||
return new AstAssignW(
|
||||
fileline, new AstVarRef(fileline, name, true),
|
||||
fileline, new AstVarRef(fileline, name, VAccess::WRITE),
|
||||
new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0")));
|
||||
}
|
||||
|
||||
|
||||
+5
-10
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user