Compare commits

...
54 Commits
Author SHA1 Message Date
Wilson Snyder 1448cc56fc Version bump 2017-09-07 21:10:22 -04:00
Wilson Snyder 074689b5de SystemPerl mode (-sp-deprecated) has been removed. 2017-09-07 21:08:49 -04:00
Wilson Snyder 8dd612a0a0 Commentary, bug1198. 2017-09-06 20:45:21 -04:00
Wilson Snyder 22fdbba0b5 Update keywords for C++11 etc, msg2325 2017-09-02 21:01:50 -04:00
Wilson Snyder 39b787670b Update keywords for C++11 etc, msg2325 2017-09-02 20:59:03 -04:00
Wilson Snyder a221278c05 Commentary 2017-08-31 19:45:53 -04:00
Wilson Snyder 5f26b9ec66 Internals: Remove dead putAlign, bug1093. 2017-08-28 23:01:19 -04:00
Wilson Snyder 48778d0a77 devel release 2017-08-28 22:51:53 -04:00
Wilson Snyder 42d2cbad41 Version bump 2017-08-28 22:46:43 -04:00
Wilson Snyder cb82c42e35 Test for bug1191. 2017-08-28 22:41:38 -04:00
Wilson Snyder f13fb330ed Reenable -Wchar-subscripts and sort flag list 2017-08-14 20:15:24 -04:00
Wilson Snyder d4bae48ca2 Fix GCC7.1 warning on new alignment 2017-08-14 19:59:21 -04:00
Wilson Snyder 590ad964b1 Add assertion on bad formed lvalues, used to debug bug1187. 2017-08-13 18:08:44 -04:00
Wilson Snyder d4595df8a4 Fix internal error on unconnected inouts, bug1187. 2017-08-13 18:08:24 -04:00
Wilson Snyder 7b642bcbb4 Support packed struct DPI imports, bug1190. 2017-08-11 19:07:47 -04:00
Wilson Snyder ca26596695 Fix undefined VL_POW_WWI. 2017-07-12 20:08:32 -04:00
Wilson Snyder 88cf5e5d98 Fix realloc leak on out-of-memory 2017-07-12 18:54:27 -04:00
Wilson Snyder 13f790360d Fix compile error on unused VL_VALUEPLUSARGS_IW, bug1181. 2017-07-07 07:50:45 -04:00
Wilson Snyder 70daadf987 Fix cpp-check warnings; support XML format 2 2017-07-06 20:25:59 -04:00
Wilson Snyder 9d5004db1c Fix GCC 7 warnings. 2017-07-06 19:49:34 -04:00
Wilson Snyder ea82bfcced Fix GCC 6 warnings. 2017-07-06 19:07:23 -04:00
Wilson Snyder 00a502942e Fix valueplus exceeding array bounds. 2017-07-06 19:01:35 -04:00
Wilson Snyder 2031bc7fc4 Commentary 2017-07-05 19:06:22 -04:00
Wilson Snyder 3adb22e971 Support x in , 2017-07-05 18:51:06 -04:00
Wilson Snyder 331ea5116f devel release 2017-06-22 18:36:29 -04:00
Wilson Snyder 1da5a33f88 Version bump 2017-06-22 18:31:22 -04:00
Wilson Snyder 6c87724af8 Support set_time_unit/set_time_precision in C traces, msg2261. 2017-06-20 19:33:58 -04:00
Wilson Snyder c7a5ff5e82 Tests: Fix broken vgen test, commentary. 2017-06-20 19:10:18 -04:00
Wilson Snyder abf2fcf820 Fix .* on interface pins, bug1176. 2017-06-20 18:40:18 -04:00
Wilson Snyder 644c22b08f Fix extract of packed array with non-zero LSB, bug1172. 2017-06-06 20:06:23 -04:00
Wilson Snyder c54024a5e6 Fix constant shifts by more than 32-bit numbers, bug1174 continued. 2017-06-05 21:15:31 -04:00
Wilson Snyder 97093fdf81 Fix power operator on wide constants, bug761. 2017-06-05 20:30:01 -04:00
Wilson Snyder 50c4f60c68 Internals: Favor preincrement. No functional change. 2017-06-05 20:16:51 -04:00
Wilson Snyder f0fb3b78d1 Internals: New VL_ZERO_W for faster inline. Prefer WData for wide. No functional change intended. 2017-06-05 20:04:09 -04:00
Wilson Snyder 9b06178f35 Fix shifts by more than 32-bit numbers, bug1174. 2017-06-05 07:56:59 -04:00
Wilson Snyder a01c96140b devel release 2017-05-30 22:04:58 -04:00
Wilson Snyder 02530172e7 Version bump 2017-05-30 22:01:21 -04:00
Wilson Snyder 447d803800 Fix internal clang warnings. 2017-05-24 23:51:15 -04:00
Wilson Snyder 6b04901c4d Fix testplusargs false width warning, bug1165. 2017-05-19 07:20:41 -04:00
Wilson Snyder 7fb29621c3 Fix interface functions returning wrong parameters, bug996. 2017-05-18 22:49:17 -04:00
Wilson Snyder b032fce962 Support $value$plusargs with variables, bug1165. 2017-05-18 22:41:43 -04:00
Wilson Snyder ce879122bb Fix --assert with complex case statements, bug1164. 2017-05-17 20:15:40 -04:00
Todd Strader 2fa16708b7 Fix non-arrayed cells with interface arrays, bug1153.
Signed-off-by: Wilson Snyder <[email protected]>
2017-05-10 19:05:42 -04:00
Todd Strader 54bc8608e3 Add stack trace when can't optimize function, bug1158.
Signed-off-by: Wilson Snyder <[email protected]>
2017-05-09 18:54:15 -04:00
Todd Strader 706a7802cc Fix non-cutable ordering loops on clock arrays, bug1009.
Signed-off-by: Wilson Snyder <[email protected]>
2017-05-09 08:05:21 -04:00
Wilson Snyder 9dc01cf540 Support arrayed parameter overrides, bug1153. 2017-05-02 19:16:54 -04:00
Wilson Snyder 8943ad5966 internals: Remove extra newlines on v3fatalSrc. No functional change. 2017-04-28 20:09:27 -04:00
Wilson Snyder deb7a1c9c0 Fix non-arrayed cells with interface arrays, bug1153. 2017-04-28 20:03:38 -04:00
Wilson Snyder 96a5445d44 Support ports of array of reals, bug1154. 2017-04-28 06:10:14 -04:00
Wilson Snyder d693065afb Fix backwards array interface error message 2017-04-27 06:36:14 -04:00
Wilson Snyder bdeee35669 Add warning on mis-sized literal, bug1156. 2017-04-26 18:34:01 -04:00
Wilson Snyder 62b3deb90d Tests: Improve vams to attach wire. 2017-04-04 19:15:15 -04:00
Wilson Snyder 9df9ff59e0 Commentary 2017-04-03 20:02:19 -04:00
Wilson Snyder 23a3271c06 devel release 2017-04-02 08:49:31 -04:00
148 changed files with 4698 additions and 1098 deletions
+57
View File
@@ -2,6 +2,63 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 3.910 2017-09-07
*** SystemPerl mode (-sp-deprecated) has been removed.
**** Update keyword warnings to include C++11 and others.
* Verilator 3.908 2017-08-28
**** Support x in $readmem, bug1180. [Arthur Kahlich]
**** Support packed struct DPI imports, bug1190. [Rob Stoddard]
**** Fix GCC 6 warnings.
**** Fix compile error on unused VL_VALUEPLUSARGS_IW, bug1181. [Thomas J Whatson]
**** Fix undefined VL_POW_WWI. [Clifford Wolf]
**** Fix internal error on unconnected inouts, bug1187. [Rob Stoddard]
* Verilator 3.906 2017-06-22
*** Support set_time_unit/set_time_precision in C traces, msg2261.
*** Fix extract of packed array with non-zero LSB, bug1172. [James Pallister]
*** Fix shifts by more than 32-bit numbers, bug1174. [Clifford Wolf]
*** Fix power operator on wide constants, bug761. [Clifford Wolf]
*** Fix .* on interface pins, bug1176. [Maciej Piechotka]
* Verilator 3.904 2017-05-30
*** Fix non-cutable ordering loops on clock arrays, bug1009. [Todd Strader]
*** Support ports of array of reals, bug1154. [J Briquet]
*** Support arrayed parameter overrides, bug1153. [John Stevenson]
*** Support $value$plusargs with variables, bug1165. [Wesley Terpstra]
**** Support modport access to un-modport objects, bug1161. [Todd Strader]
**** Add stack trace when can't optimize function, bug1158. [Todd Strader]
**** Add warning on mis-sized literal, bug1156. [Todd Strader]
**** Fix interface functions returning wrong parameters, bug996. [Todd Strader]
**** Fix non-arrayed cells with interface arrays, bug1153. [John Stevenson]
**** Fix --assert with complex case statements, bug1164. [Enzo Chi]
* Verilator 3.902 2017-04-02
+56 -35
View File
@@ -483,7 +483,7 @@ interest in adding more traditional CDC checks, please contact the authors.
Sometimes it is quite difficult for Verilator to distinguish clock signals from
other data signals. Occasionally the clock signals can end up in the checking
list of signals which determines if further evaluation is needed. This will
heavily degrade the performance of verilated model.
heavily degrade the performance of a Verilated model.
With --clk <signal-name>, user can specified root clock into the model, then
Verilator will mark the signal as clocker and propagate the clocker attribute
@@ -495,6 +495,10 @@ If the signal is the input to top-module, the directly the signal name. If you
find it difficult to find the exact name, try to use C</*verilator clocker*/> in
RTL file to mark the signal directly.
If clock signals are assigned to vectors and then later used individually,
Verilator will attempt to decompose the vector and connect the single-bit
clock signals directly. This should be transparent to the user.
=item --compiler I<compiler-name>
Enables tunings and workarounds for the specified C++ compiler.
@@ -509,7 +513,7 @@ breaking deep structures as for msvc as described below.
=item gcc
Tune for Gnu C++, although generated code should work on almost any
Tune for GNU C++, although generated code should work on almost any
compliant C++ compiler. Currently the default.
=item msvc
@@ -907,7 +911,7 @@ developers.
=item --output-split I<bytes>
Enables splitting the output .cpp/.sp files into multiple outputs. When a
Enables splitting the output .cpp files into multiple outputs. When a
C++ file exceeds the specified number of operations, a new file will be
created at the next function boundary. In addition, any slow routines will
be placed into __Slow files. This accelerates compilation by as
@@ -919,7 +923,7 @@ one-minute-compile chunks.
=item --output-split-cfuncs I<statements>
Enables splitting functions in the output .cpp/.sp files into multiple
Enables splitting functions in the output .cpp files into multiple
functions. When a generated function exceeds the specified number of
operations, a new function will be created. With --output-split, this will
enable GCC to compile faster, at a small loss in performance that gets
@@ -929,7 +933,7 @@ function.
=item --output-split-ctrace I<statements>
Enables splitting trace functions in the output .cpp/.sp files into
Enables splitting trace functions in the output .cpp files into
multiple functions. Defaults to same setting as --output-split-cfuncs.
=item -P
@@ -1426,8 +1430,8 @@ This is an example similar to the above, but using SystemC.
Verilated::commandArgs(argc, argv);
sc_clock clk ("clk",10, 0.5, 3, true);
Vour* top;
top = new Vour("top"); // SP_CELL (top, Vour);
top->clk(clk); // SP_PIN (top, clk, clk);
top = new Vour("top");
top->clk(clk);
while (!Verilated::gotFinish()) { sc_start(1, SC_NS); }
delete top;
exit(0);
@@ -1506,7 +1510,7 @@ OPT, OPT_FAST, or OPT_SLOW lib/verilated.mk. Or, use the -CFLAGS and/or
the compiler or linker. Or, just for one run, pass them on the command
line to make:
make OPT_FAST="-O2" -f Vour.mk Vour__ALL.a
make OPT_FAST="-O2 -fno-stack-protector" -f Vour.mk Vour__ALL.a
OPT_FAST specifies optimizations for those programs that are part of the
fast path, mostly code that is executed every cycle. OPT_SLOW specifies
@@ -1913,54 +1917,71 @@ documented below.
Verilator has an important difference from an event based simulator; signal
values that are changed by the VPI will not immediately propagate their
values, instead the top level header file's eval() method must be called.
Normally this would be part of the normal evaluation (IE the next clock
Normally this would be part of the normal evaluation (i.e. the next clock
edge), not as part of the value change. This makes the performance of VPI
routines extremely fast compared to event based simulators, but can confuse
some test-benches that expect immediate propagation.
Note the VPI by it's specified implementation will always be much slower
Note the VPI by its specified implementation will always be much slower
than accessing the Verilator values by direct reference
(structure->module->signame), as the VPI accessors perform lookup in
functions at runtime requiring at best hundreds of instructions, while the
direct references are evaluated by the compiler and result in only a couple
of instructions.
For signal callbacks to work the main loop of the program must call
VerilatedVpi::callValueCbs().
=head2 VPI Example
In the below example, we have readme marked read-only, and writeme which if
written from outside the model will have the same semantics as if it
changed on the specified clock edge.
module t;
reg readme /*verilator public_flat_rd*/;
reg writeme /*verilator public_flat_rw @(posedge clk) */;
endmodule
cat <<EOF >our.v
module our (input clk);
reg readme /*verilator public_flat_rd*/;
reg writeme /*verilator public_flat_rw @(posedge clk) */;
initial $finish;
endmodule
EOF
There are many online tutorials and books on the VPI, but an example that
accesses the above would be:
accesses the above signal "readme" would be:
void read_and_check() {
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.readme", NULL);
if (!vh1) { error... }
const char* name = vpi_get_str(vpiName, vh1);
printf("Module name: %s\n"); // Prints "readme"
cat <<EOF >sim_main.cpp
#include "Vour.h"
#include "verilated.h"
#include "verilated_vpi.h" // Required to get definitions
s_vpi_value v;
v.format = vpiIntVal;
vpi_get_value(vh1, &v);
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
}
vluint64_t main_time = 0; // See comments in first example
double sc_time_stamp () { return main_time; }
For signal callbacks to work the main loop of the program must call
VerilatedVpi::callValueCbs().
void read_and_check() {
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
if (!vh1) { vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found"); }
const char* name = vpi_get_str(vpiName, vh1);
printf("Module name: %s\n", name); // Prints "readme"
#include "verilated_vpi.h" // Required to get definitions
...
while (time passes) {
...
topp->eval();
VerilatedVpi::callValueCbs();
}
s_vpi_value v;
v.format = vpiIntVal;
vpi_get_value(vh1, &v);
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
}
int main(int argc, char **argv, char **env) {
Verilated::commandArgs(argc, argv);
Vour* top = new Vour;
Verilated::internalsDump(); // See scopes to help debug
while (!Verilated::gotFinish()) {
top->eval();
VerilatedVpi::callValueCbs(); // For signal callbacks
read_and_check();
}
delete top;
exit(0);
}
EOF
=head1 CROSS COMPILATION
@@ -3857,7 +3878,7 @@ From the sc_main.cpp file, you'd then:
#include "Vour.h"
#include "Vour_our.h"
cout << "clock is " << top->v->clk << endl;
cout << "clock is " << top->our->clk << endl;
In this example, clk is a bool you can read or set as any other variable.
The value of normal signals may be set, though clocks shouldn't be changed
+12 -11
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.902 2017-04-02])
AC_INIT([Verilator],[3.910 2017-09-07])
# When releasing, also update header of Changes file
AC_CONFIG_HEADER(src/config_build.h)
@@ -140,34 +140,35 @@ AC_DEFUN([_MY_CXX_CHECK_OPT],
])# _MY_CXX_CHECK_OPT
# Flags for compiling Verilator internals including parser
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-unused-parameter)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-char-subscripts)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-undefined-bool-conversion)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Qunused-arguments)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-faligned-new)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-delete-null-pointer-checks)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-unused-parameter)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-undefined-bool-conversion)
AC_SUBST(CFG_CXXFLAGS_SRC)
# Flags for compiling Verilator parser
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-unused)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-parentheses-equality)
# Flags for compiling Verilator parser (in addition to above CFG_CXXFLAGS_SRC)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-char-subscripts)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-null-conversion)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-parentheses-equality)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-unused)
AC_SUBST(CFG_CXXFLAGS_PARSER)
# Flags for Verilated makefile
# For example, -Wno-div-by-zero isn't in 4.1.2
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-char-subscripts)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-parentheses-equality)
# Random code often does / 0. Unfortunately VL_DIV_I(0,0) will warn
# without this flag, even though there's a conditional to prevent the divide.
# We still don't add no-div-by-zero as it throws message to stdout, though doesn't die.
#_MY_CXX_CHECK_OPT(-Wno-div-by-zero)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-faligned-new)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-fbracket-depth=4096)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Qunused-arguments)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-parentheses-equality)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-sign-compare)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-uninitialized)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-but-set-variable)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-parameter)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-variable)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-fbracket-depth=4096)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Qunused-arguments)
AC_SUBST(CFG_CXXFLAGS_NO_UNUSED)
# Checks for library functions.
+184 -63
View File
@@ -115,7 +115,7 @@ QData VL_RANDOM_Q(int obits) {
}
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) {
for (int i=0; i<VL_WORDS_I(obits); i++) {
for (int i=0; i<VL_WORDS_I(obits); ++i) {
if (i<(VL_WORDS_I(obits)-1)) {
outwp[i] = VL_RAND32();
} else {
@@ -146,7 +146,7 @@ QData VL_RAND_RESET_Q(int obits) {
}
WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) {
for (int i=0; i<VL_WORDS_I(obits); i++) {
for (int i=0; i<VL_WORDS_I(obits); ++i) {
if (i<(VL_WORDS_I(obits)-1)) {
outwp[i] = VL_RAND_RESET_I(32);
} else {
@@ -157,7 +157,7 @@ WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) {
}
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) {
for (int i=0; i<VL_WORDS_I(obits); i++) outwp[i] = 0;
for (int i=0; i<VL_WORDS_I(obits); ++i) outwp[i] = 0;
return outwp;
}
@@ -166,7 +166,7 @@ WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) {
void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp) {
VL_PRINTF(" Data: w%d: ", lbits);
for (int i=VL_WORDS_I(lbits)-1; i>=0; i--) { VL_PRINTF("%08x ",iwp[i]); }
for (int i=VL_WORDS_I(lbits)-1; i>=0; --i) { VL_PRINTF("%08x ",iwp[i]); }
VL_PRINTF("\n");
}
@@ -179,7 +179,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
// for debug see V3Number version
// Requires clean input
int words = VL_WORDS_I(lbits);
for (int i=0; i<words; i++) owp[i]=0;
for (int i=0; i<words; ++i) owp[i]=0;
// Find MSB and check for zero.
int umsbp1 = VL_MOSTSETBITP1_W(words,lwp); // dividend
int vmsbp1 = VL_MOSTSETBITP1_W(words,rwp); // divisor
@@ -193,14 +193,14 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0;
for (int j = uw-1; j >= 0; j--) {
for (int j = uw-1; j >= 0; --j) {
vluint64_t unw64 = ((k<<VL_ULL(32)) + (vluint64_t)(lwp[j]));
owp[j] = unw64 / (vluint64_t)(rwp[0]);
k = unw64 - (vluint64_t)(owp[j])*(vluint64_t)(rwp[0]);
}
if (is_modulus) {
owp[0] = k;
for (int i=1; i<words; i++) owp[i]=0;
for (int i=1; i<words; ++i) owp[i]=0;
}
return owp;
}
@@ -211,13 +211,13 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
// Zero for ease of debugging and to save having to zero for shifts
// Note +1 as loop will use extra word
for (int i=0; i<words+1; i++) { un[i]=vn[i]=0; }
for (int i=0; i<words+1; ++i) { un[i]=vn[i]=0; }
// Algorithm requires divisor MSB to be set
// Copy and shift to normalize divisor so MSB of vn[vw-1] is set
int s = 31-VL_BITBIT_I(vmsbp1-1); // shift amount (0...31)
vluint32_t shift_mask = s ? 0xffffffff : 0; // otherwise >> 32 won't mask the value
for (int i = vw-1; i>0; i--) {
for (int i = vw-1; i>0; --i) {
vn[i] = (rwp[i] << s) | (shift_mask & (rwp[i-1] >> (32-s)));
}
vn[0] = rwp[0] << s;
@@ -225,13 +225,13 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
// Copy and shift dividend by same amount; may set new upper word
if (s) un[uw] = lwp[uw-1] >> (32-s);
else un[uw] = 0;
for (int i=uw-1; i>0; i--) {
for (int i=uw-1; i>0; --i) {
un[i] = (lwp[i] << s) | (shift_mask & (lwp[i-1] >> (32-s)));
}
un[0] = lwp[0] << s;
// Main loop
for (int j = uw - vw; j >= 0; j--) {
for (int j = uw - vw; j >= 0; --j) {
// Estimate
vluint64_t unw64 = ((vluint64_t)(un[j+vw])<<VL_ULL(32) | (vluint64_t)(un[j+vw-1]));
vluint64_t qhat = unw64 / (vluint64_t)(vn[vw-1]);
@@ -247,7 +247,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
vlsint64_t t = 0; // Must be signed
vluint64_t k = 0;
for (int i=0; i<vw; i++) {
for (int i=0; i<vw; ++i) {
vluint64_t p = qhat*vn[i]; // Multiply by estimate
t = un[i+j] - k - (p & VL_ULL(0xFFFFFFFF)); // Subtract
un[i+j] = t;
@@ -261,7 +261,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
// Over subtracted; correct by adding back
owp[j]--;
k = 0;
for (int i=0; i<vw; i++) {
for (int i=0; i<vw; ++i) {
t = (vluint64_t)(un[i+j]) + (vluint64_t)(vn[i]) + k;
un[i+j] = t;
k = t >> VL_ULL(32);
@@ -272,16 +272,92 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
if (is_modulus) { // modulus
// Need to reverse normalization on copy to output
for (int i=0; i<vw; i++) {
for (int i=0; i<vw; ++i) {
owp[i] = (un[i] >> s) | (shift_mask & (un[i+1] << (32-s)));
}
for (int i=vw; i<words; i++) owp[i] = 0;
for (int i=vw; i<words; ++i) owp[i] = 0;
return owp;
} else { // division
return owp;
}
}
WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp) {
// obits==lbits, rbits can be different
owp[0] = 1;
for (int i=1; i < VL_WORDS_I(obits); i++) owp[i] = 0;
// cppcheck-suppress variableScope
WData powstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
WData lastpowstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
WData lastoutstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
// cppcheck-suppress variableScope
VL_ASSIGN_W(obits, powstore, lwp);
for (int bit=0; bit<rbits; bit++) {
if (bit>0) { // power = power*power
VL_ASSIGN_W(obits, lastpowstore, powstore);
VL_MUL_W(VL_WORDS_I(obits), powstore, lastpowstore, lastpowstore);
}
if (VL_BITISSET_W(rwp,bit)) { // out *= power
VL_ASSIGN_W(obits, lastoutstore, owp);
VL_MUL_W(VL_WORDS_I(obits), owp, lastoutstore, powstore);
}
}
return owp;
}
WDataOutP VL_POW_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, QData rhs) {
WData rhsw[2]; VL_SET_WQ(rhsw, rhs);
return VL_POW_WWW(obits,lbits,rbits,owp,lwp,rhsw);
}
QData VL_POW_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp) {
// Skip check for rhs == 0, as short-circuit doesn't save time
if (VL_UNLIKELY(lhs==0)) return 0;
QData power = lhs;
QData out = VL_ULL(1);
for (int bit=0; bit<rbits; ++bit) {
if (bit>0) power = power*power;
if (VL_BITISSET_W(rwp,bit)) out *= power;
}
return out;
}
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign) {
// obits==lbits, rbits can be different
if (rsign && VL_SIGN_W(rbits, rwp)) {
int words = VL_WORDS_I(obits);
VL_ZERO_W(obits, owp);
IData lor = 0; // 0=all zeros, ~0=all ones, else mix
for (int i=1; i < (words-1); ++i) {
lor |= lwp[i];
}
lor |= ( (lwp[words-1] == VL_MASK_I(rbits)) ? ~VL_UL(0) : 0);
if (lor==0 && lwp[0]==0) { return owp; } // "X" so return 0
else if (lor==0 && lwp[0]==1) { owp[0] = 1; return owp; } // 1
else if (lsign && lor == ~VL_UL(0) && lwp[0]==~VL_UL(0)) { // -1
if (rwp[0] & 1) { return VL_ALLONES_W(obits, owp); } // -1^odd=-1
else { owp[0] = 1; return owp; } // -1^even=1
}
return 0;
}
return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp);
}
WDataOutP VL_POWSS_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, QData rhs, bool lsign, bool rsign) {
WData rhsw[2]; VL_SET_WQ(rhsw, rhs);
return VL_POWSS_WWW(obits,lbits,rbits,owp,lwp,rhsw,lsign,rsign);
}
QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsign, bool rsign) {
// Skip check for rhs == 0, as short-circuit doesn't save time
if (rsign && VL_SIGN_W(rbits, rwp)) {
if (lhs==0) return 0; // "X"
else if (lhs==1) return 1;
else if (lsign && lhs==VL_MASK_I(obits)) { // -1
if (rwp[0] & 1) return VL_MASK_I(obits); // -1^odd=-1
else return 1; // -1^even=1
}
return 0;
}
return VL_POW_QQW(obits, rbits, rbits, lhs, rwp);
}
//===========================================================================
// Formatting
@@ -302,8 +378,7 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
bool inPct = false;
bool widthSet = false;
int width = 0;
const char* pos = formatp;
for (; *pos; ++pos) {
for (const char* pos = formatp; *pos; ++pos) {
if (!inPct && pos[0]=='%') {
pctp = pos;
inPct = true;
@@ -377,7 +452,7 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
if (fmt == 'd' || fmt == '#') fmt = 'x'; // Not supported, but show something
}
int lsb=lbits-1;
if (widthSet && width==0) while (lsb && !VL_BITISSET_W(lwp,lsb)) lsb--;
if (widthSet && width==0) while (lsb && !VL_BITISSET_W(lwp,lsb)) --lsb;
switch (fmt) {
case 'c': {
IData charval = ld & 0xff;
@@ -385,7 +460,7 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
break;
}
case 's':
for (; lsb>=0; lsb--) {
for (; lsb>=0; --lsb) {
lsb = (lsb / 8) * 8; // Next digit
IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff;
output += (charval==0)?' ':charval;
@@ -434,13 +509,13 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
break;
}
case 'b':
for (; lsb>=0; lsb--) {
for (; lsb>=0; --lsb) {
output += ((lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 1) + '0';
}
break;
break;
case 'o':
for (; lsb>=0; lsb--) {
for (; lsb>=0; --lsb) {
lsb = (lsb / 3) * 3; // Next digit
// Octal numbers may span more than one wide word,
// so we need to grab each bit separately and check for overrun
@@ -453,28 +528,31 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
break;
case 'u': // Packed 2-state
output.reserve(output.size() + 4*VL_WORDS_I(lbits));
for (int i=0; i<VL_WORDS_I(lbits); i++) {
output += (char)((lwp[i] >> 0) & 0xff);
for (int i=0; i<VL_WORDS_I(lbits); ++i) {
output += (char)((lwp[i] ) & 0xff);
output += (char)((lwp[i] >> 8) & 0xff);
output += (char)((lwp[i] >> 16) & 0xff);
output += (char)((lwp[i] >> 24) & 0xff);
}
break;
case 'z': // Packed 4-state
output.reserve(output.size() + 8*VL_WORDS_I(lbits));
for (int i=0; i<VL_WORDS_I(lbits); i++) {
output += (char)((lwp[i] >> 0) & 0xff);
for (int i=0; i<VL_WORDS_I(lbits); ++i) {
output += (char)((lwp[i] ) & 0xff);
output += (char)((lwp[i] >> 8) & 0xff);
output += (char)((lwp[i] >> 16) & 0xff);
output += (char)((lwp[i] >> 24) & 0xff);
output += "\0\0\0\0"; // No tristate
}
break;
case 'v': // Strength; assume always strong
for (lsb=lbits-1; lsb>=0; lsb--) {
for (lsb=lbits-1; lsb>=0; --lsb) {
if ((lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 1) output += "St1 ";
else output += "St0 ";
}
break;
case 'x':
for (; lsb>=0; lsb--) {
for (; lsb>=0; --lsb) {
lsb = (lsb / 4) * 4; // Next digit
IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xf;
output += "0123456789abcdef"[charval];
@@ -547,7 +625,7 @@ static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, int posstart, int posend) {
// Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits.
int lsb = 0;
for (int i=0, pos=posend-1; i<obits && pos>=posstart; pos--) {
for (int i=0, pos=posend-1; i<obits && pos>=posstart; --pos) {
switch (tolower (strp[pos])) {
case 'x': case 'z': case '?': //FALLTHRU
case '0': lsb += baseLog2; break;
@@ -610,12 +688,12 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
// Deal with all read-and-scan somethings
// Note LSBs are preserved if there's an overflow
const int obits = va_arg(ap, int);
WData qowp[2];
WData qowp[2] = {0, 0};
WDataOutP owp = qowp;
if (obits > VL_QUADSIZE) {
owp = va_arg(ap,WDataOutP);
}
for (int i=0; i<VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i<VL_WORDS_I(obits); ++i) owp[i] = 0;
switch (fmt) {
case 'c': {
int c = _vl_vsss_peek(fp,floc,fromp,fstr);
@@ -630,7 +708,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
if (!tmp[0]) goto done;
int pos = ((int)strlen(tmp))-1;
int lsb = 0;
for (int i=0; i<obits && pos>=0; pos--) {
for (int i=0; i<obits && pos>=0; --pos) {
_vl_vsss_setbit(owp,obits,lsb, 8, tmp[pos]); lsb+=8;
}
break;
@@ -724,7 +802,7 @@ void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
int lsb=obits-1;
bool start=true;
char* destp = destoutp;
for (; lsb>=0; lsb--) {
for (; lsb>=0; --lsb) {
lsb = (lsb / 8) * 8; // Next digit
IData charval = (sourcep[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff;
if (!start || charval) {
@@ -742,8 +820,8 @@ void _VL_STRING_TO_VINT(int obits, void* destp, int srclen, const char* srcp) {
char* op = ((char*)(destp));
if (srclen > bytes) srclen = bytes; // Don't overflow destination
int i;
for (i=0; i<srclen; i++) { *op++ = srcp[srclen-1-i]; }
for (; i<bytes; i++) { *op++ = 0; }
for (i=0; i<srclen; ++i) { *op++ = srcp[srclen-1-i]; }
for (; i<bytes; ++i) { *op++ = 0; }
}
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) {
@@ -780,7 +858,7 @@ IData VL_FOPEN_NI(const string& filename, IData mode) {
return VL_FOPEN_S(filename.c_str(), modez);
}
IData VL_FOPEN_QI(QData filename, IData mode) {
IData fnw[2]; VL_SET_WQ(fnw, filename);
WData fnw[2]; VL_SET_WQ(fnw, filename);
return VL_FOPEN_WI(2, fnw, mode);
}
IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
@@ -914,7 +992,7 @@ IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) {
}
IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) {
IData fnw[2]; VL_SET_WI(fnw, ld);
WData fnw[2]; VL_SET_WI(fnw, ld);
va_list ap;
va_start(ap,formatp);
@@ -923,7 +1001,7 @@ IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) {
return got;
}
IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) {
IData fnw[2]; VL_SET_WQ(fnw, ld);
WData fnw[2]; VL_SET_WQ(fnw, ld);
va_list ap;
va_start(ap,formatp);
@@ -948,7 +1026,7 @@ IData VL_SSCANF_INX(int, const string& ld, const char* formatp, ...) {
void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int,
QData ofilename, void* memp, IData start, IData end) {
IData fnw[2]; VL_SET_WQ(fnw, ofilename);
WData fnw[2]; VL_SET_WQ(fnw, ofilename);
return VL_READMEM_W(hex,width,depth,array_lsb,2, fnw,memp,start,end);
}
@@ -997,9 +1075,9 @@ void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
else if (c=='_') {}
else if (c=='@') { reading_addr = true; innum=false; needinc=false; }
// Check for hex or binary digits as file format requests
else if (isxdigit(c)) {
else if (isxdigit(c) || (!reading_addr && (c=='x' || c=='X'))) {
c = tolower(c);
int value = (c >= 'a' ? (c-'a'+10) : (c-'0'));
int value = (c >= 'a' ? (c=='x' ? VL_RAND_RESET_I(4) : (c-'a'+10)) : (c-'0'));
if (!innum) { // Prep for next number
if (needinc) { addr++; needinc=false; }
}
@@ -1051,7 +1129,7 @@ void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
}
lastc = c;
}
if (needinc) { addr++; needinc=false; }
if (needinc) { addr++; }
// Final checks
fclose(fp);
@@ -1061,7 +1139,7 @@ void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
}
IData VL_SYSTEM_IQ(QData lhs) {
IData lhsw[2]; VL_SET_WQ(lhsw, lhs);
WData lhsw[2]; VL_SET_WQ(lhsw, lhs);
return VL_SYSTEM_IW(2, lhsw);
}
IData VL_SYSTEM_IW(int lhswords, WDataInP filenamep) {
@@ -1077,22 +1155,36 @@ IData VL_TESTPLUSARGS_I(const char* formatp) {
else return 1;
}
IData VL_VALUEPLUSARGS_IN(int, const char* prefixp, char, string& ldr) {
const string& match = VerilatedImp::argPlusMatch(prefixp);
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp);
if (match == "") return 0;
ldr = string(dp);
return 1;
}
IData VL_VALUEPLUSARGS_INW(int rbits, const string& ld, WDataOutP rwp) {
string prefix;
bool inPct = false;
bool done = false;
char fmt = ' ';
for (const char* posp = ld.c_str(); !done && *posp; ++posp) {
if (!inPct && posp[0]=='%') {
inPct = true;
} else if (!inPct) { // Normal text
prefix += *posp;
} else { // Format character
switch (tolower(*posp)) {
case '%':
prefix += *posp;
inPct = false;
break;
default:
fmt = *posp;
done = true;
break;
}
}
}
IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp) {
const string& match = VerilatedImp::argPlusMatch(prefixp);
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp);
const string& match = VerilatedImp::argPlusMatch(prefix.c_str());
const char* dp = match.c_str() + 1 /*leading + */ + prefix.length();
if (match == "") return 0;
VL_ZERO_RESET_W(rbits, rwp);
switch (tolower(fmt)) {
case '%':
break;
case 'd':
vlsint64_t ld;
sscanf(dp,"%30" VL_PRI64 "d",&ld);
@@ -1108,18 +1200,47 @@ IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rw
case 'x':
_vl_vsss_based(rwp,rbits, 4, dp, 0, (int)strlen(dp));
break;
case 's':
for (int i=0, lsb=0, pos=((int)strlen(dp))-1; i<rbits && pos>=0; pos--) {
_vl_vsss_setbit(rwp,rbits,lsb, 8, dp[pos]); lsb+=8;
case 's': // string/no conversion
for (int i=0, lsb=0, posp=((int)strlen(dp))-1; i<rbits && posp>=0; --posp) {
_vl_vsss_setbit(rwp,rbits,lsb, 8, dp[posp]); lsb+=8;
}
break;
default: // Compile time should have found all errors before this
vl_fatal (__FILE__, __LINE__, "", "$value$plusargs format error");
break;
case 'e': //FALLTHRU - Unsupported
case 'f': //FALLTHRU - Unsupported
case 'g': //FALLTHRU - Unsupported
default: // Other simulators simply return 0 in these cases and don't error out
return 0;
}
_VL_CLEAN_INPLACE_W(rbits,rwp);
return 1;
}
IData VL_VALUEPLUSARGS_INN(int, const string& ld, string& rdr) {
string prefix;
bool inPct = false;
bool done = false;
for (const char* posp = ld.c_str(); !done && *posp; ++posp) {
if (!inPct && posp[0]=='%') {
inPct = true;
} else if (!inPct) { // Normal text
prefix += *posp;
} else { // Format character
switch (tolower(*posp)) {
case '%':
prefix += *posp;
inPct = false;
break;
default:
done = true;
break;
}
}
}
const string& match = VerilatedImp::argPlusMatch(prefix.c_str());
const char* dp = match.c_str() + 1 /*leading + */ + prefix.length();
if (match == "") return 0;
rdr = string(dp);
return 1;
}
const char* vl_mc_scan_plusargs(const char* prefixp) {
const string& match = VerilatedImp::argPlusMatch(prefixp);
@@ -1142,7 +1263,7 @@ string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) {
bool start=true;
char* destp = destout;
int len = 0;
for (; lsb>=0; lsb--) {
for (; lsb>=0; --lsb) {
lsb = (lsb / 8) * 8; // Next digit
IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff;
if (!start || charval) {
@@ -1163,7 +1284,7 @@ const char* Verilated::catName(const char* n1, const char* n2) {
static char* strp = NULL;
static size_t len = 0;
size_t newlen = strlen(n1)+strlen(n2)+2;
if (newlen > len) {
if (!strp || newlen > len) {
if (strp) delete [] strp;
strp = new char[newlen];
len = newlen;
@@ -1361,7 +1482,7 @@ void* VerilatedScope::exportFindError(int funcnum) const {
void VerilatedScope::scopeDump() const {
VL_PRINTF(" SCOPE %p: %s\n", this, name());
for (int i=0; i<m_funcnumMax; i++) {
for (int i=0; i<m_funcnumMax; ++i) {
if (m_callbacksp && m_callbacksp[i]) {
VL_PRINTF(" DPI-EXPORT %p: %s\n",
m_callbacksp[i], VerilatedImp::exportName(i));
+200 -124
View File
@@ -46,7 +46,7 @@ using namespace std;
// Switches
#if VM_TRACE // Verilator tracing requested
# define WAVES 1 // Set backward compatibility flag as in systemperl.h
# define WAVES 1 // Set backward compatibility flag
#endif
//=========================================================================
@@ -349,7 +349,7 @@ extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); ///< Randomize a signa
extern IData VL_RAND_RESET_I(int obits); ///< Random reset a signal
extern QData VL_RAND_RESET_Q(int obits); ///< Random reset a signal
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp); ///< Random reset a signal
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a signal
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a signal (slow - else use VL_ZERO_W)
/// Math
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus);
@@ -392,19 +392,19 @@ extern IData VL_SYSTEM_IQ(QData lhs);
inline IData VL_SYSTEM_II(IData lhs) { return VL_SYSTEM_IQ(lhs); }
extern IData VL_TESTPLUSARGS_I(const char* formatp);
extern IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp);
extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
//=========================================================================
// Base macros
/// Return true if data[bit] set
/// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
#define VL_BITISSET_I(data,bit) (data & (VL_UL(1)<<VL_BITBIT_I(bit)))
#define VL_BITISSET_Q(data,bit) (data & (VL_ULL(1)<<VL_BITBIT_Q(bit)))
#define VL_BITISSET_W(data,bit) (data[VL_BITWORD_I(bit)] & (VL_UL(1)<<VL_BITBIT_I(bit)))
#define VL_BITISSETLIMIT_W(data,width,bit) (((bit)<(width)) && data[VL_BITWORD_I(bit)] & (VL_UL(1)<<VL_BITBIT_I(bit)))
/// Create two 32-bit words from quadword
/// WData is always at least 2 words; does not clean upper bits
#define VL_SET_WQ(owp,data) { owp[0]=(IData)(data); owp[1]=(IData)((data)>>VL_WORDSIZE); }
#define VL_SET_WI(owp,data) { owp[0]=(IData)(data); owp[1]=0; }
#define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) ))
@@ -433,6 +433,7 @@ static inline IData VL_RTOIROUND_I_D(double lhs) { return ((vlsint32_t)(VL_ROUN
// (Requires clean input)
#define VL_SIGN_I(nbits,lhs) ((lhs) >> VL_BITBIT_I((nbits) - VL_UL(1)))
#define VL_SIGN_Q(nbits,lhs) ((lhs) >> VL_BITBIT_Q((nbits) - VL_ULL(1)))
#define VL_SIGN_W(nbits,rwp) ((rwp)[VL_BITWORD_I((nbits)-VL_UL(1))] >> VL_BITBIT_I((nbits)-VL_UL(1)))
#define VL_SIGNONES_I(nbits,lhs) (-(VL_SIGN_I(nbits,lhs)))
// Sign bit extended up to MSB, doesn't include unsigned portion
@@ -504,17 +505,28 @@ static inline WDataOutP _VL_CLEAN_INPLACE_W(int obits, WDataOutP owp) {
}
static inline WDataOutP VL_CLEAN_WW(int obits, int, WDataOutP owp, WDataInP lwp){
int words = VL_WORDS_I(obits);
for (int i=0; (i < (words-1)); i++) owp[i] = lwp[i];
for (int i=0; (i < (words-1)); ++i) owp[i] = lwp[i];
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
return(owp);
}
static inline WDataOutP VL_ZERO_W(int obits, WDataOutP owp) {
int words = VL_WORDS_I(obits);
for (int i=0; i < words; ++i) owp[i] = 0;
return owp;
}
static inline WDataOutP VL_ALLONES_W(int obits, WDataOutP owp) {
int words = VL_WORDS_I(obits);
for (int i=0; (i < (words-1)); ++i) owp[i] = ~VL_UL(0);
owp[words-1] = VL_MASK_I(obits);
return owp;
}
// EMIT_RULE: VL_ASSIGN: oclean=rclean; obits==lbits;
// For now, we always have a clean rhs.
// Note: If a ASSIGN isn't clean, use VL_ASSIGNCLEAN instead to do the same thing.
static inline WDataOutP VL_ASSIGN_W(int obits, WDataOutP owp,WDataInP lwp){
static inline WDataOutP VL_ASSIGN_W(int obits, WDataOutP owp, WDataInP lwp) {
int words = VL_WORDS_I(obits);
for (int i=0; i < words; i++) owp[i] = lwp[i];
for (int i=0; i < words; ++i) owp[i] = lwp[i];
return(owp);
}
@@ -575,7 +587,7 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) {
}
#define VL_ASSIGN_WSW(obits,owp,svar) { \
int words = VL_WORDS_I(obits); \
for (int i=0; i < words; i++) owp[i] = svar.read().get_word(i); \
for (int i=0; i < words; ++i) owp[i] = svar.read().get_word(i); \
owp[words-1] &= VL_MASK_I(obits); \
}
@@ -584,7 +596,7 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) {
#define VL_ASSIGN_WSB(obits,owp,svar) { \
int words = VL_WORDS_I(obits); \
sc_biguint<obits> _butemp = (svar).read(); \
for (int i=0; i < words; i++) { \
for (int i=0; i < words; ++i) { \
int msb = ((i+1)*VL_WORDSIZE) - 1; \
msb = (msb >= obits) ? (obits-1) : msb; \
owp[i] = _butemp.range(msb,i*VL_WORDSIZE).to_uint(); \
@@ -611,7 +623,7 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) {
}
#define VL_ASSIGN_SWW(obits,svar,rwp) { \
sc_bv<obits> _bvtemp; \
for (int i=0; i < VL_WORDS_I(obits); i++) _bvtemp.set_word(i,rwp[i]); \
for (int i=0; i < VL_WORDS_I(obits); ++i) _bvtemp.set_word(i,rwp[i]); \
svar.write(_bvtemp); \
}
@@ -621,7 +633,7 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) {
#define VL_ASSIGN_SBQ(obits,svar,rd) { (svar).write(rd); }
#define VL_ASSIGN_SBW(obits,svar,rwp) { \
sc_biguint<obits> _butemp; \
for (int i=0; i < VL_WORDS_I(obits); i++) { \
for (int i=0; i < VL_WORDS_I(obits); ++i) { \
int msb = ((i+1)*VL_WORDSIZE) - 1; \
msb = (msb >= obits) ? (obits-1) : msb; \
_butemp.range(msb,i*VL_WORDSIZE) = rwp[i]; \
@@ -643,17 +655,17 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) {
static inline WDataOutP VL_EXTEND_WI(int obits, int, WDataOutP owp, IData ld) {
// Note for extracts that obits != lbits
owp[0] = ld;
for (int i=1; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
return(owp);
}
static inline WDataOutP VL_EXTEND_WQ(int obits, int, WDataOutP owp, QData ld) {
VL_SET_WQ(owp,ld);
for (int i=2; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
return(owp);
}
static inline WDataOutP VL_EXTEND_WW(int obits, int lbits, WDataOutP owp, WDataInP lwp) {
for (int i=0; i < VL_WORDS_I(lbits); i++) owp[i] = lwp[i];
for (int i=VL_WORDS_I(lbits); i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i < VL_WORDS_I(lbits); ++i) owp[i] = lwp[i];
for (int i=VL_WORDS_I(lbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
return(owp);
}
@@ -672,22 +684,22 @@ static inline QData VL_EXTENDS_QQ(int, int lbits, QData lhs) {
static inline WDataOutP VL_EXTENDS_WI(int obits, int lbits, WDataOutP owp, IData ld) {
IData sign = VL_SIGNONES_I(lbits,ld);
owp[0] = ld | (sign & ~VL_MASK_I(lbits));
for (int i=1; i < VL_WORDS_I(obits); i++) owp[i] = sign;
for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = sign;
return(owp);
}
static inline WDataOutP VL_EXTENDS_WQ(int obits, int lbits, WDataOutP owp, QData ld) {
VL_SET_WQ(owp,ld);
IData sign = VL_SIGNONES_I(lbits,owp[1]);
owp[1] |= sign & ~VL_MASK_I(lbits);
for (int i=2; i < VL_WORDS_I(obits); i++) owp[i] = sign;
for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = sign;
return(owp);
}
static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp, WDataInP lwp) {
for (int i=0; i < VL_WORDS_I(lbits)-1; i++) owp[i] = lwp[i];
for (int i=0; i < VL_WORDS_I(lbits)-1; ++i) owp[i] = lwp[i];
int lmsw=VL_WORDS_I(lbits)-1;
IData sign = VL_SIGNONES_I(lbits,lwp[lmsw]);
owp[lmsw] = lwp[lmsw] | (sign & ~VL_MASK_I(lbits));
for (int i=VL_WORDS_I(lbits); i < VL_WORDS_I(obits); i++) owp[i] = sign;
for (int i=VL_WORDS_I(lbits); i < VL_WORDS_I(obits); ++i) owp[i] = sign;
return(owp);
}
@@ -700,7 +712,7 @@ static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp, WData
static inline IData VL_REDAND_IW(int, int lbits, WDataInP lwp) {
int words = VL_WORDS_I(lbits);
IData combine=lwp[0];
for (int i=1; i < words-1; i++) combine &= lwp[i];
for (int i=1; i < words-1; ++i) combine &= lwp[i];
combine &= ~VL_MASK_I(lbits) | lwp[words-1];
return ((~combine)==0);
}
@@ -710,7 +722,7 @@ static inline IData VL_REDAND_IW(int, int lbits, WDataInP lwp) {
#define VL_REDOR_Q(lhs) (lhs!=0)
static inline IData VL_REDOR_W(int words, WDataInP lwp) {
IData equal=0;
for (int i=0; i < words; i++) equal |= lwp[i];
for (int i=0; i < words; ++i) equal |= lwp[i];
return(equal!=0);
}
@@ -762,7 +774,7 @@ static inline IData VL_REDXOR_64(QData r) {
}
static inline IData VL_REDXOR_W(int words, WDataInP lwp) {
IData r = lwp[0];
for (int i=1; i < words; i++) r ^= lwp[i];
for (int i=1; i < words; ++i) r ^= lwp[i];
return VL_REDXOR_32(r);
}
@@ -780,7 +792,7 @@ static inline IData VL_COUNTONES_Q(QData lhs) {
}
static inline IData VL_COUNTONES_W(int words, WDataInP lwp) {
IData r = 0;
for (int i=0; (i < words); i++) r+=VL_COUNTONES_I(lwp[i]);
for (int i=0; (i < words); ++i) r+=VL_COUNTONES_I(lwp[i]);
return r;
}
@@ -792,7 +804,7 @@ static inline IData VL_ONEHOT_Q(QData lhs) {
}
static inline IData VL_ONEHOT_W(int words, WDataInP lwp) {
IData one=0;
for (int i=0; (i < words); i++) {
for (int i=0; (i < words); ++i) {
if (lwp[i]) {
if (one) return 0;
one = 1;
@@ -810,7 +822,7 @@ static inline IData VL_ONEHOT0_Q(QData lhs) {
}
static inline IData VL_ONEHOT0_W(int words, WDataInP lwp) {
bool one=false;
for (int i=0; (i < words); i++) {
for (int i=0; (i < words); ++i) {
if (lwp[i]) {
if (one) return 0;
one = true;
@@ -825,21 +837,21 @@ static inline IData VL_CLOG2_I(IData lhs) {
if (VL_UNLIKELY(!lhs)) return 0;
lhs--;
int shifts=0;
for (; lhs!=0; shifts++) lhs = lhs >> 1;
for (; lhs!=0; ++shifts) lhs = lhs >> 1;
return shifts;
}
static inline IData VL_CLOG2_Q(QData lhs) {
if (VL_UNLIKELY(!lhs)) return 0;
lhs--;
int shifts=0;
for (; lhs!=0; shifts++) lhs = lhs >> VL_ULL(1);
for (; lhs!=0; ++shifts) lhs = lhs >> VL_ULL(1);
return shifts;
}
static inline IData VL_CLOG2_W(int words, WDataInP lwp) {
IData adjust = (VL_COUNTONES_W(words,lwp)==1) ? 0 : 1;
for (int i=words-1; i>=0; i--) {
for (int i=words-1; i>=0; --i) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
for (int bit=31; bit>=0; bit--) {
for (int bit=31; bit>=0; --bit) {
if (VL_UNLIKELY(VL_BITISSET_I(lwp[i],bit))) {
return i*VL_WORDSIZE + bit + adjust;
}
@@ -852,9 +864,9 @@ static inline IData VL_CLOG2_W(int words, WDataInP lwp) {
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) {
// MSB set bit plus one; similar to FLS. 0=value is zero
for (int i=words-1; i>=0; i--) {
for (int i=words-1; i>=0; --i) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
for (int bit=31; bit>=0; bit--) {
for (int bit=31; bit>=0; --bit) {
if (VL_UNLIKELY(VL_BITISSET_I(lwp[i],bit))) {
return i*VL_WORDSIZE + bit + 1;
}
@@ -870,33 +882,33 @@ static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) {
// EMIT_RULE: VL_AND: oclean=lclean||rclean; obits=lbits; lbits==rbits;
static inline WDataOutP VL_AND_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
for (int i=0; (i < words); i++) owp[i] = (lwp[i] & rwp[i]);
for (int i=0; (i < words); ++i) owp[i] = (lwp[i] & rwp[i]);
return(owp);
}
// EMIT_RULE: VL_OR: oclean=lclean&&rclean; obits=lbits; lbits==rbits;
static inline WDataOutP VL_OR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
for (int i=0; (i < words); i++) owp[i] = (lwp[i] | rwp[i]);
for (int i=0; (i < words); ++i) owp[i] = (lwp[i] | rwp[i]);
return(owp);
}
// EMIT_RULE: VL_CHANGEXOR: oclean=1; obits=32; lbits==rbits;
static inline IData VL_CHANGEXOR_W(int words, WDataInP lwp,WDataInP rwp){
IData od = 0;
for (int i=0; (i < words); i++) od |= (lwp[i] ^ rwp[i]);
for (int i=0; (i < words); ++i) od |= (lwp[i] ^ rwp[i]);
return(od);
}
// EMIT_RULE: VL_XOR: oclean=lclean&&rclean; obits=lbits; lbits==rbits;
static inline WDataOutP VL_XOR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
for (int i=0; (i < words); i++) owp[i] = (lwp[i] ^ rwp[i]);
for (int i=0; (i < words); ++i) owp[i] = (lwp[i] ^ rwp[i]);
return(owp);
}
// EMIT_RULE: VL_XNOR: oclean=dirty; obits=lbits; lbits==rbits;
static inline WDataOutP VL_XNOR_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
for (int i=0; (i < words); i++) owp[i] = (lwp[i] ^ ~rwp[i]);
for (int i=0; (i < words); ++i) owp[i] = (lwp[i] ^ ~rwp[i]);
return(owp);
}
// EMIT_RULE: VL_NOT: oclean=dirty; obits=lbits;
static inline WDataOutP VL_NOT_W(int words, WDataOutP owp,WDataInP lwp) {
for (int i=0; i < words; i++) owp[i] = ~(lwp[i]);
for (int i=0; i < words; ++i) owp[i] = ~(lwp[i]);
return(owp);
}
@@ -918,7 +930,7 @@ static inline WDataOutP VL_NOT_W(int words, WDataOutP owp,WDataInP lwp) {
// Output clean, <lhs> AND <rhs> MUST BE CLEAN
static inline IData VL_EQ_W(int words, WDataInP lwp, WDataInP rwp) {
int nequal=0;
for (int i=0; (i < words); i++) nequal |= (lwp[i] ^ rwp[i]);
for (int i=0; (i < words); ++i) nequal |= (lwp[i] ^ rwp[i]);
return(nequal==0);
}
@@ -1012,7 +1024,7 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) {
static inline WDataOutP VL_ADD_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
QData carry = 0;
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
carry = carry + (QData)(lwp[i]) + (QData)(rwp[i]);
owp[i] = (carry & VL_ULL(0xffffffff));
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
@@ -1022,7 +1034,7 @@ static inline WDataOutP VL_ADD_W(int words, WDataOutP owp,WDataInP lwp,WDataInP
static inline WDataOutP VL_SUB_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
QData carry = 0;
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
carry = carry + (QData)(lwp[i]) + (QData)(IData)(~rwp[i]);
if (i==0) carry++; // Negation of temp2
owp[i] = (carry & VL_ULL(0xffffffff));
@@ -1039,7 +1051,7 @@ static inline QData VL_NEGATE_Q(QData data) { return -data; }
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp,WDataInP lwp){
QData carry = 0;
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
carry = carry + (QData)(IData)(~lwp[i]);
if (i==0) carry++; // Negation of temp2
owp[i] = (carry & VL_ULL(0xffffffff));
@@ -1049,11 +1061,11 @@ static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp,WDataInP lwp){
}
static inline WDataOutP VL_MUL_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
for (int i=0; i<words; i++) owp[i] = 0;
for (int lword=0; lword<words; lword++) {
for (int rword=0; rword<words; rword++) {
for (int i=0; i<words; ++i) owp[i] = 0;
for (int lword=0; lword<words; ++lword) {
for (int rword=0; rword<words; ++rword) {
QData mul = (QData)(lwp[lword]) * (QData)(rwp[rword]);
for (int qword=lword+rword; qword<words; qword++) {
for (int qword=lword+rword; qword<words; ++qword) {
mul += (QData)(owp[qword]);
owp[qword] = (mul & VL_ULL(0xffffffff));
mul = (mul >> VL_ULL(32)) & VL_ULL(0xffffffff);
@@ -1077,8 +1089,10 @@ static inline QData VL_MULS_QQQ(int,int lbits,int, QData lhs,QData rhs) {
static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lwp,WDataInP rwp){
int words = VL_WORDS_I(lbits);
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
IData rwstore[VL_MULS_MAX_WORDS];
// cppcheck-suppress variableScope
WData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
// cppcheck-suppress variableScope
WData rwstore[VL_MULS_MAX_WORDS];
WDataInP lwusp = lwp;
WDataInP rwusp = rwp;
IData lneg = VL_SIGN_I(lbits,lwp[words-1]);
@@ -1097,7 +1111,7 @@ static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lw
owp[words-1] &= VL_MASK_I(lbits); // Clean. Note it's ok for the multiply to overflow into the sign bit
if ((lneg ^ rneg) & 1) { // Negate output (not using NEGATE, as owp==lwp)
QData carry = 0;
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
carry = carry + (QData)(IData)(~owp[i]);
if (i==0) carry++; // Negation of temp2
owp[i] = (carry & VL_ULL(0xffffffff));
@@ -1139,9 +1153,9 @@ static inline WDataOutP VL_DIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDataI
IData lsign = VL_SIGN_I(lbits,lwp[words-1]);
IData rsign = VL_SIGN_I(lbits,rwp[words-1]);
// cppcheck-suppress variableScope
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
WData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
// cppcheck-suppress variableScope
IData rwstore[VL_MULS_MAX_WORDS];
WData rwstore[VL_MULS_MAX_WORDS];
WDataInP ltup = lwp;
WDataInP rtup = rwp;
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); }
@@ -1160,15 +1174,15 @@ static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDa
IData lsign = VL_SIGN_I(lbits,lwp[words-1]);
IData rsign = VL_SIGN_I(lbits,rwp[words-1]);
// cppcheck-suppress variableScope
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
WData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
// cppcheck-suppress variableScope
IData rwstore[VL_MULS_MAX_WORDS];
WData rwstore[VL_MULS_MAX_WORDS];
WDataInP ltup = lwp;
WDataInP rtup = rwp;
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); }
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
if (lsign) { // Only dividend sign matters for modulus
IData qNoSign[VL_MULS_MAX_WORDS];
WData qNoSign[VL_MULS_MAX_WORDS];
VL_MODDIV_WWW(lbits,qNoSign,ltup,rtup);
_VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), owp, qNoSign));
return owp;
@@ -1177,14 +1191,17 @@ static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDa
}
}
#define VL_POW_IIQ(obits,lbits,rbits,lhs,rhs) VL_POW_QQQ(obits,lbits,rbits,lhs,rhs)
#define VL_POW_IIW(obits,lbits,rbits,lhs,rwp) VL_POW_QQW(obits,lbits,rbits,lhs,rwp)
#define VL_POW_QQI(obits,lbits,rbits,lhs,rhs) VL_POW_QQQ(obits,lbits,rbits,lhs,rhs)
#define VL_POW_WWI(obits,lbits,rbits,owp,lwp,rhs) VL_POW_WWQ(obits,lbits,rbits,owp,lwp,rhs)
static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) {
if (VL_UNLIKELY(rhs==0)) return 1;
if (VL_UNLIKELY(lhs==0)) return 0;
IData power = lhs;
IData out = 1;
for (int i=0; i<rbits; i++) {
for (int i=0; i<rbits; ++i) {
if (i>0) power = power*power;
if (rhs & (VL_ULL(1)<<i)) out *= power;
}
@@ -1195,42 +1212,51 @@ static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) {
if (VL_UNLIKELY(lhs==0)) return 0;
QData power = lhs;
QData out = VL_ULL(1);
for (int i=0; i<rbits; i++) {
for (int i=0; i<rbits; ++i) {
if (i>0) power = power*power;
if (rhs & (VL_ULL(1)<<i)) out *= power;
}
return out;
}
WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp);
WDataOutP VL_POW_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, QData rhs);
QData VL_POW_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp);
#define VL_POWSS_IIQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
#define VL_POWSS_IIQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
#define VL_POWSS_IIW(obits,lbits,rbits,lhs,rwp,lsign,rsign) VL_POWSS_QQW(obits,lbits,rbits,lhs,rwp,lsign,rsign)
#define VL_POWSS_QQI(obits,lbits,rbits,lhs,rhs,lsign,rsign) VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
#define VL_POWSS_WWI(obits,lbits,rbits,owp,lwp,rhs,lsign,rsign) VL_POWSS_WWQ(obits,lbits,rbits,owp,lwp,rhs,lsign,rsign)
static inline IData VL_POWSS_III(int obits, int, int rbits, IData lhs, IData rhs, bool lsign, bool rsign) {
if (VL_UNLIKELY(rhs==0)) return 1;
if (rsign && VL_SIGN_I(rbits, rhs)) {
if (lhs==0) return 0; // "X"
else if (lhs==1) return 1;
else if (lsign && lhs==VL_MASK_I(obits)) { //-1
else if (lsign && lhs==VL_MASK_I(obits)) { // -1
if (rhs & 1) return VL_MASK_I(obits); // -1^odd=-1
else return 1; // -1^even=1
}
return 0;
}
return VL_POW_III(obits, obits, rbits, lhs, rhs);
return VL_POW_III(obits, rbits, rbits, lhs, rhs);
}
static inline QData VL_POWSS_QQQ(int obits, int, int rbits, QData lhs, QData rhs, bool lsign, bool rsign) {
if (VL_UNLIKELY(rhs==0)) return 1;
if (rsign && VL_SIGN_I(rbits, rhs)) {
if (lhs==0) return 0; // "X"
else if (lhs==1) return 1;
else if (lsign && lhs==VL_MASK_I(obits)) { //-1
else if (lsign && lhs==VL_MASK_I(obits)) { // -1
if (rhs & 1) return VL_MASK_I(obits); // -1^odd=-1
else return 1; // -1^even=1
}
return 0;
}
return VL_POW_QQQ(obits, obits, rbits, lhs, rhs);
return VL_POW_QQQ(obits, rbits, rbits, lhs, rhs);
}
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign);
WDataOutP VL_POWSS_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, QData rhs, bool lsign, bool rsign);
QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsign, bool rsign);
//===================================================================
// Concat/replication
@@ -1285,13 +1311,13 @@ static inline void _VL_INSERT_WW(int, WDataOutP owp, WDataInP lwp, int hbit, int
int words = VL_WORDS_I(hbit-lbit+1);
if (hoffset==VL_SIZEBITS_I && loffset==0) {
// Fast and common case, word based insertion
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
owp[lword+i] = lwp[i];
}
}
else if (loffset==0) {
// Non-32bit, but nicely aligned, so stuff all but the last word
for (int i=0; i<(words-1); i++) {
for (int i=0; i<(words-1); ++i) {
owp[lword+i] = lwp[i];
}
IData hinsmask = (VL_MASK_I(hoffset-0+1)); // Know it's not a full word as above fast case handled it
@@ -1303,7 +1329,7 @@ static inline void _VL_INSERT_WW(int, WDataOutP owp, WDataInP lwp, int hbit, int
int nbitsonright = 32-loffset; // bits that end up in lword (know loffset!=0)
// Middle words
int hword = VL_BITWORD_I(hbit);
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
{ // Lower word
int oword = lword+i;
IData d = lwp[i]<<loffset;
@@ -1336,7 +1362,7 @@ static inline void _VL_INSERT_WQ(int obits, WDataOutP owp, QData ld, int hbit, i
static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) {
IData returndata = ld;
for (unsigned i=1; i < rep; i++){
for (unsigned i=1; i < rep; ++i){
returndata = returndata << lbits;
returndata |= ld;
}
@@ -1344,7 +1370,7 @@ static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) {
}
static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) {
QData returndata = ld;
for (unsigned i=1; i < rep; i++){
for (unsigned i=1; i < rep; ++i){
returndata = returndata << lbits;
returndata |= (QData)ld;
}
@@ -1352,21 +1378,21 @@ static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) {
}
static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int, WDataOutP owp, IData ld, IData rep) {
owp[0] = ld;
for (unsigned i=1; i < rep; i++){
for (unsigned i=1; i < rep; ++i){
_VL_INSERT_WI(obits,owp,ld,i*lbits+lbits-1,i*lbits);
}
return(owp);
}
static inline WDataOutP VL_REPLICATE_WQI(int obits, int lbits, int, WDataOutP owp, QData ld, IData rep) {
VL_SET_WQ(owp,ld);
for (unsigned i=1; i < rep; i++){
for (unsigned i=1; i < rep; ++i){
_VL_INSERT_WQ(obits,owp,ld,i*lbits+lbits-1,i*lbits);
}
return(owp);
}
static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP owp, WDataInP lwp, IData rep) {
for (int i=0; i < VL_WORDS_I(lbits); i++) owp[i] = lwp[i];
for (unsigned i=1; i < rep; i++){
for (int i=0; i < VL_WORDS_I(lbits); ++i) owp[i] = lwp[i];
for (unsigned i=1; i < rep; ++i){
_VL_INSERT_WW(obits,owp,lwp,i*lbits+lbits-1,i*lbits);
}
return(owp);
@@ -1470,13 +1496,13 @@ static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) {
}
static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WDataInP lwp, IData rd) {
VL_ZERO_RESET_W(lbits, owp);
VL_ZERO_W(lbits, owp);
// Slice size should never exceed the lhs width
int ssize = (rd < (IData)lbits) ? rd : ((IData)lbits);
for (int istart=0; istart<lbits; istart+=rd) {
int ostart=lbits-rd-istart;
ostart = ostart > 0 ? ostart : 0;
for (int sbit=0; sbit<ssize && sbit<lbits-istart; sbit++) {
for (int sbit=0; sbit<ssize && sbit<lbits-istart; ++sbit) {
// Extract a single bit from lwp and shift it to the correct
// location for owp.
WData bit= ((lwp[VL_BITWORD_I(istart+sbit)] >> VL_BITBIT_I(istart+sbit)) & 1) << VL_BITBIT_I(ostart+sbit);
@@ -1498,55 +1524,55 @@ static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WData
static inline WDataOutP VL_CONCAT_WII(int obits,int lbits,int rbits,WDataOutP owp,IData ld,IData rd) {
owp[0] = rd;
for (int i=1; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits);
return(owp);
}
static inline WDataOutP VL_CONCAT_WWI(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, IData rd) {
owp[0] = rd;
for (int i=1; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits);
return(owp);
}
static inline WDataOutP VL_CONCAT_WIW(int obits,int lbits,int rbits,WDataOutP owp,IData ld, WDataInP rwp) {
for (int i=0; i < VL_WORDS_I(rbits); i++) owp[i] = rwp[i];
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits);
return(owp);
}
static inline WDataOutP VL_CONCAT_WIQ(int obits,int lbits,int rbits,WDataOutP owp,IData ld,QData rd) {
VL_SET_WQ(owp,rd);
for (int i=2; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WI(obits,owp,ld,rbits+lbits-1,rbits);
return(owp);
}
static inline WDataOutP VL_CONCAT_WQI(int obits,int lbits,int rbits,WDataOutP owp,QData ld,IData rd) {
owp[0] = rd;
for (int i=1; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits);
return(owp);
}
static inline WDataOutP VL_CONCAT_WQQ(int obits,int lbits,int rbits,WDataOutP owp,QData ld,QData rd) {
VL_SET_WQ(owp,rd);
for (int i=2; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits);
return(owp);
}
static inline WDataOutP VL_CONCAT_WWQ(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, QData rd) {
VL_SET_WQ(owp,rd);
for (int i=2; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=2; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits);
return(owp);
}
static inline WDataOutP VL_CONCAT_WQW(int obits,int lbits,int rbits,WDataOutP owp,QData ld, WDataInP rwp) {
for (int i=0; i < VL_WORDS_I(rbits); i++) owp[i] = rwp[i];
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WQ(obits,owp,ld,rbits+lbits-1,rbits);
return(owp);
}
static inline WDataOutP VL_CONCAT_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) {
for (int i=0; i < VL_WORDS_I(rbits); i++) owp[i] = rwp[i];
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i=VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WW(obits,owp,lwp,rbits+lbits-1,rbits);
return(owp);
}
@@ -1559,7 +1585,7 @@ static inline WDataOutP VL_CONCAT_WWW(int obits,int lbits,int rbits,WDataOutP ow
static inline void _VL_SHIFTL_INPLACE_W(int obits,WDataOutP iowp,IData rd/*1 or 4*/) {
int words = VL_WORDS_I(obits);
IData linsmask = VL_MASK_I(rd);
for (int i=words-1; i>=1; i--) {
for (int i=words-1; i>=1; --i) {
iowp[i] = ((iowp[i]<<rd) & ~linsmask) | ((iowp[i-1] >> (32-rd)) & linsmask);
}
iowp[0] = ((iowp[0]<<rd) & ~linsmask);
@@ -1573,16 +1599,32 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP l
int word_shift = VL_BITWORD_I(rd);
int bit_shift = VL_BITBIT_I(rd);
if (rd >= (IData)obits) { // rd may be huge with MSB set
for (int i=0; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
} else if (bit_shift==0) { // Aligned word shift (<<0,<<32,<<64 etc)
for (int i=0; i < word_shift; i++) owp[i] = 0;
for (int i=word_shift; i < VL_WORDS_I(obits); i++) owp[i] = lwp[i-word_shift];
for (int i=0; i < word_shift; ++i) owp[i] = 0;
for (int i=word_shift; i < VL_WORDS_I(obits); ++i) owp[i] = lwp[i-word_shift];
} else {
for (int i=0; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_VL_INSERT_WW(obits,owp,lwp,obits-1,rd);
}
return(owp);
}
static inline WDataOutP VL_SHIFTL_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) {
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
return VL_ZERO_W(obits, owp);
}
}
return VL_SHIFTL_WWI(obits,lbits,32,owp,lwp,rwp[0]);
}
static inline IData VL_SHIFTL_IIW(int obits,int,int rbits,IData lhs, WDataInP rwp) {
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
return 0;
}
}
return VL_CLEAN_II(obits,obits,lhs<<rwp[0]);
}
// EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean;
// Important: Unlike most other funcs, the shift might well be a computed
@@ -1591,27 +1633,43 @@ static inline WDataOutP VL_SHIFTR_WWI(int obits,int,int,WDataOutP owp,WDataInP l
int word_shift = VL_BITWORD_I(rd); // Maybe 0
int bit_shift = VL_BITBIT_I(rd);
if (rd >= (IData)obits) { // rd may be huge with MSB set
for (int i=0; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
} else if (bit_shift==0) { // Aligned word shift (>>0,>>32,>>64 etc)
int copy_words = (VL_WORDS_I(obits)-word_shift);
for (int i=0; i < copy_words; i++) owp[i] = lwp[i+word_shift];
for (int i=copy_words; i < VL_WORDS_I(obits); i++) owp[i] = 0;
for (int i=0; i < copy_words; ++i) owp[i] = lwp[i+word_shift];
for (int i=copy_words; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
} else {
int loffset = rd & VL_SIZEBITS_I;
int nbitsonright = 32-loffset; // bits that end up in lword (know loffset!=0)
// Middle words
int words = VL_WORDS_I(obits-rd);
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
owp[i] = lwp[i+word_shift]>>loffset;
int upperword = i+word_shift+1;
if (upperword < VL_WORDS_I(obits)) {
owp[i] |= lwp[upperword]<< nbitsonright;
}
}
for (int i=words; i<VL_WORDS_I(obits); i++) owp[i]=0;
for (int i=words; i<VL_WORDS_I(obits); ++i) owp[i]=0;
}
return(owp);
}
static inline WDataOutP VL_SHIFTR_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) {
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
return VL_ZERO_W(obits, owp);
}
}
return VL_SHIFTR_WWI(obits,lbits,32,owp,lwp,rwp[0]);
}
static inline IData VL_SHIFTR_IIW(int obits,int,int rbits,IData lhs, WDataInP rwp) {
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
return 0;
}
}
return VL_CLEAN_II(obits,obits,lhs>>rwp[0]);
}
// EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean;
static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData rhs) {
@@ -1637,20 +1695,20 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa
int lmsw = VL_WORDS_I(obits)-1;
IData sign = VL_SIGNONES_I(lbits,lwp[lmsw]);
if (rd >= (IData)obits) { // Shifting past end, sign in all of lbits
for (int i=0; i <= lmsw; i++) owp[i] = sign;
for (int i=0; i <= lmsw; ++i) owp[i] = sign;
owp[lmsw] &= VL_MASK_I(lbits);
} else if (bit_shift==0) { // Aligned word shift (>>0,>>32,>>64 etc)
int copy_words = (VL_WORDS_I(obits)-word_shift);
for (int i=0; i < copy_words; i++) owp[i] = lwp[i+word_shift];
for (int i=0; i < copy_words; ++i) owp[i] = lwp[i+word_shift];
if (copy_words>=0) owp[copy_words-1] |= ~VL_MASK_I(obits) & sign;
for (int i=copy_words; i < VL_WORDS_I(obits); i++) owp[i] = sign;
for (int i=copy_words; i < VL_WORDS_I(obits); ++i) owp[i] = sign;
owp[lmsw] &= VL_MASK_I(lbits);
} else {
int loffset = rd & VL_SIZEBITS_I;
int nbitsonright = 32-loffset; // bits that end up in lword (know loffset!=0)
// Middle words
int words = VL_WORDS_I(obits-rd);
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
owp[i] = lwp[i+word_shift]>>loffset;
int upperword = i+word_shift+1;
if (upperword < VL_WORDS_I(obits)) {
@@ -1658,11 +1716,49 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa
}
}
if (words) owp[words-1] |= sign & ~VL_MASK_I(obits-loffset);
for (int i=words; i<VL_WORDS_I(obits); i++) owp[i] = sign;
for (int i=words; i<VL_WORDS_I(obits); ++i) owp[i] = sign;
owp[lmsw] &= VL_MASK_I(lbits);
}
return(owp);
}
static inline WDataOutP VL_SHIFTRS_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) {
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
int lmsw = VL_WORDS_I(obits)-1;
IData sign = VL_SIGNONES_I(lbits,lwp[lmsw]);
for (int i=0; i <= lmsw; ++i) owp[i] = sign;
owp[lmsw] &= VL_MASK_I(lbits);
return owp;
}
}
return VL_SHIFTRS_WWI(obits,lbits,32,owp,lwp,rwp[0]);
}
static inline IData VL_SHIFTRS_IIW(int obits,int lbits,int rbits,IData lhs, WDataInP rwp) {
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
IData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative
return VL_CLEAN_II(obits,obits,sign);
}
}
return VL_SHIFTRS_III(obits,lbits,32,lhs,rwp[0]);
}
static inline QData VL_SHIFTRS_QQW(int obits,int lbits,int rbits,QData lhs, WDataInP rwp) {
for (int i=1; i < VL_WORDS_I(rbits); ++i) {
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
QData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative
return VL_CLEAN_QQ(obits,obits,sign);
}
}
return VL_SHIFTRS_QQI(obits,lbits,32,lhs,rwp[0]);
}
static inline IData VL_SHIFTRS_IIQ(int obits,int lbits,int rbits,IData lhs, QData rhs) {
WData rwp[2]; VL_SET_WQ(rwp,rhs);
return VL_SHIFTRS_IIW(obits,lbits,rbits,lhs,rwp);
}
static inline QData VL_SHIFTRS_QQQ(int obits,int lbits,int rbits,QData lhs, QData rhs) {
WData rwp[2]; VL_SET_WQ(rwp,rhs);
return VL_SHIFTRS_QQW(obits,lbits,rbits,lhs,rwp);
}
//===================================================================
// Bit selection
@@ -1728,25 +1824,25 @@ static inline WDataOutP VL_SEL_WWII(int obits,int lbits,int,int,WDataOutP owp,WD
int msb = lsb+width-1;
int word_shift = VL_BITWORD_I(lsb);
if (VL_UNLIKELY(msb>lbits)) { // Outside bounds,
for (int i=0; i<VL_WORDS_I(obits)-1; i++) owp[i] = ~0;
for (int i=0; i<VL_WORDS_I(obits)-1; ++i) owp[i] = ~0;
owp[VL_WORDS_I(obits)-1] = VL_MASK_I(obits);
} else if (VL_BITBIT_I(lsb)==0) {
// Just a word extract
for (int i=0; i<VL_WORDS_I(obits); i++) owp[i] = lwp[i+word_shift];
for (int i=0; i<VL_WORDS_I(obits); ++i) owp[i] = lwp[i+word_shift];
} else {
// Not a _VL_INSERT because the bits come from any bit number and goto bit 0
int loffset = lsb & VL_SIZEBITS_I;
int nbitsfromlow = 32-loffset; // bits that end up in lword (know loffset!=0)
// Middle words
int words = VL_WORDS_I(msb-lsb+1);
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
owp[i] = lwp[i+word_shift]>>loffset;
int upperword = i+word_shift+1;
if (upperword <= (int)VL_BITWORD_I(msb)) {
owp[i] |= lwp[upperword]<< nbitsfromlow;
}
}
for (int i=words; i<VL_WORDS_I(obits); i++) owp[i]=0;
for (int i=words; i<VL_WORDS_I(obits); ++i) owp[i]=0;
}
return owp;
}
@@ -1791,30 +1887,10 @@ static inline void VL_ASSIGNSEL_WIIW(int obits, int lsb, WDataOutP owp, WDataInP
static inline WDataOutP VL_COND_WIWW(int obits, int, int, int,
WDataOutP owp, int cond, WDataInP w1p, WDataInP w2p) {
int words = VL_WORDS_I(obits);
for (int i=0; i < words; i++) owp[i] = cond ? w1p[i] : w2p[i];
for (int i=0; i < words; ++i) owp[i] = cond ? w1p[i] : w2p[i];
return(owp);
}
//======================================================================
// System Functions
inline IData VL_VALUEPLUSARGS_IQ(int rbits, const char* prefixp, char fmt, QData& ldr) {
WData wd[2]; IData v=VL_VALUEPLUSARGS_IW(rbits,prefixp,fmt,wd); if (v) ldr=VL_SET_QW(wd);
return v;
}
inline IData VL_VALUEPLUSARGS_II(int rbits, const char* prefixp, char fmt, CData& ldr) {
QData qd; IData v=VL_VALUEPLUSARGS_IQ(rbits,prefixp,fmt,qd); if (v) ldr=(CData)qd;
return v;
}
inline IData VL_VALUEPLUSARGS_II(int rbits, const char* prefixp, char fmt, SData& ldr) {
QData qd; IData v=VL_VALUEPLUSARGS_IQ(rbits,prefixp,fmt,qd); if (v) ldr=(SData)qd;
return v;
}
inline IData VL_VALUEPLUSARGS_II(int rbits, const char* prefixp, char fmt, IData& ldr) {
QData qd; IData v=VL_VALUEPLUSARGS_IQ(rbits,prefixp,fmt,qd); if (v) ldr=(IData)qd;
return v;
}
//======================================================================
// Constification
@@ -1824,7 +1900,7 @@ inline IData VL_VALUEPLUSARGS_II(int rbits, const char* prefixp, char fmt, IData
// If changing the number of functions here, also change EMITCINLINES_NUM_CONSTW
#define _END(obits,wordsSet) \
for(int i=(wordsSet);i<VL_WORDS_I(obits);i++) o[i] = (IData)0x0; \
for(int i=(wordsSet);i<VL_WORDS_I(obits);++i) o[i] = (IData)0x0; \
return o
#define VL_HAVE_CONST_W_1X
+4 -19
View File
@@ -22,7 +22,6 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
######################################################################
# Programs
SP_PREPROC = sp_preproc
SP_INCLUDER = $(VERILATOR_INCLUDER)
VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage
VERILATOR_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
@@ -93,9 +92,9 @@ VM_CLASSES += $(VM_CLASSES_FAST) $(VM_CLASSES_SLOW)
VM_SUPPORT += $(VM_SUPPORT_FAST) $(VM_SUPPORT_SLOW)
#######################################################################
##### SystemC or SystemPerl builds
##### SystemC builds
ifeq ($(VM_SP_OR_SC),1)
ifeq ($(VM_SC),1)
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
SC_LIBS = -lsystemc
@@ -106,23 +105,9 @@ ifeq ($(VM_SP_OR_SC),1)
endif
#######################################################################
##### SystemPerl builds
##### Stub
ifeq ($(VM_SP),1)
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE) -DSYSTEMPERL
VPATH += $(SYSTEMPERL_INCLUDE)
LIBS += -lm -lstdc++
VK_CLASSES_SP = $(addsuffix .sp, $(VM_CLASSES))
# This rule is called manually by the upper level makefile
preproc:
@echo " SP Preprocess" $(basename $(VM_CLASSES)) ...
$(SP_PREPROC) -M sp_preproc.d --tree $(VM_PREFIX).sp_tree \
--preproc $(VK_CLASSES_SP)
else
preproc:
endif
preproc:
#######################################################################
##### C/H builds
+9 -8
View File
@@ -50,7 +50,7 @@ public: // But only local to this file
// CONSTRUCTORS
// Derived classes should call zero() in their constructor
VerilatedCovImpItem() {
for (int i=0; i<MAX_KEYS; i++) {
for (int i=0; i<MAX_KEYS; ++i) {
m_keys[i]=KEY_UNDEF;
m_vals[i]=0;
}
@@ -72,6 +72,7 @@ private:
T* m_countp; ///< Count value
public:
// METHODS
// cppcheck-suppress truncLongCastReturn
virtual vluint64_t count() const { return *m_countp; }
virtual void zero() const { *m_countp = 0; }
// CONSTRUCTORS
@@ -130,7 +131,7 @@ private:
string dequote(const string& text) {
// Quote any special characters
string rtn;
for (const char* pos = text.c_str(); *pos; pos++) {
for (const char* pos = text.c_str(); *pos; ++pos) {
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
char hex[10]; sprintf(hex,"%%%02X",pos[0]);
rtn += hex;
@@ -194,7 +195,7 @@ private:
return out;
}
bool itemMatchesString(VerilatedCovImpItem* itemp, const string& match) {
for (int i=0; i<MAX_KEYS; i++) {
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
// We don't compare keys, only values
string val = m_indexValues[itemp->m_vals[i]];
@@ -274,15 +275,15 @@ public:
// Keys -> strings
string keys[MAX_KEYS];
for (int i=0; i<MAX_KEYS; i++) {
for (int i=0; i<MAX_KEYS; ++i) {
if (ckeyps[i] && ckeyps[i][0]) {
keys[i] = ckeyps[i];
}
}
// Ignore empty keys
for (int i=0; i<MAX_KEYS; i++) {
for (int i=0; i<MAX_KEYS; ++i) {
if (keys[i]!="") {
for (int j=i+1; j<MAX_KEYS; j++) {
for (int j=i+1; j<MAX_KEYS; ++j) {
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
keys[i] = "";
break;
@@ -292,7 +293,7 @@ public:
}
// Insert the values
int addKeynum=0;
for (int i=0; i<MAX_KEYS; i++) {
for (int i=0; i<MAX_KEYS; ++i) {
const string key = keys[i];
if (keys[i]!="") {
const string val = valps[i];
@@ -334,7 +335,7 @@ public:
string hier;
bool per_instance = false;
for (int i=0; i<MAX_KEYS; i++) {
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
string val = m_indexValues[itemp->m_vals[i]];
+2 -2
View File
@@ -60,9 +60,9 @@ using namespace std;
///
/// vluint32_t m_cases[10];
/// constructor {
/// for (int i=0; i<10; i++) { m_cases[i]=0; }
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
/// }
/// for (int i=0; i<10; i++) {
/// for (int i=0; i<10; ++i) {
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
/// }
+10 -10
View File
@@ -58,31 +58,31 @@ const char* svDpiVersion() {
//======================================================================
// Bit-select utility functions.
svBit svGetBitselBit(const svBitVecVal* s, int i) {
_VL_SVDPI_UNIMP(); return 0;
svBit svGetBitselBit(const svBitVecVal* sp, int bit) {
return VL_BITISSET_W(sp,bit);
}
svLogic svGetBitselLogic(const svLogicVecVal* s, int i) {
svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
_VL_SVDPI_UNIMP(); return 0;
}
void svPutBitselBit(svBitVecVal* d, int i, svBit s) {
_VL_SVDPI_UNIMP();
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) {
VL_ASSIGNBIT_WI(32, bit, dp, s);
}
void svPutBitselLogic(svLogicVecVal* d, int i, svLogic s) {
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
_VL_SVDPI_UNIMP();
}
void svGetPartselBit(svBitVecVal* d, const svBitVecVal* s, int i, int w) {
void svGetPartselBit(svBitVecVal* dp, const svBitVecVal* sp, int i, int w) {
_VL_SVDPI_UNIMP();
}
void svGetPartselLogic(svLogicVecVal* d, const svLogicVecVal* s, int i, int w) {
void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int i, int w) {
_VL_SVDPI_UNIMP();
}
void svPutPartselBit(svBitVecVal* d, const svBitVecVal s, int i, int w) {
void svPutPartselBit(svBitVecVal* dp, const svBitVecVal s, int i, int w) {
_VL_SVDPI_UNIMP();
}
void svPutPartselLogic(svLogicVecVal* d, const svLogicVecVal* s, int i, int w) {
void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int i, int w) {
_VL_SVDPI_UNIMP();
}
+5 -5
View File
@@ -37,25 +37,25 @@
/// Return svBitVecVal from WData
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, svBitVecVal* lwp) {
int words = VL_WORDS_I(obits);
for (int i=0; i<words-1; i++) owp[i]=lwp[i];
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
}
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) {
int words = VL_WORDS_I(obits);
for (int i=0; i<words-1; i++) owp[i]=lwp[i];
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
}
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, svLogicVecVal* lwp) {
// Note we ignore X/Z in svLogicVecVal
int words = VL_WORDS_I(obits);
for (int i=0; i<words-1; i++) owp[i]=lwp[i].aval;
for (int i=0; i<words-1; ++i) owp[i]=lwp[i].aval;
owp[words-1] = lwp[words-1].aval & VL_MASK_I(obits);
}
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) {
// Note we don't create X/Z in svLogicVecVal
int words = VL_WORDS_I(obits);
for (int i=0; i<words; i++) owp[i].bval=0;
for (int i=0; i<words-1; i++) owp[i].aval=lwp[i];
for (int i=0; i<words; ++i) owp[i].bval=0;
for (int i=0; i<words-1; ++i) owp[i].aval=lwp[i];
owp[words-1].aval = lwp[words-1] & VL_MASK_I(obits);
}
+17 -4
View File
@@ -38,14 +38,14 @@
extern string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp);
inline string VL_CVT_PACK_STR_NQ(QData lhs) {
IData lw[2]; VL_SET_WQ(lw, lhs);
WData lw[2]; VL_SET_WQ(lw, lhs);
return VL_CVT_PACK_STR_NW(2, lw);
}
inline string VL_CVT_PACK_STR_NN(const string& lhs) {
return lhs;
}
inline string VL_CVT_PACK_STR_NI(IData lhs) {
IData lw[1]; lw[0] = lhs;
WData lw[1]; lw[0] = lhs;
return VL_CVT_PACK_STR_NW(1, lw);
}
inline string VL_CONCATN_NNN(const string& lhs, const string& rhs) {
@@ -53,7 +53,7 @@ inline string VL_CONCATN_NNN(const string& lhs, const string& rhs) {
}
inline string VL_REPLICATEN_NNQ(int,int,int, const string& lhs, IData rep) {
string out; out.reserve(lhs.length() * rep);
for (unsigned times=0; times<rep; times++) out += lhs;
for (unsigned times=0; times<rep; ++times) out += lhs;
return out;
}
inline string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const string& lhs, IData rep) {
@@ -66,6 +66,19 @@ extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwo
extern IData VL_SSCANF_INX(int lbits, const string& ld, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...);
extern string VL_SFORMATF_NX(const char* formatp, ...);
extern IData VL_VALUEPLUSARGS_IN(int rbits, const char* prefixp, char fmt, string& ldr);
extern IData VL_VALUEPLUSARGS_INW(int rbits, const string& ld, WDataOutP rdp);
inline IData VL_VALUEPLUSARGS_INI(int rbits, const string& ld, IData& rdr) {
WData rwp[2]; // WData must always be at least 2
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const string& ld, QData& rdr) {
WData rwp[2];
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
if (got) rdr = VL_SET_QW(rwp);
return got;
}
extern IData VL_VALUEPLUSARGS_INN(int, const string& ld, string& rdr);
#endif // Guard
+2 -2
View File
@@ -97,7 +97,7 @@ public: // But only for verilated*.cpp
}
static void commandArgsAdd(int argc, const char** argv) {
if (!s_s.m_argVecLoaded) s_s.m_argVec.clear();
for (int i=0; i<argc; i++) s_s.m_argVec.push_back(argv[i]);
for (int i=0; i<argc; ++i) s_s.m_argVec.push_back(argv[i]);
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
}
static string argPlusMatch(const char* prefixp) {
@@ -238,7 +238,7 @@ public: // But only for verilated*.cpp
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start*2);
for (size_t i=start; i<start*2; i++) s_s.m_fdFree.push_back((IData)i);
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back((IData)i);
}
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
s_s.m_fdps[idx] = fp;
+3 -1
View File
@@ -412,7 +412,7 @@ void VerilatedVcd::dumpHeader () {
// We detect the spaces in module names to determine hierarchy. This
// allows signals to be declared without fixed ordering, which is
// required as Verilog signals might be separately declared from
// "SP_TRACE" signals.
// SC module signals.
// Print the signal names
const char* lastName = "";
@@ -570,6 +570,7 @@ void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum
//=============================================================================
void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
// cppcheck-suppress invalidPointerCast
(*((double*)&m_sigs_oldvalp[code])) = newval;
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", newval);
@@ -578,6 +579,7 @@ void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
bufferCheck();
}
void VerilatedVcd::fullFloat (vluint32_t code, const float newval) {
// cppcheck-suppress invalidPointerCast
(*((float*)&m_sigs_oldvalp[code])) = newval;
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", (double)newval);
+11
View File
@@ -382,11 +382,13 @@ public:
}
}
inline void chgDouble (vluint32_t code, const double newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY((*((double*)&m_sigs_oldvalp[code])) != newval)) {
fullDouble (code, newval);
}
}
inline void chgFloat (vluint32_t code, const float newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY((*((float*)&m_sigs_oldvalp[code])) != newval)) {
fullFloat (code, newval);
}
@@ -428,6 +430,15 @@ public:
void dump (double timestamp) { dump((vluint64_t)timestamp); }
void dump (vluint32_t timestamp) { dump((vluint64_t)timestamp); }
void dump (int timestamp) { dump((vluint64_t)timestamp); }
/// Set time units (s/ms, defaults to ns)
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
void set_time_unit (const char* unit) { m_sptrace.set_time_unit(unit); }
void set_time_unit (const string& unit) { set_time_unit(unit.c_str()); }
/// Set time resolution (s/ms, defaults to ns)
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
void set_time_resolution (const char* unit) { m_sptrace.set_time_resolution(unit); }
void set_time_resolution (const string& unit) { set_time_resolution(unit.c_str()); }
/// Internal class access
inline VerilatedVcd* spTrace () { return &m_sptrace; };
};
+15 -16
View File
@@ -754,7 +754,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
vl_fatal(__FILE__,__LINE__,"", "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile");
}
WDataInP datap = ((IData*)(vop->varDatap()));
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
out[i].aval = datap[i];
out[i].bval = 0;
}
@@ -791,7 +791,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Truncating string value of %s for %s as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bits);
}
for (i=0; i<bits; i++) {
for (i=0; i<bits; ++i) {
char val = (datap[i>>3]>>(i&7))&1;
outStr[bits-i-1] = val?'1':'0';
}
@@ -821,7 +821,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars);
chars = outStrSz;
}
for (i=0; i<chars; i++) {
for (i=0; i<chars; ++i) {
div_t idx = div(i*3, 8);
int val = datap[idx.quot];
if ((idx.quot+1)<bytes) {
@@ -882,7 +882,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars);
chars = outStrSz;
}
for (i=0; i<chars; i++) {
for (i=0; i<chars; ++i) {
char val = (datap[i>>1]>>((i&1)<<2))&15;
static char hex[] = "0123456789abcdef";
if (i==(chars-1)) {
@@ -922,7 +922,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bytes);
bytes = outStrSz;
}
for (i=0; i<bytes; i++) {
for (i=0; i<bytes; ++i) {
char val = datap[bytes-i-1];
// other simulators replace [leading?] zero chars with spaces, replicate here.
outStr[i] = val?val:' ';
@@ -946,11 +946,10 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
case VLVT_UINT32:
value_p->value.integer = *((IData*)(vop->varDatap()));
return;
case VLVT_WDATA:
case VLVT_UINT64:
// Not legal
value_p->value.integer = 0;
case VLVT_WDATA: // FALLTHRU
case VLVT_UINT64: // FALLTHRU
default:
value_p->value.integer = 0;
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s",
VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
return;
@@ -1007,7 +1006,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
case VLVT_WDATA: {
int words = VL_WORDS_I(vop->varp()->range().elements());
WDataOutP datap = ((IData*)(vop->varDatap()));
for (int i=0; i<words; i++) {
for (int i=0; i<words; ++i) {
datap[i] = value_p->value.vector[i].aval;
if (i==(words-1)) {
datap[i] &= vop->mask();
@@ -1037,7 +1036,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
int bits = vop->varp()->range().elements();
int len = strlen(value_p->value.str);
CData* datap = ((CData*)(vop->varDatap()));
for (int i=0; i<bits; i++) {
for (int i=0; i<bits; ++i) {
char set = (i < len)?(value_p->value.str[len-i-1]=='1'):0;
// zero bits 7:1 of byte when assigning to bit 0, else
// or in 1 if bit set
@@ -1067,7 +1066,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
CData* datap = ((CData*)(vop->varDatap()));
div_t idx;
datap[0] = 0; // reset zero'th byte
for (int i=0; i<chars; i++) {
for (int i=0; i<chars; ++i) {
union {
char byte[2];
short half;
@@ -1105,7 +1104,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
datap[idx.quot+1] &= vop->mask_byte(idx.quot+1);
}
// zero off remaining top bytes
for (int i=idx.quot+2; i<bytes; i++) {
for (int i=idx.quot+2; i<bytes; ++i) {
datap[i] = 0;
}
return object;
@@ -1155,7 +1154,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
val += 2;
}
int len = strlen(val);
for (int i=0; i<chars; i++) {
for (int i=0; i<chars; ++i) {
char hex;
// compute hex digit value
if (i < len) {
@@ -1197,7 +1196,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
int bytes = VL_BYTES_I(vop->varp()->range().elements());
int len = strlen(value_p->value.str);
CData* datap = ((CData*)(vop->varDatap()));
for (int i=0; i<bytes; i++) {
for (int i=0; i<bytes; ++i) {
datap[i] = (i < len)?value_p->value.str[len-i-1]:0; // prepend with 0 values before placing string the least signifcant bytes
}
return object;
@@ -1255,7 +1254,7 @@ void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
}
if (time_p->type == vpiSimTime) {
QData qtime = VL_TIME_Q();
IData itime[2];
WData itime[2];
VL_SET_WQ(itime, qtime);
time_p->low = itime[0];
time_p->high = itime[1];
+14 -14
View File
@@ -99,8 +99,8 @@ public:
virtual const char* name() { return "<null>"; }
virtual const char* fullname() { return "<null>"; }
virtual const char* defname() { return "<null>"; }
virtual const vluint32_t type() { return 0; }
virtual const vluint32_t size() const { return 0; }
virtual vluint32_t type() { return 0; }
virtual vluint32_t size() const { return 0; }
virtual const VerilatedRange* rangep() const { return NULL; }
virtual vpiHandle dovpi_scan() { return 0; }
};
@@ -120,7 +120,7 @@ public:
}
virtual ~VerilatedVpioCb() {}
static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioCb*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiCallback; }
virtual vluint32_t type() { return vpiCallback; }
vluint32_t reason() const { return m_cbData.reason; }
VerilatedPliCb cb_rtnp() const { return m_cbData.cb_rtn; }
t_cb_data* cb_datap() { return &(m_cbData); }
@@ -133,7 +133,7 @@ public:
explicit VerilatedVpioConst(vlsint32_t num) : m_num(num) {}
virtual ~VerilatedVpioConst() {}
static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioConst*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiUndefined; }
virtual vluint32_t type() { return vpiUndefined; }
vlsint32_t num() const { return m_num; }
};
@@ -144,8 +144,8 @@ public:
explicit VerilatedVpioRange(const VerilatedRange* range) : m_range(range), m_iteration(0) {}
virtual ~VerilatedVpioRange() {}
static inline VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioRange*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiRange; }
virtual const vluint32_t size() const { return m_range->elements(); }
virtual vluint32_t type() { return vpiRange; }
virtual vluint32_t size() const { return m_range->elements(); }
virtual const VerilatedRange* rangep() const { return m_range; }
int iteration() const { return m_iteration; }
void iterationInc() { ++m_iteration; }
@@ -167,7 +167,7 @@ public:
: m_scopep(scopep) {}
virtual ~VerilatedVpioScope() {}
static inline VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioScope*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiScope; }
virtual vluint32_t type() { return vpiScope; }
const VerilatedScope* scopep() const { return m_scopep; }
virtual const char* name() { return m_scopep->name(); }
virtual const char* fullname() { return m_scopep->name(); }
@@ -206,12 +206,12 @@ public:
vluint32_t mask() const { return m_mask.u32; }
vluint8_t mask_byte(int idx) { return m_mask.u8[idx & 3]; }
vluint32_t entSize() const { return m_entSize; }
const vluint32_t index() { return m_index; }
virtual const vluint32_t type() {
vluint32_t index() { return m_index; }
virtual vluint32_t type() {
if (varp()->vldir() != vpiNoDirection) return vpiPort;
return (varp()->dims()>1) ? vpiMemory : vpiReg; /* but might be wire, logic */
}
virtual const vluint32_t size() const { return get_range().elements(); }
virtual vluint32_t size() const { return get_range().elements(); }
virtual const VerilatedRange* rangep() const { return &get_range(); }
virtual const char* name() { return m_varp->name(); }
virtual const char* fullname() {
@@ -239,8 +239,8 @@ public:
}
virtual ~VerilatedVpioMemoryWord() {}
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWord*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiMemoryWord; }
virtual const vluint32_t size() const { return varp()->range().elements(); }
virtual vluint32_t type() { return vpiMemoryWord; }
virtual vluint32_t size() const { return varp()->range().elements(); }
virtual const VerilatedRange* rangep() const { return &(varp()->range()); }
virtual const char* fullname() {
VL_STATIC_OR_THREAD string out;
@@ -259,7 +259,7 @@ public:
: m_scopep(scopep), m_started(false) { }
virtual ~VerilatedVpioVarIter() {}
static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVarIter*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiIterator; }
virtual vluint32_t type() { return vpiIterator; }
virtual vpiHandle dovpi_scan() {
if (VL_LIKELY(m_scopep->varsp())) {
VerilatedVarNameMap* varsp = m_scopep->varsp();
@@ -286,7 +286,7 @@ public:
: m_handle(handle), m_varp(varp), m_iteration(varp->array().right()), m_direction(VL_LIKELY(varp->array().left()>varp->array().right())?1:-1), m_done(false) { }
virtual ~VerilatedVpioMemoryWordIter() {}
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWordIter*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiIterator; }
virtual vluint32_t type() { return vpiIterator; }
void iterationInc() { if (!(m_done = (m_iteration == m_varp->array().left()))) m_iteration+=m_direction; }
virtual vpiHandle dovpi_scan() {
vpiHandle result;
+1 -1
View File
@@ -95,7 +95,7 @@
// This is not necessarily the same as #UL, depending on what the IData typedef is.
#define VL_UL(c) ((IData)(c##UL)) ///< Add appropriate suffix to 32-bit constant
#ifdef VL_CPPCHECK
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
# define VL_DANGLING(v)
#else
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
-8
View File
@@ -105,12 +105,6 @@ endif
CPPFLAGSWALL = $(CPPFLAGS)
CPPFLAGSPARSER = $(CPPFLAGS) $(CFG_CXXFLAGS_PARSER)
ifneq ($(SYSTEMPERL),) # Intuit SYSTEMPERL_INCLUDE as it's new
SYSTEMPERL_INCLUDE ?= $(SYSTEMPERL)/src
#else if set, leave as-is.
#else if SYSTEMPERL="" don't set _INCLUDE so source will figure it out
endif
# Allow RPM builds to specify hardcoded data directories
# To do this:
ifeq ($(CFG_WITH_DEFENV),yes)
@@ -118,8 +112,6 @@ ifeq ($(CFG_WITH_DEFENV),yes)
CPPFLAGS += -DDEFENV_SYSTEMC_ARCH=\"$(SYSTEMC_ARCH)\"
CPPFLAGS += -DDEFENV_SYSTEMC_INCLUDE=\"$(SYSTEMC_INCLUDE)\"
CPPFLAGS += -DDEFENV_SYSTEMC_LIBDIR=\"$(SYSTEMC_LIBDIR)\"
CPPFLAGS += -DDEFENV_SYSTEMPERL=\"$(SYSTEMPERL)\"
CPPFLAGS += -DDEFENV_SYSTEMPERL_INCLUDE=\"$(SYSTEMPERL_INCLUDE)\"
ifeq ($(VERILATOR_ROOT),) # Use what we're given, or intuit
CPPFLAGS += -DDEFENV_VERILATOR_ROOT=\"$(pkgdatadir)\"
else
+1 -1
View File
@@ -323,7 +323,7 @@ private:
// Read sensitivitues
m_itemCombo = false;
m_itemSequent = false;
oldsensesp->iterateAndNext(*this);
if (oldsensesp) oldsensesp->iterateAndNext(*this);
bool combo = m_itemCombo;
bool sequent = m_itemSequent;
+1 -1
View File
@@ -108,7 +108,7 @@ private:
// Move the active's contents to the other active
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
if (nodep->sensesStorep()) {
if (sensesp != nodep->sensesStorep()) nodep->v3fatalSrc("sensesStore should have been deleted earlier if different\n");
if (sensesp != nodep->sensesStorep()) nodep->v3fatalSrc("sensesStore should have been deleted earlier if different");
sensesp->unlinkFrBack();
// There may be other references to same sense tree,
// we'll be removing all references when we get to them,
+5 -15
View File
@@ -119,7 +119,7 @@ private:
} else {
nodep->v3fatalSrc("Unknown node type");
}
if (stmtsp) bodysp = bodysp->addNext(stmtsp);
if (bodysp && stmtsp) bodysp = bodysp->addNext(stmtsp);
AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
bodysp = ifp;
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
@@ -246,20 +246,10 @@ private:
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
AstNode* onep;
AstConst* iconstp = icondp->castConst();
if (iconstp && iconstp->num().isFourState()
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) {
V3Number nummask (itemp->fileline(), iconstp->width());
nummask.opBitsNonX(iconstp->num());
V3Number numval (itemp->fileline(), iconstp->width());
numval.opBitsOne(iconstp->num());
AstNode* and1p = new AstAnd(itemp->fileline(), nodep->exprp()->cloneTree(false),
new AstConst(itemp->fileline(), nummask));
AstNode* and2p = new AstAnd(itemp->fileline(),
new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
onep = AstEq::newTyped(itemp->fileline(), and1p, and2p);
if (nodep->casex() || nodep->casez() || nodep->caseInside()) {
onep = AstEqWild::newTyped(itemp->fileline(),
nodep->exprp()->cloneTree(false),
icondp->cloneTree(false));
} else {
onep = AstEq::newTyped(icondp->fileline(),
nodep->exprp()->cloneTree(false),
+3 -1
View File
@@ -902,7 +902,7 @@ bool AstNode::sameTreeIter(AstNode* node1p, AstNode* node2p, bool ignNext, bool
//======================================================================
// Static utilities
ostream& operator<<(ostream& os, V3Hash rhs) {
ostream& operator<<(ostream& os, const V3Hash& rhs) {
return os<<hex<<setw(2)<<setfill('0')<<rhs.depth()
<<"_"<<setw(6)<<setfill('0')<<rhs.hshval();
}
@@ -1057,6 +1057,8 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
editCountSetLast();
}
void AstNode::v3errorEndFatal(ostringstream& str) const { v3errorEnd(str); assert(0); }
void AstNode::v3errorEnd(ostringstream& str) const {
if (!dynamic_cast<const AstNode*>(this)) {
// No known cases cause this, but better than a core dump
+30 -14
View File
@@ -61,7 +61,7 @@ public:
inline bool operator== (AstType lhs, AstType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstType lhs, AstType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (AstType::en lhs, AstType rhs) { return (lhs == rhs.m_e); }
inline ostream& operator<<(ostream& os, AstType rhs) { return os<<rhs.ascii(); }
inline ostream& operator<<(ostream& os, const AstType& rhs) { return os<<rhs.ascii(); }
//######################################################################
@@ -107,7 +107,7 @@ public:
inline bool operator== (AstNumeric lhs, AstNumeric rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstNumeric lhs, AstNumeric::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (AstNumeric::en lhs, AstNumeric rhs) { return (lhs == rhs.m_e); }
inline ostream& operator<<(ostream& os, AstNumeric rhs) { return os<<rhs.ascii(); }
inline ostream& operator<<(ostream& os, const AstNumeric& rhs) { return os<<rhs.ascii(); }
//######################################################################
@@ -396,7 +396,7 @@ public:
return (m_e==LOGIC || m_e==BIT);
}
bool isDpiUnsupported() const {
return (m_e==LOGIC || m_e==TIME);
return (m_e==TIME);
}
bool isDpiUnsignable() const { // Can add "unsigned" to DPI
return (m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER);
@@ -464,7 +464,7 @@ public:
inline bool operator== (AstVarType lhs, AstVarType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstVarType lhs, AstVarType::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (AstVarType::en lhs, AstVarType rhs) { return (lhs == rhs.m_e); }
inline ostream& operator<<(ostream& os, AstVarType rhs) { return os<<rhs.ascii(); }
inline ostream& operator<<(ostream& os, const AstVarType& rhs) { return os<<rhs.ascii(); }
//######################################################################
@@ -496,7 +496,7 @@ public:
inline bool operator== (AstBranchPred lhs, AstBranchPred rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstBranchPred lhs, AstBranchPred::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (AstBranchPred::en lhs, AstBranchPred rhs) { return (lhs == rhs.m_e); }
inline ostream& operator<<(ostream& os, AstBranchPred rhs) { return os<<rhs.ascii(); }
inline ostream& operator<<(ostream& os, const AstBranchPred& rhs) { return os<<rhs.ascii(); }
//######################################################################
@@ -529,7 +529,7 @@ public:
inline bool operator== (AstVarAttrClocker lhs, AstVarAttrClocker rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstVarAttrClocker lhs, AstVarAttrClocker::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (AstVarAttrClocker::en lhs, AstVarAttrClocker rhs) { return (lhs == rhs.m_e); }
inline ostream& operator<<(ostream& os, AstVarAttrClocker rhs) { return os<<rhs.ascii(); }
inline ostream& operator<<(ostream& os, const AstVarAttrClocker& rhs) { return os<<rhs.ascii(); }
//######################################################################
@@ -628,7 +628,7 @@ public:
inline bool operator== (AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstParseRefExp lhs, AstParseRefExp::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (AstParseRefExp::en lhs, AstParseRefExp rhs) { return (lhs == rhs.m_e); }
inline ostream& operator<<(ostream& os, AstParseRefExp rhs) { return os<<rhs.ascii(); }
inline ostream& operator<<(ostream& os, const AstParseRefExp& rhs) { return os<<rhs.ascii(); }
//######################################################################
// VNumRange - Structure containing numberic range information
@@ -680,7 +680,7 @@ struct VNumRange {
{ return (!m_ranged || (m_lo==0 && m_hi>=1 && !m_littleEndian)); }
void dump(ostream& str) const { if (ranged()) str<<"["<<left()<<":"<<right()<<"]"; else str<<"[norg]"; }
};
inline ostream& operator<<(ostream& os, VNumRange rhs) { rhs.dump(os); return os; }
inline ostream& operator<<(ostream& os, const VNumRange& rhs) { rhs.dump(os); return os; }
//######################################################################
@@ -709,7 +709,7 @@ struct VBasicTypeKey {
if (!(m_nrange == rhs.m_nrange)) return false; // lhs > rhs
return false; }
VBasicTypeKey(int width, int widthMin, AstNumeric numeric, AstBasicDTypeKwd kwd,
VNumRange nrange)
const VNumRange& nrange)
: m_width(width), m_widthMin(widthMin), m_numeric(numeric),
m_keyword(kwd), m_nrange(nrange) {}
~VBasicTypeKey() {}
@@ -733,8 +733,9 @@ class VNUser {
} m_u;
public:
VNUser() {}
// non-explicit:
VNUser(int i) { m_u.up = 0; m_u.ui = i; }
VNUser(void* p) { m_u.up = p; }
explicit VNUser(void* p) { m_u.up = p; }
~VNUser() {}
// Casters
WidthVP* c() { return ((WidthVP*)m_u.up); }
@@ -891,7 +892,7 @@ public:
AstNode* oldp() const { return m_oldp; }
void dump(ostream& str=cout) const;
};
inline ostream& operator<<(ostream& os, AstNRelinker& rhs) { rhs.dump(os); return os;}
inline ostream& operator<<(ostream& os, const AstNRelinker& rhs) { rhs.dump(os); return os;}
//######################################################################
// V3Hash -- Node hashing for V3Combine
@@ -903,7 +904,8 @@ class V3Hash {
uint32_t m_both;
static const uint32_t M24 = ((1<<24)-1);
void setBoth(uint32_t depth, uint32_t hshval) {
if (depth==0) depth=1; if (depth>255) depth=255;
if (depth==0) depth=1;
if (depth>255) depth=255;
m_both = (depth<<24) | (hshval & M24);
}
public:
@@ -940,7 +942,7 @@ public:
V3Hash(V3Hash h1, V3Hash h2, V3Hash h3, V3Hash h4) {
setBoth(1,((h1.hshval()*31+h2.hshval())*31+h3.hshval())*31+h4.hshval()); }
};
ostream& operator<<(ostream& os, V3Hash rhs);
ostream& operator<<(ostream& os, const V3Hash& rhs);
//######################################################################
// AstNode -- Base type of all Ast types
@@ -1230,6 +1232,7 @@ public:
// METHODS - dump and error
void v3errorEnd(ostringstream& str) const;
void v3errorEndFatal(ostringstream& str) const VL_ATTR_NORETURN;
string warnMore() const;
virtual void dump(ostream& str=cout);
void dumpGdb(); // For GDB only
@@ -1509,6 +1512,7 @@ public:
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode*) const { return true; }
virtual string verilogKwd() const { return "="; }
virtual bool brokeLhsMustBeLvalue() const = 0;
};
class AstNodeFor : public AstNodeStmt {
@@ -1675,6 +1679,7 @@ public:
virtual bool maybePointedTo() const { return true; }
virtual AstNodeDType* virtRefDTypep() const { return NULL; } // Iff has a non-null refDTypep(), as generic node function
virtual void virtRefDTypep(AstNodeDType* nodep) { } // Iff has refDTypep(), set as generic node function
virtual bool similarDType(AstNodeDType* samep) const = 0; // Assignable equivalence. Call skipRefp() on this and samep before calling
//
// Changing the width may confuse the data type resolution, so must clear TypeTable cache after use.
void widthForce(int width, int sized) { m_width=width; m_widthMin=sized; }
@@ -1724,6 +1729,9 @@ public:
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// op1 = members
virtual bool similarDType(AstNodeDType* samep) const {
return this==samep; // We don't compare members, require exact equivalence
}
AstMemberDType* membersp() const { return op1p()->castMemberDType(); } // op1 = AstMember list
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
bool packed() const { return m_packed; }
@@ -1754,7 +1762,7 @@ public:
virtual void dump(ostream& str);
virtual void dumpSmall(ostream& str);
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep()))); return NULL; }
|| (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep();
}}
@@ -1763,6 +1771,14 @@ public:
return (msb()==sp->msb()
&& subDTypep()==sp->subDTypep()
&& rangenp()->sameTree(sp->rangenp())); } // HashedDT doesn't recurse, so need to check children
virtual bool similarDType(AstNodeDType* samep) const {
AstNodeArrayDType* sp = samep->castNodeArrayDType();
return (sp
&& type() == samep->type()
&& msb() == sp->msb()
&& rangenp()->sameTree(sp->rangenp())
&& subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()));
}
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(msb()),V3Hash(lsb())); }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
+7
View File
@@ -140,6 +140,13 @@ AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
}
}
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
} else {
return new AstEqWild(fl, lhsp, rhsp);
}
}
bool AstVar::isSigPublic() const {
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
+41 -21
View File
@@ -121,7 +121,7 @@ public:
m_littleEndian = false;
setOp2p(new AstConst(fl,msb)); setOp3p(new AstConst(fl,lsb));
}
AstRange(FileLine* fl, VNumRange range)
AstRange(FileLine* fl, const VNumRange& range)
:AstNode(fl) {
m_littleEndian = range.littleEndian();
setOp2p(new AstConst(fl,range.hi())); setOp3p(new AstConst(fl,range.lo()));
@@ -180,6 +180,10 @@ public:
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
virtual AstNodeDType* skipRefToEnump() const { return subDTypep()->skipRefToEnump(); }
virtual bool similarDType(AstNodeDType* samep) const {
AstParamTypeDType* sp = samep->castParamTypeDType();
return (sp && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()));
}
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
// METHODS
@@ -250,7 +254,9 @@ public:
m_uniqueNum = uniqueNumInc();
}
ASTNODE_NODE_FUNCS(DefImplicitDType)
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castDefImplicitDType()->m_uniqueNum; }
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castDefImplicitDType()->m_uniqueNum; }
virtual bool similarDType(AstNodeDType* samep) const {
return type()==samep->type() && same(samep); }
virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
@@ -392,6 +398,8 @@ public:
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.hi())); }
virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere
return samep->castBasicDType()->m == m; }
virtual bool similarDType(AstNodeDType* samep) const {
return type()==samep->type() && same(samep); }
virtual string name() const { return m.m_keyword.ascii(); }
virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; }
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
@@ -456,6 +464,8 @@ public:
}}
virtual bool same(AstNode* samep) const {
return (m_refDTypep==samep->castConstDType()->m_refDTypep); }
virtual bool similarDType(AstNodeDType* samep) const {
return skipRefp()->similarDType(samep->skipRefp()); }
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } // node's type() included elsewhere
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
@@ -499,6 +509,7 @@ public:
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
virtual int widthAlignBytes() const { return 1; }
virtual int widthTotalBytes() const { return 1; }
string cellName() const { return m_cellName; }
@@ -540,6 +551,8 @@ public:
return (m_refDTypep==samep->castRefDType()->m_refDTypep
&& m_name==samep->castRefDType()->m_name
&& m_packagep==samep->castRefDType()->m_packagep); }
virtual bool similarDType(AstNodeDType* samep) const {
return skipRefp()->similarDType(samep->skipRefp()); }
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(m_packagep)); }
virtual void dump(ostream& str=cout);
virtual string name() const { return m_name; }
@@ -623,6 +636,7 @@ public:
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
//
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
@@ -704,6 +718,7 @@ public:
m_refDTypep = m_refDTypep->clonep();
}}
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castEnumDType()->m_uniqueNum; }
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Data type
@@ -728,11 +743,12 @@ class AstParseTypeDType : public AstNodeDType {
// During parsing, this indicates the type of a parameter is a "parameter type"
// e.g. the data type is a container of any data type
public:
AstParseTypeDType(FileLine* fl)
explicit AstParseTypeDType(FileLine* fl)
: AstNodeDType(fl) {}
ASTNODE_NODE_FUNCS(ParseTypeDType)
AstNodeDType* dtypep() const { return NULL; }
// METHODS
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return NULL; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
@@ -1639,7 +1655,7 @@ private:
string m_name; // Cell name
public:
AstCellRef(FileLine* fl,
string name, AstNode* cellp, AstNode* exprp)
const string& name, AstNode* cellp, AstNode* exprp)
: AstNode(fl)
, m_name(name) {
addNOp1p(cellp); addNOp2p(exprp); }
@@ -1656,7 +1672,7 @@ private:
string m_name; // Array name
public:
AstCellArrayRef(FileLine* fl,
string name, AstNode* selectExprp)
const string& name, AstNode* selectExprp)
: AstNode(fl)
, m_name(name) {
addNOp1p(selectExprp); }
@@ -1672,7 +1688,7 @@ private:
string m_name; // Var name
public:
AstUnlinkedRef(FileLine* fl,
AstNode* refp, string name, AstNode* crp)
AstNode* refp, const string& name, AstNode* crp)
: AstNode(fl)
, m_name(name) {
addNOp1p(refp); addNOp2p(crp); }
@@ -2023,6 +2039,7 @@ public:
}
ASTNODE_NODE_FUNCS(Assign)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssign(this->fileline(), lhsp, rhsp); }
virtual bool brokeLhsMustBeLvalue() const { return true; }
};
class AstAssignAlias : public AstNodeAssign {
@@ -2033,6 +2050,7 @@ public:
: AstNodeAssign(fileline, lhsp, rhsp) {}
ASTNODE_NODE_FUNCS(AssignAlias)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { V3ERROR_NA; return NULL; }
virtual bool brokeLhsMustBeLvalue() const { return false; }
};
class AstAssignDly : public AstNodeAssign {
@@ -2043,6 +2061,7 @@ public:
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignDly(this->fileline(), lhsp, rhsp); }
virtual bool isGateOptimizable() const { return false; }
virtual string verilogKwd() const { return "<="; }
virtual bool brokeLhsMustBeLvalue() const { return true; }
};
class AstAssignW : public AstNodeAssign {
@@ -2052,6 +2071,7 @@ public:
: AstNodeAssign(fileline, lhsp, rhsp) { }
ASTNODE_NODE_FUNCS(AssignW)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignW(this->fileline(), lhsp, rhsp); }
virtual bool brokeLhsMustBeLvalue() const { return true; }
AstAlways* convertToAlways() {
AstNode* lhs1p = lhsp()->unlinkFrBack();
AstNode* rhs1p = rhsp()->unlinkFrBack();
@@ -2071,6 +2091,7 @@ public:
}
ASTNODE_NODE_FUNCS(AssignVarScope)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignVarScope(this->fileline(), lhsp, rhsp); }
virtual bool brokeLhsMustBeLvalue() const { return false; }
};
class AstPull : public AstNode {
@@ -2097,6 +2118,7 @@ public:
: AstNodeAssign(fileline, lhsp, rhsp) {}
ASTNODE_NODE_FUNCS(AssignPre)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignPre(this->fileline(), lhsp, rhsp); }
virtual bool brokeLhsMustBeLvalue() const { return true; }
};
class AstAssignPost : public AstNodeAssign {
@@ -2106,6 +2128,7 @@ public:
: AstNodeAssign(fileline, lhsp, rhsp) {}
ASTNODE_NODE_FUNCS(AssignPost)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignPost(this->fileline(), lhsp, rhsp); }
virtual bool brokeLhsMustBeLvalue() const { return true; }
};
class AstComment : public AstNodeStmt {
@@ -2642,28 +2665,24 @@ public:
class AstValuePlusArgs : public AstNodeMath {
// Parents: expr
// Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs
private:
string m_text;
public:
AstValuePlusArgs(FileLine* fileline, const string& text, AstNode* exprsp)
: AstNodeMath (fileline), m_text(text) {
setOp1p(exprsp);
AstValuePlusArgs(FileLine* fileline, AstNode* searchp, AstNode* outp)
: AstNodeMath (fileline) {
setOp1p(searchp); setOp2p(outp);
}
ASTNODE_NODE_FUNCS(ValuePlusArgs)
virtual string name() const { return m_text; }
virtual string verilogKwd() const { return "$value$plusargs"; }
virtual string emitVerilog() { return verilogKwd(); }
virtual string emitC() { return "VL_VALUEPLUSARGS_%nq(%lw, %P, NULL)"; }
virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool cleanOut() { return true; }
virtual V3Hash sameHash() const { return V3Hash(text()); }
virtual bool same(AstNode* samep) const {
return text()==samep->castValuePlusArgs()->text(); }
AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output
void exprsp(AstNode* nodep) { setOp1p(nodep); } // op1 = Expressions to output
string text() const { return m_text; } // * = Text to display
void text(const string& text) { m_text=text; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
AstNode* searchp() const { return op1p(); } // op1 = Search expression
void searchp(AstNode* nodep) { setOp1p(nodep); }
AstNode* outp() const { return op2p(); } // op2 = Expressions to output
void outp(AstNode* nodep) { setOp2p(nodep); }
};
class AstTestPlusArgs : public AstNodeMath {
@@ -4657,6 +4676,7 @@ public:
dtypeSetLogicBool(); }
ASTNODE_NODE_FUNCS(EqWild)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqWild(this->fileline(), lhsp, rhsp); }
static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp); // Return AstEqWild/AstEqD
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildEq(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f==? %r)"; }
virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
+14 -5
View File
@@ -62,7 +62,7 @@ public:
if (debug()>=9) cout<<"-nodeDel: "<<(void*)(nodep)<<endl;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)) {
((AstNode*)(nodep))->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted\n");
((AstNode*)(nodep))->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted");
}
if (iter!=s_nodes.end()) s_nodes.erase(iter);
}
@@ -71,7 +71,7 @@ public:
if (debug()>=9) cout<<"-nodeNew: "<<(void*)(nodep)<<endl;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter!=s_nodes.end() || (iter->second & FLAG_ALLOCATED)) {
((AstNode*)(nodep))->v3fatalSrc("Newing AstNode object that is already allocated\n");
((AstNode*)(nodep))->v3fatalSrc("Newing AstNode object that is already allocated");
}
if (iter == s_nodes.end()) {
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2
@@ -94,16 +94,16 @@ public:
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) {
#ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated\n");
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
#endif
} else {
if (!(iter->second & FLAG_ALLOCATED)) {
#ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated\n");
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
#endif
}
if (iter->second & FLAG_IN_TREE) {
nodep->v3fatalSrc("AstNode is already in tree at another location\n");
nodep->v3fatalSrc("AstNode is already in tree at another location");
}
}
int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
@@ -236,6 +236,15 @@ private:
nodep->iterateChildrenConst(*this);
BrokenTable::setUnder(nodep,false);
}
virtual void visit(AstNodeAssign* nodep) {
processAndIterate(nodep);
if (v3Global.assertDTypesResolved()
&& nodep->brokeLhsMustBeLvalue()
&& nodep->lhsp()->castNodeVarRef()
&& !nodep->lhsp()->castNodeVarRef()->lvalue()) {
nodep->v3fatalSrc("Assignment LHS is not an lvalue");
}
}
virtual void visit(AstNode* nodep) {
processAndIterate(nodep);
}
+8 -2
View File
@@ -75,7 +75,8 @@ public:
m_numStmts += 1;
}
V3CCtorsVisitor(AstNodeModule* nodep, string basename, string argsp="", string callargsp="") {
V3CCtorsVisitor(AstNodeModule* nodep, string basename, string argsp="", string callargsp="",
const string& stmt="") {
m_basename = basename;
m_argsp = argsp;
m_callargsp = callargsp;
@@ -87,9 +88,13 @@ public:
m_tlFuncp->isStatic(false);
m_tlFuncp->slow(true);
m_tlFuncp->argTypes(m_argsp);
if (stmt != "") {
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
m_funcp = m_tlFuncp;
m_modp->addStmtp(m_tlFuncp);
}
~V3CCtorsVisitor() {}
};
//######################################################################
@@ -100,7 +105,8 @@ void V3CCtors::cctorsAll() {
// Process each module in turn
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
V3CCtorsVisitor configure_coverage (modp, "_configure_coverage",
EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first");
EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first",
"if (0 && vlSymsp && first) {} // Prevent unused\n");
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
AstVar* varp = np->castVar();
+2 -2
View File
@@ -174,7 +174,7 @@ private:
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
//if (debug()>=9) icondp->dumpTree(cout," caseitem: ");
AstConst* iconstp = icondp->castConst();
if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this\n");
if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this");
if (neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
} else {
@@ -423,7 +423,7 @@ private:
// Handle any assertions
replaceCaseParallel(nodep, false);
// Replace the CASE... with IF...
if (debug()>=9) grouprootp->dumpTree(cout," _new: ");
if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout," _new: ");
if (grouprootp) nodep->replaceWith(grouprootp);
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
+4 -4
View File
@@ -591,14 +591,14 @@ private:
vertexp->dstDomainp(senoutp);
if (debug()>=9) {
UINFO(9,spaces(level)+" Tracedst "<<vertexp);
if (senoutp) V3EmitV::verilogForTree(senoutp, cout); cout<<endl;
if (senoutp) { V3EmitV::verilogForTree(senoutp, cout); cout<<endl; }
}
} else {
vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that
vertexp->srcDomainp(senoutp);
if (debug()>=9) {
UINFO(9,spaces(level)+" Tracesrc "<<vertexp);
if (senoutp) V3EmitV::verilogForTree(senoutp, cout); cout<<endl;
if (senoutp) { V3EmitV::verilogForTree(senoutp, cout); cout<<endl; }
}
}
}
@@ -629,9 +629,9 @@ private:
}
virtual void visit(AstNodeVarRef* nodep) {
if (m_scopep) {
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block\n");
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
CdcVarVertex* varvertexp = makeVarVertex(varscp);
UINFO(5," VARREF to "<<varscp<<endl);
// We use weight of one for normal edges,
+1 -1
View File
@@ -253,7 +253,7 @@ private:
AstNode::user1ClearTree();
// Create the change detection function
AstScope* scopep = nodep->scopep();
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n");
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?");
m_statep->m_scopetopp = scopep;
// Create a wrapper change detection function that calls each change detection function
+3 -2
View File
@@ -559,7 +559,7 @@ class GaterVisitor : public GaterBaseVisitor {
if (!vVxp->inBeginp()) {
// At this point, any variable not linked is an error
// (It should have at least landed under the Head node)
vVxp->nodep()->v3fatalSrc("Variable became stranded in clk gate detection\n");
vVxp->nodep()->v3fatalSrc("Variable became stranded in clk gate detection");
}
if (!lastVxp || vVxp->sortCmp(lastVxp)) {
// Different sources for this new node
@@ -611,7 +611,8 @@ class GaterVisitor : public GaterBaseVisitor {
// Edges from IFs represent a real IF branch in the equation tree
//UINFO(9," ifver "<<(void*)(edgep)<<" cc"<<edgep->dotColor()<<endl);
eqnp = cVxp->nodep()->condp()->cloneTree(true);
if (eqnp && cedgep->ifelseFalse()) {
if (!eqnp) cVxp->nodep()->v3fatalSrc("null condition");
if (cedgep->ifelseFalse()) {
eqnp = new AstNot(eqnp->fileline(),eqnp);
}
// We need to AND this term onto whatever was found below it
+1 -1
View File
@@ -192,7 +192,7 @@ private:
UINFO(4," TOPSCOPE "<<nodep<<endl);
m_topScopep=nodep;
m_scopep = nodep->scopep();
if (!m_scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n");
if (!m_scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?");
//VV***** We reset all user1p()
AstNode::user1ClearTree();
// Make top functions
+1 -1
View File
@@ -239,7 +239,7 @@ private:
V3Hash hashval = it->first;
AstNode* node1p = it->second;
if (!node1p->castCFunc()) continue;
if (hashval.isIllegal()) node1p->v3fatalSrc("Illegal (unhashed) nodes\n");
if (hashval.isIllegal()) node1p->v3fatalSrc("Illegal (unhashed) nodes");
for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) {
AstNode* node2p = eqit->second;
if (!(eqit->first == hashval)) break;
+1 -1
View File
@@ -104,7 +104,7 @@ class V3ConfigIgnores {
public:
inline static V3ConfigIgnores& singleton() { return s_singleton; }
void addIgnore(V3ErrorCode code, string wildname, int lineno, bool on) {
void addIgnore(V3ErrorCode code, const string& wildname, int lineno, bool on) {
// Insert
IgnLines* linesp = findWilds(wildname);
UINFO(9,"config addIgnore "<<wildname<<":"<<lineno<<", "<<code<<", "<<on<<endl);
+10 -1
View File
@@ -555,7 +555,7 @@ private:
// Replace oldp node with a constant set to specified value
UASSERT (oldp, "Null old\n");
if (oldp->castConst() && !oldp->castConst()->num().isFourState()) {
oldp->v3fatalSrc("Already constant??\n");
oldp->v3fatalSrc("Already constant??");
}
AstNode* newp = new AstConst(oldp->fileline(), num);
newp->dtypeFrom(oldp);
@@ -1374,6 +1374,7 @@ private:
AstNode* fromp = repp->lhsp()->unlinkFrBack();
AstConst* lsbp = nodep->lsbp()->castConst();
AstNode* widthp = nodep->widthp()->unlinkFrBack();
if (!fromp->width()) nodep->v3fatalSrc("Not widthed");
AstSel* newp = new AstSel(nodep->fileline(),
fromp,
new AstConst(lsbp->fileline(), lsbp->toUInt() % fromp->width()),
@@ -1491,6 +1492,14 @@ private:
did=true;
}
}
else if (m_params && valuep->castInitArray() && nodep->backp()->castPin()) {
// Allow parameters to pass arrays
// Earlier recursion of InitArray made sure each array value is constant
// This exception is fairly fragile, i.e. doesn't support arrays of arrays or other stuff
AstNode* newp = valuep->cloneTree(false);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
did = true;
}
}
}
if (!did && m_required) {
+5 -5
View File
@@ -158,7 +158,7 @@ private:
if (oldactivep->sensesp() != m_activep->sensesp()) {
if (!varrefp->varp()->fileline()->warnIsOff(V3ErrorCode::MULTIDRIVEN)
&& !varrefp->varp()->user2()) {
varrefp->varp()->v3warn(MULTIDRIVEN,"Signal has multiple driving blocks: "<<varrefp->varp()->prettyName()<<endl
varrefp->varp()->v3warn(MULTIDRIVEN,"Signal has multiple driving blocks with different clocking: "<<varrefp->varp()->prettyName()<<endl
<<varrefp->warnMore()<<"... Location of first driving block"<<endl
<<oldactivep->warnMore()<<"... Location of other driving block");
varrefp->varp()->user2(true);
@@ -207,8 +207,8 @@ private:
dimvalp.push_front(valp);
}
AstVarRef* varrefp = dimselp->castVarRef();
if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels\n");
if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels");
if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
varrefp->unlinkFrBack();
AstVar* oldvarp = varrefp->varp();
int modVecNum = oldvarp->user4(); oldvarp->user4(modVecNum+1);
@@ -393,7 +393,7 @@ private:
if (!m_activep) nodep->v3fatalSrc("<= not under sensitivity block");
if (!m_activep->hasClocked()) nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active");
AstVarScope* oldvscp = nodep->varScopep();
if (!oldvscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
if (!oldvscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
AstVarScope* dlyvscp = oldvscp->user1p()->castVarScope();
if (dlyvscp) { // Multiple use of delayed variable
AstActive* oldactivep = dlyvscp->user2p()->castActive();
@@ -433,7 +433,7 @@ private:
}
virtual void visit(AstNodeFor* nodep) {
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin\n");
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin");
}
virtual void visit(AstWhile* nodep) {
bool oldloop = m_inLoop;
+3 -2
View File
@@ -138,8 +138,9 @@ private:
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO() && !portp->isFuncReturn()) {
argsp = argsp->addNextNull(new AstVarRef(portp->fileline(), portp,
portp->isOutput()));
AstNode* newp = new AstVarRef(portp->fileline(), portp, portp->isOutput());
if (argsp) argsp = argsp->addNextNull(newp);
else argsp = newp;
}
}
}
+70 -135
View File
@@ -69,7 +69,7 @@ public:
const string& vformat, AstNode* exprsp, bool isScan);
void displayEmit(AstNode* nodep, bool isScan);
void displayArg(AstNode* dispp, AstNode** elistp, bool isScan,
string vfmt, char fmtLetter);
const string& vfmt, char fmtLetter);
void emitVarDecl(AstVar* nodep, const string& prefixIfImp);
typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_PAR, EVL_ALL} EisWhich;
@@ -217,7 +217,7 @@ public:
}
virtual void visit(AstNodeCase* nodep) {
// In V3Case...
nodep->v3fatalSrc("Case statements should have been reduced out\n");
nodep->v3fatalSrc("Case statements should have been reduced out");
}
virtual void visit(AstComment* nodep) {
putsDecoration((string)"// "+nodep->name()+" at "+nodep->fileline()->ascii()+"\n");
@@ -277,54 +277,15 @@ public:
displayNode(nodep, NULL, nodep->text(), nodep->exprsp(), true);
}
virtual void visit(AstValuePlusArgs* nodep) {
string prefix;
char format = '?';
bool pct=false;
int got=0;
string txt = nodep->text();
for (string::const_iterator it=txt.begin(); it!=txt.end(); ++it) {
char ch = *it;
if (pct) {
pct = false;
switch (tolower(ch)) {
case '%':
prefix += ch;
break;
case 'd': // FALLTHRU
case 'o': // FALLTHRU
case 'h': // FALLTHRU
case 'x': // FALLTHRU
case 'b': // FALLTHRU
case 'v': // FALLTHRU
case 's':
got++; format = tolower(ch);
break;
case 'e': // FALLTHRU
case 'f': // FALLTHRU
case 'g':
got++; format = tolower(ch);
nodep->v3error("Unsupported $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
break;
default:
got++;
nodep->v3error("Illegal $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
break;
}
}
else if (ch == '%') pct = true;
else prefix += ch;
}
if (got!=1) nodep->v3error("Missing or extra $value$plusargs format qualifier: '"<<nodep->text()<<"'"<<endl);
puts("VL_VALUEPLUSARGS_I");
emitIQW(nodep->exprsp());
puts("VL_VALUEPLUSARGS_IN");
emitIQW(nodep->outp());
puts("(");
puts(cvtToStr(nodep->exprsp()->widthMin())); // Note argument width, not node width (which is always 32)
putbs(",");
putsQuoted(prefix);
putbs(",");
puts("'"); puts(cvtToStr(format)); puts("'");
puts(cvtToStr(nodep->outp()->widthMin()));
puts(",");
nodep->exprsp()->iterateAndNext(*this);
emitCvtPackStr(nodep->searchp());
puts(",");
putbs("");
nodep->outp()->iterateAndNext(*this);
puts(")");
}
virtual void visit(AstTestPlusArgs* nodep) {
@@ -548,6 +509,30 @@ public:
}
visit(nodep->castNodeBiop());
}
virtual void visit(AstPow* nodep) {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Power of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(nodep->castNodeBiop());
}
virtual void visit(AstPowSS* nodep) {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Power of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(nodep->castNodeBiop());
}
virtual void visit(AstPowSU* nodep) {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Power of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(nodep->castNodeBiop());
}
virtual void visit(AstPowUS* nodep) {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Power of "<<nodep->width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(nodep->castNodeBiop());
}
virtual void visit(AstCCast* nodep) {
// Extending a value of the same word width is just a NOP.
if (nodep->size()>VL_WORDSIZE) {
@@ -618,6 +603,23 @@ public:
puts(nodep->hiername());
puts(nodep->varp()->name());
}
void emitCvtPackStr(AstNode* nodep) {
if (AstConst* constp = nodep->castConst()) {
putbs("string(");
putsQuoted(constp->num().toString());
puts(")");
} else {
putbs("VL_CVT_PACK_STR_N");
emitIQW(nodep);
puts("(");
if (nodep->isWide()) {
puts(cvtToStr(nodep->widthWords())); // Note argument width, not node width (which is always 32)
puts(",");
}
nodep->iterateAndNext(*this);
puts(")");
}
}
void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) {
// Put out constant set to the specified variable, or given variable in a string
if (nodep->num().isFourState()) {
@@ -780,12 +782,7 @@ class EmitCImp : EmitCStmts {
// We should move them to a different stage.
string filename = VL_DEV_NULL;
newCFile(filename, slow, source);
ofp = new V3OutSpFile (filename);
}
else if (optSystemPerl()) {
string filename = filenameNoExt+".sp";
newCFile(filename, slow, source);
ofp = new V3OutSpFile (filename);
ofp = new V3OutCFile (filename);
}
else if (optSystemC()) {
string filename = filenameNoExt+(source?".cpp":".h");
@@ -845,16 +842,13 @@ class EmitCImp : EmitCStmts {
if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n");
if (nodep->initsp()) putsDecoration("// Variables\n");
ofp()->putAlign(V3OutFile::AL_AUTO, 4);
for (AstNode* subnodep=nodep->argsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* varp=subnodep->castVar()) {
if (varp->isFuncReturn()) emitVarDecl(varp, "");
}
}
emitVarList(nodep->initsp(), EVL_ALL, "");
ofp()->putAlign(V3OutFile::AL_AUTO, 4);
emitVarList(nodep->stmtsp(), EVL_ALL, "");
ofp()->putAlign(V3OutFile::AL_AUTO, 4);
nodep->initsp()->iterateAndNext(*this);
@@ -962,7 +956,6 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
if (nodep->isIO()) {
if (nodep->isSc()) {
m_ctorVarsVec.push_back(nodep);
ofp()->putAlign(nodep->isStatic(), 4); // sc stuff is a structure, so bigger alignment
if (nodep->attrScClocked() && nodep->isInput()) {
puts("sc_in_clk\t");
} else {
@@ -983,8 +976,6 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
emitDeclArrayBrackets(nodep);
puts(";\n");
} else { // C++ signals
ofp()->putAlign(nodep->isStatic(), nodep->dtypeSkipRefp()->widthAlignBytes(),
nodep->dtypeSkipRefp()->widthTotalBytes());
if (nodep->isInout()) puts("VL_INOUT");
else if (nodep->isInput()) puts("VL_IN");
else if (nodep->isOutput()) puts("VL_OUT");
@@ -1011,8 +1002,6 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
} else {
// Arrays need a small alignment, but may need different padding after.
// For example three VL_SIG8's needs alignment 1 but size 3.
ofp()->putAlign(nodep->isStatic(), nodep->dtypeSkipRefp()->widthAlignBytes(),
nodep->dtypeSkipRefp()->widthTotalBytes());
if (nodep->isStatic() && prefixIfImp=="") puts("static ");
if (nodep->isStatic()) puts("VL_ST_"); else puts("VL_");
if (nodep->widthMin() <= 8) {
@@ -1235,7 +1224,6 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
if (dispp) {}
puts("VL_SFORMATF_NX(");
} else {
isStmt = true;
nodep->v3fatalSrc("Unknown displayEmit node type");
}
ofp()->putsQuoted(emitDispState.m_format);
@@ -1267,7 +1255,7 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
}
void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan,
string vfmt, char fmtLetter) {
const string& vfmt, char fmtLetter) {
// Print display argument, edits elistp
AstNode* argp = *elistp;
if (!argp) {
@@ -1482,9 +1470,7 @@ void EmitCImp::emitCoverageDecl(AstNodeModule* modp) {
void EmitCImp::emitCtorImp(AstNodeModule* modp) {
puts("\n");
if (optSystemPerl() && modp->isTop()) {
puts("SP_CTOR_IMP("+modClassName(modp)+")");
} else if (optSystemC() && modp->isTop()) {
if (optSystemC() && modp->isTop()) {
puts("VL_SC_CTOR_IMP("+modClassName(modp)+")");
} else {
puts("VL_CTOR_IMP("+modClassName(modp)+")");
@@ -1502,7 +1488,6 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
putsDecoration("// Reset structure values\n");
puts("_ctor_var_reset();\n");
emitTextSection(AstType::atScCtor);
if (optSystemPerl()) puts("SP_AUTO_CTOR;\n");
puts("}\n");
}
@@ -1521,9 +1506,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
if (v3Global.opt.coverage() ) {
puts("\n// Coverage\n");
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this function
// This gets around gcc slowness constructing all of the template arguments
// SystemPerl 1.301 is much faster, but it's nice to remain back
// compatible, and have a common wrapper.
// This gets around gcc slowness constructing all of the template arguments.
puts("void "+modClassName(m_modp)+"::__vlCoverInsert(uint32_t* countp, bool enable, const char* filenamep, int lineno, int column,\n");
puts( "const char* hierp, const char* pagep, const char* commentp) {\n");
puts( "static uint32_t fake_zero_count = 0;\n"); // static doesn't need save-restore as constant
@@ -1787,7 +1770,6 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
}
}
}
ofp()->putAlign(isstatic, 4, 0, prefixIfImp);
}
}
@@ -1823,11 +1805,9 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
void EmitCImp::emitInt(AstNodeModule* modp) {
// Always have this first; gcc has short circuiting if #ifdef is first in a file
if (!optSystemPerl()) { // else done for us automatically
puts("#ifndef _"+modClassName(modp)+"_H_\n");
puts("#define _"+modClassName(modp)+"_H_\n");
puts("\n");
}
puts("#ifndef _"+modClassName(modp)+"_H_\n");
puts("#define _"+modClassName(modp)+"_H_\n");
puts("\n");
ofp()->putsIntTopInclude();
if (v3Global.needHeavy()) {
@@ -1871,21 +1851,16 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
} else {
puts("VL_MODULE("+modClassName(modp)+") {\n");
}
if (optSystemPerl()) puts("/*AUTOATTR(verilated)*/\n\n");
ofp()->resetPrivate();
ofp()->putsPrivate(false); // public:
// Instantiated modules
if (optSystemPerl()) {
puts("/*AUTOSUBCELLS*/\n\n");
} else {
putsDecoration("// CELLS\n");
if (modp->isTop()) puts("// Public to allow access to /*verilator_public*/ items;\n");
if (modp->isTop()) puts("// otherwise the application code can consider these internals.\n");
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstCell* cellp=nodep->castCell()) {
ofp()->putsCellDecl(modClassName(cellp->modp()), cellp->name());
}
putsDecoration("// CELLS\n");
if (modp->isTop()) puts("// Public to allow access to /*verilator_public*/ items;\n");
if (modp->isTop()) puts("// otherwise the application code can consider these internals.\n");
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstCell* cellp=nodep->castCell()) {
ofp()->putsCellDecl(modClassName(cellp->modp()), cellp->name());
}
}
@@ -1907,18 +1882,14 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("\n// INTERNAL VARIABLES\n");
if (modp->isTop()) puts("// Internals; generally not touched by application code\n");
ofp()->putsPrivate(!modp->isTop()); // private: unless top
ofp()->putAlign(V3OutFile::AL_AUTO, 8);
puts(symClassName()+"*\t__VlSymsp;\t\t// Symbol table\n");
ofp()->putsPrivate(false); // public:
if (modp->isTop()) {
if (v3Global.opt.inhibitSim()) {
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
puts("bool\t__Vm_inhibitSim;\t///< Set true to disable evaluation of module\n");
}
}
ofp()->putAlign(V3OutFile::AL_AUTO, 8);
emitCoverageDecl(modp); // may flip public/private
ofp()->putAlign(V3OutFile::AL_AUTO, 8);
puts("\n// PARAMETERS\n");
if (modp->isTop()) puts("// Parameters marked /*verilator public*/ for use by application code\n");
@@ -1970,7 +1941,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
if (modp->isTop()) puts("/// Destroy the model; called (often implicitly) by application code\n");
puts("~"+modClassName(modp)+"();\n");
}
if (v3Global.opt.trace() && !optSystemPerl()) {
if (v3Global.opt.trace()) {
if (modp->isTop()) puts("/// Trace signals in the model; called by application code\n");
puts("void trace (VerilatedVcdC* tfp, int levels, int options=0);\n");
if (modp->isTop() && optSystemC()) {
@@ -1980,7 +1951,6 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
}
puts("\n// USER METHODS\n");
if (optSystemPerl()) puts("/*AUTOMETHODS*/\n");
emitTextSection(AstType::atScInt);
puts("\n// API METHODS\n");
@@ -2007,7 +1977,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
emitIntFuncDecls(modp);
if (!optSystemPerl() && v3Global.opt.trace()) {
if (v3Global.opt.trace()) {
ofp()->putsPrivate(false); // public:
puts("static void traceInit ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n");
puts("static void traceFull ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n");
@@ -2031,18 +2001,12 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
}
// finish up h-file
if (!optSystemPerl()) {
puts("#endif /*guard*/\n");
}
puts("#endif /*guard*/\n");
}
//----------------------------------------------------------------------
void EmitCImp::emitImp(AstNodeModule* modp) {
if (optSystemPerl()) {
puts("//############################################################\n");
puts("#sp implementation\n");
}
ofp()->printf("#include \"%-20s // For This\n",
(modClassName(modp)+".h\"").c_str());
@@ -2054,11 +2018,6 @@ void EmitCImp::emitImp(AstNodeModule* modp) {
puts("#include \"verilated_dpi.h\"\n");
}
if (optSystemPerl() && (splitFilenum() || !m_fast)) {
puts("\n");
puts("SP_MODULE_CONTINUED("+modClassName(modp)+");\n");
}
emitTextSection(AstType::atScImpHdr);
if (m_slow && splitFilenum()==0) {
@@ -2090,13 +2049,6 @@ void EmitCImp::emitImp(AstNodeModule* modp) {
}
}
if (m_fast && splitFilenum()==0) {
if (v3Global.opt.trace() && optSystemPerl() && m_modp->isTop()) {
puts("\n");
puts("\n/*AUTOTRACE(__MODULE__,recurse,activity,exists)*/\n\n");
}
}
// Blocks
puts("\n//--------------------\n");
puts("// Internal Methods\n");
@@ -2114,15 +2066,7 @@ void EmitCImp::main(AstNodeModule* modp, bool slow, bool fast) {
UINFO(0," Emitting "<<modClassName(modp)<<endl);
}
if (optSystemPerl()) {
m_ofp = newOutCFile(modp, !m_fast, true);
if (m_fast) {
puts("#sp interface\n");
emitInt (modp);
}
}
else if (optSystemC()) {
if (optSystemC()) {
if (m_fast) {
m_ofp = newOutCFile (modp, !m_fast, false/*source*/);
emitInt (modp);
@@ -2187,11 +2131,7 @@ class EmitCTrace : EmitCStmts {
void emitTraceHeader() {
// Includes
if (optSystemPerl()) {
puts("#include \"SpTraceVcd.h\"\n");
} else {
puts("#include \"verilated_vcd_c.h\"\n");
}
puts("#include \"verilated_vcd_c.h\"\n");
puts("#include \""+ symClassName() +".h\"\n");
puts("\n");
}
@@ -2200,11 +2140,7 @@ class EmitCTrace : EmitCStmts {
puts("\n//======================\n\n");
puts("void "+topClassName()+"::trace (");
if (optSystemPerl()) {
puts("SpTraceFile* tfp, int, int) {\n");
} else {
puts("VerilatedVcdC* tfp, int, int) {\n");
}
puts("VerilatedVcdC* tfp, int, int) {\n");
puts( "tfp->spTrace()->addCallback ("
"&"+topClassName()+"::traceInit"
+", &"+topClassName()+"::traceFull"
@@ -2221,7 +2157,7 @@ class EmitCTrace : EmitCStmts {
puts("vcdp->scopeEscape(' ');\n");
puts("t->traceInitThis (vlSymsp, vcdp, code);\n");
puts("vcdp->scopeEscape('.');\n"); // Restore so SystemPerl traced files won't break
puts("vcdp->scopeEscape('.');\n"); // Restore so later traced files won't break
puts("}\n");
splitSizeInc(10);
@@ -2399,7 +2335,6 @@ class EmitCTrace : EmitCStmts {
if (nodep->initsp()) putsDecoration("// Variables\n");
emitVarList(nodep->initsp(), EVL_ALL, "");
nodep->initsp()->iterateAndNext(*this);
ofp()->putAlign(V3OutFile::AL_AUTO, 4);
putsDecoration("// Body\n");
puts("{\n");
-1
View File
@@ -46,7 +46,6 @@ public:
void putsDecoration(const string& str) { if (v3Global.opt.decoration()) puts(str); }
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
bool optSystemC() { return v3Global.opt.systemC(); }
bool optSystemPerl() { return v3Global.opt.systemPerl(); }
static string symClassName() { return v3Global.opt.prefix()+"__Syms"; }
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
-6
View File
@@ -238,7 +238,6 @@ class EmitCSyms : EmitCBaseVisitor {
virtual void visit(AstConst*) {}
// Default
virtual void visit(AstNode* nodep) {
nameCheck(nodep);
nodep->iterateChildren(*this);
}
//---------------------------------------
@@ -303,14 +302,10 @@ void EmitCSyms::emitSymHdr() {
ofp()->putsPrivate(false); // public:
puts("\n// LOCAL STATE\n");
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(vluint64_t));
puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert.
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
puts("bool\t__Vm_activity;\t\t///< Used by trace routines to determine change occurred\n");
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
puts("bool\t__Vm_didInit;\n");
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(vluint64_t));
puts("\n// SUBCELL STATE\n");
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
@@ -326,7 +321,6 @@ void EmitCSyms::emitSymHdr() {
puts("\n// COVERAGE\n");
if (m_coverBins) {
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint32_t));
puts("uint32_t\t__Vcoverage["); puts(cvtToStr(m_coverBins)); puts("];\n");
}
+8 -19
View File
@@ -90,15 +90,10 @@ public:
if (v3Global.opt.coverage()) {
putMakeClassEntry(of, "verilated_cov.cpp");
}
if (v3Global.opt.systemPerl()) {
putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC
}
else {
if (v3Global.opt.trace()) {
putMakeClassEntry(of, "verilated_vcd_c.cpp");
if (v3Global.opt.systemC()) {
putMakeClassEntry(of, "verilated_vcd_sc.cpp");
}
if (v3Global.opt.trace()) {
putMakeClassEntry(of, "verilated_vcd_c.cpp");
if (v3Global.opt.systemC()) {
putMakeClassEntry(of, "verilated_vcd_sc.cpp");
}
}
}
@@ -106,7 +101,7 @@ public:
}
else {
for (AstCFile* nodep = v3Global.rootp()->filesp(); nodep; nodep=nodep->nextp()->castCFile()) {
if (nodep->source() && nodep->slow()==slow && nodep->support()==support) {
if (nodep->source() && nodep->slow()==(slow!=0) && nodep->support()==(support!=0)) {
putMakeClassEntry(of, nodep->name());
}
}
@@ -139,22 +134,16 @@ public:
of.puts("PERL = "+V3Options::getenvPERL()+"\n");
of.puts("# Path to Verilator kit (from $VERILATOR_ROOT)\n");
of.puts("VERILATOR_ROOT = "+V3Options::getenvVERILATOR_ROOT()+"\n");
of.puts("# Path to SystemPerl kit top (from $SYSTEMPERL)\n");
of.puts("SYSTEMPERL = "+V3Options::getenvSYSTEMPERL()+"\n");
of.puts("# Path to SystemPerl kit includes (from $SYSTEMPERL_INCLUDE)\n");
of.puts("SYSTEMPERL_INCLUDE = "+V3Options::getenvSYSTEMPERL_INCLUDE()+"\n");
of.puts("# SystemC include directory with systemc.h (from $SYSTEMC_INCLUDE)\n");
of.puts(string("SYSTEMC_INCLUDE ?= ")+V3Options::getenvSYSTEMC_INCLUDE()+"\n");
of.puts("# SystemC library directory with libsystemc.a (from $SYSTEMC_LIBDIR)\n");
of.puts(string("SYSTEMC_LIBDIR ?= ")+V3Options::getenvSYSTEMC_LIBDIR()+"\n");
of.puts("\n### Switches...\n");
of.puts("# SystemPerl output mode? 0/1 (from --sp)\n");
of.puts(string("VM_SP = ")+(v3Global.opt.systemPerl()?"1":"0")+"\n");
of.puts("# SystemC output mode? 0/1 (from --sc)\n");
of.puts(string("VM_SC = ")+((v3Global.opt.systemC()&&!v3Global.opt.systemPerl())?"1":"0")+"\n");
of.puts("# SystemPerl or SystemC output mode? 0/1 (from --sp/--sc)\n");
of.puts(string("VM_SP_OR_SC = ")+(v3Global.opt.systemC()?"1":"0")+"\n");
of.puts(string("VM_SC = ")+((v3Global.opt.systemC())?"1":"0")+"\n");
of.puts("# Legacy or SystemC output mode? 0/1 (from --sc)\n");
of.puts(string("VM_SP_OR_SC = $(VM_SC)\n"));
of.puts("# Deprecated\n");
of.puts(string("VM_PCLI = ")+(v3Global.opt.systemC()?"0":"1")+"\n");
of.puts("# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n");
-4
View File
@@ -238,10 +238,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstSFormatF* nodep) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
}
virtual void visit(AstValuePlusArgs* nodep) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
}
virtual void visit(AstFOpen* nodep) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
+9 -5
View File
@@ -29,6 +29,7 @@
#include <map>
#include <set>
#include <deque>
#include <cassert>
//######################################################################
@@ -253,18 +254,21 @@ class V3Error {
// Global versions, so that if the class doesn't define a operator, we get the functions anyways.
inline int debug() { return V3Error::debugDefault(); }
inline void v3errorEnd(ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
inline void v3errorEndFatal(ostringstream& sstr) VL_ATTR_NORETURN;
inline void v3errorEndFatal(ostringstream& sstr) { V3Error::v3errorEnd(sstr); assert(0); }
// Theses allow errors using << operators: v3error("foo"<<"bar");
// Careful, you can't put () around msg, as you would in most macro definitions
// Note the commas are the comma operator, not separating arguments. These are needed to insure
// evaluation order as otherwise we couldn't insure v3errorPrep is called first.
#define v3warnCode(code,msg) v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
#define v3warn(code,msg) v3warnCode(V3ErrorCode::code,msg)
#define v3info(msg) v3warn(EC_INFO,msg)
#define v3fatal(msg) v3warn(EC_FATAL,msg)
#define v3error(msg) v3warn(EC_ERROR,msg)
#define v3warnCodeFatal(code,msg) v3errorEndFatal((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
#define v3warn(code,msg) v3warnCode(V3ErrorCode::code, msg)
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
#define v3fatal(msg) v3warnCodeFatal(V3ErrorCode::EC_FATAL, msg)
// Use this instead of fatal() to mention the source code line.
#define v3fatalSrc(msg) v3warn(EC_FATALSRC,__FILE__<<":"<<dec<<__LINE__<<": "<<msg)
#define v3fatalSrc(msg) v3warnCodeFatal(V3ErrorCode::EC_FATALSRC, __FILE__<<":"<<dec<<__LINE__<<": "<<msg)
#define UINFO(level,stmsg) {if(VL_UNLIKELY(debug()>=(level))) { cout<<"- "<<V3Error::lineStr(__FILE__,__LINE__)<<stmsg; }}
#define UINFONL(level,stmsg) {if(VL_UNLIKELY(debug()>=(level))) { cout<<stmsg; } }
+1 -20
View File
@@ -553,8 +553,7 @@ bool V3InFilter::readWholefile(const string& filename, V3InFilter::StrList& outl
V3OutFormatter::V3OutFormatter(const string& filename, V3OutFormatter::Language lang)
: m_filename(filename), m_lang(lang)
, m_lineno(1), m_column(0)
, m_nobreak(false), m_prependIndent(true), m_indentLevel(0)
, m_declSAlign(0), m_declNSAlign(0), m_declPadNum(0) {
, m_nobreak(false), m_prependIndent(true), m_indentLevel(0) {
m_blockIndent = v3Global.opt.decoration() ? 4 : 1;
m_commaWidth = v3Global.opt.decoration() ? 50 : 150;
}
@@ -797,24 +796,6 @@ void V3OutFormatter::putcNoTracking (char chr) {
putcOutput (chr);
}
void V3OutFormatter::putAlign (bool/*AlignClass*/ isStatic, int align, int size, const string& prefix) {
if (size==0) size=align;
int alignSize = size; if (alignSize>8) alignSize=8;
int& alignr = isStatic ? m_declSAlign : m_declNSAlign;
int padsize = alignSize - (alignr % alignSize);
if (padsize && padsize!=alignSize) {
// Modern versions of GCC no longer need this, they'll pad for us, so
// we'll save the work and danger of getting it wrong.
puts("//char\t");
puts(prefix);
puts("__VpadToAlign"+cvtToStr(alignr)
+"["+cvtToStr(padsize)+"];\n");
alignr += padsize;
m_declPadNum++;
}
alignr += size;
}
//----------------------------------------------------------------------
// Simple wrappers
-16
View File
@@ -120,9 +120,6 @@ private:
int m_nobreak; // Basic operator or begin paren, don't break next
bool m_prependIndent;
int m_indentLevel; // Current {} indentation
int m_declSAlign; // Byte alignment of next declaration, statics
int m_declNSAlign; // Byte alignment of next declaration, nonstatics
int m_declPadNum; // Pad variable number
stack<int> m_parenVec; // Stack of columns where last ( was
int endLevels(const char* strg);
@@ -144,7 +141,6 @@ public:
void putsQuoted(const string& strg);
void putBreak(); // Print linebreak if line is too wide
void putBreakExpr(); // Print linebreak in expression if line is too wide
void putAlign(bool isstatic/*AlignClass*/, int align, int size=0/*=align*/, const string& prefix=""); // Declare a variable, with natural alignment
void putbs(const char* strg) { putBreakExpr(); puts(strg); }
void putbs(const string& strg) { putBreakExpr(); puts(strg); }
bool exceededWidth() const { return m_column > m_commaWidth; }
@@ -222,18 +218,6 @@ public:
}
};
class V3OutSpFile : public V3OutCFile {
public:
explicit V3OutSpFile(const string& filename) : V3OutCFile(filename) {}
virtual ~V3OutSpFile() {}
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
virtual void putsIntTopInclude() {
putsForceIncs();
puts("#include \"systemperl.h\"\n");
puts("#include \"verilated_sc.h\"\n");
}
};
class V3OutVFile : public V3OutFile {
public:
explicit V3OutVFile(const string& filename) : V3OutFile(filename, V3OutFormatter::LA_VERILOG) {}
+1 -1
View File
@@ -270,7 +270,7 @@ void FileLine::operator delete(void* objp, size_t size) {
if (it != fileLineLeakChecks.end()) {
fileLineLeakChecks.erase(it);
} else {
flp->v3fatalSrc("Deleting FileLine object that was never tracked\n");
flp->v3fatalSrc("Deleting FileLine object that was never tracked");
}
::operator delete(objp);
}
+3
View File
@@ -161,6 +161,7 @@ public:
// OPERATORS
void v3errorEnd(ostringstream& str);
void v3errorEndFatal(ostringstream& str) VL_ATTR_NORETURN;
string warnMore() const;
inline bool operator==(FileLine rhs) const {
return (m_lineno==rhs.m_lineno && m_filenameno==rhs.m_filenameno && m_warnOn==rhs.m_warnOn);
@@ -168,4 +169,6 @@ public:
};
ostream& operator<<(ostream& os, FileLine* fileline);
inline void FileLine::v3errorEndFatal(ostringstream& str) { v3errorEnd(str); assert(0); }
#endif // Guard
+216 -4
View File
@@ -113,6 +113,20 @@ public:
}
return ret;
}
// Returns only the result from the LAST vertex iterated over
// Note: This behaves differently than iterateInEdges() in that it will traverse
// all edges that exist when it is initially called, whereas
// iterateInEdges() will stop traversing edges if one is deleted
VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu=VNUser(0)) {
VNUser ret = VNUser(0);
V3GraphEdge* next_edgep = NULL;
for (V3GraphEdge* edgep = outBeginp(); edgep; edgep = next_edgep) {
// Need to find the next edge before visiting in case the edge is deleted
next_edgep = edgep->outNextp();
ret = dynamic_cast<GateEitherVertex*>(edgep->top())->accept(v, vu);
}
return ret;
}
};
class GateVarVertex : public GateEitherVertex {
@@ -291,6 +305,7 @@ private:
// {statement}Node::user1p -> GateLogicVertex* for this statement
// AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement
// AstVar::user2 -> bool: Warned about SYNCASYNCNET
// AstVarNodeRef::user2 -> bool: ConcatOffset visited
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
@@ -358,6 +373,7 @@ private:
void replaceAssigns();
void dedupe();
void mergeAssigns();
void decomposeClkVectors();
// VISITORS
virtual void visit(AstNetlist* nodep) {
@@ -365,6 +381,8 @@ private:
//if (debug()>6) m_graph.dump();
if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre");
warnSignals(); // Before loss of sync/async pointers
// Decompose clock vectors -- need to do this before removing redundant edges
decomposeClkVectors();
m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("gate_simp");
// Find gate interconnect and optimize
@@ -409,9 +427,9 @@ private:
}
virtual void visit(AstNodeVarRef* nodep) {
if (m_scopep) {
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block\n");
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
GateVarVertex* vvertexp = makeVarVertex(varscp);
UINFO(5," VARREF to "<<varscp<<endl);
if (m_inSenItem) vvertexp->setIsClock();
@@ -484,7 +502,7 @@ private:
}
virtual void visit(AstConcat* nodep) {
if (nodep->backp()->castNodeAssign() && nodep->backp()->castNodeAssign()->lhsp()==nodep) {
nodep->v3fatalSrc("Concat on LHS of assignment; V3Const should have deleted it\n");
nodep->v3fatalSrc("Concat on LHS of assignment; V3Const should have deleted it");
}
nodep->iterateChildren(*this);
}
@@ -704,7 +722,7 @@ void GateVisitor::replaceAssigns() {
if (!vscp->valuep()->castNodeMath()
|| vscp->valuep()->nextp()) {
vscp->dumpTree(cerr, "vscStrange: ");
vscp->v3fatalSrc("Value of varscope not mathematical\n");
vscp->v3fatalSrc("Value of varscope not mathematical");
}
}
}
@@ -1238,6 +1256,200 @@ void GateVisitor::mergeAssigns() {
m_statAssignMerged += merger.numMergedAssigns();
}
//######################################################################
// Find a var's offset in a concatenation
class GateConcatVisitor : public GateBaseVisitor {
private:
// STATE
AstVarScope* m_vscp; // Varscope we're trying to find
int m_offset; // Current offset of varscope
int m_found_offset; // Found offset of varscope
bool m_found; // Offset found
// VISITORS
virtual void visit(AstNodeVarRef* nodep) {
UINFO(9,"CLK DECOMP Concat search var (off = "<<m_offset<<") - "<<nodep<<endl);
if (nodep->varScopep() == m_vscp && !nodep->user2() && !m_found) {
// A concatenation may use the same var multiple times
// But the graph will initially have an edge per instance
nodep->user2(true);
m_found_offset = m_offset;
m_found = true;
UINFO(9,"CLK DECOMP Concat found var (off = "<<m_offset<<") - "<<nodep<<endl);
}
m_offset += nodep->dtypep()->width();
}
virtual void visit(AstConcat* nodep) {
UINFO(9,"CLK DECOMP Concat search (off = "<<m_offset<<") - "<<nodep<<endl);
nodep->rhsp()->iterate(*this);
nodep->lhsp()->iterate(*this);
}
//--------------------
// Default
virtual void visit(AstNode* nodep) {
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
GateConcatVisitor() {
m_vscp = NULL;
m_offset = 0;
m_found_offset = 0;
m_found = false;
}
virtual ~GateConcatVisitor() {}
// PUBLIC METHODS
bool concatOffset(AstConcat* concatp, AstVarScope* vscp, int& offsetr) {
m_vscp = vscp;
m_offset = 0;
m_found = false;
// Iterate
concatp->accept(*this);
UINFO(9,"CLK DECOMP Concat Offset (found = "<<m_found<<") ("<<m_found_offset<<") - "<<concatp<<" : "<<vscp<<endl);
offsetr = m_found_offset;
return m_found;
}
};
//######################################################################
// Recurse through the graph, looking for clock vectors to bypass
class GateClkDecompState {
public:
int m_offset;
AstVarScope* m_last_vsp;
GateClkDecompState(int offset, AstVarScope* vsp) {
m_offset = offset;
m_last_vsp = vsp;
}
virtual ~GateClkDecompState() {}
};
class GateClkDecompGraphVisitor : public GateGraphBaseVisitor {
private:
// NODE STATE
// AstVarScope::user2p -> bool: already visited
V3Graph* m_graphp;
int m_seen_clk_vectors;
AstVarScope* m_clk_vsp;
GateVarVertex* m_clk_vvertexp;
GateConcatVisitor m_concat_visitor;
int m_total_seen_clk_vectors;
int m_total_decomposed_clk_vectors;
virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) {
// Check that we haven't been here before
AstVarScope* vsp = vvertexp->varScp();
if (vsp->user2SetOnce()) return VNUser(0);
UINFO(9,"CLK DECOMP Var - "<<vvertexp<<" : "<<vsp<<endl);
if (vsp->varp()->width() > 1) {
m_seen_clk_vectors++;
m_total_seen_clk_vectors++;
}
GateClkDecompState* currState = (GateClkDecompState*) vu.c();
GateClkDecompState nextState(currState->m_offset, vsp);
vvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState));
if (vsp->varp()->width() > 1) {
m_seen_clk_vectors--;
}
vsp->user2(false);
return VNUser(0);
}
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) {
GateClkDecompState* currState = (GateClkDecompState*) vu.c();
int clk_offset = currState->m_offset;
if (AstAssignW* assignp = lvertexp->nodep()->castAssignW()) {
UINFO(9,"CLK DECOMP Logic (off = "<<clk_offset<<") - "<<lvertexp<<" : "<<m_clk_vsp<<endl);
if (AstSel* rselp = assignp->rhsp()->castSel()) {
if (rselp->lsbp()->castConst() && rselp->widthp()->castConst()) {
if (clk_offset < rselp->lsbConst() || clk_offset > rselp->msbConst()) {
UINFO(9,"CLK DECOMP Sel [ "<<rselp->msbConst()<<" : "<<rselp->lsbConst()<<" ] dropped clock ("<<clk_offset<<")"<<endl);
return VNUser(0);
}
clk_offset -= rselp->lsbConst();
} else {
return VNUser(0);
}
} else if (AstConcat* catp = assignp->rhsp()->castConcat()) {
UINFO(9,"CLK DECOMP Concat searching - "<<assignp->lhsp()<<endl);
int concat_offset;
if (!m_concat_visitor.concatOffset(catp, currState->m_last_vsp, concat_offset)) {
return VNUser(0);
}
clk_offset += concat_offset;
}
if (AstSel* lselp = assignp->lhsp()->castSel()) {
if (lselp->lsbp()->castConst() && lselp->widthp()->castConst()) {
clk_offset += lselp->lsbConst();
} else {
return VNUser(0);
}
} else if (AstVarRef* vrp = assignp->lhsp()->castVarRef()) {
if (vrp->dtypep()->width() == 1 && m_seen_clk_vectors) {
if (clk_offset != 0) {
UINFO(9,"Should only make it here with clk_offset = 0"<<endl);
return VNUser(0);
}
UINFO(9,"CLK DECOMP Connecting - "<<assignp->lhsp()<<" <-> "<<m_clk_vsp<<endl);
AstNode* rhsp = assignp->rhsp();
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false));
for (V3GraphEdge* edgep = lvertexp->inBeginp(); edgep; ) {
edgep->unlinkDelete(); VL_DANGLING(edgep);
}
new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1);
m_total_decomposed_clk_vectors++;
}
}
GateClkDecompState nextState(clk_offset, currState->m_last_vsp);
return lvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState));
}
return VNUser(0);
}
public:
explicit GateClkDecompGraphVisitor(V3Graph* graphp) {
m_graphp = graphp;
m_seen_clk_vectors = 0;
m_clk_vsp = NULL;
m_clk_vvertexp = NULL;
m_total_seen_clk_vectors = 0;
m_total_decomposed_clk_vectors = 0;
}
virtual ~GateClkDecompGraphVisitor() {
V3Stats::addStat("Optimizations, Clocker seen vectors", m_total_seen_clk_vectors);
V3Stats::addStat("Optimizations, Clocker decomposed vectors", m_total_decomposed_clk_vectors);
}
void clkDecomp(GateVarVertex* vvertexp) {
UINFO(9,"CLK DECOMP Starting Var - "<<vvertexp<<endl);
m_seen_clk_vectors = 0;
m_clk_vsp = vvertexp->varScp();
m_clk_vvertexp = vvertexp;
GateClkDecompState nextState(0, m_clk_vsp);
vvertexp->accept(*this, VNUser(&nextState));
}
};
void GateVisitor::decomposeClkVectors() {
UINFO(9,"Starting clock decomposition"<<endl);
AstNode::user2ClearTree();
GateClkDecompGraphVisitor decomposer(&m_graph);
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vertp = dynamic_cast<GateVarVertex*>(itp)) {
AstVarScope* vsp = vertp->varScp();
if (vsp->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) {
if (vsp->varp()->width() > 1) {
UINFO(9,"Clocker > 1 bit, not decomposing: "<<vsp<<endl);
} else {
UINFO(9,"CLK DECOMP - "<<vertp<<" : "<<vsp<<endl);
decomposer.clkDecomp(vertp);
}
}
}
}
}
//######################################################################
// Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default)
+1 -1
View File
@@ -529,7 +529,7 @@ double V3Graph::orderDFSIterate(V3GraphVertex* vertexp) {
// Compute fanouts of each node
// If forward edge, don't double count that fanout
if (vertexp->user() == 2) return vertexp->fanout(); // Already processed it
if (vertexp->user() == 1) v3fatalSrc("Loop found, backward edges should be dead\n");
if (vertexp->user() == 1) v3fatalSrc("Loop found, backward edges should be dead");
vertexp->user(1);
double fanout = 0;
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
+2 -2
View File
@@ -44,7 +44,7 @@ DfaVertex* DfaGraph::findStart() {
startp = vvertexp;
}
} else {
v3fatalSrc("Non DfaVertex in DfaGraph\n");
v3fatalSrc("Non DfaVertex in DfaGraph");
}
}
if (!startp) v3fatalSrc("No start point in NFA graph");
@@ -520,7 +520,7 @@ private:
}
}
}
if (!acceptp) v3fatalSrc("No accepting vertex in DFA\n");
if (!acceptp) v3fatalSrc("No accepting vertex in DFA");
// Remap edges
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
+1 -1
View File
@@ -124,7 +124,7 @@ public:
static DfaInput EPSILON() { return VNUser::fromInt(0); }
static DfaInput NA() { return VNUser::fromInt(1); } // as in not-applicable
// CONSTRUCTORS
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, DfaInput input)
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaInput& input)
: V3GraphEdge(graphp, fromp, top, 1)
, m_input(input), m_complement(false) {}
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaEdge* copyfrom)
+3 -3
View File
@@ -72,7 +72,7 @@ public:
class V3GraphTestVertex : public V3GraphVertex {
string m_name;
public:
V3GraphTestVertex(V3Graph* graphp, string name) : V3GraphVertex(graphp), m_name(name) {}
V3GraphTestVertex(V3Graph* graphp, const string& name) : V3GraphVertex(graphp), m_name(name) {}
virtual ~V3GraphTestVertex() {}
// Accessors
virtual string name() const { return m_name; }
@@ -80,7 +80,7 @@ public:
class V3GraphTestVarVertex : public V3GraphTestVertex {
public:
V3GraphTestVarVertex(V3Graph* graphp, string name) : V3GraphTestVertex(graphp, name) {}
V3GraphTestVarVertex(V3Graph* graphp, const string& name) : V3GraphTestVertex(graphp, name) {}
virtual ~V3GraphTestVarVertex() {}
// Accessors
virtual string dotColor() const { return "blue"; }
@@ -270,7 +270,7 @@ public:
class DfaTestVertex : public DfaVertex {
string m_name;
public:
DfaTestVertex(DfaGraph* graphp, string name) : DfaVertex(graphp), m_name(name) {}
DfaTestVertex(DfaGraph* graphp, const string& name) : DfaVertex(graphp), m_name(name) {}
virtual ~DfaTestVertex() {}
// Accessors
virtual string name() const { return m_name; }
+3 -3
View File
@@ -277,7 +277,7 @@ private:
AstVarRef* exprvarrefp = nodep->user2p()->castVarRef();
UINFO(8,"connectto: "<<nodep->user2p()<<endl);
if (!exprconstp && !exprvarrefp) {
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
}
if (exprconstp) {
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
@@ -362,7 +362,7 @@ private:
nodep->varp( exprvarrefp->varp() );
}
else {
nodep->v3fatalSrc("Null connection?\n");
nodep->v3fatalSrc("Null connection?");
}
}
nodep->name(nodep->varp()->name());
@@ -514,7 +514,7 @@ private:
AstNode* connectRefp = pinp->exprp();
if (!connectRefp->castConst() && !connectRefp->castVarRef()) {
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
}
if (pinNewVarp->isOutOnly() && connectRefp->castConst()) {
pinp->v3error("Output port is connected to a constant pin, electrical short");
+109 -51
View File
@@ -90,7 +90,7 @@ private:
// Make a ASSIGNW (expr, pin)
AstNode* exprp = nodep->exprp()->cloneTree(false);
if (exprp->width() != nodep->modVarp()->width())
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple\n");
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple");
if (nodep->modVarp()->isInout()) {
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
} else if (nodep->modVarp()->isOutput()) {
@@ -154,14 +154,10 @@ public:
//######################################################################
class InstDeVisitor : public AstNVisitor {
// Find all cells with arrays, and convert to non-arrayed
class InstDeModVarVisitor : public AstNVisitor {
// Expand all module variables, and save names for later reference
private:
// STATE
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
int m_instNum; // Current instantiation number
int m_instLsb; // Current instantiation number
typedef map<string,AstVar*> VarNameMap;
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
@@ -172,15 +168,109 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
virtual void visit(AstVar* nodep) {
if (nodep->dtypep()->castIfaceRefDType()) {
UINFO(8," dm-1-VAR "<<nodep<<endl);
insert(nodep);
}
nodep->iterateChildren(*this);
}
// Save some time
virtual void visit(AstNodeMath*) {}
// Default: Just iterate
virtual void visit(AstNode* nodep) {
nodep->iterateChildren(*this);
}
public:
// METHODS
void insert(AstVar* nodep) {
UINFO(8," dmINSERT "<<nodep<<endl);
m_modVarNameMap.insert(make_pair(nodep->name(), nodep));
}
AstVar* find(const string& name) {
VarNameMap::iterator it = m_modVarNameMap.find(name);
if (it != m_modVarNameMap.end()) {
return it->second;
} else {
return NULL;
}
}
void dump() {
for (VarNameMap::iterator it=m_modVarNameMap.begin(); it!=m_modVarNameMap.end(); ++it) {
cout<<"-namemap: "<<it->first<<" -> "<<it->second<<endl;
}
}
public:
// CONSTUCTORS
explicit InstDeModVarVisitor() {}
void accept(AstNodeModule* nodep) {
UINFO(8," dmMODULE "<<nodep<<endl);
m_modVarNameMap.clear();
nodep->accept(*this);
}
virtual ~InstDeModVarVisitor() {}
};
//######################################################################
class InstDeVisitor : public AstNVisitor {
// Find all cells with arrays, and convert to non-arrayed
private:
// STATE
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
int m_instNum; // Current instantiation number
int m_instLsb; // Current instantiation number
InstDeModVarVisitor m_deModVars; // State of variables for current cell module
typedef map<string,AstVar*> VarNameMap;
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// VISITORS
virtual void visit(AstVar* nodep) {
if (nodep->dtypep()->castUnpackArrayDType()
&& nodep->dtypep()->castUnpackArrayDType()->subDTypep()->castIfaceRefDType()) {
UINFO(8," dv-vec-VAR "<<nodep<<endl);
AstUnpackArrayDType* arrdtype = nodep->dtypep()->castUnpackArrayDType();
AstNode* prevp = NULL;
for (int i = arrdtype->lsb(); i <= arrdtype->msb(); ++i) {
string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
UINFO(8,"VAR name insert "<<varNewName<<" "<<nodep<<endl);
if (!m_deModVars.find(varNewName)) {
AstIfaceRefDType* ifaceRefp = arrdtype->subDTypep()->castIfaceRefDType()->cloneTree(false);
arrdtype->addNextHere(ifaceRefp);
ifaceRefp->cellp(NULL);
AstVar* varNewp = nodep->cloneTree(false);
varNewp->name(varNewName);
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
varNewp->dtypep(ifaceRefp);
m_deModVars.insert(varNewp);
if (!prevp) {
prevp = varNewp;
} else {
prevp->addNextHere(varNewp);
}
}
}
if (prevp) nodep->addNextHere(prevp);
if (prevp && debug()==9) { prevp->dumpTree(cout, "newintf: "); cout << endl; }
}
nodep->iterateChildren(*this);
}
virtual void visit(AstCell* nodep) {
UINFO(4," CELL "<<nodep<<endl);
// Find submodule vars
if (!nodep->modp()) nodep->v3fatalSrc("Unlinked");
m_deModVars.accept(nodep->modp());
//
if (nodep->rangep()) {
m_cellRangep = nodep->rangep();
UINFO(4," CELL "<<nodep<<endl);
AstVar* ifaceVarp = nodep->nextp()->castVar();
bool isIface = ifaceVarp
@@ -199,9 +289,10 @@ private:
// The spec says we add [x], but that won't work in C...
newp->name(newp->name()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
newp->origName(newp->origName()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
UINFO(8," CELL loop "<<newp<<endl);
// If this AstCell is actually an interface instantiation, let's ensure we also clone
// the IfaceRef.
// If this AstCell is actually an interface instantiation, also clone the IfaceRef
// within the same parent module as the cell
if (isIface) {
AstUnpackArrayDType* arrdtype = ifaceVarp->dtypep()->castUnpackArrayDType();
AstIfaceRefDType* origIfaceRefp = arrdtype->subDTypep()->castIfaceRefDType();
@@ -229,42 +320,11 @@ private:
}
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
} else {
m_cellRangep = NULL;
nodep->iterateChildren(*this);
}
}
virtual void visit(AstVar* nodep) {
bool isIface = nodep->dtypep()->castUnpackArrayDType()
&& nodep->dtypep()->castUnpackArrayDType()->subDTypep()->castIfaceRefDType();
if (isIface) {
AstUnpackArrayDType* arrdtype = nodep->dtypep()->castUnpackArrayDType();
AstNode* prev = NULL;
for (int i = arrdtype->lsb(); i <= arrdtype->msb(); ++i) {
AstIfaceRefDType* ifaceRefp = arrdtype->subDTypep()->castIfaceRefDType()->cloneTree(false);
arrdtype->addNextHere(ifaceRefp);
ifaceRefp->cellp(NULL);
string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
VarNameMap::iterator it = m_modVarNameMap.find(varNewName);
if (it == m_modVarNameMap.end()) {
AstVar* varNewp = nodep->cloneTree(false);
m_modVarNameMap.insert(make_pair(varNewName, varNewp));
varNewp->name(varNewName);
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
varNewp->dtypep(ifaceRefp);
if (!prev) {
prev = varNewp;
} else {
prev->addNextHere(varNewp);
}
}
}
if (prev) nodep->addNextHere(prev);
if (prev && debug()==9) { prev->dumpTree(cout, "newintf: "); cout << endl; }
}
nodep->iterateChildren(*this);
}
virtual void visit(AstPin* nodep) {
// Any non-direct pins need reconnection with a part-select
if (!nodep->exprp()) return; // No-connect
@@ -334,30 +394,28 @@ private:
// Clone pin varp:
for (int i = pinArrp->lsb(); i <= pinArrp->msb(); ++i) {
string varNewName = pinVarp->name() + "__BRA__" + cvtToStr(i) + "__KET__";
VarNameMap::iterator it = m_modVarNameMap.find(varNewName);
AstVar* varNewp = NULL;
// Only clone the var once for each module
// Only clone the var once for all usages of a given child module
if (!pinVarp->backp()) {
if (it != m_modVarNameMap.end()) {
varNewp = it->second;
}
varNewp = m_deModVars.find(varNewName);
} else {
AstIfaceRefDType* ifaceRefp = pinArrp->subDTypep()->castIfaceRefDType();
ifaceRefp->cellp(NULL);
varNewp = pinVarp->cloneTree(false);
m_modVarNameMap.insert(make_pair(varNewName, varNewp));
varNewp->name(varNewName);
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
varNewp->dtypep(ifaceRefp);
m_deModVars.insert(varNewp);
if (!prevp) {
prevp = varNewp;
} else {
prevp->addNextHere(varNewp);
}
}
if (varNewp == NULL) {
nodep->v3fatalSrc("Module dearray failed\n");
if (!varNewp) {
if (debug()>=9) m_deModVars.dump();
nodep->v3fatalSrc("Module dearray failed for "<<AstNode::prettyName(varNewName));
}
// But clone the pin for each module instance
+104 -43
View File
@@ -45,70 +45,132 @@ class V3LanguageWords {
public:
V3LanguageWords() {
// C++ keywords
addKwd("asm", "C++ reserved word");
addKwd("auto", "C++ reserved word");
addKwd("catch", "C++ reserved word");
addKwd("cdecl", "C++ reserved word");
addKwd("char", "C++ reserved word");
addKwd("const_cast", "C++ reserved word");
addKwd("delete", "C++ reserved word");
addKwd("double", "C++ reserved word");
addKwd("dynamic_cast", "C++ reserved word");
addKwd("explicit", "C++ reserved word");
addKwd("far", "C++ reserved word");
addKwd("float", "C++ reserved word");
addKwd("friend", "C++ reserved word");
addKwd("goto", "C++ reserved word");
addKwd("huge", "C++ reserved word");
addKwd("inline", "C++ reserved word");
addKwd("interrupt", "C++ reserved word");
addKwd("long", "C++ reserved word");
addKwd("mutable", "C++ reserved word");
addKwd("near", "C++ reserved word");
addKwd("operator", "C++ reserved word");
addKwd("pascal", "C++ reserved word");
addKwd("private", "C++ reserved word");
addKwd("public", "C++ reserved word");
addKwd("register", "C++ reserved word");
addKwd("reinterpret_cast ", "C++ reserved word");
addKwd("restrict", "C++ reserved word");
addKwd("short", "C++ reserved word");
addKwd("sizeof", "C++ reserved word");
addKwd("static_cast", "C++ reserved word");
addKwd("switch", "C++ reserved word");
addKwd("template", "C++ reserved word");
addKwd("throw", "C++ reserved word");
addKwd("try", "C++ reserved word");
addKwd("typeid", "C++ reserved word");
addKwd("typename", "C++ reserved word");
addKwd("unsigned", "C++ reserved word");
addKwd("using", "C++ reserved word");
addKwd("volatile", "C++ reserved word");
// C++
addKwd("NULL", "C++ common word");
addKwd("abort", "C++ common word");
addKwd("alignas", "C++11 keyword");
addKwd("alignof", "C++11 keyword");
addKwd("and", "C++11 keyword");
addKwd("and_eq", "C++11 keyword");
addKwd("asm", "C++ common word");
addKwd("atomic_cancel", "C++ TM TS keyword");
addKwd("atomic_commit", "C++ TM TS keyword");
addKwd("atomic_noexcept", "C++ TM TS keyword");
addKwd("auto", "C++ keyword");
addKwd("bit_vector", "C++ common word");
addKwd("bool", "C++ common word");
addKwd("bitand", "C++ keyword");
addKwd("bitor", "C++ keyword");
addKwd("bool", "C++ keyword");
addKwd("break", "C++ keyword");
addKwd("case", "C++ keyword");
addKwd("catch", "C++ keyword");
addKwd("cdecl", "C++ common word");
addKwd("char", "C++ keyword");
addKwd("char16_t", "C++11 keyword");
addKwd("char32_t", "C++11 keyword");
addKwd("class", "C++11 keyword");
addKwd("compl", "C++11 keyword");
addKwd("complex", "C++ common word");
addKwd("concept", "C++20 keyword");
addKwd("const", "C++ keyword");
addKwd("const_cast", "C++ common word");
addKwd("const_iterator", "C++ common word");
addKwd("const_reference ", "C++ common word");
addKwd("constexpr", "C++11 keyword");
addKwd("continue", "C++ keyword");
addKwd("decltype", "C++11 keyword");
addKwd("default", "C++ keyword");
addKwd("delete", "C++ keyword");
addKwd("deque", "C++ common word");
addKwd("false", "C++ common word");
addKwd("do", "C++ keyword");
addKwd("double", "C++ keyword");
addKwd("dynamic_cast", "C++ keyword");
addKwd("else", "C++ keyword");
addKwd("enum", "C++ keyword");
addKwd("explicit", "C++ keyword");
addKwd("export", "C++ keyword");
addKwd("extern", "C++ keyword");
addKwd("false", "C++ keyword");
addKwd("far", "C++ common word");
addKwd("float", "C++ keyword");
addKwd("for", "C++ keyword");
addKwd("friend", "C++ keyword");
addKwd("goto", "C++ keyword");
addKwd("huge", "C++ keyword");
addKwd("if", "C++ keyword");
addKwd("import", "C++ modules TS keyword");
addKwd("inline", "C++ keyword");
addKwd("int", "C++ keyword");
addKwd("interrupt", "C++ common word");
addKwd("iterator", "C++ common word");
addKwd("list", "C++ common word");
addKwd("long", "C++ keyword");
addKwd("map", "C++ common word");
addKwd("module", "C++ modules TS keyword");
addKwd("multimap", "C++ common word");
addKwd("multiset", "C++ common word");
addKwd("mutable", "C++ keyword");
addKwd("namespace", "C++ keyword");
addKwd("near", "C++ common word");
addKwd("new", "C++ keyword");
addKwd("noexcept", "C++11 keyword");
addKwd("not", "C++ keyword");
addKwd("not_eq", "C++ keyword");
addKwd("nullptr", "C++11 keyword");
addKwd("operator", "C++ keyword");
addKwd("or", "C++ keyword");
addKwd("or_eq", "C++ keyword");
addKwd("override", "C++ common word");
addKwd("pascal", "C++ keyword");
addKwd("private", "C++ keyword");
addKwd("protected", "C++ keyword");
addKwd("public", "C++ keyword");
addKwd("queue", "C++ common word");
addKwd("reference", "C++ common word");
addKwd("register", "C++ keyword");
addKwd("reinterpret_cast ", "C++ keyword");
addKwd("requires", "C++20 keyword");
addKwd("restrict", "C++ keyword");
addKwd("return", "C++ keyword");
addKwd("set", "C++ common word");
addKwd("short", "C++ keyword");
addKwd("signed", "C++ keyword");
addKwd("sizeof", "C++ keyword");
addKwd("stack", "C++ common word");
addKwd("true", "C++ common word");
addKwd("static", "C++ keyword");
addKwd("static_assert", "C++11 keyword");
addKwd("static_cast", "C++ keyword");
addKwd("struct", "C++ keyword");
addKwd("switch", "C++ keyword");
addKwd("synchronized", "C++ TM TS keyword");
addKwd("template", "C++ keyword");
addKwd("this", "C++ keyword");
addKwd("thread_local", "C++11 keyword");
addKwd("throw", "C++ keyword");
addKwd("transaction_safe", "C++ common word");
addKwd("transaction_safe_dynamic", "C++ common word");
addKwd("true", "C++ keyword");
addKwd("try", "C++ keyword");
addKwd("type_info", "C++ common word");
addKwd("typedef", "C++ keyword");
addKwd("typeid", "C++ keyword");
addKwd("typename", "C++ keyword");
addKwd("uint16_t", "C++ common word");
addKwd("uint32_t", "C++ common word");
addKwd("uint8_t", "C++ common word");
addKwd("union", "C++ keyword");
addKwd("unsigned", "C++ keyword");
addKwd("using", "C++ keyword");
addKwd("vector", "C++ common word");
addKwd("virtual", "C++ keyword");
addKwd("void", "C++ keyword");
addKwd("volatile", "C++ keyword");
addKwd("wchar_t", "C++ keyword");
addKwd("while", "C++ keyword");
addKwd("xor", "C++ keyword");
addKwd("xor_eq", "C++ keyword");
// This conflicts with header functions, so is ignored
//dKwd("final", "C++11 keyword"); // Member function or class head, otherwise not reserved
// SystemC
addKwd("sc_clock", "SystemC common word");
addKwd("sc_in", "SystemC common word");
@@ -123,4 +185,3 @@ class V3LanguageWords {
#endif // Guard
+2 -1
View File
@@ -335,7 +335,8 @@ private:
UINFO(9," need .* PORT "<<portp<<endl);
// Create any not already connected
AstPin* newp = new AstPin(nodep->fileline(),0,portp->name(),
new AstVarRef(nodep->fileline(),portp->name(),false));
new AstParseRef(nodep->fileline(),
AstParseRefExp::PX_TEXT, portp->name(), NULL, NULL));
newp->svImplicit(true);
nodep->addPinsp(newp);
} else { // warn on the CELL that needs it, not the port
+10 -6
View File
@@ -445,6 +445,10 @@ public:
<<") <- se"<<srcp<<" "<<srcp->nodep()<<endl);
// srcp should be an interface reference pointing to the interface we want to import
lhsp->importFromIface(symsp(), srcp);
// Allow access to objects not permissible to be listed in a modport
if (srcp->nodep()->castModport()) {
lhsp->importFromIface(symsp(), srcp->parentp(), true);
}
}
//m_scopeAliasMap[samn].clear(); // Done with it, but put into debug file
}
@@ -839,7 +843,7 @@ class LinkDotFindVisitor : public AstNVisitor {
virtual void visit(AstNodeFTask* nodep) {
// NodeTask: Remember its name for later resolution
UINFO(5," "<<nodep<<endl);
if (!m_curSymp || !m_modSymp) nodep->v3fatalSrc("Function/Task not under module??\n");
if (!m_curSymp || !m_modSymp) nodep->v3fatalSrc("Function/Task not under module?");
// Remember the existing symbol table scope
VSymEnt* oldCurSymp = m_curSymp;
{
@@ -873,7 +877,7 @@ class LinkDotFindVisitor : public AstNVisitor {
}
virtual void visit(AstVar* nodep) {
// Var: Remember its name for later resolution
if (!m_curSymp || !m_modSymp) nodep->v3fatalSrc("Var not under module??\n");
if (!m_curSymp || !m_modSymp) nodep->v3fatalSrc("Var not under module?");
nodep->iterateChildren(*this);
if (!m_statep->forScopeCreation()) {
// Find under either a task or the module's vars
@@ -957,12 +961,12 @@ class LinkDotFindVisitor : public AstNVisitor {
}
virtual void visit(AstTypedef* nodep) {
// Remember its name for later resolution
if (!m_curSymp) nodep->v3fatalSrc("Typedef not under module??\n");
if (!m_curSymp) nodep->v3fatalSrc("Typedef not under module?");
nodep->iterateChildren(*this);
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
}
virtual void visit(AstParamTypeDType* nodep) {
if (!m_curSymp) nodep->v3fatalSrc("Parameter type not under module??\n");
if (!m_curSymp) nodep->v3fatalSrc("Parameter type not under module?");
nodep->iterateChildren(*this);
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
}
@@ -1593,7 +1597,7 @@ private:
checkNoDot(nodep);
nodep->iterateChildren(*this);
if (!nodep->modVarp()) {
if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?\n");
if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?");
VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name());
const char* whatp = nodep->param() ? "parameter pin" : "pin";
if (!foundp) {
@@ -1861,7 +1865,7 @@ private:
}
//
if (!ok) {
//Cells/interfaces can't be implicit
// Cells/interfaces can't be implicit
bool isCell = foundp ? foundp->nodep()->castCell() != NULL : false;
bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="" && !isCell);
bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
+3 -1
View File
@@ -174,8 +174,10 @@ private:
virtual void visit(AstValuePlusArgs* nodep) {
bool last_setRefLvalue = m_setRefLvalue;
{
m_setRefLvalue = false;
nodep->searchp()->iterateAndNext(*this);
m_setRefLvalue = true;
nodep->exprsp()->iterateAndNext(*this);
nodep->outp()->iterateAndNext(*this);
}
m_setRefLvalue = last_setRefLvalue;
}
+3 -1
View File
@@ -131,7 +131,9 @@ private:
AstNode* valuep = NULL;
if (nodep->valuep()) valuep = new AstAdd(nodep->fileline(), nodep->valuep()->cloneTree(true),
new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init));
addp = addp->addNextNull(new AstEnumItem(nodep->fileline(), name, NULL, valuep));
AstNode* newp = new AstEnumItem(nodep->fileline(), name, NULL, valuep);
if (addp) addp = addp->addNextNull(newp);
else addp = newp;
}
nodep->replaceWith(addp);
nodep->deleteTree();
+2 -2
View File
@@ -236,12 +236,12 @@ private:
virtual void visit(AstPragma* nodep) {
if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) {
if (!m_modp) nodep->v3fatalSrc("PUBLIC_MODULE not under a module\n");
if (!m_modp) nodep->v3fatalSrc("PUBLIC_MODULE not under a module");
m_modp->modPublic(true);
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
}
else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) {
if (!m_ftaskp) nodep->v3fatalSrc("PUBLIC_TASK not under a task\n");
if (!m_ftaskp) nodep->v3fatalSrc("PUBLIC_TASK not under a task");
m_ftaskp->taskPublic(true);
m_modp->modPublic(true); // Need to get to the task...
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
+27 -10
View File
@@ -48,7 +48,7 @@ V3Number::V3Number(VerilogStringLiteral, FileLine* fileline, const string& str)
}
}
}
opCleanThis();
opCleanThis(true);
}
V3Number::V3Number (FileLine* fileline, const char* sourcep) {
@@ -71,7 +71,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
if (*cp != '_') *wp++ = *cp;
}
*wp++ = '\0';
while (*cp && *cp == '_') cp++;
while (*cp == '_') cp++;
if (*cp && tolower(*cp)=='s') {
cp++; isSigned(true);
}
@@ -254,7 +254,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
setBit(obit, bitIs(obit-1));
obit++;
}
opCleanThis();
opCleanThis(true);
//printf("Dump \"%s\" CP \"%s\" B '%c' %d W %d\n", sourcep, value_startp, base, width(), m_value[0]);
}
@@ -1217,6 +1217,9 @@ V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) {
// L(lhs) bit return
if (rhs.isFourState()) return setAllBitsX();
setZero();
for (int bit=32; bit<rhs.width(); bit++) {
if (rhs.bitIs1(bit)) return *this; // shift of over 2^32 must be zero
}
uint32_t rhsval = rhs.toUInt();
if (rhsval < (uint32_t)lhs.width()) {
for (int bit=0; bit<this->width(); bit++) {
@@ -1232,6 +1235,13 @@ V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_
// We presume it is signed; as that's V3Width's job to convert to opShiftR
if (rhs.isFourState()) return setAllBitsX();
setZero();
for (int bit=32; bit<rhs.width(); bit++) {
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIs(lbits-1)); // 0/1/X/Z
}
if (rhs.bitIs1(lbits-1)) setAllBits1(); // -1 else 0
return *this; // shift of over 2^32 must be -1/0
}
uint32_t rhsval = rhs.toUInt();
if (rhsval < (uint32_t)lhs.width()) {
for (int bit=0; bit<this->width(); bit++) {
@@ -1239,7 +1249,7 @@ V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_
}
} else {
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIs(lbits-1));
setBit(bit,lhs.bitIs(lbits-1)); // 0/1/X/Z
}
}
return *this;
@@ -1249,6 +1259,9 @@ V3Number& V3Number::opShiftL (const V3Number& lhs, const V3Number& rhs) {
// L(lhs) bit return
if (rhs.isFourState()) return setAllBitsX();
setZero();
for (int bit=32; bit<rhs.width(); bit++) {
if (rhs.bitIs1(bit)) return *this; // shift of over 2^32 must be zero
}
uint32_t rhsval = rhs.toUInt();
for (int bit=0; bit<this->width(); bit++) {
if (bit >= (int)rhsval) {
@@ -1518,8 +1531,6 @@ V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs, bool lsign,
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setQuad(1); // Overrides lhs 0 -> return 0
// We may want to special case when the lhs is 2, so we can get larger outputs
if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
if (rsign && rhs.isNegative()) {
if (lhs.isEqZero()) return setAllBitsXRemoved();
else if (lhs.isEqOne()) return setQuad(1);
@@ -1587,10 +1598,16 @@ V3Number& V3Number::opClean (const V3Number& lhs, uint32_t bits) {
return opSel(lhs, bits-1, 0);
}
void V3Number::opCleanThis() {
// Clean in place number
m_value[words()-1] &= hiWordMask();
m_valueX[words()-1] &= hiWordMask();
void V3Number::opCleanThis(bool warnOnTruncation) {
// Clean MSB of number
uint32_t newValueMsb = m_value[words()-1] & hiWordMask();
uint32_t newValueXMsb = m_valueX[words()-1] & hiWordMask();
if (warnOnTruncation && (newValueMsb != m_value[words()-1] || newValueXMsb != m_valueX[words()-1])) {
// Displaying in decimal avoids hiWordMask truncation
m_fileline->v3warn(WIDTH,"Value too large for "<<width()<<" bit number: "<<displayed(m_fileline, "%d"));
}
m_value[words()-1] = newValueMsb;
m_valueX[words()-1] = newValueXMsb;
}
V3Number& V3Number::opSel (const V3Number& lhs, const V3Number& msb, const V3Number& lsb) {
+2 -2
View File
@@ -45,7 +45,7 @@ class V3Number {
// METHODS
V3Number& setSingleBits(char value);
V3Number& setString(const string& str) { m_isString=true; m_stringVal=str; return *this; }
void opCleanThis();
void opCleanThis(bool warnOnTruncation = false);
public:
FileLine* fileline() const { return m_fileline; }
void fileline(FileLine* fl) { m_fileline=fl; }
@@ -327,6 +327,6 @@ public:
V3Number& opLtN (const V3Number& lhs, const V3Number& rhs);
V3Number& opLteN (const V3Number& lhs, const V3Number& rhs);
};
inline ostream& operator<<(ostream& os, V3Number rhs) { return os<<rhs.ascii(); }
inline ostream& operator<<(ostream& os, const V3Number& rhs) { return os<<rhs.ascii(); }
#endif // Guard
+2 -2
View File
@@ -32,7 +32,7 @@
#include <algorithm>
#include "V3Number.h"
void test(string lhss, string op, string rhss, string exps) {
void test(const string& lhss, const string& op, const string& rhss, const string& exps) {
char* l1 = strdup(lhss.c_str());
char* r1 = strdup(rhss.c_str());
char* e1 = strdup(exps.c_str());
@@ -84,7 +84,7 @@ void test(string lhss, string op, string rhss, string exps) {
V3Number ok (new FileLine("ck",__LINE__), 1);
ok.opCaseEq(expnum,gotnum);
if (ok.toUInt()!=1) {
v3fatalSrc("%Error:Test FAILED\n");
v3fatalSrc("%Error:Test FAILED");
}
}
+6 -57
View File
@@ -491,52 +491,6 @@ string V3Options::getenvSYSTEMC_LIBDIR() {
return var;
}
string V3Options::getenvSYSTEMPERL() {
// Must be careful to set SYSTEMPERL_INCLUDE first else we'd setenv
// SYSTEMPERL which would override a DEFENVed SYSTEMPERL_INCLUDE.
V3Options::getenvSYSTEMPERL_INCLUDE();
return V3Options::getenvSYSTEMPERLGuts();
}
string V3Options::getenvSYSTEMPERLGuts() {
// Get SYSTEMPERL when SYSTEMPERL_INCLUDE has already been tested
string var = V3Os::getenvStr("SYSTEMPERL","");
if (var == "" && string(DEFENV_SYSTEMPERL) != "") {
var = DEFENV_SYSTEMPERL;
V3Os::setenvStr("SYSTEMPERL", var, "Hardcoded at build time");
}
return var;
}
string V3Options::getenvSYSTEMPERL_INCLUDE() {
string var = V3Os::getenvStr("SYSTEMPERL_INCLUDE","");
if (var == "") {
string sp_src = V3Options::getenvSYSTEMPERLGuts()+"/src";
if (V3Options::fileStatNormal(sp_src+"/systemperl.h")) {
var = sp_src;
V3Os::setenvStr ("SYSTEMPERL_INCLUDE", var, "From $SYSTEMPERL/src");
} else if (string(DEFENV_SYSTEMPERL_INCLUDE) != "") {
// Note if SYSTEMPERL is DEFENVed, then SYSTEMPERL_INCLUDE is also DEFENVed
// So we don't need to sweat testing DEFENV_SYSTEMPERL also
var = DEFENV_SYSTEMPERL_INCLUDE;
V3Os::setenvStr("SYSTEMPERL_INCLUDE", var, "Hardcoded at build time");
}
}
// Only correct or check it if we really need the value
if (v3Global.opt.usingSystemPerlLibs()) {
// We warn about $SYSTEMPERL instead of _INCLUDE since that's more likely
// what users will want to set.
if (var == "") {
v3fatal("Need $SYSTEMPERL and $SYSTEMPERL_INCLUDE in environment for --sp or --coverage\n"
"Probably System-Perl isn't installed, see http://www.veripool.org/systemperl\n");
}
else if (var != "" && !V3Options::fileStatNormal(var+"/systemperl.h")) {
v3fatal("Neither $SYSTEMPERL nor $SYSTEMPERL_INCLUDE environment vars to point to System-Perl kit: "<<var<<endl);
}
}
return var;
}
string V3Options::getenvVERILATOR_ROOT() {
string var = V3Os::getenvStr("VERILATOR_ROOT","");
if (var == "" && string(DEFENV_VERILATOR_ROOT) != "") {
@@ -559,8 +513,9 @@ string V3Options::version() {
}
void V3Options::throwSigsegv() {
// cppcheck-suppress nullPointer
char* zp=NULL; *zp=0;
#if !(defined(VL_CPPCHECK) || defined(__clang_analyzer__))
char* zp=NULL; *zp=0; // Intentional core dump, ignore warnings here
#endif
}
//######################################################################
@@ -607,7 +562,7 @@ bool V3Options::onoff(const char* sw, const char* arg, bool& flag) {
// if sw=="-no-arg", then return true (found it), and flag=false
// if sw=="-noarg", then return true (found it), and flag=false
// else return false
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.\n");
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash");
if (0==strcmp(sw,arg)) { flag=true; return true; }
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
@@ -682,7 +637,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-autoflush", flag/*ref*/) ) { m_autoflush = flag; }
else if ( onoff (sw, "-bbox-sys", flag/*ref*/) ) { m_bboxSys = flag; }
else if ( onoff (sw, "-bbox-unsup", flag/*ref*/) ) { m_bboxUnsup = flag; }
else if ( !strcmp (sw, "-cc") ) { m_outFormatOk = true; m_systemC = false; m_systemPerl = false; }
else if ( !strcmp (sw, "-cc") ) { m_outFormatOk = true; m_systemC = false; }
else if ( onoff (sw, "-cdc", flag/*ref*/) ) { m_cdc = flag; }
else if ( onoff (sw, "-coverage", flag/*ref*/) ) { coverage(flag); }
else if ( onoff (sw, "-coverage-line", flag/*ref*/) ){ m_coverageLine = flag; }
@@ -713,9 +668,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-report-unoptflat", flag/*ref*/) ) { m_reportUnoptflat = flag; }
else if ( onoff (sw, "-relative-includes", flag/*ref*/) ) { m_relativeIncludes = flag; }
else if ( onoff (sw, "-savable", flag/*ref*/) ) { m_savable = flag; }
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = false; }
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; }
else if ( onoff (sw, "-skip-identical", flag/*ref*/) ) { m_skipIdentical = flag; }
else if ( !strcmp (sw, "-sp-deprecated") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = true; } // Undocumented, old
else if ( onoff (sw, "-stats", flag/*ref*/) ) { m_stats = flag; }
else if ( onoff (sw, "-stats-vars", flag/*ref*/) ) { m_statsVars = flag; m_stats |= flag; }
else if ( !strcmp (sw, "-sv") ) { m_defaultLanguage = V3LangCode::L1800_2005; }
@@ -1178,8 +1132,6 @@ void V3Options::showVersion(bool verbose) {
cout << " SYSTEMC_ARCH = " << DEFENV_SYSTEMC_ARCH<<endl;
cout << " SYSTEMC_INCLUDE = " << DEFENV_SYSTEMC_INCLUDE<<endl;
cout << " SYSTEMC_LIBDIR = " << DEFENV_SYSTEMC_LIBDIR<<endl;
cout << " SYSTEMPERL = " << DEFENV_SYSTEMPERL<<endl;
cout << " SYSTEMPERL_INCLUDE = " << DEFENV_SYSTEMPERL_INCLUDE<<endl;
cout << " VERILATOR_ROOT = " << DEFENV_VERILATOR_ROOT<<endl;
cout <<endl;
@@ -1189,8 +1141,6 @@ void V3Options::showVersion(bool verbose) {
cout << " SYSTEMC_ARCH = " << V3Os::getenvStr("SYSTEMC_ARCH","")<<endl;
cout << " SYSTEMC_INCLUDE = " << V3Os::getenvStr("SYSTEMC_INCLUDE","")<<endl;
cout << " SYSTEMC_LIBDIR = " << V3Os::getenvStr("SYSTEMC_LIBDIR","")<<endl;
cout << " SYSTEMPERL = " << V3Os::getenvStr("SYSTEMPERL","")<<endl;
cout << " SYSTEMPERL_INCLUDE = " << V3Os::getenvStr("SYSTEMPERL_INCLUDE","")<<endl;
cout << " VERILATOR_ROOT = " << V3Os::getenvStr("VERILATOR_ROOT","")<<endl;
cout << " VERILATOR_BIN = " << V3Os::getenvStr("VERILATOR_BIN","")<<endl; // wrapper uses this
}
@@ -1234,7 +1184,6 @@ V3Options::V3Options() {
m_stats = false;
m_statsVars = false;
m_systemC = false;
m_systemPerl = false;
m_trace = false;
m_traceDups = false;
m_traceParams = true;
+2 -9
View File
@@ -93,7 +93,6 @@ class V3Options {
bool m_savable; // main switch: --savable
bool m_systemC; // main switch: --sc: System C instead of simple C++
bool m_skipIdentical;// main switch: --skip-identical
bool m_systemPerl; // main switch: --sp: System Perl instead of SystemC (m_systemC also set)
bool m_stats; // main switch: --stats
bool m_statsVars; // main switch: --stats-vars
bool m_trace; // main switch: --trace
@@ -179,8 +178,6 @@ class V3Options {
bool parseLangExt(const char* swp, const char* langswp, const V3LangCode& lc);
string filePathCheckOneDir(const string& modname, const string& dirname);
static string getenvSYSTEMPERLGuts();
V3Options(const V3Options&); ///< N/A, no copy constructor
public:
@@ -212,9 +209,7 @@ class V3Options {
string bin() const { return m_bin; }
string flags() const { return m_flags; }
bool systemC() const { return m_systemC; }
bool systemPerl() const { return m_systemPerl; }
bool usingSystemCLibs() const { return !lintOnly() && (systemPerl() || systemC()); }
bool usingSystemPerlLibs() const { return !lintOnly() && systemPerl(); }
bool usingSystemCLibs() const { return !lintOnly() && systemC(); }
bool savable() const { return m_savable; }
bool skipIdentical() const { return m_skipIdentical; }
bool stats() const { return m_stats; }
@@ -319,7 +314,7 @@ class V3Options {
bool oTable() const { return m_oTable; }
// METHODS (uses above)
string traceClassBase() const { return systemPerl() ? "SpTraceVcd" : "VerilatedVcd"; }
string traceClassBase() const { return "VerilatedVcd"; }
// METHODS (from main)
static string version();
@@ -339,8 +334,6 @@ class V3Options {
static string getenvSYSTEMC_ARCH();
static string getenvSYSTEMC_INCLUDE();
static string getenvSYSTEMC_LIBDIR();
static string getenvSYSTEMPERL();
static string getenvSYSTEMPERL_INCLUDE();
static string getenvVERILATOR_ROOT();
// METHODS (file utilities using these options)
+5 -5
View File
@@ -194,7 +194,7 @@ public:
// METHODS
OrderVarVertex* newVarUserVertex(V3Graph* graphp, AstScope* scopep,
AstVarScope* varscp, WhichVertex type, bool* createdp=NULL) {
if (type>=WV_MAX) varscp->v3fatalSrc("Bad Case\n");
if (type>=WV_MAX) varscp->v3fatalSrc("Bad case");
OrderVarVertex* vertexp = m_vertexp[type];
if (!vertexp) {
UINFO(6,"New vertex "<<varscp<<endl);
@@ -205,7 +205,7 @@ public:
case WV_PORD: vertexp = new OrderVarPordVertex (graphp, scopep, varscp); break;
case WV_POST: vertexp = new OrderVarPostVertex (graphp, scopep, varscp); break;
case WV_SETL: vertexp = new OrderVarSettleVertex(graphp, scopep, varscp); break;
default: varscp->v3fatalSrc("Bad Case\n");
default: varscp->v3fatalSrc("Bad case");
}
m_vertexp[type] = vertexp;
} else {
@@ -806,15 +806,15 @@ private:
virtual void visit(AstNodeVarRef* nodep) {
if (m_scopep) {
AstVarScope* varscp = nodep->varScopep();
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
if (m_inSenTree) {
// Add CLOCK dependency... This is a root of the tree we'll trace
if (nodep->lvalue()) nodep->v3fatalSrc("How can a sensitivity be setting a var?\n");
if (nodep->lvalue()) nodep->v3fatalSrc("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);
} else {
if (!m_logicVxp) nodep->v3fatalSrc("Var ref not under a logic block\n");
if (!m_logicVxp) nodep->v3fatalSrc("Var ref not under a logic block");
// What new directions is this used
// We don't want to add extra edges if the logic block has many usages of same var
bool gen = false;
+61 -3
View File
@@ -204,7 +204,7 @@ private:
pinp->modPTypep(cloneiter->second->castParamTypeDType());
}
else {
pinp->v3fatalSrc("Not linked?\n");
pinp->v3fatalSrc("Not linked?");
}
}
}
@@ -283,7 +283,59 @@ private:
virtual void visit(AstVarRef* nodep) {
if (nodep->varp()) nodep->varp()->iterate(*this);
}
bool ifaceParamReplace(AstVarXRef* nodep, AstNode* candp) {
for (; candp; candp = candp->nextp()) {
if (nodep->name() == candp->name()) {
if (AstVar* varp = candp->castVar()) {
UINFO(9,"Found interface parameter: "<<varp<<endl);
nodep->varp(varp);
return true;
} else if (AstPin* pinp = candp->castPin()) {
UINFO(9,"Found interface parameter: "<<pinp<<endl);
if (!pinp->exprp()) pinp->v3fatalSrc("Interface parameter pin missing expression");
nodep->replaceWith(pinp->exprp()->cloneTree(false)); VL_DANGLING(nodep);
return true;
}
}
}
return false;
}
virtual void visit(AstVarXRef* nodep) {
// Check to see if the scope is just an interface because interfaces are special
string dotted = nodep->dotted();
if (!dotted.empty() && nodep->varp() && nodep->varp()->isParam()) {
AstNode* backp = nodep;
while ((backp = backp->backp())) {
if (backp->castNodeModule()) {
UINFO(9,"Hit module boundary, done looking for interface"<<endl);
break;
}
if (backp->castVar()
&& backp->castVar()->isIfaceRef()
&& backp->castVar()->childDTypep()
&& backp->castVar()->childDTypep()->castIfaceRefDType()) {
AstIfaceRefDType* ifacerefp = backp->castVar()->childDTypep()->castIfaceRefDType();
// Interfaces passed in on the port map have ifaces
if (AstIface* ifacep = ifacerefp->ifacep()) {
if (dotted == backp->name()) {
UINFO(9,"Iface matching scope: "<<ifacep<<endl);
if (ifaceParamReplace(nodep, ifacep->stmtsp())) {
return;
}
}
}
// Interfaces declared in this module have cells
else if (AstCell* cellp = ifacerefp->cellp()) {
if (dotted == cellp->name()) {
UINFO(9,"Iface matching scope: "<<cellp<<endl);
if (ifaceParamReplace(nodep, cellp->paramsp())) {
return;
}
}
}
}
}
}
nodep->varp(NULL); // Needs relink, as may remove pointed-to var
}
@@ -493,6 +545,12 @@ void ParamVisitor::visitCell(AstCell* nodep) {
if (AstVar* modvarp = pinp->modVarp()) {
if (!modvarp->isGParam()) {
pinp->v3error("Attempted parameter setting of non-parameter: Param "<<pinp->prettyName()<<" of "<<nodep->prettyName());
} else if (pinp->exprp()->castInitArray()
&& modvarp->subDTypep()->castUnpackArrayDType()) {
// Array assigned to array
AstNode* exprp = pinp->exprp();
longname += "_" + paramSmallName(nodep->modp(),modvarp)+paramValueNumber(exprp);
any_overrides = true;
} else {
AstConst* exprp = pinp->exprp()->castConst();
AstConst* origp = modvarp->valuep()->castConst();
@@ -651,11 +709,11 @@ void ParamVisitor::visitCell(AstCell* nodep) {
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
if (pinp->exprp()) {
if (AstVar* modvarp = pinp->modVarp()) {
AstConst* constp = pinp->exprp()->castConst();
AstNode* newp = pinp->exprp(); // Const or InitArray
// Remove any existing parameter
if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree();
// Set this parameter to value requested by cell
modvarp->valuep(constp->cloneTree(false));
modvarp->valuep(newp->cloneTree(false));
}
else if (AstParamTypeDType* modptp = pinp->modPTypep()) {
AstNodeDType* dtypep = pinp->exprp()->castNodeDType();
+1
View File
@@ -1188,6 +1188,7 @@ int V3PreProcImp::getStateToken() {
}
else if (tok==VP_EOF) {
error("`\" not terminated at EOF\n");
break;
}
else if (tok==VP_BACKQUOTE) {
m_strify += "\\\"";
+2 -2
View File
@@ -90,8 +90,8 @@ public:
virtual string removeDefines(const string& text)=0; // Remove defines in a text string
// UTILITIES
void error(string msg) { fileline()->v3error(msg); } ///< Report a error
void fatal(string msg) { fileline()->v3fatalSrc(msg); } ///< Report a fatal error
void error(const string& msg) { fileline()->v3error(msg); } ///< Report a error
void fatal(const string& msg) { fileline()->v3fatalSrc(msg); } ///< Report a fatal error
protected:
// CONSTUCTORS
+78
View File
@@ -44,12 +44,25 @@
#include "V3Task.h"
#include <deque>
#include <sstream>
//============================================================================
//######################################################################
// Simulate class functions
class SimulateStackNode {
public:
// MEMBERS
AstFuncRef* m_funcp;
V3TaskConnects* m_tconnects;
// CONSTRUCTORS
SimulateStackNode(AstFuncRef* funcp, V3TaskConnects* tconnects):
m_funcp(funcp),
m_tconnects(tconnects) {}
~SimulateStackNode() {}
};
class SimulateVisitor : public AstNVisitor {
// Simulate a node tree, returning value of variables
// Two major operating modes:
@@ -90,6 +103,7 @@ private:
// Simulating:
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
deque<SimulateStackNode*> m_callStack; ///< Call stack for verbose error messages
// Cleanup
// V3Numbers that represents strings are a bit special and the API for V3Number does not allow changing them.
@@ -103,6 +117,54 @@ private:
return level;
}
// Potentially very slow, intended for debugging
string prettyNumber(V3Number* nump, AstNodeDType* dtypep) {
if (AstRefDType* refdtypep = dtypep->castRefDType()) {
dtypep = refdtypep->skipRefp();
}
if (AstStructDType* stp = dtypep->castStructDType()) {
if (stp->packed()) {
ostringstream out;
out<<"'{";
for (AstMemberDType* itemp = stp->membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
int width = itemp->width();
int lsb = itemp->lsb();
int msb = lsb + width - 1;
V3Number fieldNum = V3Number(nump->fileline(), width);
fieldNum.opSel(*nump, msb, lsb);
out<<itemp->name()<<": ";
if (AstNodeDType * childTypep = itemp->subDTypep()) {
out<<prettyNumber(&fieldNum, childTypep);
} else {
out<<fieldNum;
}
if (itemp->nextp()) out<<", ";
}
out<<"}";
return out.str();
}
} else if (AstPackArrayDType * arrayp = dtypep->castPackArrayDType()) {
if (AstNodeDType * childTypep = arrayp->subDTypep()) {
ostringstream out;
out<<"[";
int arrayElements = arrayp->elementsConst();
for (int element = 0; element < arrayElements; ++element) {
int width = childTypep->width();
int lsb = width * element;
int msb = lsb + width - 1;
V3Number fieldNum = V3Number(nump->fileline(), width);
fieldNum.opSel(*nump, msb, lsb);
int arrayElem = arrayp->lsb() + element;
out<<arrayElem<<" = "<<prettyNumber(&fieldNum, childTypep);
if (element < arrayElements - 1) out<<", ";
}
out<<"]";
return out.str();
}
}
return nump->ascii();
}
// Checking METHODS
public:
/// Call other-this function on all new *non-constant* var references
@@ -119,6 +181,19 @@ public:
cout<<endl;
}
m_whyNotOptimizable = why;
ostringstream stack;
for (deque<SimulateStackNode*>::iterator it=m_callStack.begin(); it !=m_callStack.end(); ++it) {
AstFuncRef* funcp = (*it)->m_funcp;
stack<<"\nCalled from:\n"<<funcp->fileline()<<" "<<funcp->prettyName()<<"() with parameters:";
V3TaskConnects* tconnects = (*it)->m_tconnects;
for (V3TaskConnects::iterator conIt = tconnects->begin(); conIt != tconnects->end(); ++conIt) {
AstVar* portp = conIt->first;
AstNode* pinp = conIt->second->exprp();
AstNodeDType* dtypep = pinp->dtypep();
stack<<"\n "<<portp->prettyName()<<" = "<<prettyNumber(fetchNumber(pinp), dtypep);
}
}
m_whyNotOptimizable += stack.str();
}
}
inline bool optimizable() const { return m_whyNotNodep==NULL; }
@@ -718,8 +793,11 @@ private:
}
}
}
SimulateStackNode stackNode(nodep, &tconnects);
m_callStack.push_front(&stackNode);
// Evaluate the function
funcp->accept(*this);
m_callStack.pop_front();
if (!m_checkOnly && optimizable()) {
// Grab return value from output variable (if it's a function)
if (!funcp->fvarp()) nodep->v3fatalSrc("Function reference points at non-function");
+6 -5
View File
@@ -272,12 +272,12 @@ private:
//UINFO(9," push "<<nodep<<endl);
SplitLogicVertex* vertexp = new SplitLogicVertex(&m_graph, nodep);
m_stmtStackps.push_back(vertexp);
if (nodep->user3p()) nodep->v3fatalSrc("user3p should not be used; cleared in processBlock\n");
if (nodep->user3p()) nodep->v3fatalSrc("user3p should not be used; cleared in processBlock");
nodep->user3p(vertexp);
}
void scoreboardPopStmt() {
//UINFO(9," pop"<<endl);
if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow\n");
if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow");
m_stmtStackps.pop_back();
}
@@ -346,8 +346,8 @@ private:
SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
vvertexp->splitColor(vvertexp->color());
uint32_t color = vvertexp->splitColor();
if (color >= numVertexes) nextp->v3fatalSrc("More colors than vertexes!\n");
if (!color) nextp->v3fatalSrc("No node color assigned\n");
if (color >= numVertexes) nextp->v3fatalSrc("More colors than vertexes");
if (!color) nextp->v3fatalSrc("No node color assigned");
if (lastOfColor[color]) {
new SplitStrictEdge(&m_graph, lastOfColor[color], vvertexp);
}
@@ -411,7 +411,8 @@ private:
UINFO(6, " Color="<<color<<" New order: "<<nextp<<endl);
if (nextp == nodep && !splitAlwaysp) nodep->unlinkFrBack(&replaceHandle);
else nextp->unlinkFrBack();
newListp = newListp->addNext(nextp);
if (newListp) newListp = newListp->addNext(nextp);
else newListp = nextp;
}
if (splitAlwaysp) {
++m_statSplits;
+8 -5
View File
@@ -183,16 +183,19 @@ public:
}
return any;
}
void importFromIface(VSymGraph* graphp, const VSymEnt* srcp) {
void importFromIface(VSymGraph* graphp, const VSymEnt* srcp, bool onlyUnmodportable = false) {
// Import interface tokens from source symbol table into this symbol table, recursively
UINFO(9, " importIf se"<<(void*)this<<" from se"<<(void*)srcp<<endl);
for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
const string& name = it->first;
VSymEnt* subSrcp = it->second;
VSymEnt* subSymp = new VSymEnt(graphp, subSrcp);
reinsert(name, subSymp);
// And recurse to create children
subSymp->importFromIface(graphp, subSrcp);
AstVar* varp = subSrcp->nodep()->castVar();
if (!onlyUnmodportable || (varp && varp->varType() == AstVarType::GPARAM)) {
VSymEnt* subSymp = new VSymEnt(graphp, subSrcp);
reinsert(name, subSymp);
// And recurse to create children
subSymp->importFromIface(graphp, subSrcp);
}
}
}
void cellErrorScopes(AstNode* lookp, string prettyName="") {
+6 -4
View File
@@ -263,7 +263,7 @@ private:
if (nodep->varp()->user2p()) { // It's being converted to a alias.
UINFO(9, " relinkVar "<<(void*)nodep->varp()->user2p()<<" "<<nodep<<endl);
AstVarScope* newvscp = nodep->varp()->user2p()->castVarScope();
if (!newvscp) nodep->v3fatalSrc("Null?\n");
if (!newvscp) nodep->v3fatalSrc("not linked");
nodep->varScopep(newvscp);
nodep->varp(nodep->varScopep()->varp());
nodep->name(nodep->varp()->name());
@@ -357,7 +357,7 @@ private:
return newvscp;
}
AstNode* createInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) {
AstNode* createInlinedFTask(AstNodeFTaskRef* refp, const string& namePrefix, AstVarScope* outvscp) {
// outvscp is the variable for functions only, if NULL, it's a task
if (!refp->taskp()) refp->v3fatalSrc("Unlinked?");
AstNode* newbodysp = refp->taskp()->stmtsp()->cloneTree(true); // Maybe NULL
@@ -463,7 +463,7 @@ private:
return beginp;
}
AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) {
AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, const string& namePrefix, AstVarScope* outvscp) {
// outvscp is the variable for functions only, if NULL, it's a task
if (!refp->taskp()) refp->v3fatalSrc("Unlinked?");
AstCFunc* cfuncp = m_statep->ftaskCFuncp(refp->taskp());
@@ -938,6 +938,8 @@ private:
if (!portp->basicp() || portp->basicp()->keyword().isDpiUnsupported()) {
portp->v3error("Unsupported: DPI argument of type "<<portp->basicp()->prettyTypeName()<<endl
<<portp->warnMore()<<"... For best portability, use bit, byte, int, or longint");
// We don't warn on logic either, although the 4-stateness is lost.
// That's what other simulators do.
}
}
} else {
@@ -1147,7 +1149,7 @@ private:
m_insStmtp = NULL; // Next thing should be new statement
}
virtual void visit(AstNodeFor* nodep) {
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin.cpp\n");
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin.cpp");
}
virtual void visit(AstNodeStmt* nodep) {
m_insMode = IM_BEFORE;
+2 -1
View File
@@ -1074,7 +1074,8 @@ class TristateVisitor : public TristateBaseVisitor {
UINFO(5,"Unconnected pin terminate "<<nodep<<endl);
AstVar* ucVarp = getCreateUnconnVarp(nodep, nodep->modVarp()->dtypep());
nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp,
nodep->modVarp()->isOutput()));
// We converted, so use declaration output state
nodep->modVarp()->isDeclOutput()));
m_tgraph.setTristate(ucVarp);
// We don't need a driver on the wire; the lack of one will default to tristate
} else if (inDeclProcessing) { // Not an input that was a converted tristate
+1 -1
View File
@@ -387,7 +387,7 @@ private:
} else if (basefromp->castConst()) {
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
} else {
nodep->v3fatalSrc("No VarRef or Const under ArraySel\n");
nodep->v3fatalSrc("No VarRef or Const under ArraySel");
}
// Find range of dtype we are selecting from
int declElements = -1;
+22 -16
View File
@@ -803,7 +803,6 @@ private:
nodep->dtypeFrom(expDTypep);
// rhs already finalized in iterate_shift_prelim
iterateCheck(nodep,"LHS",nodep->lhsp(),SELF,FINAL,nodep->dtypep(),EXTEND_EXP);
if (nodep->width()>64) nodep->v3error("Unsupported: Large >64bit ** power operator not implemented.");
AstNode* newp = NULL; // No change
if (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()) {
newp = new AstPowSS (nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
@@ -2094,8 +2093,9 @@ private:
}
virtual void visit(AstValuePlusArgs* nodep) {
if (m_vup->prelim()) {
userIterateAndNext(nodep->exprsp(), WidthVP(SELF,BOTH).p());
nodep->dtypeSetSigned32(); // Spec says integer return
userIterateAndNext(nodep->searchp(), WidthVP(SELF,BOTH).p());
userIterateAndNext(nodep->outp(), WidthVP(SELF,BOTH).p());
nodep->dtypeChgWidthSigned(32,1,AstNumeric::SIGNED); // Spec says integer return
}
}
virtual void visit(AstUCStmt* nodep) {
@@ -2136,7 +2136,8 @@ private:
AstNodeDType* subDTypep = pinDTypep;
int pinwidth = pinDTypep->width();
int conwidth = conDTypep->width();
if (conDTypep == pinDTypep) { // If match, we're golden
if (conDTypep == pinDTypep // If match, we're golden
|| similarDTypeRecurse(conDTypep, pinDTypep)) {
userIterateAndNext(nodep->exprp(), WidthVP(subDTypep,FINAL).p());
}
else if (m_cellRangep) {
@@ -2178,22 +2179,22 @@ private:
}
// TODO Simple dtype checking, should be a more general check
AstNodeArrayDType* loArrayp = exprDTypep->skipRefp()->castUnpackArrayDType();
AstNodeArrayDType* hiArrayp = modDTypep->skipRefp()->castUnpackArrayDType();
if (loArrayp && hiArrayp && loArrayp->subDTypep()->skipRefp()->castIfaceRefDType()
&& loArrayp->declRange().elements() != hiArrayp->declRange().elements()) {
int loSize = loArrayp->declRange().elements();
int hiSize = hiArrayp->declRange().elements();
AstNodeArrayDType* exprArrayp = exprDTypep->skipRefp()->castUnpackArrayDType();
AstNodeArrayDType* modArrayp = modDTypep->skipRefp()->castUnpackArrayDType();
if (exprArrayp && modArrayp && exprArrayp->subDTypep()->skipRefp()->castIfaceRefDType()
&& exprArrayp->declRange().elements() != modArrayp->declRange().elements()) {
int exprSize = exprArrayp->declRange().elements();
int modSize = modArrayp->declRange().elements();
nodep->v3error("Illegal "<<nodep->prettyOperatorName()<<","
<<" mismatch between port which is an interface array of size "<<loSize<<","
<<" and expression which is an interface array of size "<<hiSize<<".");
<<" mismatch between port which is an interface array of size "<<modSize<<","
<<" and expression which is an interface array of size "<<exprSize<<".");
UINFO(1," Related lo: "<<modDTypep->skipRefp()<<endl);
UINFO(1," Related hi: "<<exprDTypep->skipRefp()<<endl);
} else if ((loArrayp && !hiArrayp && pinwidth != conwidth)
|| (!loArrayp && hiArrayp && pinwidth != conwidth)) {
} else if ((exprArrayp && !modArrayp && pinwidth != conwidth)
|| (!exprArrayp && modArrayp && pinwidth != conwidth)) {
nodep->v3error("Illegal "<<nodep->prettyOperatorName()<<","
<<" mismatch between port which is"<<(loArrayp?"":" not")<<" an array,"
<<" and expression which is"<<(hiArrayp?"":" not")<<" an array.");
<<" mismatch between port which is"<<(modArrayp?"":" not")<<" an array,"
<<" and expression which is"<<(exprArrayp?"":" not")<<" an array.");
UINFO(1," Related lo: "<<modDTypep->skipRefp()<<endl);
UINFO(1," Related hi: "<<exprDTypep->skipRefp()<<endl);
}
@@ -2748,6 +2749,8 @@ private:
AstNodeDType* expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
AstNodeDType* subDTypep = expDTypep;
nodep->dtypeFrom(expDTypep);
// We don't use LHS && RHS -- unspecified language corner, see t_math_signed5 test
//bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
if (AstNodeBiop* newp=replaceWithUOrSVersion(nodep, expDTypep->isSigned())) { VL_DANGLING(nodep);
nodep = newp; // Process new node instead
}
@@ -2909,6 +2912,9 @@ private:
return false; // No change
}
bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) {
return node1p->skipRefp()->similarDType(node2p->skipRefp());
}
void iterateCheckFileDesc (AstNode* nodep, AstNode* underp, Stage stage) {
if (stage != BOTH) nodep->v3fatalSrc("Bad call");
// underp may change as a result of replacement
+17 -4
View File
@@ -154,7 +154,7 @@ private:
return newp;
}
AstNode* newSubLsbOf(AstNode* underp, VNumRange fromRange) {
AstNode* newSubLsbOf(AstNode* underp, const VNumRange& fromRange) {
// Account for a variable's LSB in bit selections
// Will likely become SUB(underp, lsb_of_signal)
// Don't report WIDTH warnings etc here, as may be inside a generate branch that will be deleted
@@ -223,7 +223,11 @@ private:
// SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex)
AstNode* subp = rhsp;
if (fromRange.lo()!=0 || fromRange.hi()<0) {
subp = newSubNeg (subp, fromRange.lo());
if (fromRange.littleEndian()) {
subp = newSubNeg(fromRange.hi(), subp);
} else {
subp = newSubNeg(subp, fromRange.lo());
}
}
if (!fromRange.elements() || (adtypep->width() % fromRange.elements())!=0)
adtypep->v3fatalSrc("Array extraction with width miscomputed "
@@ -311,11 +315,20 @@ private:
if (!fromRange.elements() || (adtypep->width() % fromRange.elements())!=0)
adtypep->v3fatalSrc("Array extraction with width miscomputed "
<<adtypep->width()<<"/"<<fromRange.elements());
if (fromRange.littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
}
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
int x = msb; msb = lsb; lsb = x;
}
int elwidth = adtypep->width() / fromRange.elements();
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
new AstConst(nodep->fileline(),AstConst::Unsized32(),lsb*elwidth),
new AstConst(nodep->fileline(),AstConst::Unsized32(),(msb-lsb+1)*elwidth));
new AstMul(nodep->fileline(), newSubLsbOf(lsbp, fromRange),
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth)),
new AstConst(nodep->fileline(), AstConst::Unsized32(), (msb-lsb+1)*elwidth));
newp->declRange(fromRange);
newp->declElWidth(elwidth);
newp->dtypeFrom(sliceDType(adtypep, msb, lsb));
+1 -3
View File
@@ -106,7 +106,7 @@ AstNetlist* V3Global::makeNetlist() {
void V3Global::checkTree() { rootp()->checkTree(); }
void V3Global::clear() {
if (m_rootp) m_rootp->deleteTree(); m_rootp=NULL;
if (m_rootp) { m_rootp->deleteTree(); m_rootp=NULL; }
}
void V3Global::readFiles() {
@@ -568,8 +568,6 @@ int main(int argc, char** argv, char** env) {
V3Options::getenvSYSTEMC_ARCH();
V3Options::getenvSYSTEMC_INCLUDE();
V3Options::getenvSYSTEMC_LIBDIR();
V3Options::getenvSYSTEMPERL();
V3Options::getenvSYSTEMPERL_INCLUDE();
V3Error::abortIfErrors();
+3 -2
View File
@@ -44,8 +44,9 @@ private:
if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL; // Keep power of two
m_dataSize *= 2;
//UINFO(9, "Realloc "<<allocSize()<<" for "<<point<<" "<<(void*)(m_datap)<<endl);
m_datap = (vluint64_t*)realloc(m_datap, allocSize());
if (!m_datap) {v3fatal("Out of memory increasing buckets"); }
vluint64_t* newp = (vluint64_t*)realloc(m_datap, allocSize());
if (!newp) { free(m_datap); v3fatal("Out of memory increasing buckets"); }
m_datap = newp;
for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
}
+1 -1
View File
@@ -52,7 +52,7 @@ bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) {
// if sw=="-no-arg", then return true (found it), and flag=false
// if sw=="-noarg", then return true (found it), and flag=false
// else return false
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.\n");
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.");
if (0==strcmp(sw,arg)) { flag=true; return true; }
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
-6
View File
@@ -53,12 +53,6 @@
#ifndef DEFENV_SYSTEMC_LIBDIR
# define DEFENV_SYSTEMC_LIBDIR ""
#endif
#ifndef DEFENV_SYSTEMPERL
# define DEFENV_SYSTEMPERL ""
#endif
#ifndef DEFENV_SYSTEMPERL_INCLUDE
# define DEFENV_SYSTEMPERL_INCLUDE ""
#endif
#ifndef DEFENV_VERILATOR_ROOT
# define DEFENV_VERILATOR_ROOT ""
#endif
+29 -2
View File
@@ -52,14 +52,19 @@ sub process {
$fh or die "%Error: '$cmd' failed: $!\n";
my %uniq;
my %errs;
my $last_error = "";
while (defined(my $line = $fh->getline())) {
$line =~ s/^\s+//;
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
# General gunk
next if $uniq{$line}++;
next if $line =~ m!^<\?xml version!;
next if $line =~ m!^<results>!;
next if $line =~ m!^<cppcheck!;
next if $line =~ m!^<results!;
next if $line =~ m!^</results>!;
next if $line =~ m!^<errors!;
next if $line =~ m!^</error>!;
next if $line =~ m!^</errors>!;
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
next if $line =~ m!^Checking !;
@@ -80,10 +85,32 @@ sub process {
print $line;
} else {
my $suppress;
# --xml-format=1
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
my $file = $1; my $linenum = $2; my $id = $3;
$suppress = 1 if _suppress($file,$linenum,$id);
}
# --xml-format=2
if ($line =~ /<error id.*/) {
$last_error = $line;
chomp $last_error;
$suppress = 1;
}
elsif ($line =~ /<location.* file="([^"]+)"\s+line="(\d+)"/) {
my $file = $1; my $linenum = $2; my $id;
if ($last_error =~ / id="([^"]+)"/) {
$id = $1;
} else {
$id = "?";
}
$suppress = 1 if _suppress($file,$linenum,$id);
$suppress = 1 if $file eq "*";
if (!$suppress) {
chomp $line;
print "$file:$linenum: ".$last_error."\n";
$suppress = 1;
}
}
if (!$suppress) {
my $eline = "%Error: cppcheck: $line";
print $eline;
@@ -122,7 +149,7 @@ sub _suppress {
my $supids = $1;
foreach my $supid (split /\s+/, $supids) {
if ($supid eq $id
|| $supid eq $SuppressMap{$id}) {
|| $supid eq ($SuppressMap{$id}||'')) {
return 1;
}
}
+1 -1
View File
@@ -873,7 +873,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* Attributes */
/* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
"(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } // Doesn't match (*), but (* attr_spec
"(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } /* Doesn't match (*), but (* attr_spec */
}
/************************************************************************/
+2 -2
View File
@@ -2710,12 +2710,12 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); }
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
| yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); }
| yD_TIME parenE { $$ = new AstTime($1); }
| yD_UNPACKED_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); }
| yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); }
| yD_VALUEPLUSARGS '(' str ',' expr ')' { $$ = new AstValuePlusArgs($1,*$3,$5); }
| yD_VALUEPLUSARGS '(' expr ',' expr ')' { $$ = new AstValuePlusArgs($1,$3,$5); }
;
exprOrDataType<nodep>: // expr | data_type: combined to prevent conflicts
+2 -2
View File
@@ -15,7 +15,7 @@
default: $(VM_PREFIX)
ifneq ($(MAKE_MAIN),0)
# Add main to classes rather then SP_SRCS to save a compiler run
# Add main to classes rather then SC_SRCS to save a compiler run
VM_CLASSES += ${VM_PREFIX}__main $(VM_USER_CLASSES) $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW)
endif
@@ -38,7 +38,7 @@ CPPFLAGS += $(CPPFLAGS_ADD)
#######################################################################
# Linking final exe
ifeq ($(VM_SP_OR_SC),1)
ifeq ($(VM_SC),1)
LIBS += $(SC_LIBS)
endif
+16 -55
View File
@@ -18,6 +18,7 @@ use Data::Dumper; $Data::Dumper::Sortkeys=1;
use strict;
use vars qw ($Debug %Vars $Driver $Fork);
use POSIX qw(strftime);
use lib ".";
$::Driver = 1;
$::Have_Forker = 0;
@@ -27,9 +28,6 @@ $Fork = Forker->new(use_sig_child=>1) if !$Fork;
$SIG{CHLD} = sub { $Fork->sig_child() if $Fork; };
$SIG{TERM} = sub { $Fork->kill_tree_all('TERM') if $Fork; die "Quitting...\n"; };
our $Have_System_Perl;
eval "use SystemC::Netlist; \$Have_System_Perl=1;";
#======================================================================
#======================================================================
@@ -506,7 +504,6 @@ sub compile_vlt_flags {
@{$param{verilator_flags2}},
@{$param{verilator_flags3}});
$self->{sc} = 1 if ($checkflags =~ /-sc\b/);
$self->{sp} = 1 if ($checkflags =~ /-sp\b/);
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/);
$self->{savable} = 1 if ($checkflags =~ /-savable\b/);
$self->{coverage} = 1 if ($checkflags =~ /-coverage\b/);
@@ -662,7 +659,7 @@ sub compile {
elsif ($param{vlt}) {
my @cmdargs = $self->compile_vlt_flags(%param);
if ($self->sc_or_sp && !defined $ENV{SYSTEMC} && !defined $ENV{SYSTEMC_INCLUDE}) {
if ($self->sc && !defined $ENV{SYSTEMC} && !defined $ENV{SYSTEMC_INCLUDE}) {
$self->skip("Test requires SystemC; ignore error since not installed\n");
return 1;
}
@@ -679,9 +676,6 @@ sub compile {
return 1 if $self->errors || $self->skips || $self->unsupporteds;
if (!$param{fails} && $param{verilator_make_gcc}) {
if ($self->sp) {
$self->_sp_preproc(%param);
}
$self->oprint("GCC\n");
$self->_run(logfile=>"$self->{obj_dir}/vlt_gcc.log",
cmd=>["cd $self->{obj_dir} && ",
@@ -907,20 +901,11 @@ sub v_suffix {
return $self->{vhdl} ? "vhdl" : "v";
}
sub sp {
my $self = (ref $_[0]? shift : $Self);
return $self->{sp};
}
sub sc {
my $self = (ref $_[0]? shift : $Self);
return $self->{sc};
}
sub sc_or_sp {
return sc($_[0]) || sp($_[0]);
}
#----------------------------------------------------------------------
sub _run {
@@ -1058,13 +1043,11 @@ sub _make_main {
print $fh "// General headers\n";
print $fh "#include \"verilated.h\"\n";
print $fh "#include \"systemc.h\"\n" if $self->sc;
print $fh "#include \"systemperl.h\"\n" if $self->sp;
print $fh "#include \"verilated_vcd_c.h\"\n" if $self->{trace} && !$self->sp;
print $fh "#include \"verilated_vcd_c.h\"\n" if $self->{trace};
print $fh "#include \"verilated_save.h\"\n" if $self->{savable};
print $fh "#include \"SpTraceVcd.h\"\n" if $self->{trace} && $self->sp;
print $fh "$VM_PREFIX * topp;\n";
if (!$self->sc_or_sp) {
if (!$self->sc) {
print $fh "vluint64_t main_time = false;\n";
print $fh "double sc_time_stamp () {\n";
print $fh " return main_time;\n";
@@ -1093,7 +1076,7 @@ sub _make_main {
}
#### Main
if ($self->sc_or_sp) {
if ($self->sc) {
print $fh "extern int sc_main(int argc, char **argv);\n";
print $fh "int sc_main(int argc, char **argv) {\n";
print $fh " sc_signal<bool> fastclk;\n" if $self->{inputs}{fastclk};
@@ -1108,11 +1091,7 @@ sub _make_main {
print $fh " Verilated::randReset(".$self->{verilated_randReset}.");\n" if defined $self->{verilated_randReset};
print $fh " topp = new $VM_PREFIX (\"top\");\n";
my $set;
if ($self->sp) {
print $fh " SP_PIN(topp,fastclk,fastclk);\n" if $self->{inputs}{fastclk};
print $fh " SP_PIN(topp,clk,clk);\n" if $self->{inputs}{clk};
$set = "";
} elsif ($self->sc) {
if ($self->sc) {
print $fh " topp->fastclk(fastclk);\n" if $self->{inputs}{fastclk};
print $fh " topp->clk(clk);\n" if $self->{inputs}{clk};
$set = "";
@@ -1125,14 +1104,10 @@ sub _make_main {
$fh->print("\n");
$fh->print("#if VM_TRACE\n");
$fh->print(" Verilated::traceEverOn(true);\n");
if ($self->{sp}) {
$fh->print(" SpTraceFile* tfp = new SpTraceFile;\n");
} else {
$fh->print(" VerilatedVcdC* tfp = new VerilatedVcdC;\n");
}
$fh->print(" VerilatedVcdC* tfp = new VerilatedVcdC;\n");
$fh->print(" topp->trace (tfp, 99);\n");
$fh->print(" tfp->open (\"$self->{obj_dir}/simx.vcd\");\n");
if ($self->{trace} && !$self->sc_or_sp) {
if ($self->{trace} && !$self->sc) {
$fh->print(" if (tfp) tfp->dump (main_time);\n");
}
$fh->print("#endif\n");
@@ -1208,11 +1183,10 @@ sub _print_advance_time {
my $action = shift;
my $set;
if ($self->sp) { $set = ""; }
elsif ($self->sc) { $set = ""; }
if ($self->sc) { $set = ""; }
else { $set = "topp->"; }
if ($self->sc_or_sp) {
if ($self->sc) {
print $fh "#if (SYSTEMC_VERSION>=20070314)\n";
print $fh " sc_start(${time},SC_NS);\n";
print $fh "#else\n";
@@ -1221,7 +1195,7 @@ sub _print_advance_time {
} else {
if ($action) {
print $fh " ${set}eval();\n";
if ($self->{trace} && !$self->sc_or_sp) {
if ($self->{trace} && !$self->sc) {
$fh->print("#if VM_TRACE\n");
$fh->print(" if (tfp) tfp->dump (main_time);\n");
$fh->print("#endif //VM_TRACE\n");
@@ -1349,22 +1323,6 @@ sub _make_top_vhdl {
#######################################################################
sub _sp_preproc {
my $self = shift;
my %param = (%{$self}, @_); # Default arguments are from $self
$self->oprint("Preproc\n");
$self->_run(logfile=>"simx.log",
fails=>0,
cmd=>["cd $self->{obj_dir} ; sp_preproc",
"--preproc",
"$self->{VM_PREFIX}.sp",
]);
}
#######################################################################
sub _read_inputs_v {
my $self = shift;
my $filename = $self->top_filename;
@@ -1463,9 +1421,12 @@ sub vcd_identical {
if (!-r $fn2) { $self->error("File does not exist $fn2\n"); return 0; }
{
# vcddiff to check transitions, if installed
my $out = `vcddiff --help`;
my $cmd = qq{vcddiff --help};
print "\t$cmd\n" if $::Debug;
my $out = `$cmd`;
if ($out !~ /Usage:/) { $self->skip("No vcddiff installed\n"); return 0; }
my $cmd = qq{vcddiff "$fn1" "$fn2"};
$cmd = qq{vcddiff "$fn1" "$fn2"};
print "\t$cmd\n" if $::Debug;
$out = `$cmd`;
if ($out ne '') {
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ['--assert'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+33
View File
@@ -0,0 +1,33 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2016 by Wilson Snyder
module t (/*AUTOARG*/
// Outputs
dout,
// Inputs
clk, sel, a, c
);
input clk;
input bit [3:0] sel;
input bit [3:0] a;
input bit c;
output bit dout;
localparam logic DC = 1'b?;
always_ff @(posedge clk) begin
unique casez(sel)
4'b0000: dout <= a[0];
4'b001?: dout <= a[1];
{1'b0, 1'b1, 1'b?, 1'b?}: dout <= a[2];
{1'b1, 1'b?, 1'b?, DC}: dout <= a[3];
default: dout <= '0;
endcase
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+97
View File
@@ -0,0 +1,97 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
//
module some_module (
input wrclk
);
logic [ 1 : 0 ] some_state;
logic [1:0] some_other_state;
always @(posedge wrclk) begin
case (some_state)
2'b11:
if (some_other_state == 0)
some_state <= 2'b00;
default:
$display ("This is a display statement");
endcase
if (wrclk)
some_other_state <= 0;
end
endmodule
`define BROKEN
module t1(
input [3:0] i_clks,
input i_clk0,
input i_clk1
);
some_module
some_module
(
`ifdef BROKEN
.wrclk (i_clks[3])
`else
.wrclk (i_clk1)
`endif
);
endmodule
module t2(
input [2:0] i_clks,
input i_clk0,
input i_clk1,
input i_clk2,
input i_data
);
logic [3:0] the_clks;
logic data_q;
assign the_clks = {i_clk1, i_clk2, i_clk1, i_clk0};
always @(posedge i_clk0) begin
data_q <= i_data;
end
t1 t1
(
.i_clks (the_clks),
.i_clk0 (i_clk0),
.i_clk1 (i_clk1)
);
endmodule
module t(
input clk0 /*verilator clocker*/,
input clk1 /*verilator clocker*/,
input clk2 /*verilator clocker*/,
input data_in
);
logic [2:0] clks;
assign clks = {1'b0, clk1, clk0};
t2
t2
(
.i_clks (clks),
.i_clk0 (clk0),
.i_clk1 (clk1),
.i_clk2 (clk2),
.i_data (data_in)
);
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+106
View File
@@ -0,0 +1,106 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
//
module some_module (
input wrclk
);
logic [ 1 : 0 ] some_state;
logic [1:0] some_other_state;
always @(posedge wrclk) begin
case (some_state)
2'b11:
if (some_other_state == 0)
some_state <= 2'b00;
default:
$display ("This is a display statement");
endcase
if (wrclk)
some_other_state <= 0;
end
endmodule
`define BROKEN
module t1(
input [3:0] i_clks,
input i_clk0,
input i_clk1
);
some_module
some_module
(
`ifdef BROKEN
.wrclk (i_clks[3])
`else
.wrclk (i_clk1)
`endif
);
endmodule
module t2(
input [2:0] i_clks,
input i_clk0,
input i_clk1,
input i_clk2,
input i_data
);
logic [3:0] the_clks;
logic data_q;
assign the_clks[3] = i_clk1;
assign the_clks[2] = i_clk2;
assign the_clks[1] = i_clk1;
assign the_clks[0] = i_clk0;
always @(posedge i_clk0) begin
data_q <= i_data;
end
t1 t1
(
.i_clks (the_clks),
.i_clk0 (i_clk0),
.i_clk1 (i_clk1)
);
endmodule
module t(
/*AUTOARG*/
// Inputs
clk /*verilator clocker*/,
input clk0 /*verilator clocker*/,
input clk1 /*verilator clocker*/,
input clk2 /*verilator clocker*/,
input data_in
);
input clk;
logic [2:0] clks;
assign clks = {1'b0, clk1, clk0};
t2
t2
(
.i_clks (clks),
.i_clk0 (clk0),
.i_clk1 (clk),
.i_clk2 (clk2),
.i_data (data_in)
);
always @(posedge clk) begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+101
View File
@@ -0,0 +1,101 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
//
/* verilator lint_off LITENDIAN */
module some_module (
input wrclk
);
logic [ 1 : 0 ] some_state;
logic [1:0] some_other_state;
always @(posedge wrclk) begin
case (some_state)
2'b11:
if (some_other_state == 0)
some_state <= 2'b00;
default:
$display ("This is a display statement");
endcase
if (wrclk)
some_other_state <= 0;
end
endmodule
`define BROKEN
module t1(
input [-12:-9] i_clks,
input i_clk0,
input i_clk1
);
some_module
some_module
(
`ifdef BROKEN
.wrclk (i_clks[-12])
`else
.wrclk (i_clk1)
`endif
);
endmodule
module t2(
input [2:0] i_clks,
input i_clk0,
input i_clk1,
input i_clk2,
input i_data
);
logic [-12:-9] the_clks;
logic data_q;
assign the_clks[-12] = i_clk1;
assign the_clks[-11] = i_clk2;
assign the_clks[-10] = i_clk1;
assign the_clks[-9] = i_clk0;
always @(posedge i_clk0) begin
data_q <= i_data;
end
t1 t1
(
.i_clks (the_clks),
.i_clk0 (i_clk0),
.i_clk1 (i_clk1)
);
endmodule
module t(
input clk0 /*verilator clocker*/,
input clk1 /*verilator clocker*/,
input clk2 /*verilator clocker*/,
input data_in
);
logic [2:0] clks;
assign clks = {1'b0, clk1, clk0};
t2
t2
(
.i_clks (clks),
.i_clk0 (clk0),
.i_clk1 (clk1),
.i_clk2 (clk2),
.i_data (data_in)
);
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+105
View File
@@ -0,0 +1,105 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
//
module some_module (
input wrclk
);
logic [ 1 : 0 ] some_state;
logic [1:0] some_other_state;
always @(posedge wrclk) begin
case (some_state)
2'b11:
if (some_other_state == 0)
some_state <= 2'b00;
default:
$display ("This is a display statement");
endcase
if (wrclk)
some_other_state <= 0;
end
endmodule
`define BROKEN
module t1(
input [3:0] i_clks,
input i_clk0,
input i_clk1
);
generate
genvar i;
for (i = 0; i < 2; i = i + 1) begin: a_generate_block
some_module
some_module
(
`ifdef BROKEN
.wrclk (i_clks[3])
`else
.wrclk (i_clk1)
`endif
);
end
endgenerate
endmodule
module t2(
input [2:0] i_clks,
input i_clk0,
input i_clk1,
input i_clk2,
input i_data
);
logic [3:0] the_clks;
logic data_q;
assign the_clks[3] = i_clk1;
assign the_clks[2] = i_clk2;
assign the_clks[1] = i_clk1;
assign the_clks[0] = i_clk0;
always @(posedge i_clk0) begin
data_q <= i_data;
end
t1 t1
(
.i_clks (the_clks),
.i_clk0 (i_clk0),
.i_clk1 (i_clk1)
);
endmodule
module t(
input clk0 /*verilator clocker*/,
input clk1 /*verilator clocker*/,
input clk2 /*verilator clocker*/,
input data_in
);
logic [2:0] clks;
assign clks = {1'b0, clk1, clk0};
t2
t2
(
.i_clks (clks),
.i_clk0 (clk0),
.i_clk1 (clk1),
.i_clk2 (clk2),
.i_data (data_in)
);
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+104
View File
@@ -0,0 +1,104 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
//
module some_module (
input [3:0] i_clks
);
logic [ 1 : 0 ] some_state;
logic [1:0] some_other_state;
always @(posedge i_clks[3]) begin
case (some_state)
2'b11:
if (some_other_state == 0)
some_state <= 2'b00;
default:
$display ("This is a display statement");
endcase
if (i_clks[3])
some_other_state <= 0;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
`define BROKEN
module t1(
input [3:0] i_clks,
input i_clk0,
input i_clk1
);
some_module
some_module
(
.i_clks (i_clks)
);
endmodule
module t2(
input [2:0] i_clks,
input i_clk0,
input i_clk1,
input i_clk2,
input i_data
);
logic [3:0] the_clks;
logic data_q;
assign the_clks[3] = i_clk1;
assign the_clks[2] = i_clk2;
assign the_clks[1] = i_clk1;
assign the_clks[0] = i_clk0;
always @(posedge i_clk0) begin
data_q <= i_data;
end
t1 t1
(
.i_clks (the_clks),
.i_clk0 (i_clk0),
.i_clk1 (i_clk1)
);
endmodule
module t(
/*AUTOARG*/
// Inputs
clk /*verilator clocker*/,
input clk0 /*verilator clocker*/,
input clk1 /*verilator clocker*/,
input clk2 /*verilator clocker*/,
input data_in
);
input clk;
logic [2:0] clks;
assign clks = {1'b0, clk1, clk0};
t2
t2
(
.i_clks (clks),
.i_clk0 (clk0),
.i_clk1 (clk),
.i_clk2 (clk2),
.i_data (data_in)
);
// initial begin
// $write("*-* All Finished *-*\n");
// $finish;
// end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+113
View File
@@ -0,0 +1,113 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
//
module some_module (
input [3:0] i_clks
);
logic [ 1 : 0 ] some_state;
logic [1:0] some_other_state;
logic the_clk;
assign the_clk = i_clks[3];
always @(posedge the_clk) begin
case (some_state)
2'b11:
if (some_other_state == 0)
some_state <= 2'b00;
default:
$display ("This is a display statement");
endcase
if (the_clk)
some_other_state <= 0;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
`define BROKEN
module t1(
input [3:0] i_clks,
input i_clk0,
input i_clk1
);
some_module
some_module
(
.i_clks (i_clks)
);
endmodule
module ident(
input i_ident,
output o_ident
);
assign o_ident = i_ident;
endmodule
module t2(
input [2:0] i_clks,
input i_clk0,
input i_clk1,
input i_clk2,
input i_data
);
logic [3:0] the_clks;
logic data_q;
logic ident_clk1;
always @(posedge i_clk0) begin
data_q <= i_data;
end
ident
ident
(
.i_ident (i_clk1),
.o_ident (ident_clk1)
);
t1 t1
(
.i_clks ({ident_clk1, i_clk2, ident_clk1, i_clk0}),
.i_clk0 (i_clk0),
.i_clk1 (i_clk1)
);
endmodule
module t(
/*AUTOARG*/
// Inputs
clk /*verilator clocker*/ /*verilator public_flat*/,
input clk0 /*verilator clocker*/,
input clk1 /*verilator clocker*/,
input clk2 /*verilator clocker*/,
input data_in
);
input clk;
logic [2:0] clks;
assign clks = {1'b0, clk1, clk0};
t2
t2
(
.i_clks (clks),
.i_clk0 (clk0),
.i_clk1 (clk),
.i_clk2 (clk2),
.i_data (data_in)
);
endmodule

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