mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1448cc56fc | ||
|
|
074689b5de | ||
|
|
8dd612a0a0 | ||
|
|
22fdbba0b5 | ||
|
|
39b787670b | ||
|
|
a221278c05 | ||
|
|
5f26b9ec66 | ||
|
|
48778d0a77 | ||
|
|
42d2cbad41 | ||
|
|
cb82c42e35 | ||
|
|
f13fb330ed | ||
|
|
d4bae48ca2 | ||
|
|
590ad964b1 | ||
|
|
d4595df8a4 | ||
|
|
7b642bcbb4 | ||
|
|
ca26596695 | ||
|
|
88cf5e5d98 | ||
|
|
13f790360d | ||
|
|
70daadf987 | ||
|
|
9d5004db1c | ||
|
|
ea82bfcced | ||
|
|
00a502942e | ||
|
|
2031bc7fc4 | ||
|
|
3adb22e971 | ||
|
|
331ea5116f | ||
|
|
1da5a33f88 | ||
|
|
6c87724af8 | ||
|
|
c7a5ff5e82 | ||
|
|
abf2fcf820 | ||
|
|
644c22b08f | ||
|
|
c54024a5e6 | ||
|
|
97093fdf81 | ||
|
|
50c4f60c68 | ||
|
|
f0fb3b78d1 | ||
|
|
9b06178f35 | ||
|
|
a01c96140b | ||
|
|
02530172e7 | ||
|
|
447d803800 | ||
|
|
6b04901c4d | ||
|
|
7fb29621c3 | ||
|
|
b032fce962 | ||
|
|
ce879122bb | ||
|
|
2fa16708b7 | ||
|
|
54bc8608e3 | ||
|
|
706a7802cc | ||
|
|
9dc01cf540 | ||
|
|
8943ad5966 | ||
|
|
deb7a1c9c0 | ||
|
|
96a5445d44 | ||
|
|
d693065afb | ||
|
|
bdeee35669 | ||
|
|
62b3deb90d | ||
|
|
9df9ff59e0 | ||
|
|
23a3271c06 |
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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]];
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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");
|
||||
|
||||
@@ -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;"; }
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()));
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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; }
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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 '') {
|
||||
|
||||
Executable
+19
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
Reference in New Issue
Block a user