Four-state logic squash - signals interleave
Signed-off-by: Igor Zaworski <izaworski@antmicro.com>
This commit is contained in:
parent
3503b9d853
commit
8a24a518c4
|
|
@ -107,7 +107,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2, dist-vlt4-0, dist-vlt4-1, dist-vlt4-2, dist-vlt4-3, vltmt4-0, vltmt4-1, vltmt4-2]
|
||||
|
||||
test-2604-clang:
|
||||
name: Test | 26.04 | clang | ${{ matrix.suite }}
|
||||
|
|
@ -121,7 +121,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2, dist-vlt4-0, dist-vlt4-1, dist-vlt4-2, dist-vlt4-3, vltmt4-0, vltmt4-1, vltmt4-2]
|
||||
|
||||
test-2404-gcc:
|
||||
name: Test | 24.04 | gcc | ${{ matrix.suite }}
|
||||
|
|
@ -135,7 +135,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2, dist-vlt4-0, dist-vlt4-1, dist-vlt4-2, dist-vlt4-3, vltmt4-0, vltmt4-1, vltmt4-2]
|
||||
|
||||
test-2404-clang:
|
||||
name: Test | 24.04 | clang | ${{ matrix.suite }}
|
||||
|
|
@ -150,7 +150,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2, dist-vlt4-0, dist-vlt4-1, dist-vlt4-2, dist-vlt4-3, vltmt4-0, vltmt4-1, vltmt4-2]
|
||||
|
||||
test-2204-gcc:
|
||||
name: Test | 22.04 | gcc | ${{ matrix.suite }}
|
||||
|
|
@ -164,7 +164,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1, vltmt-2, dist-vlt4-0, dist-vlt4-1, dist-vlt4-2, dist-vlt4-3, vltmt4-0, vltmt4-1, vltmt4-2]
|
||||
|
||||
lint-py:
|
||||
name: Lint Python
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test: [coverage-vlt-, coverage-vltmt-]
|
||||
test: [coverage-vlt-, coverage-vltmt-, coverage-vlt4-, coverage-vltmt4-]
|
||||
num: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
include:
|
||||
- {test: coverage-dist, num: ''}
|
||||
|
|
|
|||
|
|
@ -628,6 +628,8 @@ detailed descriptions of these arguments.
|
|||
--x-initial <mode> Assign initial Xs to this value
|
||||
--x-initial-edge Enable initial X->0 and X->1 edge triggers
|
||||
-y <dir> Directory to search for modules
|
||||
--zero-top-ports Enables initialization of top level ports with zeros in fourstate logic mode
|
||||
--no-zero-top-ports Disables initialization of top level ports with zeros in fourstate logic mode
|
||||
|
||||
This is a short summary of the simulation runtime arguments, i.e. for the
|
||||
final Verilated simulation runtime models. See
|
||||
|
|
|
|||
|
|
@ -96,6 +96,27 @@ case $OPT_SUITE in
|
|||
vltmt-2)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt --driver-clean" DRIVER_HASHSET=--hashset=2/3
|
||||
;;
|
||||
dist-vlt4-0)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt4 --driver-clean" DRIVER_HASHSET=--hashset=0/4
|
||||
;;
|
||||
dist-vlt4-1)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt4 --driver-clean" DRIVER_HASHSET=--hashset=1/4
|
||||
;;
|
||||
dist-vlt4-2)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt4 --driver-clean" DRIVER_HASHSET=--hashset=2/4
|
||||
;;
|
||||
dist-vlt4-3)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist --vlt4 --driver-clean" DRIVER_HASHSET=--hashset=3/4
|
||||
;;
|
||||
vltmt4-0)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4 --driver-clean" DRIVER_HASHSET=--hashset=0/3
|
||||
;;
|
||||
vltmt4-1)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4 --driver-clean" DRIVER_HASHSET=--hashset=1/3
|
||||
;;
|
||||
vltmt4-2)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4 --driver-clean" DRIVER_HASHSET=--hashset=2/3
|
||||
;;
|
||||
coverage-dist)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist"
|
||||
;;
|
||||
|
|
@ -159,6 +180,66 @@ case $OPT_SUITE in
|
|||
coverage-vltmt-9)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=9/10
|
||||
;;
|
||||
coverage-vlt4-0)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=0/10
|
||||
;;
|
||||
coverage-vlt4-1)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=1/10
|
||||
;;
|
||||
coverage-vlt4-2)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=2/10
|
||||
;;
|
||||
coverage-vlt4-3)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=3/10
|
||||
;;
|
||||
coverage-vlt4-4)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=4/10
|
||||
;;
|
||||
coverage-vlt4-5)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=5/10
|
||||
;;
|
||||
coverage-vlt4-6)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=6/10
|
||||
;;
|
||||
coverage-vlt4-7)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=7/10
|
||||
;;
|
||||
coverage-vlt4-8)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=8/10
|
||||
;;
|
||||
coverage-vlt4-9)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vlt4" DRIVER_HASHSET=--hashset=9/10
|
||||
;;
|
||||
coverage-vltmt4-0)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=0/10
|
||||
;;
|
||||
coverage-vltmt4-1)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=1/10
|
||||
;;
|
||||
coverage-vltmt4-2)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=2/10
|
||||
;;
|
||||
coverage-vltmt4-3)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=3/10
|
||||
;;
|
||||
coverage-vltmt4-4)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=4/10
|
||||
;;
|
||||
coverage-vltmt4-5)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=5/10
|
||||
;;
|
||||
coverage-vltmt4-6)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=6/10
|
||||
;;
|
||||
coverage-vltmt4-7)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=7/10
|
||||
;;
|
||||
coverage-vltmt4-8)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=8/10
|
||||
;;
|
||||
coverage-vltmt4-9)
|
||||
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt4" DRIVER_HASHSET=--hashset=9/10
|
||||
;;
|
||||
*)
|
||||
fatal "Unknown suite: $OPT_SUITE"
|
||||
;;
|
||||
|
|
|
|||
|
|
@ -2380,3 +2380,12 @@ Summary:
|
|||
user-specified directories. This allows '-y "$(pwd)"' to be used if
|
||||
absolute filenames are desired for error messages instead of relative
|
||||
filenames.
|
||||
|
||||
.. option:: --zero-top-ports
|
||||
|
||||
.. option:: --no-zero-top-ports
|
||||
|
||||
Options used with :vlopt:`--fourstate` to enable/disable
|
||||
initialization of top module ports with zeros instead of `x`.
|
||||
This is useful to keep the backward compatibility with existing C++.
|
||||
Enabled by default with :vlopt:`--fourstate`.
|
||||
|
|
|
|||
|
|
@ -631,9 +631,44 @@ IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
|||
return data;
|
||||
}
|
||||
|
||||
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
||||
QData data = ~0ULL;
|
||||
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
|
||||
data = VL_RANDOM_Q();
|
||||
}
|
||||
data &= VL_MASK_Q(obits);
|
||||
return data;
|
||||
}
|
||||
|
||||
WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = VL_RAND_RESET_I(32);
|
||||
outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits);
|
||||
return outwp;
|
||||
}
|
||||
WDataOutP VL_ZERO_RESET_W_T(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
// Not inlined to speed up compilation of slowpath code
|
||||
return VL_ZERO_W(obits, outwp);
|
||||
return VL_ZERO_W_T(obits, outwp);
|
||||
}
|
||||
WDataOutP VL_ZERO_RESET_W_V(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
// Not inlined to speed up compilation of slowpath code
|
||||
return VL_ZERO_W_V(obits, outwp);
|
||||
}
|
||||
WDataOutP VL_ZERO_RESET_W_X(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
// Not inlined to speed up compilation of slowpath code
|
||||
return VL_ZERO_W_X(obits, outwp);
|
||||
}
|
||||
WDataOutP VL_ALLONES_RESET_W_T(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
// Not inlined to speed up compilation of slowpath code
|
||||
return VL_ALLONES_W_T(obits, outwp);
|
||||
}
|
||||
WDataOutP VL_ALLONES_RESET_W_V(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
// Not inlined to speed up compilation of slowpath code
|
||||
return VL_ALLONES_W_V(obits, outwp);
|
||||
}
|
||||
WDataOutP VL_ALLONES_RESET_W_X(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
// Not inlined to speed up compilation of slowpath code
|
||||
return VL_ALLONES_W_X(obits, outwp);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
@ -648,20 +683,39 @@ void _vl_debug_print_w(int lbits, const WDataInP iwp) VL_MT_SAFE {
|
|||
//===========================================================================
|
||||
// Slow expressions
|
||||
|
||||
WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WDataInP rwp,
|
||||
bool is_modulus) VL_MT_SAFE {
|
||||
WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus,
|
||||
const int outputOffset, int outputJump, const int lhsOffset, int lhsJump,
|
||||
const int rhsOffset, int rhsJump) VL_MT_SAFE {
|
||||
// See Knuth Algorithm D. Computes u/v = q.r
|
||||
// This isn't massively tuned, as wide division is rare
|
||||
// for debug see V3Number version
|
||||
// Requires clean input
|
||||
VL_DEBUG_IFDEF(assert((outputOffset == 0 && (outputJump == 1 || outputJump == 2))
|
||||
|| (outputOffset == 1 && outputJump == 2)););
|
||||
VL_DEBUG_IFDEF(assert((lhsOffset == 0 && (lhsJump == 1 || lhsJump == 2))
|
||||
|| (lhsOffset == 1 && lhsJump == 2)););
|
||||
VL_DEBUG_IFDEF(assert((rhsOffset == 0 && (rhsJump == 1 || rhsJump == 2))
|
||||
|| (rhsOffset == 1 && rhsJump == 2)););
|
||||
const int words = VL_WORDS_I(lbits);
|
||||
for (int i = 0; i < words; ++i) owp[i] = 0;
|
||||
// Find MSB and check for zero.
|
||||
const int umsbp1 = VL_MOSTSETBITP1_W(words, lwp); // dividend
|
||||
const int vmsbp1 = VL_MOSTSETBITP1_W(words, rwp); // divisor
|
||||
const int umsbp1 = (lhsJump == 2) ? (lhsOffset ? VL_MOSTSETBITP1_W_X(words, lwp)
|
||||
: VL_MOSTSETBITP1_W_V(words, lwp))
|
||||
: VL_MOSTSETBITP1_W_T(words, lwp); // dividend
|
||||
const int vmsbp1 = (rhsJump == 2) ? (rhsOffset ? VL_MOSTSETBITP1_W_X(words, rwp)
|
||||
: VL_MOSTSETBITP1_W_V(words, rwp))
|
||||
: VL_MOSTSETBITP1_W_T(words, rwp); // divisor
|
||||
const WDataOutP resultp = owp;
|
||||
owp += outputOffset;
|
||||
lwp += lhsOffset;
|
||||
rwp += rhsOffset;
|
||||
// Since jump may be 1 or 2 we substract one to just use bit-shift left
|
||||
--outputJump;
|
||||
--lhsJump;
|
||||
--rhsJump;
|
||||
for (int i = 0; i < words; ++i) owp[i << outputJump] = 0;
|
||||
if (VL_UNLIKELY(vmsbp1 == 0) // rwp==0 so division by zero. Return 0.
|
||||
|| VL_UNLIKELY(umsbp1 == 0)) { // 0/x so short circuit and return 0
|
||||
return owp;
|
||||
return resultp;
|
||||
}
|
||||
|
||||
const int uw = VL_WORDS_I(umsbp1); // aka "m" in the algorithm
|
||||
|
|
@ -672,15 +726,16 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
|
|||
if (vw == 1) { // Single divisor word breaks rest of algorithm
|
||||
uint64_t k = 0;
|
||||
for (int j = uw - 1; j >= 0; --j) {
|
||||
const uint64_t unw64 = ((k << 32ULL) + static_cast<uint64_t>(lwp[j]));
|
||||
owp[j] = unw64 / static_cast<uint64_t>(rwp[0]);
|
||||
k = unw64 - static_cast<uint64_t>(owp[j]) * static_cast<uint64_t>(rwp[0]);
|
||||
const uint64_t unw64 = ((k << 32ULL) + static_cast<uint64_t>(lwp[j << lhsJump]));
|
||||
owp[j << outputJump] = unw64 / static_cast<uint64_t>(rwp[0]);
|
||||
k = unw64
|
||||
- static_cast<uint64_t>(owp[j << outputJump]) * static_cast<uint64_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 << outputJump] = 0;
|
||||
}
|
||||
return owp;
|
||||
return resultp;
|
||||
}
|
||||
|
||||
// +1 word as we may shift during normalization
|
||||
|
|
@ -696,16 +751,20 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
|
|||
const int s = 31 - VL_BITBIT_I(vmsbp1 - 1); // shift amount (0...31)
|
||||
// Copy and shift dividend by same amount; may set new upper word
|
||||
if (s) {
|
||||
for (int i = vw - 1; i > 0; --i) vn[i] = (rwp[i] << s) | (rwp[i - 1] >> (32 - s));
|
||||
for (int i = vw - 1; i > 0; --i) {
|
||||
vn[i] = (rwp[i << rhsJump] << s) | (rwp[(i - 1) << rhsJump] >> (32 - s));
|
||||
}
|
||||
vn[0] = rwp[0] << s;
|
||||
un[uw] = lwp[uw - 1] >> (32 - s);
|
||||
for (int i = uw - 1; i > 0; --i) un[i] = (lwp[i] << s) | (lwp[i - 1] >> (32 - s));
|
||||
un[uw] = lwp[(uw - 1) << lhsJump] >> (32 - s);
|
||||
for (int i = uw - 1; i > 0; --i) {
|
||||
un[i] = (lwp[i << lhsJump] << s) | (lwp[(i - 1) << lhsJump] >> (32 - s));
|
||||
}
|
||||
un[0] = lwp[0] << s;
|
||||
} else {
|
||||
for (int i = vw - 1; i > 0; --i) vn[i] = rwp[i];
|
||||
for (int i = vw - 1; i > 0; --i) vn[i] = rwp[i << rhsJump];
|
||||
vn[0] = rwp[0];
|
||||
un[uw] = 0;
|
||||
for (int i = uw - 1; i > 0; --i) un[i] = lwp[i];
|
||||
for (int i = uw - 1; i > 0; --i) un[i] = lwp[i << lhsJump];
|
||||
un[0] = lwp[0];
|
||||
}
|
||||
|
||||
|
|
@ -734,11 +793,11 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
|
|||
}
|
||||
t = un[j + vw] - k;
|
||||
un[j + vw] = t;
|
||||
owp[j] = qhat; // Save quotient digit
|
||||
owp[j << outputJump] = qhat; // Save quotient digit
|
||||
|
||||
if (t < 0) {
|
||||
// Over subtracted; correct by adding back
|
||||
owp[j]--;
|
||||
owp[j << outputJump]--;
|
||||
k = 0;
|
||||
for (int i = 0; i < vw; ++i) {
|
||||
t = static_cast<uint64_t>(un[i + j]) + static_cast<uint64_t>(vn[i]) + k;
|
||||
|
|
@ -752,15 +811,17 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
|
|||
if (is_modulus) { // modulus
|
||||
// Need to reverse normalization on copy to output
|
||||
if (s) {
|
||||
for (int i = 0; i < vw; ++i) owp[i] = (un[i] >> s) | (un[i + 1] << (32 - s));
|
||||
for (int i = 0; i < vw; ++i) {
|
||||
owp[i << outputJump] = (un[i] >> s) | (un[i + 1] << (32 - s));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < vw; ++i) owp[i] = un[i];
|
||||
for (int i = 0; i < vw; ++i) owp[i << outputJump] = un[i];
|
||||
}
|
||||
for (int i = vw; i < words; ++i) owp[i] = 0;
|
||||
return owp;
|
||||
for (int i = vw; i < words; ++i) owp[i << outputJump] = 0;
|
||||
return resultp;
|
||||
}
|
||||
// division
|
||||
return owp;
|
||||
return resultp;
|
||||
}
|
||||
|
||||
WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp,
|
||||
|
|
@ -773,15 +834,15 @@ WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lw
|
|||
VlWide<VL_MULS_MAX_WORDS> powstore; // Fixed size, as MSVC++ doesn't allow [words] here
|
||||
VlWide<VL_MULS_MAX_WORDS> lastpowstore; // Fixed size, as MSVC++ doesn't allow [words] here
|
||||
VlWide<VL_MULS_MAX_WORDS> lastoutstore; // Fixed size, as MSVC++ doesn't allow [words] here
|
||||
VL_ASSIGN_W(obits, powstore, lwp);
|
||||
VL_ASSIGN_W_TT(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(owords, powstore, lastpowstore, lastpowstore);
|
||||
VL_ASSIGN_W_TT(obits, lastpowstore, powstore);
|
||||
VL_MUL_W_TTT(owords, powstore, lastpowstore, lastpowstore);
|
||||
}
|
||||
if (VL_BITISSET_W(rwp, bit)) { // out *= power
|
||||
VL_ASSIGN_W(obits, lastoutstore, owp);
|
||||
VL_MUL_W(owords, owp, lastoutstore, powstore);
|
||||
VL_ASSIGN_W_TT(obits, lastoutstore, owp);
|
||||
VL_MUL_W_TTT(owords, owp, lastoutstore, powstore);
|
||||
}
|
||||
}
|
||||
return owp;
|
||||
|
|
@ -789,7 +850,7 @@ WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lw
|
|||
WDataOutP VL_POW_WWQ(int obits, int lbits, int rbits, WDataOutP owp, const WDataInP lwp,
|
||||
QData rhs) VL_MT_SAFE {
|
||||
VlWide<VL_WQ_WORDS_E> rhsw;
|
||||
VL_SET_WQ(rhsw, rhs);
|
||||
VL_SET_WQ_T(rhsw, rhs);
|
||||
return VL_POW_WWW(obits, lbits, rbits, owp, lwp, rhsw);
|
||||
}
|
||||
QData VL_POW_QQW(int, int, int rbits, QData lhs, const WDataInP rwp) VL_MT_SAFE {
|
||||
|
|
@ -810,9 +871,9 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, const WDataInP rwp) VL_MT_SAFE
|
|||
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp,
|
||||
const WDataInP rwp, bool lsign, bool rsign) VL_MT_SAFE {
|
||||
// obits==lbits, rbits can be different
|
||||
if (rsign && VL_SIGN_W(rbits, rwp)) {
|
||||
if (rsign && VL_SIGN_W_T(rbits, rwp)) {
|
||||
const int words = VL_WORDS_I(obits);
|
||||
VL_ZERO_W(obits, owp);
|
||||
VL_ZERO_W_T(obits, owp);
|
||||
EData 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_E(rbits)) ? ~VL_EUL(0) : 0);
|
||||
|
|
@ -825,7 +886,7 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP
|
|||
}
|
||||
if (lsign && lor == ~VL_EUL(0) && lwp[0] == ~VL_EUL(0)) { // -1
|
||||
if (rwp[0] & 1) { // -1^odd=-1
|
||||
return VL_ALLONES_W(obits, owp);
|
||||
return VL_ALLONES_W_T(obits, owp);
|
||||
}
|
||||
// -1^even=1
|
||||
owp[0] = 1;
|
||||
|
|
@ -838,13 +899,13 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP
|
|||
WDataOutP VL_POWSS_WWQ(int obits, int lbits, int rbits, WDataOutP owp, const WDataInP lwp,
|
||||
QData rhs, bool lsign, bool rsign) VL_MT_SAFE {
|
||||
VlWide<VL_WQ_WORDS_E> rhsw;
|
||||
VL_SET_WQ(rhsw, rhs);
|
||||
VL_SET_WQ_T(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, const WDataInP rwp, bool lsign,
|
||||
bool rsign) VL_MT_SAFE {
|
||||
// Skip check for rhs == 0, as short-circuit doesn't save time
|
||||
if (rsign && VL_SIGN_W(rbits, rwp)) {
|
||||
if (rsign && VL_SIGN_W_T(rbits, rwp)) {
|
||||
if (lhs == 0) return 0; // "X"
|
||||
if (lhs == 1) return 1;
|
||||
if (lsign && lhs == VL_MASK_Q(obits)) { // -1
|
||||
|
|
@ -873,12 +934,12 @@ double VL_ITOR_D_W(int lbits, const WDataInP lwp) VL_PURE {
|
|||
return d;
|
||||
}
|
||||
double VL_ISTOR_D_W(int lbits, const WDataInP lwp) VL_MT_SAFE {
|
||||
if (!VL_SIGN_W(lbits, lwp)) return VL_ITOR_D_W(lbits, lwp);
|
||||
if (!VL_SIGN_W_T(lbits, lwp)) return VL_ITOR_D_W(lbits, lwp);
|
||||
const int words = VL_WORDS_I(lbits);
|
||||
VL_DEBUG_IFDEF(assert(words <= VL_MULS_MAX_WORDS););
|
||||
VlWide<VL_MULS_MAX_WORDS + 1> pos;
|
||||
VL_NEGATE_W(words, pos, lwp);
|
||||
_vl_clean_inplace_w(lbits, pos);
|
||||
VL_NEGATE_W_TT(words, pos, lwp);
|
||||
_vl_clean_inplace_w_T(lbits, pos);
|
||||
return -VL_ITOR_D_W(lbits, pos);
|
||||
}
|
||||
|
||||
|
|
@ -891,7 +952,7 @@ std::string VL_DECIMAL_NW(int width, const WDataInP lwp) VL_MT_SAFE {
|
|||
// Or (maxdecwidth+7)/8], but can't have more than 4 BCD bits per word
|
||||
std::vector<EData> bcd(VL_WORDS_I(maxdecwidth));
|
||||
WDataOutP bcdp = WDataOutP::external(bcd.data());
|
||||
VL_ZERO_W(maxdecwidth, bcdp);
|
||||
VL_ZERO_W_T(maxdecwidth, bcdp);
|
||||
std::vector<EData> tmp(VL_WORDS_I(maxdecwidth));
|
||||
std::vector<EData> tmp2(VL_WORDS_I(maxdecwidth));
|
||||
WDataOutP tmpp = WDataOutP::external(tmp.data());
|
||||
|
|
@ -904,15 +965,15 @@ std::string VL_DECIMAL_NW(int width, const WDataInP lwp) VL_MT_SAFE {
|
|||
// Any digits >= 5 need an add 3 (via tmp)
|
||||
for (int nibble_bit = 0; nibble_bit < maxdecwidth; nibble_bit += 4) {
|
||||
if ((VL_BITRSHIFT_W(bcd, nibble_bit) & 0xf) >= 5) {
|
||||
VL_ZERO_W(maxdecwidth, tmp2p);
|
||||
VL_ZERO_W_T(maxdecwidth, tmp2p);
|
||||
tmp2[VL_BITWORD_E(nibble_bit)] |= VL_EUL(0x3) << VL_BITBIT_E(nibble_bit);
|
||||
VL_ASSIGN_W(maxdecwidth, tmpp, bcdp);
|
||||
VL_ADD_W(VL_WORDS_I(maxdecwidth), bcdp, tmpp, tmp2p);
|
||||
VL_ASSIGN_W_TT(maxdecwidth, tmpp, bcdp);
|
||||
VL_ADD_W_TTT(VL_WORDS_I(maxdecwidth), bcdp, tmpp, tmp2p);
|
||||
}
|
||||
}
|
||||
// Shift; bcd = bcd << 1
|
||||
VL_ASSIGN_W(maxdecwidth, tmpp, bcdp);
|
||||
VL_SHIFTL_WWI(maxdecwidth, maxdecwidth, 32, bcdp, tmpp, 1);
|
||||
VL_ASSIGN_W_TT(maxdecwidth, tmpp, bcdp);
|
||||
VL_SHIFTL_WWI_TTT(maxdecwidth, maxdecwidth, 32, bcdp, tmpp, 1);
|
||||
// bcd[0] = lwp[from_bit]
|
||||
if (VL_BITISSET_W(lwp, from_bit)) bcd[0] |= 1;
|
||||
}
|
||||
|
|
@ -944,36 +1005,36 @@ std::string _vl_vsformat_time(std::string& tmp, T ld, int timeunit, bool left,
|
|||
VlWide<w> tmp2;
|
||||
VlWide<w> tmp3;
|
||||
|
||||
WDataInP shifted = VL_EXTEND_WQ(b, 0, tmp0, static_cast<QData>(ld));
|
||||
WDataInP shifted = VL_EXTEND_WQ_TT(b, 0, tmp0, static_cast<QData>(ld));
|
||||
if (shift < 0) {
|
||||
const WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(-shift));
|
||||
shifted = VL_DIV_WWW(b, tmp2, shifted, pow10);
|
||||
const WDataInP pow10 = VL_EXTEND_WQ_TT(b, 0, tmp1, vl_time_pow10(-shift));
|
||||
shifted = VL_DIV_WWW_TTT(b, tmp2, shifted, pow10);
|
||||
} else {
|
||||
const WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(shift));
|
||||
shifted = VL_MUL_W(w, tmp2, shifted, pow10);
|
||||
const WDataInP pow10 = VL_EXTEND_WQ_TT(b, 0, tmp1, vl_time_pow10(shift));
|
||||
shifted = VL_MUL_W_TTT(w, tmp2, shifted, pow10);
|
||||
}
|
||||
|
||||
const WDataInP fracDigitsPow10 = VL_EXTEND_WQ(b, 0, tmp3, vl_time_pow10(fracDigits));
|
||||
const WDataInP integer = VL_DIV_WWW(b, tmp0, shifted, fracDigitsPow10);
|
||||
const WDataInP frac = VL_MODDIV_WWW(b, tmp1, shifted, fracDigitsPow10);
|
||||
const WDataInP fracDigitsPow10 = VL_EXTEND_WQ_TT(b, 0, tmp3, vl_time_pow10(fracDigits));
|
||||
const WDataInP integer = VL_DIV_WWW_TTT(b, tmp0, shifted, fracDigitsPow10);
|
||||
const WDataInP frac = VL_MODDIV_WWW_TTT(b, tmp1, shifted, fracDigitsPow10);
|
||||
const WDataInP max64Bit
|
||||
= VL_EXTEND_WQ(b, 0, tmp2, std::numeric_limits<uint64_t>::max()); // breaks shifted
|
||||
if (VL_GT_W(w, integer, max64Bit)) {
|
||||
WDataOutP v = VL_ASSIGN_W(b, tmp3, integer); // breaks fracDigitsPow10
|
||||
= VL_EXTEND_WQ_TT(b, 0, tmp2, std::numeric_limits<uint64_t>::max()); // breaks shifted
|
||||
if (VL_GT_W_TT(w, integer, max64Bit)) {
|
||||
WDataOutP v = VL_ASSIGN_W_TT(b, tmp3, integer); // breaks fracDigitsPow10
|
||||
VlWide<w> zero;
|
||||
VlWide<w> ten;
|
||||
VL_ZERO_W(b, zero);
|
||||
VL_EXTEND_WI(b, 0, ten, 10);
|
||||
VL_ZERO_W_T(b, zero);
|
||||
VL_EXTEND_WI_TT(b, 0, ten, 10);
|
||||
char buf[128]; // 128B is obviously long enough to represent 128bit integer in decimal
|
||||
char* ptr = buf + sizeof(buf) - 1;
|
||||
*ptr = '\0';
|
||||
while (VL_GT_W(w, v, zero)) {
|
||||
while (VL_GT_W_TT(w, v, zero)) {
|
||||
--ptr;
|
||||
const WDataInP mod = VL_MODDIV_WWW(b, tmp2, v, ten); // breaks max64Bit
|
||||
const WDataInP mod = VL_MODDIV_WWW_TTT(b, tmp2, v, ten); // breaks max64Bit
|
||||
*ptr = "0123456789"[VL_SET_QW(mod)];
|
||||
VlWide<w> divided;
|
||||
VL_DIV_WWW(b, divided, v, ten);
|
||||
VL_ASSIGN_W(b, v, divided);
|
||||
VL_DIV_WWW_TTT(b, divided, v, ten);
|
||||
VL_ASSIGN_W_TT(b, v, divided);
|
||||
}
|
||||
if (!fracDigits) {
|
||||
digits = _vl_snprintf_string(tmp, "%s%s", ptr, suffix.c_str());
|
||||
|
|
@ -1159,7 +1220,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
|
|||
ld = VL_RTOIROUND_Q_D(real);
|
||||
strwide.resize(2);
|
||||
WDataOutP strwidep = WDataOutP::external(strwide.data());
|
||||
VL_SET_WQ(strwidep, ld);
|
||||
VL_SET_WQ_T(strwidep, ld);
|
||||
lwp = strwidep;
|
||||
lbits = 64;
|
||||
// Not changint fmt == 'p' to fmt = 'g', as need fmts correct
|
||||
|
|
@ -1172,7 +1233,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
|
|||
ld = VL_VA_ARG_Q_(ap, lbits);
|
||||
strwide.resize(2);
|
||||
WDataOutP strwidep = WDataOutP::external(strwide.data());
|
||||
VL_SET_WQ(strwidep, ld);
|
||||
VL_SET_WQ_T(strwidep, ld);
|
||||
lwp = strwidep;
|
||||
lsb = lbits - 1;
|
||||
++argn; // Enum value is followed by the generated name string argument
|
||||
|
|
@ -1200,7 +1261,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
|
|||
ld = VL_VA_ARG_Q_(ap, lbits);
|
||||
strwide.resize(2);
|
||||
WDataOutP strwidep = WDataOutP::external(strwide.data());
|
||||
VL_SET_WQ(strwidep, ld);
|
||||
VL_SET_WQ_T(strwidep, ld);
|
||||
lwp = strwidep;
|
||||
} else {
|
||||
lwp = WDataInP::external(va_arg(ap, EData*));
|
||||
|
|
@ -1284,13 +1345,13 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
|
|||
if (lbits <= VL_QUADSIZE) {
|
||||
digits = _vl_snprintf_string(
|
||||
t_tmp, "%" PRId64,
|
||||
static_cast<int64_t>(VL_EXTENDS_QQ(lbits, lbits, ld)));
|
||||
static_cast<int64_t>(VL_EXTENDS_QQ_TT(lbits, lbits, ld)));
|
||||
append = t_tmp;
|
||||
} else {
|
||||
if (VL_SIGN_E(lbits, lwp[VL_WORDS_I(lbits) - 1])) {
|
||||
if (VL_SIGN_E_T(lbits, lwp[VL_WORDS_I(lbits) - 1])) {
|
||||
std::vector<EData> neg(VL_WORDS_I(lbits));
|
||||
WDataOutP negp = WDataOutP::external(neg.data());
|
||||
VL_NEGATE_W(VL_WORDS_I(lbits), negp, lwp);
|
||||
VL_NEGATE_W_TT(VL_WORDS_I(lbits), negp, lwp);
|
||||
append = "-"s + VL_DECIMAL_NW(lbits, negp);
|
||||
} else {
|
||||
append = VL_DECIMAL_NW(lbits, lwp);
|
||||
|
|
@ -1365,7 +1426,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
|
|||
}
|
||||
|
||||
if (widthSet || left) {
|
||||
lsb = VL_MOSTSETBITP1_W(VL_WORDS_I(lbits), lwp);
|
||||
lsb = VL_MOSTSETBITP1_W_T(VL_WORDS_I(lbits), lwp);
|
||||
lsb = (lsb < 1) ? 0 : (lsb - 1);
|
||||
}
|
||||
|
||||
|
|
@ -1520,7 +1581,7 @@ static void _vl_vsss_setbit(WDataOutP iowp, int obits, int lsb, int nbits, IData
|
|||
void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, size_t posstart,
|
||||
size_t posend) VL_MT_SAFE {
|
||||
// Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits.
|
||||
VL_ZERO_W(obits, owp);
|
||||
VL_ZERO_W_T(obits, owp);
|
||||
int lsb = 0;
|
||||
for (int i = 0, pos = static_cast<int>(posend) - 1;
|
||||
i < obits && pos >= static_cast<int>(posstart); --pos, ++i) {
|
||||
|
|
@ -1641,7 +1702,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||
double real = 0;
|
||||
|
||||
VlWide<VL_WQ_WORDS_E> qowp;
|
||||
VL_SET_WQ(qowp, 0ULL);
|
||||
VL_SET_WQ_T(qowp, 0ULL);
|
||||
WDataOutP owp = WDataOutP::external((obits <= 64) ? qowp.data()
|
||||
: static_cast<EData*>(thingp));
|
||||
|
||||
|
|
@ -1677,11 +1738,11 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||
if (formatAttr == VL_VFORMATATTR_SIGNED) {
|
||||
QData ld = 0;
|
||||
std::sscanf(t_tmp.c_str(), "%30" PRIu64, &ld);
|
||||
VL_SET_WQ(owp, ld);
|
||||
VL_SET_WQ_T(owp, ld);
|
||||
} else if (formatAttr == VL_VFORMATATTR_UNSIGNED) {
|
||||
int64_t ld = 0;
|
||||
std::sscanf(t_tmp.c_str(), "%30" PRId64, &ld);
|
||||
VL_SET_WQ(owp, ld);
|
||||
VL_SET_WQ_T(owp, ld);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1699,7 +1760,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||
} u;
|
||||
real = std::strtod(t_tmp.c_str(), nullptr);
|
||||
u.r = real;
|
||||
VL_SET_WQ(owp, u.ld);
|
||||
VL_SET_WQ_T(owp, u.ld);
|
||||
break;
|
||||
}
|
||||
case 't': { // Time
|
||||
|
|
@ -1713,7 +1774,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||
// 0..-15
|
||||
const int shift = -userUnits + timeunit; // 0..-15
|
||||
real = std::strtod(t_tmp.c_str(), nullptr) * vl_time_multiplier(-shift);
|
||||
VL_SET_WQ(owp, static_cast<uint64_t>(real));
|
||||
VL_SET_WQ_T(owp, static_cast<uint64_t>(real));
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
|
|
@ -1800,7 +1861,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
|||
QData* const p = static_cast<QData*>(thingp);
|
||||
*p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp));
|
||||
} else {
|
||||
_vl_clean_inplace_w(obits, owp);
|
||||
_vl_clean_inplace_w_T(obits, owp);
|
||||
}
|
||||
}
|
||||
} // switch
|
||||
|
|
@ -2130,7 +2191,7 @@ IData VL_SSCANF_IINX(int lbits, IData ld, const std::string& format, int argc, .
|
|||
}
|
||||
IData VL_SSCANF_IQNX(int lbits, QData ld, const std::string& format, int argc, ...) VL_MT_SAFE {
|
||||
VlWide<VL_WQ_WORDS_E> fnw;
|
||||
VL_SET_WQ(fnw, ld);
|
||||
VL_SET_WQ_T(fnw, ld);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, argc);
|
||||
|
|
@ -2238,7 +2299,7 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
|
|||
} else {
|
||||
const WDataOutP datap = WDataOutP::external(
|
||||
&(reinterpret_cast<EData*>(memp))[entry * VL_WORDS_I(width)]);
|
||||
if (shift == start_shift) VL_ZERO_W(width, datap);
|
||||
if (shift == start_shift) VL_ZERO_W_T(width, datap);
|
||||
datap[VL_BITWORD_E(shift)] |= (static_cast<EData>(c) << VL_BITBIT_E(shift));
|
||||
}
|
||||
// Prep for next
|
||||
|
|
@ -2324,7 +2385,7 @@ void VL_STACKTRACE() VL_MT_SAFE {
|
|||
|
||||
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
|
||||
VlWide<VL_WQ_WORDS_E> lhsw;
|
||||
VL_SET_WQ(lhsw, lhs);
|
||||
VL_SET_WQ_T(lhsw, lhs);
|
||||
return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw);
|
||||
}
|
||||
IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE {
|
||||
|
|
@ -2376,12 +2437,12 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
|
|||
const char* const dp = match.c_str() + 1 /*leading + */ + prefix.length();
|
||||
if (match.empty()) return 0;
|
||||
|
||||
VL_ZERO_W(rbits, rwp);
|
||||
VL_ZERO_W_T(rbits, rwp);
|
||||
switch (std::tolower(fmt)) {
|
||||
case 'd': {
|
||||
int64_t lld = 0;
|
||||
std::sscanf(dp, "%30" PRId64, &lld);
|
||||
VL_SET_WQ(rwp, lld);
|
||||
VL_SET_WQ_T(rwp, lld);
|
||||
break;
|
||||
}
|
||||
case 'b': _vl_vsss_based(rwp, rbits, 1, dp, 0, std::strlen(dp)); break;
|
||||
|
|
@ -2399,25 +2460,25 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
|
|||
case 'e': {
|
||||
double temp = 0.F;
|
||||
std::sscanf(dp, "%le", &temp);
|
||||
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
||||
VL_SET_WQ_T(rwp, VL_CVT_Q_D(temp));
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
double temp = 0.F;
|
||||
std::sscanf(dp, "%lf", &temp);
|
||||
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
||||
VL_SET_WQ_T(rwp, VL_CVT_Q_D(temp));
|
||||
break;
|
||||
}
|
||||
case 'g': {
|
||||
double temp = 0.F;
|
||||
std::sscanf(dp, "%lg", &temp);
|
||||
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
||||
VL_SET_WQ_T(rwp, VL_CVT_Q_D(temp));
|
||||
break;
|
||||
}
|
||||
default: // Other simulators return 0 in these cases and don't error out
|
||||
return 0;
|
||||
}
|
||||
_vl_clean_inplace_w(rbits, rwp);
|
||||
_vl_clean_inplace_w_T(rbits, rwp);
|
||||
return 1;
|
||||
}
|
||||
IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_SAFE {
|
||||
|
|
@ -2737,7 +2798,7 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
|||
& VL_MASK_Q(m_bits);
|
||||
} else {
|
||||
const WDataOutP datap = WDataOutP::external(reinterpret_cast<EData*>(valuep));
|
||||
if (!innum) VL_ZERO_W(m_bits, datap);
|
||||
if (!innum) VL_ZERO_W_T(m_bits, datap);
|
||||
_vl_shiftl_inplace_w(m_bits, datap, static_cast<IData>(shift));
|
||||
datap[0] |= value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
|||
case VLVT_UINT32: d[0] = *(reinterpret_cast<IData*>(datap)); return;
|
||||
case VLVT_UINT64: {
|
||||
VlWide<2> lwp;
|
||||
VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||
VL_SET_WQ_T(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||
d[0] = lwp[0];
|
||||
d[1] = lwp[1];
|
||||
break;
|
||||
|
|
@ -323,7 +323,7 @@ static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandl
|
|||
return;
|
||||
case VLVT_UINT64: {
|
||||
VlWide<2> lwp;
|
||||
VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||
VL_SET_WQ_T(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||
d[0].aval = lwp[0];
|
||||
d[0].bval = 0;
|
||||
d[1].aval = lwp[1];
|
||||
|
|
@ -781,7 +781,7 @@ int svGetTime(const svScope /*scope*/, svTimeVal* time) {
|
|||
if (VL_UNLIKELY(!time)) return -1;
|
||||
const QData qtime = VL_TIME_Q();
|
||||
VlWide<2> itime;
|
||||
VL_SET_WQ(itime, qtime);
|
||||
VL_SET_WQ_T(itime, qtime);
|
||||
time->low = itime[0];
|
||||
time->high = itime[1];
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, const WDataInP lwp
|
|||
}
|
||||
static inline void VL_SET_SVBV_I(int, svBitVecVal* owp, const IData ld) VL_MT_SAFE { owp[0] = ld; }
|
||||
static inline void VL_SET_SVBV_Q(int, svBitVecVal* owp, const QData ld) VL_MT_SAFE {
|
||||
VL_SET_WQ(WDataOutP::external(owp), ld);
|
||||
VL_SET_WQ_T(WDataOutP::external(owp), ld);
|
||||
}
|
||||
|
||||
// Convert svLogicVecVal to Verilator internal data
|
||||
|
|
@ -100,7 +100,7 @@ static inline void VL_SET_SVLV_I(int, svLogicVecVal* owp, const IData ld) VL_MT_
|
|||
}
|
||||
static inline void VL_SET_SVLV_Q(int, svLogicVecVal* owp, const QData ld) VL_MT_SAFE {
|
||||
VlWide<2> lwp;
|
||||
VL_SET_WQ(lwp, ld);
|
||||
VL_SET_WQ_T(lwp, ld);
|
||||
owp[0].aval = lwp[0];
|
||||
owp[0].bval = 0;
|
||||
owp[1].aval = lwp[1];
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ private:
|
|||
}
|
||||
|
||||
WDataInP rhswp = WDataInP::external(static_cast<const EData*>(entry.m_rhsDatap));
|
||||
return VL_SEL_QWII(rhsWidth, rhswp, rhsLsb, width) & mask;
|
||||
return VL_SEL_QWII_TTTT(rhsWidth, rhswp, rhsLsb, width) & mask;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -260,7 +260,7 @@ private:
|
|||
}
|
||||
|
||||
void readSel(int lbits, WDataInP valp, WDataOutP reswp, int lsb, int width) const {
|
||||
VL_SEL_WWII(width, lbits, reswp, valp, lsb, width);
|
||||
VL_SEL_WWII_TTTT(width, lbits, reswp, valp, lsb, width);
|
||||
const int msb = lsb + width - 1;
|
||||
auto it = std::lower_bound(m_entries.begin(), m_entries.end(), lsb,
|
||||
[](const Entry& e, int bit) { return e.m_msb < bit; });
|
||||
|
|
|
|||
|
|
@ -461,22 +461,11 @@ void VerilatedFstBuffer::emitWData(uint32_t code, const WDataInP newval, int) {
|
|||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitFourstateWData(uint32_t code, const WDataInP newval,
|
||||
const WDataInP newvalXZ, int bits) {
|
||||
void VerilatedFstBuffer::emitFourstateWData(uint32_t code, const WDataInP newval, int) {
|
||||
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
|
||||
// TODO: When four-states will be shuffled remove it since copying will be no longer necessary
|
||||
thread_local std::vector<uint32_t> newvals;
|
||||
newvals.clear();
|
||||
const size_t wordCount = static_cast<size_t>(VL_WORDS_I(bits));
|
||||
newvals.reserve(wordCount * 2);
|
||||
for (size_t i = 0; i < wordCount; ++i) {
|
||||
newvals.push_back(newval[i]);
|
||||
newvals.push_back(newvalXZ[i]);
|
||||
}
|
||||
|
||||
m_owner.emitTimeChangeMaybe();
|
||||
// call emitValueChange(handle, uint32_t*)
|
||||
m_fst->emitValueChange(m_symbolp[code], newvals.data(), fst::EncodingType::VERILOG);
|
||||
m_fst->emitValueChange(m_symbolp[code], newval.datap(), fst::EncodingType::VERILOG);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
|
|
|
|||
|
|
@ -238,8 +238,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
|
|||
VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int);
|
||||
VL_ATTR_ALWINLINE void emitFourstateQData(uint32_t code, QData newval, QData newvalXZ, int);
|
||||
VL_ATTR_ALWINLINE void emitWData(uint32_t code, WDataInP newval, int);
|
||||
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, WDataInP newvalXZ,
|
||||
int bits);
|
||||
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, int);
|
||||
VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval);
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -386,11 +386,11 @@ static bool parseSMTNum(int obits, WDataOutP owp, const std::string& val) {
|
|||
}
|
||||
bool VlRandomVar::set(const std::string& idx, const std::string& val) const {
|
||||
VlWide<VL_WQ_WORDS_E> qowp;
|
||||
VL_SET_WQ(qowp, 0ULL);
|
||||
VL_SET_WQ_T(qowp, 0ULL);
|
||||
WDataOutP owp = qowp;
|
||||
const int obits = width();
|
||||
VlWide<VL_WQ_WORDS_E> qiwp;
|
||||
VL_SET_WQ(qiwp, 0ULL);
|
||||
VL_SET_WQ_T(qiwp, 0ULL);
|
||||
if (!idx.empty() && !parseSMTNum(64, qiwp, idx)) return false;
|
||||
const int nidx = qiwp[0];
|
||||
if (obits > VL_QUADSIZE) owp = WDataOutP::external(reinterpret_cast<EData*>(datap(nidx)));
|
||||
|
|
@ -409,7 +409,7 @@ bool VlRandomVar::set(const std::string& idx, const std::string& val) const {
|
|||
QData* const p = static_cast<QData*>(datap(nidx));
|
||||
*p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp));
|
||||
} else {
|
||||
_vl_clean_inplace_w(obits, owp);
|
||||
_vl_clean_inplace_w_T(obits, owp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,8 +137,7 @@ public:
|
|||
}
|
||||
|
||||
VL_ATTR_ALWINLINE void emitWData(uint64_t time, WDataInP newval, uint32_t bits);
|
||||
VL_ATTR_ALWINLINE void emitFourstateWData(uint64_t time, WDataInP newval, WDataInP newvalXZ,
|
||||
uint32_t bits);
|
||||
VL_ATTR_ALWINLINE void emitFourstateWData(uint64_t time, WDataInP newval, uint32_t bits);
|
||||
VL_ATTR_ALWINLINE void updateLastTime(uint64_t val) { m_lastTime = val; }
|
||||
|
||||
// ACCESSORS
|
||||
|
|
@ -272,13 +271,13 @@ void VerilatedSaifActivityVar::emitWData(const uint64_t time, const WDataInP new
|
|||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedSaifActivityVar::emitFourstateWData(const uint64_t time, const WDataInP newval,
|
||||
const WDataInP newvalXZ, const uint32_t bits) {
|
||||
const uint32_t bits) {
|
||||
assert(m_lastTime <= time);
|
||||
const uint64_t dt = time - m_lastTime;
|
||||
for (std::size_t i = 0; i < std::min(m_width, bits); ++i) {
|
||||
const size_t wordIndex = i / VL_EDATASIZE;
|
||||
const size_t wordIndex = (i / VL_EDATASIZE) << 1;
|
||||
m_bits[i].aggregateVal(dt, VL_BITISSET_E(newval[wordIndex], i),
|
||||
VL_BITISSET_E(newvalXZ[wordIndex], i));
|
||||
VL_BITISSET_E(newval[wordIndex | 1], i));
|
||||
}
|
||||
|
||||
updateLastTime(time);
|
||||
|
|
@ -772,12 +771,12 @@ void VerilatedSaifBuffer::emitWData(const uint32_t code, const WDataInP newval,
|
|||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedSaifBuffer::emitFourstateWData(const uint32_t code, const WDataInP newval,
|
||||
const WDataInP newvalXZ, const int bits) {
|
||||
const int bits) {
|
||||
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
|
||||
&& "Activity must be declared earlier");
|
||||
VerilatedSaifActivityVar& activity
|
||||
= m_owner.m_activityAccumulators.at(m_fidx)->m_activity.at(code);
|
||||
activity.emitFourstateWData(m_owner.currentTime(), newval, newvalXZ, bits);
|
||||
activity.emitFourstateWData(m_owner.currentTime(), newval, bits);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
|
|
|
|||
|
|
@ -257,8 +257,7 @@ class VerilatedSaifBuffer VL_NOT_FINAL {
|
|||
VL_ATTR_ALWINLINE void emitFourstateQData(uint32_t code, QData newval, QData newvalXZ,
|
||||
int bits);
|
||||
VL_ATTR_ALWINLINE void emitWData(uint32_t code, WDataInP newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, WDataInP newvalXZ,
|
||||
int bits);
|
||||
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ public:
|
|||
void fullQData(uint32_t* oldp, QData newval, int bits);
|
||||
void fullFourstateQData(uint32_t* oldp, QData newval, QData newvalXZ, int bits);
|
||||
void fullWData(uint32_t* oldp, WDataInP newval, int bits);
|
||||
void fullFourstateWData(uint32_t* oldp, WDataInP newval, WDataInP newvalXZ, int bits);
|
||||
void fullFourstateWData(uint32_t* oldp, WDataInP newval, int bits);
|
||||
void fullDouble(uint32_t* oldp, double newval);
|
||||
void fullEvent(uint32_t* oldp, const VlEventBase* newvalp);
|
||||
void fullEventTriggered(uint32_t* oldp);
|
||||
|
|
@ -463,12 +463,10 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgFourstateWData(uint32_t* oldp, const WDataInP newval,
|
||||
const WDataInP newvalXZ, int bits) {
|
||||
VL_ATTR_ALWINLINE void chgFourstateWData(uint32_t* oldp, const WDataInP newval, int bits) {
|
||||
for (int i = 0; i < VL_WORDS_I(bits); ++i) {
|
||||
const int oldIdx = i << 1;
|
||||
if (VL_UNLIKELY((oldp[oldIdx] ^ newval[i]) | (oldp[oldIdx | 1] ^ newvalXZ[i]))) {
|
||||
fullFourstateWData(oldp, newval, newvalXZ, bits);
|
||||
if (VL_UNLIKELY(oldp[i] ^ newval[i])) {
|
||||
fullFourstateWData(oldp, newval, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -664,15 +664,11 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullWData(uint32_t* oldp, const WDataInP ne
|
|||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullFourstateWData(uint32_t* oldp, const WDataInP newval,
|
||||
const WDataInP newvalXZp, int bits) {
|
||||
int bits) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
for (int i = 0; i < VL_WORDS_I(bits); ++i) {
|
||||
const int oldIdx = i << 1;
|
||||
oldp[oldIdx] = newval[i];
|
||||
oldp[oldIdx | 1] = newvalXZp[i];
|
||||
}
|
||||
for (int i = 0; i < VL_WORDS_I(bits) * 2; ++i) oldp[i] = newval[i];
|
||||
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
|
||||
emitFourstateWData(code, newval, newvalXZp, bits);
|
||||
emitFourstateWData(code, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
|
|
|
|||
|
|
@ -95,37 +95,37 @@ struct VlWide final {
|
|||
return std::memcmp(m_storage, that.m_storage, N_Words * sizeof(EData)) == 0;
|
||||
}
|
||||
bool operator!=(const VlWide<N_Words>& that) const VL_PURE { return !(*this == that); }
|
||||
EData& operator[](size_t index) VL_MT_SAFE { return m_storage[index]; }
|
||||
const EData& operator[](size_t index) const VL_MT_SAFE { return m_storage[index]; }
|
||||
EData& operator[](size_t index) VL_PURE { return m_storage[index]; }
|
||||
const EData& operator[](size_t index) const VL_PURE { return m_storage[index]; }
|
||||
VlWide<N_Words>& operator&=(const VlWide& rhs) {
|
||||
VL_AND_W(N_Words, *this, *this, rhs);
|
||||
VL_AND_W_TTT(N_Words, *this, *this, rhs);
|
||||
return *this;
|
||||
}
|
||||
VlWide<N_Words>& operator|=(const VlWide& rhs) {
|
||||
VL_OR_W(N_Words, *this, *this, rhs);
|
||||
VL_OR_W_TTT(N_Words, *this, *this, rhs);
|
||||
return *this;
|
||||
}
|
||||
VlWide<N_Words>& operator^=(const VlWide& rhs) {
|
||||
VL_XOR_W(N_Words, *this, *this, rhs);
|
||||
VL_XOR_W_TTT(N_Words, *this, *this, rhs);
|
||||
return *this;
|
||||
}
|
||||
VlWide<N_Words>& operator+=(const VlWide& rhs) {
|
||||
VL_ADD_W(N_Words, *this, *this, rhs);
|
||||
VL_ADD_W_TTT(N_Words, *this, *this, rhs);
|
||||
return *this;
|
||||
}
|
||||
VlWide<N_Words>& operator*=(const VlWide& rhs) {
|
||||
VlWide<N_Words> out{};
|
||||
VL_MUL_W(N_Words, out, *this, rhs);
|
||||
VL_MUL_W_TTT(N_Words, out, *this, rhs);
|
||||
for (size_t i = 0; i < N_Words; ++i) m_storage[i] = out.m_storage[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
// METHODS
|
||||
EData& at(size_t index) VL_MT_SAFE { return m_storage[index]; }
|
||||
const EData& at(size_t index) const VL_MT_SAFE { return m_storage[index]; }
|
||||
EData& at(size_t index) VL_MT_SAFE VL_PURE { return m_storage[index]; }
|
||||
const EData& at(size_t index) const VL_MT_SAFE VL_PURE { return m_storage[index]; }
|
||||
size_t size() const VL_PURE { return N_Words; }
|
||||
EData* data() VL_MT_SAFE { return &m_storage[0]; }
|
||||
const EData* data() const VL_MT_SAFE { return &m_storage[0]; }
|
||||
EData* data() VL_MT_SAFE VL_PURE { return &m_storage[0]; }
|
||||
const EData* data() const VL_MT_SAFE VL_PURE { return &m_storage[0]; }
|
||||
inline bool operator<(const VlWide<N_Words>& rhs) const VL_PURE;
|
||||
};
|
||||
|
||||
|
|
@ -169,9 +169,28 @@ public:
|
|||
// METHODS
|
||||
EData* datap() const VL_PURE { return m_datap; }
|
||||
operator bool() const VL_PURE { return m_datap; }
|
||||
EData& operator*() const VL_PURE { return *m_datap; }
|
||||
EData& operator[](size_t index) const VL_PURE { return m_datap[index]; }
|
||||
WDataOutP operator+(size_t index) const VL_PURE { return WDataOutP(m_datap + index); }
|
||||
WDataOutP operator+(int index) const VL_PURE { return WDataOutP(m_datap + index); }
|
||||
WDataOutP& operator+=(size_t index) {
|
||||
m_datap += index;
|
||||
return *this;
|
||||
}
|
||||
WDataOutP& operator+=(int index) {
|
||||
m_datap += index;
|
||||
return *this;
|
||||
}
|
||||
WDataOutP operator-(size_t index) const VL_PURE { return WDataOutP(m_datap - index); }
|
||||
WDataOutP operator-(int index) const VL_PURE { return WDataOutP(m_datap - index); }
|
||||
WDataOutP& operator-=(size_t index) {
|
||||
m_datap -= index;
|
||||
return *this;
|
||||
}
|
||||
WDataOutP& operator-=(int index) {
|
||||
m_datap -= index;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(WDataOutP) == sizeof(EData*), "WDataOutP should be a single pointer");
|
||||
|
||||
|
|
@ -208,17 +227,36 @@ public:
|
|||
// METHODS
|
||||
const EData* datap() const VL_PURE { return m_datap; }
|
||||
operator bool() const VL_PURE { return m_datap; }
|
||||
const EData& operator*() const VL_PURE { return *m_datap; }
|
||||
const EData& operator[](size_t index) const VL_PURE { return m_datap[index]; }
|
||||
WDataInP operator+(size_t index) const VL_PURE { return WDataInP(m_datap + index); }
|
||||
WDataInP operator+(int index) const VL_PURE { return WDataInP(m_datap + index); }
|
||||
WDataInP& operator+=(size_t index) {
|
||||
m_datap += index;
|
||||
return *this;
|
||||
}
|
||||
WDataInP& operator+=(int index) {
|
||||
m_datap += index;
|
||||
return *this;
|
||||
}
|
||||
WDataInP operator-(size_t index) const VL_PURE { return WDataInP(m_datap - index); }
|
||||
WDataInP operator-(int index) const VL_PURE { return WDataInP(m_datap - index); }
|
||||
WDataInP& operator-=(size_t index) {
|
||||
m_datap -= index;
|
||||
return *this;
|
||||
}
|
||||
WDataInP& operator-=(int index) {
|
||||
m_datap -= index;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(WDataInP) == sizeof(EData*), "WDataInP should be a single pointer");
|
||||
|
||||
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
|
||||
static int _vl_cmp_w_TT(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
|
||||
|
||||
template <std::size_t N_Words>
|
||||
bool VlWide<N_Words>::operator<(const VlWide<N_Words>& rhs) const VL_PURE {
|
||||
return _vl_cmp_w(N_Words, *this, rhs) < 0;
|
||||
return _vl_cmp_w_TT(N_Words, *this, rhs) < 0;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
|
|
|||
|
|
@ -741,22 +741,21 @@ void VerilatedVcdBuffer::emitWData(uint32_t code, const WDataInP newval, int bit
|
|||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedVcdBuffer::emitFourstateWData(uint32_t code, const WDataInP newval,
|
||||
const WDataInP newvalXZ, int bits) {
|
||||
void VerilatedVcdBuffer::emitFourstateWData(uint32_t code, const WDataInP newval, int bits) {
|
||||
char* wp = m_writep;
|
||||
*wp++ = 'b';
|
||||
const int lastIdx = (bits - 1) / VL_EDATASIZE;
|
||||
const int lastIdx = ((bits - 1) / VL_EDATASIZE) << 1;
|
||||
{
|
||||
const EData value = newval[lastIdx];
|
||||
const EData xz = newvalXZ[lastIdx];
|
||||
const EData xz = newval[lastIdx | 1];
|
||||
for (int i = (bits - 1) % VL_EDATASIZE; i >= 0; --i) {
|
||||
const CData index = (((xz >> i) & 1) << 1) | ((value >> i) & 1);
|
||||
*wp++ = "01zx"[index];
|
||||
}
|
||||
}
|
||||
for (int w = lastIdx - 1; w >= 0; --w) {
|
||||
for (int w = lastIdx - 2; w >= 0; w -= 2) {
|
||||
const EData value = newval[w];
|
||||
const EData xz = newvalXZ[w];
|
||||
const EData xz = newval[w | 1];
|
||||
for (int i = VL_EDATASIZE - 1; i >= 0; --i) {
|
||||
const CData index = (((xz >> i) & 1) << 1) | ((value >> i) & 1);
|
||||
*wp++ = "01zx"[index];
|
||||
|
|
|
|||
|
|
@ -261,8 +261,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
|
|||
VL_ATTR_ALWINLINE void emitFourstateQData(uint32_t code, QData newval, QData newvalXZ,
|
||||
int bits);
|
||||
VL_ATTR_ALWINLINE void emitWData(uint32_t code, WDataInP newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, WDataInP newvalXZ,
|
||||
int bits);
|
||||
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4466,7 +4466,7 @@ void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
|
|||
if (time_p->type == vpiSimTime) {
|
||||
const QData qtime = VL_TIME_Q();
|
||||
VlWide<2> itime;
|
||||
VL_SET_WQ(itime, qtime);
|
||||
VL_SET_WQ_T(itime, qtime);
|
||||
time_p->low = itime[0];
|
||||
time_p->high = itime[1];
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -131,6 +131,19 @@ AstNode::AstNode(VNType t, FileLine* fl)
|
|||
editCountInc();
|
||||
}
|
||||
|
||||
int AstNode::widthWords() const {
|
||||
UASSERT_OBJ(m_dtypep, this, "DType is not set");
|
||||
return VL_WORDS_I(width()) * (m_dtypep->isShuffledFourstate() ? 2 : 1);
|
||||
}
|
||||
bool AstNode::isQuad() const VL_MT_STABLE {
|
||||
UASSERT_OBJ(m_dtypep, this, "DType is not set");
|
||||
return !m_dtypep->isShuffledFourstate() && (width() > VL_IDATASIZE && width() <= VL_QUADSIZE);
|
||||
}
|
||||
bool AstNode::isWide() const VL_MT_STABLE {
|
||||
UASSERT_OBJ(m_dtypep, this, "DType is not set");
|
||||
return m_dtypep->isShuffledFourstate() || (width() > VL_QUADSIZE);
|
||||
}
|
||||
|
||||
AstNode* AstNode::abovep() const {
|
||||
// m_headtailp only valid at beginning or end of list
|
||||
// Avoid supporting at other locations as would require walking
|
||||
|
|
@ -1601,28 +1614,30 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, VSigning numeric) {
|
|||
}
|
||||
}
|
||||
|
||||
AstNodeDType* AstNode::findBasicDType(VBasicDTypeKwd kwd) const {
|
||||
AstNodeDType* AstNode::findBasicDType(VBasicDTypeKwd kwd, bool isShuffledFourstate) const {
|
||||
// For 'simple' types we use the global directory. These are all unsized.
|
||||
// More advanced types land under the module/task/etc
|
||||
return v3Global.rootp()->typeTablep()->findBasicDType(fileline(), kwd);
|
||||
return v3Global.rootp()->typeTablep()->findBasicDType(fileline(), kwd, isShuffledFourstate);
|
||||
}
|
||||
AstNodeDType* AstNode::findBitDType(int width, int widthMin, VSigning numeric) const {
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), VBasicDTypeKwd::BIT,
|
||||
width, widthMin, numeric);
|
||||
AstNodeDType* AstNode::findBitDType(int width, int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate) const {
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(
|
||||
fileline(), VBasicDTypeKwd::BIT, width, widthMin, numeric, isShuffledFourstate);
|
||||
}
|
||||
AstNodeDType* AstNode::findLogicDType(int width, int widthMin, VSigning numeric) const {
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), VBasicDTypeKwd::LOGIC,
|
||||
width, widthMin, numeric);
|
||||
AstNodeDType* AstNode::findLogicDType(int width, int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate) const {
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(
|
||||
fileline(), VBasicDTypeKwd::LOGIC, width, widthMin, numeric, isShuffledFourstate);
|
||||
}
|
||||
AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin,
|
||||
VSigning numeric) const {
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), VBasicDTypeKwd::LOGIC,
|
||||
range, widthMin, numeric);
|
||||
AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate) const {
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(
|
||||
fileline(), VBasicDTypeKwd::LOGIC, range, widthMin, numeric, isShuffledFourstate);
|
||||
}
|
||||
AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin,
|
||||
VSigning numeric) const {
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), VBasicDTypeKwd::BIT,
|
||||
range, widthMin, numeric);
|
||||
AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate) const {
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(
|
||||
fileline(), VBasicDTypeKwd::BIT, range, widthMin, numeric, isShuffledFourstate);
|
||||
}
|
||||
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
|
||||
return v3Global.rootp()->typeTablep()->findInsertSameDType(nodep);
|
||||
|
|
|
|||
22
src/V3Ast.h
22
src/V3Ast.h
|
|
@ -644,9 +644,9 @@ public:
|
|||
int widthMinV() const {
|
||||
return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width();
|
||||
}
|
||||
int widthWords() const { return VL_WORDS_I(width()); }
|
||||
bool isQuad() const VL_MT_STABLE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
|
||||
bool isWide() const VL_MT_STABLE { return (width() > VL_QUADSIZE); }
|
||||
int widthWords() const;
|
||||
bool isQuad() const VL_MT_STABLE;
|
||||
bool isWide() const VL_MT_STABLE;
|
||||
inline bool isCHandle() const VL_MT_STABLE;
|
||||
inline bool isDouble() const VL_MT_STABLE;
|
||||
inline bool isSigned() const VL_MT_STABLE;
|
||||
|
|
@ -793,18 +793,20 @@ public:
|
|||
AstNodeDType* findQueueIndexDType() const;
|
||||
AstNodeDType* findStreamDType() const;
|
||||
AstNodeDType* findVoidDType() const;
|
||||
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
|
||||
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
|
||||
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate = false) const;
|
||||
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate = false) const;
|
||||
AstNodeDType* findBitOrLogicDType(int width, int widthMin, VSigning numeric,
|
||||
bool isFourstate) const {
|
||||
return isFourstate ? findLogicDType(width, widthMin, numeric)
|
||||
: findBitDType(width, widthMin, numeric);
|
||||
}
|
||||
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,
|
||||
VSigning numeric) const VL_MT_STABLE;
|
||||
AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin,
|
||||
VSigning numeric) const VL_MT_STABLE;
|
||||
AstNodeDType* findBasicDType(VBasicDTypeKwd kwd) const;
|
||||
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate = false) const VL_MT_STABLE;
|
||||
AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate = false) const VL_MT_STABLE;
|
||||
AstNodeDType* findBasicDType(VBasicDTypeKwd kwd, bool isShuffledFourstate = false) const;
|
||||
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||
|
||||
static VCastable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
|
|
|
|||
|
|
@ -2172,9 +2172,11 @@ public:
|
|||
const VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
|
||||
const VSigning m_numeric; // From AstNodeDType: Node is signed
|
||||
const VBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
|
||||
const bool m_isShuffledFourstate; // Whether it is a shuffled fourstate
|
||||
bool operator==(const VBasicTypeKey& rhs) const {
|
||||
return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric
|
||||
&& m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange;
|
||||
&& m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange
|
||||
&& m_isShuffledFourstate == rhs.m_isShuffledFourstate;
|
||||
}
|
||||
bool operator<(const VBasicTypeKey& rhs) const {
|
||||
if ((m_width < rhs.m_width)) return true;
|
||||
|
|
@ -2187,15 +2189,17 @@ public:
|
|||
if (!(m_keyword == rhs.m_keyword)) return false; // lhs > rhs
|
||||
if ((m_nrange < rhs.m_nrange)) return true;
|
||||
if (!(m_nrange == rhs.m_nrange)) return false; // lhs > rhs
|
||||
if (!m_isShuffledFourstate && rhs.m_isShuffledFourstate) return true;
|
||||
return false;
|
||||
}
|
||||
VBasicTypeKey(int width, int widthMin, VSigning numeric, VBasicDTypeKwd kwd,
|
||||
const VNumRange& nrange)
|
||||
const VNumRange& nrange, bool isShuffledFourstate)
|
||||
: m_width{width}
|
||||
, m_widthMin{widthMin}
|
||||
, m_nrange{nrange}
|
||||
, m_numeric{numeric}
|
||||
, m_keyword{kwd} {}
|
||||
, m_keyword{kwd}
|
||||
, m_isShuffledFourstate{isShuffledFourstate} {}
|
||||
~VBasicTypeKey() = default;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,9 @@ public:
|
|||
bool isSigned() const VL_MT_STABLE { return m_numeric.isSigned(); }
|
||||
bool isNosign() const VL_MT_SAFE { return m_numeric.isNosign(); }
|
||||
VSigning numeric() const VL_MT_STABLE { return m_numeric; }
|
||||
int widthWords() const VL_MT_STABLE { return VL_WORDS_I(width()); }
|
||||
int widthWords() const VL_MT_STABLE {
|
||||
return VL_WORDS_I(width()) * (isShuffledFourstate() ? 2 : 1);
|
||||
}
|
||||
int widthMin() const VL_MT_STABLE { // If sized, the size,
|
||||
// if unsized the min digits to represent it
|
||||
return m_widthMin ? m_widthMin : m_width;
|
||||
|
|
@ -183,6 +185,7 @@ public:
|
|||
// Represents a C++ LiteralType? (can be constexpr)
|
||||
bool isLiteralType() const VL_MT_STABLE;
|
||||
virtual bool isDynamicallySized() const { return false; }
|
||||
virtual bool isShuffledFourstate() const VL_MT_STABLE { return false; }
|
||||
|
||||
private:
|
||||
class CTypeRecursed;
|
||||
|
|
@ -407,37 +410,47 @@ class AstBasicDType final : public AstNodeDType {
|
|||
struct Members final {
|
||||
VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type
|
||||
VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword)
|
||||
bool m_isShuffledFourstate; // (also in VBasicTypeKey) whether it is a shuffled four-state
|
||||
// value (forty shuffled bits will be represented as 80bits in
|
||||
// 128 bits VlWide) - shuffled implies wide that stores values
|
||||
// as described in:
|
||||
// IEEE 1800-2023 38. VPI routine definitions
|
||||
// Figure 38-8 - s_vpi_vecval structure definition
|
||||
bool operator==(const Members& rhs) const {
|
||||
return rhs.m_keyword == m_keyword && rhs.m_nrange == m_nrange;
|
||||
return rhs.m_keyword == m_keyword && rhs.m_nrange == m_nrange
|
||||
&& rhs.m_isShuffledFourstate == m_isShuffledFourstate;
|
||||
}
|
||||
} m;
|
||||
// See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned)
|
||||
public:
|
||||
AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN)
|
||||
AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN,
|
||||
bool isShuffledFourstate = false)
|
||||
: ASTGEN_SUPER_BasicDType(fl) {
|
||||
init(kwd, signst, 0, -1, nullptr);
|
||||
init(kwd, signst, 0, -1, nullptr, isShuffledFourstate);
|
||||
}
|
||||
AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth)
|
||||
AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth, bool isShuffledFourstate = false)
|
||||
: ASTGEN_SUPER_BasicDType(fl) {
|
||||
init(VBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, nullptr);
|
||||
init(VBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, nullptr, isShuffledFourstate);
|
||||
}
|
||||
AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth)
|
||||
AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth, bool isShuffledFourstate = false)
|
||||
: ASTGEN_SUPER_BasicDType(fl) {
|
||||
init(VBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, nullptr);
|
||||
init(VBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, nullptr, isShuffledFourstate);
|
||||
}
|
||||
AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin)
|
||||
AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin,
|
||||
bool isShuffledFourstate = false)
|
||||
: ASTGEN_SUPER_BasicDType(fl) {
|
||||
init(kwd, numer, wantwidth, widthmin, nullptr);
|
||||
init(kwd, numer, wantwidth, widthmin, nullptr, isShuffledFourstate);
|
||||
}
|
||||
AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin)
|
||||
AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin,
|
||||
bool isShuffledFourstate = false)
|
||||
: ASTGEN_SUPER_BasicDType(fl) {
|
||||
init(kwd, numer, range.elements(), widthmin, nullptr);
|
||||
init(kwd, numer, range.elements(), widthmin, nullptr, isShuffledFourstate);
|
||||
m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be
|
||||
}
|
||||
// See also addRange in verilog.y
|
||||
private:
|
||||
void init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin,
|
||||
AstRange* rangep);
|
||||
AstRange* rangep, bool isShuffledFourstate);
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstBasicDType;
|
||||
|
|
@ -521,6 +534,7 @@ public:
|
|||
void cvtRangeConst(); // Convert to smaller representation
|
||||
bool isCompound() const override { return isString(); }
|
||||
bool isIntegralOrPacked() const override { return keyword().isIntNumeric(); }
|
||||
bool isShuffledFourstate() const VL_MT_STABLE override { return m.m_isShuffledFourstate; }
|
||||
};
|
||||
class AstBracketArrayDType final : public AstNodeDType {
|
||||
// Associative/Queue/Normal array data type, ie "[dtype_or_expr]"
|
||||
|
|
|
|||
|
|
@ -487,6 +487,8 @@ private:
|
|||
VSelfPointerText m_selfPointer
|
||||
= VSelfPointerText{VSelfPointerText::Empty()}; // Output code object
|
||||
// pointer (e.g.: 'this')
|
||||
bool m_fourstateXZPart : 1; // If references four-state shuffled var true for XZ part and
|
||||
// false for value part
|
||||
protected:
|
||||
AstNodeVarRef(VNType t, FileLine* fl, AstVar* varp, const VAccess& access)
|
||||
: AstNodeExpr{t, fl}
|
||||
|
|
@ -516,6 +518,8 @@ public:
|
|||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||
static AstNodeVarRef* varRefLValueRecurse(AstNode* nodep);
|
||||
void fourstateXZPart(bool xz) { m_fourstateXZPart = xz; }
|
||||
bool fourstateXZPart() const { return m_fourstateXZPart; }
|
||||
};
|
||||
|
||||
// === Concrete node types =====================================================
|
||||
|
|
@ -3122,7 +3126,7 @@ public:
|
|||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opConcat(lhs, rhs);
|
||||
}
|
||||
string emitC() override { return "VL_CONCAT_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_CONCAT_%nq%lq%rq_%nf%lf%rf(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(concat %l %r)"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -3164,7 +3168,7 @@ public:
|
|||
out.opDiv(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f/ %r)"; }
|
||||
string emitC() override { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_DIV_%nq%lq%rq_%nf%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvudiv %l %r)"; }
|
||||
bool emitCheckMaxWords() override { return true; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -3207,7 +3211,7 @@ public:
|
|||
out.opDivS(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f/ %r)"; }
|
||||
string emitC() override { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_DIVS_%nq%lq%rq_%nf%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvsdiv %l %r)"; }
|
||||
bool emitCheckMaxWords() override { return true; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -3242,7 +3246,7 @@ public:
|
|||
if (v3Global.opt.fourstate()) {
|
||||
V3ERROR_NA_RETURN("");
|
||||
} else {
|
||||
return "VL_EQ_%lq(%lW, %P, %li, %ri)";
|
||||
return "VL_EQ_%lq_%lf%rf(%lW, %P, %li, %ri)";
|
||||
}
|
||||
}
|
||||
string emitSMT() const override { return "(__Vbv (= %l %r))"; }
|
||||
|
|
@ -3355,7 +3359,7 @@ public:
|
|||
out.opGt(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f> %r)"; }
|
||||
string emitC() override { return "VL_GT_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_GT_%lq_%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvugt %l %r))"; }
|
||||
string emitSimpleOperator() override { return ">"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3418,7 +3422,7 @@ public:
|
|||
out.opGtS(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f> %r)"; }
|
||||
string emitC() override { return "VL_GTS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_GTS_%nq%lq%rq_%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvsgt %l %r))"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3440,7 +3444,7 @@ public:
|
|||
out.opGte(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f>= %r)"; }
|
||||
string emitC() override { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_GTE_%lq_%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvuge %l %r))"; }
|
||||
string emitSimpleOperator() override { return ">="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3503,7 +3507,7 @@ public:
|
|||
out.opGteS(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f>= %r)"; }
|
||||
string emitC() override { return "VL_GTES_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_GTES_%nq%lq%rq_%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvsge %l %r))"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3525,7 +3529,7 @@ public:
|
|||
out.opLogAnd(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f&& %r)"; }
|
||||
string emitC() override { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSMT() const override { return "(bvand %l %r)"; }
|
||||
string emitSimpleOperator() override { return "&&"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3547,7 +3551,7 @@ public:
|
|||
out.opLogIf(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f-> %r)"; }
|
||||
string emitC() override { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSMT() const override { return "(__Vbv (=> (__Vbool %l) (__Vbool %r)))"; }
|
||||
string emitSimpleOperator() override { return "->"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3569,7 +3573,7 @@ public:
|
|||
out.opLogOr(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f|| %r)"; }
|
||||
string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSMT() const override { return "(bvor %l %r)"; }
|
||||
string emitSimpleOperator() override { return "||"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3591,7 +3595,7 @@ public:
|
|||
out.opLt(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f< %r)"; }
|
||||
string emitC() override { return "VL_LT_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_LT_%lq_%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvult %l %r))"; }
|
||||
string emitSimpleOperator() override { return "<"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3654,7 +3658,7 @@ public:
|
|||
out.opLtS(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f< %r)"; }
|
||||
string emitC() override { return "VL_LTS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_LTS_%nq%lq%rq_%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvslt %l %r))"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3676,7 +3680,7 @@ public:
|
|||
out.opLte(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f<= %r)"; }
|
||||
string emitC() override { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_LTE_%lq_%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvule %l %r))"; }
|
||||
string emitSimpleOperator() override { return "<="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3739,7 +3743,7 @@ public:
|
|||
out.opLteS(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f<= %r)"; }
|
||||
string emitC() override { return "VL_LTES_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_LTES_%nq%lq%rq_%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (bvsle %l %r))"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -3761,7 +3765,7 @@ public:
|
|||
out.opModDiv(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f%% %r)"; }
|
||||
string emitC() override { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_MODDIV_%nq%lq%rq_%nf%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvurem %l %r)"; }
|
||||
bool emitCheckMaxWords() override { return true; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -3783,7 +3787,7 @@ public:
|
|||
out.opModDivS(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f%% %r)"; }
|
||||
string emitC() override { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_MODDIVS_%nq%lq%rq_%nf%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvsmod %l %r)"; }
|
||||
bool emitCheckMaxWords() override { return true; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -3815,7 +3819,7 @@ public:
|
|||
if (v3Global.opt.fourstate()) {
|
||||
V3ERROR_NA_RETURN("");
|
||||
} else {
|
||||
return "VL_NEQ_%lq(%lW, %P, %li, %ri)";
|
||||
return "VL_NEQ_%lq_%lf%rf(%lW, %P, %li, %ri)";
|
||||
}
|
||||
}
|
||||
string emitSimpleOperator() override {
|
||||
|
|
@ -3950,9 +3954,17 @@ public:
|
|||
if (const AstConst* const constp = VN_CAST(rhsp, Const)) {
|
||||
if (constp->num().isFourState()
|
||||
|| (constp->dtypep()->isSigned() && constp->num().isNegative())) {
|
||||
dtypeSetLogicSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns
|
||||
if (lhsp->dtypep() && !lhsp->dtypep()->isFourstate()) {
|
||||
dtypeSetBitSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns
|
||||
} else {
|
||||
dtypeSetLogicSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns
|
||||
}
|
||||
} else {
|
||||
dtypeSetLogicSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
|
||||
if (lhsp->dtypep() && !lhsp->dtypep()->isFourstate()) {
|
||||
dtypeSetBitSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
|
||||
} else {
|
||||
dtypeSetLogicSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3964,7 +3976,7 @@ public:
|
|||
out.opRepl(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%f{%r{%k%l}}"; }
|
||||
string emitC() override { return "VL_REPLICATE_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_REPLICATE_%nq%lq%rq_%nf%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override {
|
||||
return "((_ repeat " + cvtToStr(width() / lhsp()->width()) + ") %l)";
|
||||
}
|
||||
|
|
@ -4127,7 +4139,15 @@ public:
|
|||
: ASTGEN_SUPER_Sel(fl, fromp, lsbp)
|
||||
, m_declElWidth{1}
|
||||
, m_widthConst{bitwidth} {
|
||||
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED);
|
||||
if (const AstNodeDType* const dtypep = fromp->dtypep()) {
|
||||
if (dtypep->isFourstate()) {
|
||||
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED);
|
||||
} else {
|
||||
dtypeSetBitSized(bitwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
} else {
|
||||
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
AstSel(FileLine* fl, AstNodeExpr* fromp, int lsb, int bitwidth)
|
||||
: ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb)) // Need () constructor
|
||||
|
|
@ -4143,9 +4163,9 @@ public:
|
|||
}
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override {
|
||||
return widthConst() == 1 ? "VL_BITSEL_%nq%lq%rqI(%lw, %P, %li, %ri)"
|
||||
: isWide() ? "VL_SEL_%nq%lq%rqI(%nw, %lw, %P, %li, %ri, %nw)"
|
||||
: "VL_SEL_%nq%lq%rqI(%lw, %P, %li, %ri, %nw)";
|
||||
return widthConst() == 1 ? "VL_BITSEL_%nq%lq%rqI_%nf%lf%rfT(%lw, %P, %li, %ri)"
|
||||
: isWide() ? "VL_SEL_%nq%lq%rqI_%nf%lf%rfT(%nw, %lw, %P, %li, %ri, %nw)"
|
||||
: "VL_SEL_%nq%lq%rqI_%nf%lf%rfT(%lw, %P, %li, %ri, %nw)";
|
||||
}
|
||||
string emitSMT() const override { return "((_ extract %t %r) %l)"; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -4192,7 +4212,7 @@ public:
|
|||
out.opShiftL(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f<< %r)"; }
|
||||
string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_SHIFTL_%nq%lq%rq_%nf%lf%rf(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvshl %l %r)"; }
|
||||
string emitSimpleOperator() override {
|
||||
return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<";
|
||||
|
|
@ -4209,14 +4229,25 @@ class AstShiftLOvr final : public AstNodeBiop {
|
|||
public:
|
||||
AstShiftLOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER_ShiftLOvr(fl, lhsp, rhsp) {
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
|
||||
&& !rhsp->dtypep()->isFourstate()) {
|
||||
dtypeSetBitUnsized(setwidth ? setwidth : lhsp->width(),
|
||||
setwidth ? 0 : lhsp->dtypep()->widthMin(),
|
||||
lhsp->dtypep()->numeric());
|
||||
} else if (lhsp->dtypep()) {
|
||||
dtypeSetLogicUnsized(setwidth ? setwidth : lhsp->width(),
|
||||
setwidth ? 0 : lhsp->dtypep()->widthMin(),
|
||||
lhsp->dtypep()->numeric());
|
||||
} else {
|
||||
dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
ASTGEN_MEMBERS_AstShiftLOvr;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opShiftL(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f<< %r)"; }
|
||||
string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_SHIFTL_%nq%lq%rq_%nf%lf%rf(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
|
|
@ -4247,7 +4278,7 @@ public:
|
|||
out.opShiftR(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f>> %r)"; }
|
||||
string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_SHIFTR_%nq%lq%rq_%nf%lf%rf(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvlshr %l %r)"; }
|
||||
string emitSimpleOperator() override {
|
||||
return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>";
|
||||
|
|
@ -4265,14 +4296,25 @@ class AstShiftROvr final : public AstNodeBiop {
|
|||
public:
|
||||
AstShiftROvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER_ShiftROvr(fl, lhsp, rhsp) {
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
|
||||
&& !rhsp->dtypep()->isFourstate()) {
|
||||
dtypeSetBitUnsized(setwidth ? setwidth : lhsp->width(),
|
||||
setwidth ? 0 : lhsp->dtypep()->widthMin(),
|
||||
lhsp->dtypep()->numeric());
|
||||
} else if (lhsp->dtypep()) {
|
||||
dtypeSetLogicUnsized(setwidth ? setwidth : lhsp->width(),
|
||||
setwidth ? 0 : lhsp->dtypep()->widthMin(),
|
||||
lhsp->dtypep()->numeric());
|
||||
} else {
|
||||
dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
ASTGEN_MEMBERS_AstShiftROvr;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opShiftR(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f>> %r)"; }
|
||||
string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_SHIFTR_%nq%lq%rq_%nf%lf%rf(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -4289,7 +4331,18 @@ public:
|
|||
AstShiftRS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) {
|
||||
// Important that widthMin be correct, as opExtend requires it after V3Expand
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED);
|
||||
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
|
||||
&& !rhsp->dtypep()->isFourstate()) {
|
||||
dtypeSetBitUnsized(setwidth ? setwidth : lhsp->width(),
|
||||
setwidth ? 0 : lhsp->dtypep()->widthMin(),
|
||||
lhsp->dtypep()->numeric());
|
||||
} else if (lhsp->dtypep()) {
|
||||
dtypeSetLogicUnsized(setwidth ? setwidth : lhsp->width(),
|
||||
setwidth ? 0 : lhsp->dtypep()->widthMin(),
|
||||
lhsp->dtypep()->numeric());
|
||||
} else {
|
||||
dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
ASTGEN_MEMBERS_AstShiftRS;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
|
|
@ -4297,7 +4350,7 @@ public:
|
|||
}
|
||||
string emitVerilog() override { return "%k(%l %f>>> %r)"; }
|
||||
string emitSMT() const override { return "(bvashr %l %r)"; }
|
||||
string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_SHIFTRS_%nq%lq%rq_%nf%lf%rf(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -4314,14 +4367,25 @@ public:
|
|||
AstShiftRSOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER_ShiftRSOvr(fl, lhsp, rhsp) {
|
||||
// Important that widthMin be correct, as opExtend requires it after V3Expand
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED);
|
||||
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
|
||||
&& !rhsp->dtypep()->isFourstate()) {
|
||||
dtypeSetBitUnsized(setwidth ? setwidth : lhsp->width(),
|
||||
setwidth ? 0 : lhsp->dtypep()->widthMin(),
|
||||
lhsp->dtypep()->numeric());
|
||||
} else if (lhsp->dtypep()) {
|
||||
dtypeSetLogicUnsized(setwidth ? setwidth : lhsp->width(),
|
||||
setwidth ? 0 : lhsp->dtypep()->widthMin(),
|
||||
lhsp->dtypep()->numeric());
|
||||
} else {
|
||||
dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
ASTGEN_MEMBERS_AstShiftRSOvr;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opShiftRS(lhs, rhs, lhsp()->widthMinV());
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f>>> %r)"; }
|
||||
string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_SHIFTRS_%nq%lq%rq_%nf%lf%rf(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -4342,7 +4406,7 @@ public:
|
|||
out.opSub(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f- %r)"; }
|
||||
string emitC() override { return "VL_SUB_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_SUB_%lq_%nf%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvsub %l %r)"; }
|
||||
string emitSimpleOperator() override { return "-"; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -4415,7 +4479,7 @@ public:
|
|||
out.opEq(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f== %r)"; }
|
||||
string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_EQ_%lq_%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(__Vbv (= %l %r))"; }
|
||||
string emitSimpleOperator() override { return "=="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -4436,7 +4500,7 @@ public:
|
|||
out.opCaseEq(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f=== %r)"; }
|
||||
string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_EQ_%lq_%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return "=="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -4517,7 +4581,7 @@ public:
|
|||
out.opLogEq(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f<-> %r)"; }
|
||||
string emitC() override { return "VL_LOGEQ_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSMT() const override { return "(bvxnor %l %r)"; }
|
||||
string emitSimpleOperator() override { return "<->"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -4545,7 +4609,7 @@ public:
|
|||
out.opNeq(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f!= %r)"; }
|
||||
string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_NEQ_%lq_%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return "!="; }
|
||||
string emitSMT() const override { return "(__Vbv (not (= %l %r)))"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -4566,7 +4630,7 @@ public:
|
|||
out.opCaseNeq(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f!== %r)"; }
|
||||
string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_NEQ_%lq_%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return "!="; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -4649,7 +4713,7 @@ public:
|
|||
out.opAdd(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f+ %r)"; }
|
||||
string emitC() override { return "VL_ADD_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_ADD_%lq_%nf%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvadd %l %r)"; }
|
||||
string emitSimpleOperator() override { return "+"; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -4691,7 +4755,7 @@ public:
|
|||
out.opAnd(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f& %r)"; }
|
||||
string emitC() override { return "VL_AND_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_AND_%lq_%nf%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvand %l %r)"; }
|
||||
string emitSimpleOperator() override { return "&"; }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
|
||||
|
|
@ -4713,7 +4777,7 @@ public:
|
|||
out.opMul(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f* %r)"; }
|
||||
string emitC() override { return "VL_MUL_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_MUL_%lq_%nf%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvmul %l %r)"; }
|
||||
string emitSimpleOperator() override { return "*"; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -4756,7 +4820,7 @@ public:
|
|||
out.opMulS(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f* %r)"; }
|
||||
string emitC() override { return "VL_MULS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_MULS_%nq%lq%rq_%nf%lf%rf(%lw, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvmul %l %r)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool emitCheckMaxWords() override { return true; }
|
||||
|
|
@ -4780,7 +4844,7 @@ public:
|
|||
out.opOr(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f| %r)"; }
|
||||
string emitC() override { return "VL_OR_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_OR_%lq_%nf%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvor %l %r)"; }
|
||||
string emitSimpleOperator() override { return "|"; }
|
||||
bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
|
||||
|
|
@ -4802,7 +4866,7 @@ public:
|
|||
out.opXor(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f^ %r)"; }
|
||||
string emitC() override { return "VL_XOR_%lq(%lW, %P, %li, %ri)"; }
|
||||
string emitC() override { return "VL_XOR_%lq_%nf%lf%rf(%lW, %P, %li, %ri)"; }
|
||||
string emitSMT() const override { return "(bvxor %l %r)"; }
|
||||
string emitSimpleOperator() override { return "^"; }
|
||||
bool cleanOut() const override { return false; } // Lclean && Rclean
|
||||
|
|
@ -4990,7 +5054,7 @@ public:
|
|||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opAssign(lhs);
|
||||
}
|
||||
string emitC() override { return isWide() ? "VL_ASSIGN_W(%nw, %P, %li)" : "%li"; }
|
||||
string emitC() override { return isWide() ? "VL_ASSIGN_W_%lf%rf(%nw, %P, %li)" : "%li"; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool cleanRhs() const override { return false; }
|
||||
|
|
@ -5219,7 +5283,7 @@ class AstInferredDisable final : public AstNodeTermop {
|
|||
public:
|
||||
explicit AstInferredDisable(FileLine* fl)
|
||||
: ASTGEN_SUPER_InferredDisable(fl) {
|
||||
dtypeSetLogicSized(1, VSigning::UNSIGNED);
|
||||
dtypeSetBitSized(1, VSigning::UNSIGNED);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstInferredDisable;
|
||||
string emitVerilog() override { return "%f$inferred_disable"; }
|
||||
|
|
@ -5288,7 +5352,7 @@ public:
|
|||
out.opAssign(lhs.isNeqZero() ? rhs : ths);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
|
||||
string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
|
||||
string emitC() override { return "VL_COND_%nq%lq%rq%tq_%nf%lf%rf%tf(%nw, %P, %li, %ri, %ti)"; }
|
||||
string emitSMT() const override { return "(ite (__Vbool %l) %r %t)"; }
|
||||
bool cleanOut() const override { return false; } // clean if e1 & e2 clean
|
||||
bool cleanLhs() const override { return true; }
|
||||
|
|
@ -5571,12 +5635,20 @@ public:
|
|||
: ASTGEN_SUPER_Extend(fl, lhsp) {}
|
||||
AstExtend(FileLine* fl, AstNodeExpr* lhsp, int width)
|
||||
: ASTGEN_SUPER_Extend(fl, lhsp) {
|
||||
dtypeSetLogicSized(width, VSigning::UNSIGNED);
|
||||
if (const AstNodeDType* const dtypep = lhsp->dtypep()) {
|
||||
if (dtypep->isFourstate()) {
|
||||
dtypeSetLogicSized(width, VSigning::UNSIGNED);
|
||||
} else {
|
||||
dtypeSetBitSized(width, VSigning::UNSIGNED);
|
||||
}
|
||||
} else {
|
||||
dtypeSetLogicSized(width, VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
ASTGEN_MEMBERS_AstExtend;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
|
||||
string emitVerilog() override { return "%l"; }
|
||||
string emitC() override { return "VL_EXTEND_%nq%lq(%nw,%lw, %P, %li)"; }
|
||||
string emitC() override { return "VL_EXTEND_%nq%lq_%nf%lf(%nw,%lw, %P, %li)"; }
|
||||
string emitSMT() const override {
|
||||
return "((_ zero_extend " + cvtToStr(width() - lhsp()->width()) + ") %l)";
|
||||
}
|
||||
|
|
@ -5596,14 +5668,22 @@ public:
|
|||
AstExtendS(FileLine* fl, AstNodeExpr* lhsp, int width)
|
||||
// Important that widthMin be correct, as opExtend requires it after V3Expand
|
||||
: ASTGEN_SUPER_ExtendS(fl, lhsp) {
|
||||
dtypeSetLogicSized(width, VSigning::UNSIGNED);
|
||||
if (const AstNodeDType* const dtypep = lhsp->dtypep()) {
|
||||
if (dtypep->isFourstate()) {
|
||||
dtypeSetLogicSized(width, VSigning::UNSIGNED);
|
||||
} else {
|
||||
dtypeSetBitSized(width, VSigning::UNSIGNED);
|
||||
}
|
||||
} else {
|
||||
dtypeSetLogicSized(width, VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
ASTGEN_MEMBERS_AstExtendS;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override {
|
||||
out.opExtendS(lhs, lhsp()->widthMinV());
|
||||
}
|
||||
string emitVerilog() override { return "%l"; }
|
||||
string emitC() override { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; }
|
||||
string emitC() override { return "VL_EXTENDS_%nq%lq_%nf%lf(%nw,%lw, %P, %li)"; }
|
||||
string emitSMT() const override {
|
||||
return "((_ sign_extend " + cvtToStr(width() - lhsp()->width()) + ") %l)";
|
||||
}
|
||||
|
|
@ -5749,7 +5829,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstLogNot;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); }
|
||||
string emitVerilog() override { return "%f(! %l)"; }
|
||||
string emitC() override { return "VL_LOGNOT_%nq%lq(%nw,%lw, %P, %li)"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitSMT() const override { return "(__Vbv (not (__Vbool %l)))"; }
|
||||
string emitSimpleOperator() override { return "!"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
|
@ -5769,7 +5849,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstMostSetBitP1;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opMostSetBitP1(lhs); }
|
||||
string emitVerilog() override { return "%f$mostsetbitp1(%l)"; }
|
||||
string emitC() override { return "VL_MOSTSETBITP1_%lq(%lW, %P, %li)"; }
|
||||
string emitC() override { return "VL_MOSTSETBITP1_%lq_%lf(%lW, %P, %li)"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
|
|
@ -5800,7 +5880,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstNegate;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegate(lhs); }
|
||||
string emitVerilog() override { return "%f(- %l)"; }
|
||||
string emitC() override { return "VL_NEGATE_%lq(%lW, %P, %li)"; }
|
||||
string emitC() override { return "VL_NEGATE_%lq_%nf%lf(%lW, %P, %li)"; }
|
||||
string emitSMT() const override { return "(bvneg %l)"; }
|
||||
string emitSimpleOperator() override { return "-"; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -5834,7 +5914,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstNot;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNot(lhs); }
|
||||
string emitVerilog() override { return "%f(~ %l)"; }
|
||||
string emitC() override { return "VL_NOT_%lq(%lW, %P, %li)"; }
|
||||
string emitC() override { return "VL_NOT_%lq_%nf%lf(%lW, %P, %li)"; }
|
||||
string emitSMT() const override { return "(bvnot %l)"; }
|
||||
string emitSimpleOperator() override { return "~"; }
|
||||
bool cleanOut() const override { return false; }
|
||||
|
|
@ -6026,7 +6106,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstRedAnd;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); }
|
||||
string emitVerilog() override { return "%f(& %l)"; }
|
||||
string emitC() override { return "VL_REDAND_%nq%lq(%lw, %P, %li)"; }
|
||||
string emitC() override { return "VL_REDAND_%lq_%lf(%lw, %P, %li)"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
|
|
@ -6041,7 +6121,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstRedOr;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); }
|
||||
string emitVerilog() override { return "%f(| %l)"; }
|
||||
string emitC() override { return "VL_REDOR_%lq(%lW, %P, %li)"; }
|
||||
string emitC() override { return "VL_REDOR_%lq_%lf(%lW, %P, %li)"; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
|
|
@ -6056,7 +6136,7 @@ public:
|
|||
ASTGEN_MEMBERS_AstRedXor;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); }
|
||||
string emitVerilog() override { return "%f(^ %l)"; }
|
||||
string emitC() override { return "VL_REDXOR_%lq(%lW, %P, %li)"; }
|
||||
string emitC() override { return "VL_REDXOR_%lq_%lf(%lW, %P, %li)"; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override {
|
||||
const int w = lhsp()->width();
|
||||
|
|
|
|||
|
|
@ -1968,11 +1968,12 @@ public:
|
|||
ASTGEN_MEMBERS_AstTypeTable;
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
void cloneRelink() override { V3ERROR_NA; } // Not cloneable
|
||||
AstBasicDType* findBasicDType(FileLine* fl, VBasicDTypeKwd kwd);
|
||||
AstBasicDType* findBasicDType(FileLine* fl, VBasicDTypeKwd kwd,
|
||||
bool isShuffledFourstate = false);
|
||||
AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width, int widthMin,
|
||||
VSigning numeric);
|
||||
VSigning numeric, bool isShuffledFourstate);
|
||||
AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, const VNumRange& range,
|
||||
int widthMin, VSigning numeric);
|
||||
int widthMin, VSigning numeric, bool isShuffledFourstate);
|
||||
AstBasicDType* findCreateSameDType(AstBasicDType& node);
|
||||
AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||
AstConstraintRefDType* findConstraintRefDType(FileLine* fl);
|
||||
|
|
@ -2203,6 +2204,7 @@ class AstVar final : public AstNode {
|
|||
bool m_processQueue : 1; // Process queue variable
|
||||
bool m_mtaskCacheLineAlign : 1; // Start MTask affinity group on a cache line
|
||||
bool m_isFourstateComplement : 1; // Set in four-state xz part
|
||||
bool m_isTopLevelPort : 1; // Whether this variable used to be a top level input
|
||||
void init() {
|
||||
m_fourstateOriginalDTypeKwd = VBasicDTypeKwd::UNKNOWN;
|
||||
m_ansi = false;
|
||||
|
|
@ -2269,6 +2271,7 @@ class AstVar final : public AstNode {
|
|||
m_processQueue = false;
|
||||
m_mtaskCacheLineAlign = false;
|
||||
m_isFourstateComplement = false;
|
||||
m_isTopLevelPort = false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -2372,18 +2375,35 @@ public:
|
|||
void declTyped(bool flag) { m_declTyped = flag; }
|
||||
void sensIfacep(AstIface* nodep) { m_sensIfacep = nodep; }
|
||||
void fourstateComplementp(AstVar* const varp) {
|
||||
UASSERT_OBJ(!isFourstateComplement(), this, "Varp is four-state complement i");
|
||||
UASSERT_OBJ(!m_fourstateComplementp, this, "Varp already has a complement");
|
||||
UASSERT_OBJ(!varp->isFourstateComplement(), varp, "It is already a four-state complement");
|
||||
UASSERT_OBJ(!isFourstateComplement(), this,
|
||||
"The variable is a four-state complement itself");
|
||||
UASSERT_OBJ(!m_fourstateComplementp, this, "Four-state complement is already added");
|
||||
UASSERT_OBJ(!varp->isFourstateComplement(), varp,
|
||||
"Varp is already a four-state complement");
|
||||
UASSERT_OBJ(!varp->fourstateComplementp(), varp,
|
||||
"Varp has a complement - it can't can be a complement at the same time");
|
||||
varp->m_isFourstateComplement = true;
|
||||
m_fourstateComplementp = varp;
|
||||
}
|
||||
AstVar* cloneWithFourstateComplementp() {
|
||||
UASSERT_OBJ(fourstateComplementp(), this, "Variable has no complement");
|
||||
AstVar* const newp = cloneTree(false);
|
||||
newp->m_fourstateComplementp = fourstateComplementp()->cloneTree(false);
|
||||
return newp;
|
||||
}
|
||||
AstVar* fourstateComplementp() const { return m_fourstateComplementp; }
|
||||
VBasicDTypeKwd fourstateOriginalDTypeKwd() const { return m_fourstateOriginalDTypeKwd; }
|
||||
void fourstateOriginalDTypeKwd(const VBasicDTypeKwd dtypeKwd) {
|
||||
m_fourstateOriginalDTypeKwd = dtypeKwd;
|
||||
}
|
||||
bool isFourstateComplement() const { return m_isFourstateComplement; }
|
||||
void unsetIsFourstateComplement() { m_isFourstateComplement = false; }
|
||||
bool isFourstateConstruct() const {
|
||||
return m_isFourstateComplement || dtypep()->isShuffledFourstate()
|
||||
|| fourstateComplementp();
|
||||
}
|
||||
bool isTopLevelPort() const { return m_isTopLevelPort; }
|
||||
void setIsTopLevelPort() { m_isTopLevelPort = true; }
|
||||
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
||||
void attrScBv(bool flag) { m_attrScBv = flag; }
|
||||
void attrScBigUint(bool flag) { m_attrScBigUint = flag; }
|
||||
|
|
@ -2593,6 +2613,7 @@ public:
|
|||
&& !noCReset() && !(basicp() && basicp()->isEvent());
|
||||
}
|
||||
static AstVar* scVarRecurse(AstNode* nodep);
|
||||
const char* broken() const override;
|
||||
};
|
||||
class AstVarScope final : public AstNode {
|
||||
// A particular scoped usage of a variable
|
||||
|
|
|
|||
|
|
@ -199,11 +199,12 @@ void AstAddrOfCFunc::dump(std::ostream& str) const {
|
|||
}
|
||||
|
||||
void AstBasicDType::init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin,
|
||||
AstRange* rangep) {
|
||||
AstRange* rangep, bool isShuffledFourstate) {
|
||||
// wantwidth=0 means figure it out, but if a widthmin is >=0
|
||||
// we allow width 0 so that {{0{x}},y} works properly
|
||||
// wantwidthmin=-1: default, use wantwidth if it is non-zero
|
||||
m.m_keyword = kwd;
|
||||
m.m_isShuffledFourstate = isShuffledFourstate;
|
||||
// Implicitness: // "parameter X" is implicit and sized from initial
|
||||
// value, "parameter reg x" not
|
||||
if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) {
|
||||
|
|
@ -1026,6 +1027,15 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const char* AstVar::broken() const {
|
||||
BROKEN_RTN(v3Global.fourstateHandled() && dtypep()->isFourstate());
|
||||
BROKEN_RTN(v3Global.fourstateShuffled() && dtypep()->isWide()
|
||||
&& (isFourstateComplement()
|
||||
|| name().rfind("__Vxz") // TODO: make this not a hard coded value
|
||||
!= std::string::npos));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum,
|
||||
bool assertOn) const VL_MT_STABLE {
|
||||
static constexpr int MAX_TYPEDEF_DEPTH = 1000;
|
||||
|
|
@ -1221,7 +1231,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
|
|||
// We don't print msb()/lsb() as multidim packed would require recursion,
|
||||
// and may confuse users as C++ data is stored always with bit 0 used
|
||||
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
|
||||
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
|
||||
? "/*" + cvtToStr(dtypep->width() - 1) + ":0"
|
||||
+ (isShuffledFourstate() ? " 4-state" : "") + "*/"
|
||||
: "";
|
||||
if (bdtypep->keyword() == VBasicDTypeKwd::CHARPTR) {
|
||||
info.m_type = "const char*";
|
||||
|
|
@ -1249,6 +1260,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
|
|||
info.m_type = "VlStdRandomizer";
|
||||
} else if (bdtypep->isEvent()) {
|
||||
info.m_type = v3Global.assignsEvents() ? "VlAssignableEvent" : "VlEvent";
|
||||
} else if (dtypep->isWide()) {
|
||||
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + ">" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
||||
info.m_type = "CData" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 16) {
|
||||
|
|
@ -1257,8 +1270,6 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
|
|||
info.m_type = "IData" + bitvec;
|
||||
} else if (dtypep->isQuad()) {
|
||||
info.m_type = "QData" + bitvec;
|
||||
} else if (dtypep->isWide()) {
|
||||
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + ">" + bitvec;
|
||||
}
|
||||
// CData, SData, IData, QData or VlWide are packed type.
|
||||
const bool packedType = VString::startsWith(info.m_type, "CData")
|
||||
|
|
@ -1604,32 +1615,34 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
|||
return m_voidp;
|
||||
}
|
||||
|
||||
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, VBasicDTypeKwd kwd) {
|
||||
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, VBasicDTypeKwd kwd,
|
||||
bool isShuffledFourstate) {
|
||||
// Because the detailed map doesn't update m_basicps, check the detailed
|
||||
// map for this same node. Also adds this new node to the detailed map
|
||||
if (!m_basicps[kwd]) {
|
||||
AstBasicDType basic{fl, kwd};
|
||||
AstBasicDType basic{fl, kwd, VSigning::NOSIGN, isShuffledFourstate};
|
||||
m_basicps[kwd] = findCreateSameDType(basic);
|
||||
}
|
||||
return m_basicps[kwd];
|
||||
}
|
||||
|
||||
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width,
|
||||
int widthMin, VSigning numeric) {
|
||||
AstBasicDType basic{fl, kwd, numeric, width, widthMin};
|
||||
int widthMin, VSigning numeric,
|
||||
bool isShuffledFourstate) {
|
||||
AstBasicDType basic{fl, kwd, numeric, width, widthMin, isShuffledFourstate};
|
||||
return findCreateSameDType(basic);
|
||||
}
|
||||
|
||||
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
|
||||
const VNumRange& range, int widthMin,
|
||||
VSigning numeric) {
|
||||
AstBasicDType basic{fl, kwd, numeric, range, widthMin};
|
||||
VSigning numeric, bool isShuffledFourstate) {
|
||||
AstBasicDType basic{fl, kwd, numeric, range, widthMin, isShuffledFourstate};
|
||||
return findCreateSameDType(basic);
|
||||
}
|
||||
|
||||
AstBasicDType* AstTypeTable::findCreateSameDType(AstBasicDType& node) {
|
||||
const VBasicTypeKey key{node.width(), node.widthMin(), node.numeric(), node.keyword(),
|
||||
node.nrange()};
|
||||
const VBasicTypeKey key{node.width(), node.widthMin(), node.numeric(),
|
||||
node.keyword(), node.nrange(), node.isShuffledFourstate()};
|
||||
AstBasicDType*& entryr = m_detailedMap[key];
|
||||
if (!entryr) {
|
||||
entryr = node.cloneTree(false);
|
||||
|
|
@ -1641,8 +1654,8 @@ AstBasicDType* AstTypeTable::findCreateSameDType(AstBasicDType& node) {
|
|||
|
||||
// cppcheck-suppress duplInheritedMember
|
||||
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
|
||||
const VBasicTypeKey key{nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
|
||||
nodep->nrange()};
|
||||
const VBasicTypeKey key{nodep->width(), nodep->widthMin(), nodep->numeric(),
|
||||
nodep->keyword(), nodep->nrange(), nodep->isShuffledFourstate()};
|
||||
auto pair = m_detailedMap.emplace(key, nodep);
|
||||
if (pair.second) nodep->generic(true);
|
||||
// No addTypesp; the upper function that called new() is responsible for adding
|
||||
|
|
@ -1956,6 +1969,7 @@ void AstAttrOf::dumpJson(std::ostream& str) const {
|
|||
void AstBasicDType::dump(std::ostream& str) const {
|
||||
this->AstNodeDType::dump(str);
|
||||
str << " kwd=" << keyword().ascii();
|
||||
if (isShuffledFourstate()) str << " [SHUFFLED4STATE]";
|
||||
if (isRanged() && !rangep()) str << " range=[" << left() << ":" << right() << "]";
|
||||
}
|
||||
void AstBasicDType::dumpJson(std::ostream& str) const {
|
||||
|
|
@ -3287,6 +3301,10 @@ void AstVar::dump(std::ostream& str) const {
|
|||
} else if (isFuncLocal()) {
|
||||
str << " [FUNC]";
|
||||
}
|
||||
if (const AstVar* const varp = fourstateComplementp()) {
|
||||
str << " [COMPL=" << nodeAddr(varp) << "]";
|
||||
}
|
||||
if (isFourstateComplement()) str << " [4STATECOMPL]";
|
||||
if (hasUserInit()) str << " [UINIT]";
|
||||
if (icoMaybeWritten()) str << " [ICOMAYBEWRITTEN]";
|
||||
if (isDpiOpenArray()) str << " [DPIOPENA]";
|
||||
|
|
|
|||
|
|
@ -3709,6 +3709,16 @@ class ConstVisitor final : public VNVisitor {
|
|||
if (!m_doNConst) return;
|
||||
const AstBasicDType* const bdtypep = VN_CAST(nodep->dtypep()->skipRefp(), BasicDType);
|
||||
if (!bdtypep) return;
|
||||
{
|
||||
const AstNodeExpr* const lhsp = VN_AS(nodep->abovep(), NodeAssign)->lhsp();
|
||||
const AstVar* varp;
|
||||
if (const AstMemberSel* memberSel = VN_CAST(lhsp, MemberSel)) {
|
||||
varp = memberSel->varp();
|
||||
} else {
|
||||
varp = VN_AS(lhsp, NodeVarRef)->varp();
|
||||
}
|
||||
if (varp->isFourstateConstruct()) return;
|
||||
}
|
||||
if (!bdtypep->isZeroInit()) return;
|
||||
AstConst* const newp = new AstConst{nodep->fileline(), V3Number{nodep, bdtypep}};
|
||||
UINFO(9, "CRESET(0) => CONST(0) " << nodep);
|
||||
|
|
@ -3846,7 +3856,7 @@ class ConstVisitor final : public VNVisitor {
|
|||
nodep->condp(new AstLogNot{condp->fileline(),
|
||||
condp}); // LogNot, as C++ optimization also possible
|
||||
nodep->addThensp(elsesp);
|
||||
} else if (v3Global.fourstateHandled()
|
||||
} else if ((!v3Global.opt.fourstate() || v3Global.fourstateHandled())
|
||||
&& ((VN_IS(nodep->condp(), Not) && nodep->condp()->width() == 1)
|
||||
|| VN_IS(nodep->condp(), LogNot))
|
||||
&& nodep->thensp() && nodep->elsesp()) {
|
||||
|
|
@ -3860,7 +3870,8 @@ class ConstVisitor final : public VNVisitor {
|
|||
ifp->branchPred(nodep->branchPred().invert());
|
||||
nodep->replaceWith(ifp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (v3Global.fourstateHandled() && ifSameAssign(nodep)) {
|
||||
} else if ((!v3Global.opt.fourstate() || v3Global.fourstateHandled())
|
||||
&& ifSameAssign(nodep)) {
|
||||
UINFO(4,
|
||||
"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})");
|
||||
AstNodeAssign* const thensp = VN_AS(nodep->thensp(), NodeAssign);
|
||||
|
|
|
|||
|
|
@ -489,6 +489,76 @@ class DelayedVisitor final : public VNVisitor {
|
|||
return varscp;
|
||||
}
|
||||
|
||||
AstVarScope* getFourstateComplementScope(const AstVarScope* const vscp) {
|
||||
const AstVar* const varp = vscp->varp()->fourstateComplementp();
|
||||
UASSERT_OBJ(varp, vscp, "Non four-state won't have a complement");
|
||||
AstVarScope* resultp = VN_AS(vscp->nextp(), VarScope);
|
||||
do {
|
||||
// In most (if not in all) cases the complement VarScope is right after main part
|
||||
if (resultp->varp() == varp) return resultp;
|
||||
resultp = VN_AS(resultp->nextp(), VarScope);
|
||||
} while (resultp);
|
||||
// Fallback to looking elsewhere
|
||||
resultp = vscp->scopep()->varsp();
|
||||
while (resultp != vscp) {
|
||||
// In most (if not in all) cases the complement VarScope is right after main part
|
||||
if (resultp->varp() == varp) return resultp;
|
||||
resultp = VN_AS(resultp->nextp(), VarScope);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstVarScope* createTemp(const std::string& prefix, AstVarScope* vscp, AstNodeDType* dtypep,
|
||||
VarScopeInfo* vscpInfo = nullptr) {
|
||||
const AstVar* const varp = vscp->varp();
|
||||
AstScope* const scopep = vscp->scopep();
|
||||
auto getName
|
||||
= [this, &prefix, scopep](const AstVarScope* const vscp, VarScopeInfo* vscpInfo) {
|
||||
return prefix
|
||||
+ (vscpInfo ? uniqueTmpName(scopep, vscp, *vscpInfo)
|
||||
: vscp->varp()->shortName());
|
||||
};
|
||||
FileLine* const flp = vscp->fileline();
|
||||
|
||||
AstNodeModule* const modp = scopep->modp();
|
||||
// Get/create the corresponding AstVar
|
||||
AstVar*& newVarp = m_varMap(modp)[getName(vscp, vscpInfo)];
|
||||
bool newlyCreated = false;
|
||||
if (!newVarp) {
|
||||
newVarp = new AstVar{flp, VVarType::BLOCKTEMP, getName(vscp, vscpInfo), dtypep};
|
||||
modp->addStmtsp(newVarp);
|
||||
newlyCreated = true;
|
||||
}
|
||||
|
||||
if (varp->fourstateComplementp()) {
|
||||
if (AstVarScope* const complementVscp = getFourstateComplementScope(vscp)) {
|
||||
std::string name
|
||||
= getName(complementVscp, vscpInfo ? &m_vscpInfo(complementVscp) : nullptr);
|
||||
AstVar*& newComplementVarp = m_varMap(modp)[name];
|
||||
if (!newComplementVarp) {
|
||||
newComplementVarp = new AstVar{flp, VVarType::BLOCKTEMP, name, dtypep};
|
||||
modp->addStmtsp(newComplementVarp);
|
||||
}
|
||||
if (newlyCreated) newVarp->fourstateComplementp(newComplementVarp);
|
||||
}
|
||||
}
|
||||
|
||||
// We should be able to assert this here, but unfortuantely
|
||||
// 'isAssignmentCompatible' does not exist as of right now.
|
||||
// UASSERT_OBJ(isAssignmentCompatible(varp->dtypep(), dtypep), flp, "Invalid temporary");
|
||||
|
||||
// Create the AstVarScope
|
||||
AstVarScope* const varscp = new AstVarScope{flp, scopep, newVarp};
|
||||
scopep->addVarsp(varscp);
|
||||
return varscp;
|
||||
}
|
||||
|
||||
AstVarScope* createTemp(const std::string& prefix, AstVarScope* vscp, int width,
|
||||
VarScopeInfo* vscpInfo = nullptr) {
|
||||
return createTemp(prefix, vscp, vscp->findBitDType(width, width, VSigning::UNSIGNED),
|
||||
vscpInfo);
|
||||
}
|
||||
|
||||
// Same as above but create a 2-state scalar of the given 'width'
|
||||
AstVarScope* createTemp(FileLine* flp, AstScope* scopep, const std::string& name, int width) {
|
||||
AstNodeDType* const dtypep = scopep->findBitDType(width, width, VSigning::UNSIGNED);
|
||||
|
|
@ -591,8 +661,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||
FileLine* const flp = vscp->fileline();
|
||||
AstScope* const scopep = vscp->scopep();
|
||||
// Create the shadow variable
|
||||
const std::string name = "__Vdly__" + vscp->varp()->shortName();
|
||||
AstVarScope* const shadowVscp = createTemp(flp, scopep, name, vscp->dtypep());
|
||||
AstVarScope* const shadowVscp = createTemp("__Vdly__", vscp, vscp->dtypep());
|
||||
vscpInfo.shadowVariableKit().vscp = shadowVscp;
|
||||
// Mark both for V3LifePsot
|
||||
vscp->optimizeLifePost(true);
|
||||
|
|
@ -631,12 +700,10 @@ class DelayedVisitor final : public VNVisitor {
|
|||
FileLine* const flp = vscp->fileline();
|
||||
AstScope* const scopep = vscp->scopep();
|
||||
// Create the shadow variable
|
||||
const std::string shadowName = "__Vdly__" + vscp->varp()->shortName();
|
||||
AstVarScope* const shadowVscp = createTemp(flp, scopep, shadowName, vscp->dtypep());
|
||||
AstVarScope* const shadowVscp = createTemp("__Vdly__", vscp, vscp->dtypep());
|
||||
vscpInfo.shadowVarMaskedKit().vscp = shadowVscp;
|
||||
// Create the makk variable
|
||||
const std::string maskName = "__VdlyMask__" + vscp->varp()->shortName();
|
||||
AstVarScope* const maskVscp = createTemp(flp, scopep, maskName, vscp->dtypep());
|
||||
AstVarScope* const maskVscp = createTemp("__VdlyMask__", vscp, vscp->dtypep());
|
||||
maskVscp->varp()->setIgnorePostWrite();
|
||||
vscpInfo.shadowVarMaskedKit().maskp = maskVscp;
|
||||
// Create the AstActive for the Post logic
|
||||
|
|
@ -742,7 +809,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||
|
||||
if (!reuseTheFlag) {
|
||||
// Create new flag
|
||||
AstVarScope* const flagVscp = createTemp(flp, scopep, "__VdlySet" + baseName, 1);
|
||||
AstVarScope* const flagVscp = createTemp("__VdlySet", vscp, 1, &vscpInfo);
|
||||
// Set the flag at the original NBA
|
||||
nodep->addHereThisAsNext( //
|
||||
new AstAssign{flp, new AstVarRef{flp, flagVscp, VAccess::WRITE},
|
||||
|
|
@ -818,7 +885,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||
= captureLhs(scopep, nodep, nodep->lhsp()->unlinkFrBack(), baseName);
|
||||
|
||||
// Create new flag
|
||||
AstVarScope* const flagVscp = createTemp(flp, scopep, "__VdlySet" + baseName, 1);
|
||||
AstVarScope* const flagVscp = createTemp("__VdlySet", vscp, 1, &vscpInfo);
|
||||
flagVscp->varp()->setIgnorePostWrite();
|
||||
// Set the flag at the original NBA
|
||||
nodep->addHereThisAsNext( //
|
||||
|
|
@ -850,8 +917,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||
auto* const cqDTypep
|
||||
= new AstNBACommitQueueDType{flp, vscp->dtypep()->skipRefp(), N_Partial};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(cqDTypep);
|
||||
const std::string name = "__VdlyCommitQueue" + vscp->varp()->shortName();
|
||||
AstVarScope* const queueVscp = createTemp(flp, scopep, name, cqDTypep);
|
||||
AstVarScope* const queueVscp = createTemp("__VdlyCommitQueue", vscp, cqDTypep);
|
||||
queueVscp->varp()->noReset(true);
|
||||
queueVscp->varp()->setIgnorePostWrite();
|
||||
vscpInfo.valueQueueKit().vscp = queueVscp;
|
||||
|
|
@ -1198,9 +1264,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||
AstNode* newp = cstmtp;
|
||||
if (nodep->isDelayed()) {
|
||||
const AstVarRef* const vrefp = VN_AS(eventp, VarRef);
|
||||
const std::string newvarname = "__Vdly__" + vrefp->varp()->shortName();
|
||||
AstVarScope* const dlyvscp
|
||||
= createTemp(flp, vrefp->varScopep()->scopep(), newvarname, 1);
|
||||
AstVarScope* const dlyvscp = createTemp("__Vdly__", vrefp->varScopep(), 1);
|
||||
|
||||
const auto dlyRef = [=](VAccess access) { //
|
||||
return new AstVarRef{flp, dlyvscp, access};
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ class DfgDataType final {
|
|||
|
||||
// METHODS
|
||||
static AstNodeDType* canonicalPackedDType(uint32_t width) {
|
||||
return v3Global.rootp()->typeTablep()->findLogicDType(width, width, VSigning::UNSIGNED);
|
||||
return v3Global.rootp()->typeTablep()->findBitDType(width, width, VSigning::UNSIGNED);
|
||||
}
|
||||
static AstNodeDType* canonicalArrayDType(uint32_t size, const DfgDataType& elemType) {
|
||||
AstNodeDType* const elemDTypep = elemType.m_astDtypep;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ template <>
|
|||
AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeExpr*>( //
|
||||
const DfgCountOnes* vtxp, AstNodeExpr* op1) {
|
||||
AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1};
|
||||
nodep->dtypeSetLogicSized(vtxp->width(), VSigning::UNSIGNED);
|
||||
nodep->dtypeSetBitSized(vtxp->width(), VSigning::UNSIGNED);
|
||||
return nodep;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,16 @@ class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
}
|
||||
|
||||
protected:
|
||||
void emitTVX(const AstNode* const nodep) {
|
||||
const AstVarRef* const varRefp = VN_CAST(nodep, VarRef);
|
||||
if (varRefp && varRefp->varp()->dtypep()->isShuffledFourstate()) {
|
||||
UASSERT_OBJ(v3Global.opt.fourstate(), nodep,
|
||||
"Tried to use four-state function in two state mode");
|
||||
puts(varRefp->fourstateXZPart() ? "X" : "V");
|
||||
} else {
|
||||
puts("T");
|
||||
}
|
||||
}
|
||||
// VISITORS
|
||||
void visit(AstInitArray* nodep) override {
|
||||
VL_RESTORER(m_unpackedWord);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
|
|||
// and write out appropriate text.
|
||||
// %n* node
|
||||
// %nq emitIQW on the [node]
|
||||
// %nf data format T/V/X
|
||||
// %nw width in bits
|
||||
// %nW width in words
|
||||
// %ni iterate
|
||||
|
|
@ -50,6 +51,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
|
|||
// %t* thsp - if appropriate, then second char as above
|
||||
// %k Potential line break
|
||||
// %P Wide temporary name
|
||||
// %p* Wide temporary - if appropriate, then second char as above
|
||||
// , Commas suppressed if the previous field is suppressed
|
||||
string out;
|
||||
putnbs(nodep, "");
|
||||
|
|
@ -128,6 +130,16 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
|
|||
needComma = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'p':
|
||||
if (nodep->isWide()) {
|
||||
UASSERT_OBJ(m_wideTempRefp, nodep,
|
||||
"Wide Op w/ no temp, perhaps missing op in V3EmitC?");
|
||||
detail = true;
|
||||
detailp = m_wideTempRefp;
|
||||
} else {
|
||||
++pos;
|
||||
}
|
||||
break;
|
||||
default: nodep->v3fatalSrc("Unknown emitOperator format code: %" << pos[0]); break;
|
||||
}
|
||||
|
|
@ -149,15 +161,22 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
|
|||
emitIQW(detailp);
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
putOut();
|
||||
emitTVX(detailp);
|
||||
break;
|
||||
case 'w':
|
||||
commaOut();
|
||||
out += cvtToStr(detailp->widthMin());
|
||||
needComma = true;
|
||||
break;
|
||||
case 'W':
|
||||
if (lhsp->isWide()) {
|
||||
if (detailp->isWide()) {
|
||||
commaOut();
|
||||
out += cvtToStr(lhsp->widthWords());
|
||||
out += cvtToStr(VL_WORDS_I(
|
||||
detailp->width())); // Even if signal is shuffled we want to emit
|
||||
// width that does not take into account the fact
|
||||
// that 4-states takes 2 bits
|
||||
needComma = true;
|
||||
} else if (VN_IS(lhsp, StreamR)) {
|
||||
commaOut();
|
||||
|
|
@ -521,6 +540,15 @@ void EmitCFunc::emitVarReset(const string& prefix, AstVar* varp, bool constructi
|
|||
}
|
||||
}
|
||||
|
||||
bool isModulePort(const AstVar* const varp) {
|
||||
if (varp->varType() == VVarType::PORT) {
|
||||
const AstNode* iter = varp;
|
||||
while (!iter->firstAbovep()) iter = iter->backp();
|
||||
if (VN_IS(iter->firstAbovep(), Module)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
||||
const string& varNameProtected, AstNodeDType* dtypep,
|
||||
int depth, const string& suffix, const AstNode* valuep) {
|
||||
|
|
@ -617,28 +645,47 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = ";
|
||||
out += cvtToStr(constp->num().edataWord(w)) + "U;\n";
|
||||
}
|
||||
} else if (v3Global.opt.fourstate()
|
||||
&& (varp->isFourstateComplement() || varp->fourstateComplementp())) {
|
||||
bool setTozero = false;
|
||||
if (varp->varType() == VVarType::PORT) {
|
||||
const AstNode* iter = varp;
|
||||
while (!iter->firstAbovep()) iter = iter->backp();
|
||||
if (AstModule* const modep = VN_CAST(iter->firstAbovep(), Module)) {
|
||||
setTozero = modep->isTop();
|
||||
} else if (v3Global.opt.fourstate() && dtypep->isShuffledFourstate()) {
|
||||
const std::string& reset = slow ? "RESET_" : "";
|
||||
if (v3Global.opt.zeroTopPorts().isTrue() && varp->isTopLevelPort()) {
|
||||
// Instead of using VL_ZERO_RESET_W V and X we just use T and pretend the
|
||||
// signal is twice as wide. this way we resets whole thing and sets to zero at
|
||||
// once. We can do that because of the four-state internal representation
|
||||
out += "VL_ZERO_" + reset + "W_T(";
|
||||
out += cvtToStr(dtypep->widthMin() * 2);
|
||||
out += ", " + varNameProtected + suffix;
|
||||
out += ");\n";
|
||||
} else if (varp->varType().isNet() || isModulePort(varp)) {
|
||||
out += "VL_ZERO_" + reset + "W_V(";
|
||||
out += cvtToStr(dtypep->widthMin());
|
||||
out += ", " + varNameProtected + suffix;
|
||||
out += ");\n";
|
||||
out += "VL_ALLONES_" + reset + "W_X(";
|
||||
out += cvtToStr(dtypep->widthMin());
|
||||
out += ", " + varNameProtected + suffix;
|
||||
out += ");\n";
|
||||
} else {
|
||||
// The same as above we can do a trick and use the internal representation to
|
||||
// set everything up in one go but this time it is important to clear the
|
||||
// result
|
||||
out += "VL_ALLONES_" + reset + "W_T(";
|
||||
out += cvtToStr(dtypep->widthWords() * VL_EDATASIZE);
|
||||
out += ", " + varNameProtected + suffix;
|
||||
out += ");\n";
|
||||
if ((dtypep->widthMin() & VL_SIZEBITS_E) != 0) {
|
||||
// Need cleaning
|
||||
out += "_vl_clean_inplace_w_V(";
|
||||
out += cvtToStr(dtypep->widthMin());
|
||||
out += ", " + varNameProtected + suffix;
|
||||
out += ");\n";
|
||||
out += "_vl_clean_inplace_w_X(";
|
||||
out += cvtToStr(dtypep->widthMin());
|
||||
out += ", " + varNameProtected + suffix;
|
||||
out += ");\n";
|
||||
}
|
||||
}
|
||||
if (!setTozero && (varp->isFourstateComplement() || !varp->varType().isNet())) {
|
||||
out += "VL_ALLONES_W("; // This is a temporary solution - interleaved signals
|
||||
// will change this
|
||||
} else {
|
||||
out += (slow ? "VL_ZERO_RESET_W(" : "VL_ZERO_W(");
|
||||
}
|
||||
out += cvtToStr(dtypep->widthMin());
|
||||
out += ", " + varNameProtected + suffix;
|
||||
out += ");\n";
|
||||
return out;
|
||||
} else {
|
||||
out += zeroit ? (slow ? "VL_ZERO_RESET_W(" : "VL_ZERO_W(")
|
||||
out += zeroit ? (slow ? "VL_ZERO_RESET_W_T(" : "VL_ZERO_W_T(")
|
||||
: (varp->isXTemp() ? "VL_SCOPED_RAND_RESET_ASSIGN_W("
|
||||
: "VL_SCOPED_RAND_RESET_W(");
|
||||
out += cvtToStr(dtypep->widthMin());
|
||||
|
|
@ -665,18 +712,11 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
UASSERT_OBJ(constp, varp, "non-const initializer for variable");
|
||||
out += cvtToStr(constp->num().edataWord(0)) + "U;\n";
|
||||
out += ";\n";
|
||||
} else if (v3Global.opt.fourstate()
|
||||
&& (varp->fourstateComplementp() || varp->isFourstateComplement())) {
|
||||
} else if (v3Global.opt.fourstate() && varp->isFourstateConstruct()) {
|
||||
V3Number xNum{varp->fileline(), varp->width(), 0};
|
||||
bool setTozero = false;
|
||||
if (varp->varType() == VVarType::PORT) {
|
||||
const AstNode* iter = varp;
|
||||
while (!iter->firstAbovep()) iter = iter->backp();
|
||||
if (AstModule* const modep = VN_CAST(iter->firstAbovep(), Module)) {
|
||||
setTozero = modep->isTop();
|
||||
}
|
||||
}
|
||||
if (!setTozero && (varp->isFourstateComplement() || !varp->varType().isNet())) {
|
||||
if (!(v3Global.opt.zeroTopPorts().isTrue() && varp->isTopLevelPort())
|
||||
&& (varp->isFourstateComplement()
|
||||
|| !(varp->varType().isNet() || isModulePort(varp)))) {
|
||||
xNum.setAllBits1();
|
||||
}
|
||||
out += " = ";
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@
|
|||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
// Number of VL_CONST_W_*X's in verilated.h (IE VL_CONST_W_8X is last)
|
||||
constexpr int EMITC_NUM_CONSTW = 8;
|
||||
|
||||
//######################################################################
|
||||
// Emit lazy forward declarations
|
||||
|
||||
|
|
@ -299,58 +296,23 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
int upWidth = nodep->num().widthToFit();
|
||||
int chunks = 0;
|
||||
if (upWidth > EMITC_NUM_CONSTW * VL_EDATASIZE) {
|
||||
// Output e.g. 8 words in groups of e.g. 8
|
||||
chunks = (upWidth - 1) / (EMITC_NUM_CONSTW * VL_EDATASIZE);
|
||||
upWidth %= (EMITC_NUM_CONSTW * VL_EDATASIZE);
|
||||
if (upWidth == 0) upWidth = (EMITC_NUM_CONSTW * VL_EDATASIZE);
|
||||
const int width = nodep->num().widthToFit();
|
||||
putnbs(nodep, "VL_CONST_W_");
|
||||
emitTVX(assigntop);
|
||||
puts("(");
|
||||
puts(cvtToStr(assigntop->width()));
|
||||
puts(",");
|
||||
if (!assigntop->selfPointer().isEmpty()) {
|
||||
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
|
||||
}
|
||||
{ // Upper e.g. 8 words
|
||||
if (chunks) {
|
||||
putnbs(nodep, "VL_CONSTHI_W_");
|
||||
puts(cvtToStr(VL_WORDS_I(upWidth)));
|
||||
puts("X(");
|
||||
puts(cvtToStr(nodep->widthMin()));
|
||||
puts(",");
|
||||
puts(cvtToStr(chunks * EMITC_NUM_CONSTW * VL_EDATASIZE));
|
||||
} else {
|
||||
putnbs(nodep, "VL_CONST_W_");
|
||||
puts(cvtToStr(VL_WORDS_I(upWidth)));
|
||||
puts("X(");
|
||||
puts(cvtToStr(nodep->widthMin()));
|
||||
}
|
||||
puts(",");
|
||||
if (!assigntop->selfPointer().isEmpty()) {
|
||||
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
|
||||
}
|
||||
puts(assigntop->varp()->nameProtect());
|
||||
for (int word = VL_WORDS_I(upWidth) - 1; word >= 0; word--) {
|
||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||
ofp()->printf(",0x%08" PRIx64, static_cast<uint64_t>(nodep->num().edataWord(
|
||||
word + chunks * EMITC_NUM_CONSTW)));
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
for (chunks--; chunks >= 0; chunks--) {
|
||||
puts(";\n");
|
||||
putbs("VL_CONSTLO_W_");
|
||||
puts(cvtToStr(EMITC_NUM_CONSTW));
|
||||
puts("X(");
|
||||
puts(cvtToStr(chunks * EMITC_NUM_CONSTW * VL_EDATASIZE));
|
||||
puts(",");
|
||||
if (!assigntop->selfPointer().isEmpty()) {
|
||||
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
|
||||
}
|
||||
puts(assigntop->varp()->nameProtect());
|
||||
for (int word = EMITC_NUM_CONSTW - 1; word >= 0; word--) {
|
||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||
ofp()->printf(",0x%08" PRIx64, static_cast<uint64_t>(nodep->num().edataWord(
|
||||
word + chunks * EMITC_NUM_CONSTW)));
|
||||
}
|
||||
puts(")");
|
||||
puts(assigntop->varp()->nameProtect());
|
||||
puts(", {");
|
||||
for (int word = 0; word < VL_WORDS_I(width); ++word) {
|
||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||
if (word) puts(",");
|
||||
ofp()->printf("0x%08" PRIx64, static_cast<uint64_t>(nodep->num().edataWord(word)));
|
||||
}
|
||||
puts("})");
|
||||
}
|
||||
|
||||
void emitNodesWithText(AstNode* nodesp, bool useSelfForThis, bool tracking,
|
||||
|
|
@ -609,6 +571,9 @@ public:
|
|||
putnbs(nodep, "VL_ASSIGNSEL_");
|
||||
emitIQW(selp->fromp());
|
||||
emitIQW(nodep->rhsp());
|
||||
puts("_");
|
||||
emitTVX(selp->fromp());
|
||||
emitTVX(nodep->rhsp());
|
||||
puts("(");
|
||||
putns(selp->fromp(), cvtToStr(selp->fromp()->widthMin()) + ", ");
|
||||
puts(cvtToStr(nodep->widthMin()) + ", ");
|
||||
|
|
@ -694,8 +659,10 @@ public:
|
|||
m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef);
|
||||
paren = false;
|
||||
} else if (nodep->isWide() && !unpackDtp && !VN_IS(nodep->rhsp(), Const)) {
|
||||
putnbs(nodep, "VL_ASSIGN_W(");
|
||||
puts(cvtToStr(nodep->widthMin()) + ", ");
|
||||
putnbs(nodep, "VL_ASSIGN_W_");
|
||||
emitTVX(nodep->lhsp());
|
||||
emitTVX(nodep->rhsp());
|
||||
puts("(" + cvtToStr(nodep->widthMin()) + ", ");
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
} else if (VN_IS(nodep->lhsp()->dtypep()->skipRefp(), QueueDType)
|
||||
|
|
@ -1792,7 +1759,6 @@ public:
|
|||
}
|
||||
void visit(AstConst* nodep) override { //
|
||||
if (m_wideTempRefp && nodep->isWide()) {
|
||||
UASSERT_OBJ(m_wideTempRefp, nodep, "Wide Constant w/ no temp");
|
||||
emitConstantW(nodep, m_wideTempRefp);
|
||||
m_wideTempRefp = nullptr; // We used it, fail if set it a second time
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -442,7 +442,9 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
puts(getfunc ? "VL_ASSIGNSEL_" : "VL_SELASSIGN_");
|
||||
puts(lhstype->charIQWN());
|
||||
puts(rhstype->charIQWN());
|
||||
puts("(" + std::to_string(lhstype->width()) + ", "); // LHS width
|
||||
UASSERT_OBJ(!v3Global.opt.fourstate(), lhstype,
|
||||
"Four-state currently do not support structs and unions");
|
||||
puts("_TT(" + std::to_string(lhstype->width()) + ", "); // LHS width
|
||||
if (getfunc) {
|
||||
puts(std::to_string(rhstype->width()) + ", "); // Number of copy bits
|
||||
puts(off + ", "); // LHS offset
|
||||
|
|
|
|||
|
|
@ -809,16 +809,26 @@ class EmitCTrace final : public EmitCFunc {
|
|||
};
|
||||
puts("(");
|
||||
if (AstFourstateExpr* const exprp = VN_CAST(nodep->valuep(), FourstateExpr)) {
|
||||
if (AstVarRef* const varrefp = VN_CAST(exprp->valuep(), VarRef)) {
|
||||
putVarRef(varrefp);
|
||||
AstVarRef* const valueVarrefp = VN_CAST(exprp->valuep(), VarRef);
|
||||
AstVarRef* const xzVarrefp = VN_CAST(exprp->xzp(), VarRef);
|
||||
if (valueVarrefp && xzVarrefp && valueVarrefp->varp() == xzVarrefp->varp()) {
|
||||
UASSERT_OBJ(valueVarrefp->isWide()
|
||||
&& valueVarrefp->varp()->dtypep()->isShuffledFourstate(),
|
||||
nodep,
|
||||
"This shall only happen with wide shuffled four-state variables");
|
||||
putVarRef(valueVarrefp);
|
||||
} else {
|
||||
iterateConst(exprp->valuep());
|
||||
}
|
||||
puts("), (");
|
||||
if (AstVarRef* const varrefp = VN_CAST(exprp->xzp(), VarRef)) {
|
||||
putVarRef(varrefp);
|
||||
} else {
|
||||
iterateConst(exprp->xzp());
|
||||
if (!valueVarrefp) {
|
||||
iterateConst(exprp->valuep());
|
||||
} else {
|
||||
putVarRef(valueVarrefp);
|
||||
}
|
||||
puts("), (");
|
||||
if (!xzVarrefp) {
|
||||
iterateConst(exprp->xzp());
|
||||
} else {
|
||||
putVarRef(xzVarrefp);
|
||||
}
|
||||
}
|
||||
} else if (AstVarRef* const varrefp = VN_CAST(nodep->valuep(), VarRef)) {
|
||||
putVarRef(varrefp);
|
||||
|
|
|
|||
|
|
@ -937,7 +937,7 @@ class ExpandVisitor final : public VNVisitor {
|
|||
if (lhswidth == 1) {
|
||||
newp = new AstNegate{fl, lhsp->cloneTreePure(true)};
|
||||
// Replicate always unsigned
|
||||
newp->dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED);
|
||||
newp->dtypeSetBitSized(VL_EDATASIZE, VSigning::UNSIGNED);
|
||||
} else {
|
||||
newp = newAstWordSelClone(lhsp, w);
|
||||
FileLine* const rfl = rhsp->fileline();
|
||||
|
|
|
|||
|
|
@ -123,6 +123,8 @@
|
|||
|
||||
#include "V3Fourstate.h"
|
||||
|
||||
#include "V3Const.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
#include <map>
|
||||
|
|
@ -143,16 +145,17 @@ struct FourstatePair final {
|
|||
enum LogicType : char {
|
||||
UNINITIALIZED = 0, // Logic type has not been evaluated
|
||||
TWO_STATE, // Two-state expression
|
||||
TWO_STATE_HARD, // Expression is guaranteed by user that it won't be a four-state (propagator
|
||||
// may not change it)
|
||||
TWO_STATE_WITH_FOUR_STATE_IN_SUBTREE, // Two-state expression with four-state expression in
|
||||
// its subtree - this is necessary since some AstNodes
|
||||
// (e.g.: AstCastWrap or AstSel) may contain four-state
|
||||
// expression as a child but itself be a two-state. When
|
||||
// this occurs we need to know that for the sake of
|
||||
// short-circuiting (because we use precalculation
|
||||
// statements we need to know that we cannot put them
|
||||
// before current expression unconditionally)
|
||||
TWO_STATE_HARD, // Expression is guaranteed by user that it won't be a four-state
|
||||
// (propagator may not change it)
|
||||
TWO_STATE_WITH_FOUR_STATE_IN_SUBTREE, // Two-state expression with four-state expression
|
||||
// in its subtree - this is necessary since some
|
||||
// AstNodes (e.g.: AstCastWrap or AstSel) may
|
||||
// contain four-state expression as a child but
|
||||
// itself be a two-state. When this occurs we need
|
||||
// to know that for the sake of short-circuiting
|
||||
// (because we use precalculation statements we need
|
||||
// to know that we cannot put them before current
|
||||
// expression unconditionally)
|
||||
FOUR_STATE, // Four-state expression
|
||||
};
|
||||
static void setLogicType(AstNodeExpr* const exprp, const LogicType logic) {
|
||||
|
|
@ -243,8 +246,7 @@ public:
|
|||
"Tried to build a port map while another exists");
|
||||
for (AstNode* stmtp = ftaskp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* const varp = VN_CAST(stmtp, Var)) {
|
||||
if (varp->direction().isAny()
|
||||
&& !(varp->fourstateComplementp() || varp->isFourstateComplement())) {
|
||||
if (varp->direction().isAny() && !varp->isFourstateConstruct()) {
|
||||
m_currentFTaskRefPortps.push_back(varp);
|
||||
m_currentFTaskRefPortpsNamesToVarps[varp->name()] = varp;
|
||||
}
|
||||
|
|
@ -1369,8 +1371,8 @@ class FourstateVisitor final : public VNVisitor {
|
|||
new AstRedXor{flp, getFourstateExpressionValue(redXorp->lhsp(), false)}};
|
||||
}
|
||||
|
||||
template <typename CompoarisonOp_T>
|
||||
void getFourstateExpressionArithmeticValue(CompoarisonOp_T* const biop) {
|
||||
template <typename ComparisonOp_T>
|
||||
void getFourstateExpressionArithmeticValue(ComparisonOp_T* const biop) {
|
||||
// |(a.xz | b.xz) ? '1 : (a op b)
|
||||
FileLine* const flp = biop->fileline();
|
||||
m_resultp = new AstCond{
|
||||
|
|
@ -1378,7 +1380,7 @@ class FourstateVisitor final : public VNVisitor {
|
|||
new AstRedOr{flp, new AstOr{flp, getFourstateExpressionXZ(biop->lhsp()),
|
||||
getFourstateExpressionXZ(biop->rhsp())}},
|
||||
createZeroOrOnesp(biop, true),
|
||||
new CompoarisonOp_T{
|
||||
new ComparisonOp_T{
|
||||
flp,
|
||||
getFourstateExpressionValue(
|
||||
biop->lhsp(), true /*must be in tmp so it always gets evaluated*/),
|
||||
|
|
@ -1390,11 +1392,11 @@ class FourstateVisitor final : public VNVisitor {
|
|||
void visit(AstMul* const mulp) override { getFourstateExpressionArithmeticValue(mulp); }
|
||||
void visit(AstMulS* const mulsp) override { getFourstateExpressionArithmeticValue(mulsp); }
|
||||
|
||||
template <typename CompoarisonOp_T>
|
||||
void getFourstateExpressionDivValue(CompoarisonOp_T* const biop) {
|
||||
template <typename ModDivOp_T>
|
||||
void getFourstateExpressionDivValue(ModDivOp_T* const biop) {
|
||||
// |(a.xz | b.xz) | ~|b.value ? '1 : (a op b)
|
||||
FileLine* const flp = biop->fileline();
|
||||
CompoarisonOp_T* const resultp = new CompoarisonOp_T{
|
||||
ModDivOp_T* const resultp = new ModDivOp_T{
|
||||
flp,
|
||||
getFourstateExpressionValue(biop->lhsp(),
|
||||
true /*must be in tmp so it always gets evaluated*/),
|
||||
|
|
@ -2013,7 +2015,7 @@ class FourstateVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstPin* const nodep) override {
|
||||
AstVar* const varp = nodep->modVarp();
|
||||
if (!(varp->fourstateComplementp() || varp->isFourstateComplement())) {
|
||||
if (!varp->isFourstateConstruct()) {
|
||||
if (AstNodeExpr* const exprp = VN_CAST(nodep->exprp(), NodeExpr)) {
|
||||
if (VL_UNLIKELY(!(VN_IS(exprp, NodeVarRef) || VN_IS(exprp, Const)))) {
|
||||
// The issue lays in need for precalculations, potential side effects and lack
|
||||
|
|
@ -2309,7 +2311,7 @@ public:
|
|||
triorTriandReduce(m_assignWToWire, triReducer);
|
||||
V3Error::abortIfErrors();
|
||||
{ FourstateLogicTypePropagator{netlistp}; }
|
||||
netlistp->foreach([](const AstNodeExpr* const nodep) {
|
||||
netlistp->foreach([](AstNodeExpr* const nodep) {
|
||||
if (VN_IS(nodep, NodeFTaskRef)) {
|
||||
// Changing it in type propagador is unnecessary since those will be 100% handled
|
||||
return;
|
||||
|
|
@ -2317,6 +2319,12 @@ public:
|
|||
if (isFourstate(nodep)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "This four-state expression has not been handled");
|
||||
}
|
||||
if (nodep->dtypep()->isFourstate()) {
|
||||
// If it is not a fourstate expression according to the
|
||||
// `FourstateLogicTypePropagator` lets set the bit
|
||||
nodep->dtypeSetBitUnsized(nodep->width(), nodep->widthMin(),
|
||||
nodep->dtypep()->numeric());
|
||||
}
|
||||
});
|
||||
V3Error::abortIfErrors();
|
||||
for (AstVar* const varp : m_varpsToRemove) varp->unlinkFrBack()->deleteTree();
|
||||
|
|
@ -2324,9 +2332,122 @@ public:
|
|||
~FourstateVisitor() override = default;
|
||||
};
|
||||
|
||||
void V3Fourstate::fourstateAll(AstNetlist* netlistp) {
|
||||
// Creates one wide shuffled variable from two wide signals that together create a four-state
|
||||
// From:
|
||||
// VlWide<128> a_value;
|
||||
// VlWide<128> a_xz;
|
||||
// creates a:
|
||||
// VlWide<256> a; // keeps [value1, xz1, value2, xz2,...]
|
||||
class FourstateShuffleVisitor final : public VNVisitor {
|
||||
const VNUser1InUse m_user1InUse;
|
||||
|
||||
// Node status
|
||||
// AstVar*::user1p -> AstVar*. Four-state wide complemetary (xz part) variable keeps here
|
||||
// a pointer to a newly created wide four-state shuffled
|
||||
// signal
|
||||
|
||||
VDouble0 m_shuffledVars;
|
||||
|
||||
static bool needsShuffle(const AstVar* const varp) {
|
||||
return varp->isWide() && (varp->fourstateComplementp() || varp->isFourstateComplement());
|
||||
}
|
||||
|
||||
AstVar* getCreateShuffledVariantp(AstVar* varp) {
|
||||
UASSERT_OBJ(
|
||||
varp->fourstateComplementp() || varp->isFourstateComplement(), varp,
|
||||
"This function is ment to be called on variables which create a four-state value");
|
||||
UASSERT_OBJ(varp->isWide(), varp,
|
||||
"This function is only ment to be called on wide wariables");
|
||||
if (AstVar* newp = varp->fourstateComplementp()) varp = newp;
|
||||
const size_t pos = varp->name().rfind(XZ_SUFFIX);
|
||||
UASSERT_OBJ(pos != std::string::npos, varp,
|
||||
"Four-state complementary value (xz part) shall have '"
|
||||
<< XZ_SUFFIX << "', but it is named: " << varp->name());
|
||||
if (AstVar* resultp = VN_AS(varp->user1p(), Var)) return resultp;
|
||||
UINFO(4, "SHUFFLED4STATE: " << varp);
|
||||
++m_shuffledVars;
|
||||
AstVar* const resultp = varp->cloneTree(false);
|
||||
resultp->unsetIsFourstateComplement();
|
||||
resultp->name(resultp->name().erase(pos, sizeof(XZ_SUFFIX)));
|
||||
resultp->dtypep(resultp->findBitDType(resultp->width(), resultp->dtypep()->widthMin(),
|
||||
varp->dtypep()->numeric(), true));
|
||||
varp->addNextHere(resultp);
|
||||
varp->user1p(resultp);
|
||||
return resultp;
|
||||
}
|
||||
|
||||
void visit(AstNodeCCall* const nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (nodep->funcp()->dpiImportPrototype()) return;
|
||||
AstNodeExpr* exprp = nodep->argsp();
|
||||
for (AstVar* varp = nodep->funcp()->argsp(); varp; varp = VN_AS(varp->nextp(), Var)) {
|
||||
UASSERT_OBJ(exprp, varp, "Too little arguments");
|
||||
if (needsShuffle(varp)) {
|
||||
UASSERT_OBJ(!varp->isFourstateComplement(), varp,
|
||||
"This loop shall never reach four-state complement");
|
||||
if (AstVar* const complement = varp->fourstateComplementp()) {
|
||||
getCreateShuffledVariantp(complement);
|
||||
UASSERT_OBJ(
|
||||
VN_IS(exprp, NodeVarRef) && VN_IS(exprp->nextp(), NodeVarRef), exprp,
|
||||
"Wide four-state signals shall be passed only as lvalue references");
|
||||
exprp->nextp()->unlinkFrBack()->deleteTree();
|
||||
varp = VN_AS(varp->nextp()->nextp(), Var);
|
||||
}
|
||||
}
|
||||
exprp = VN_AS(exprp->nextp(), NodeExpr);
|
||||
}
|
||||
UASSERT_OBJ(!exprp, exprp, "Too many arguments");
|
||||
}
|
||||
|
||||
void visit(AstVar* const nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (needsShuffle(nodep)) {
|
||||
getCreateShuffledVariantp(nodep);
|
||||
pushDeletep(nodep->unlinkFrBack());
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstNodeVarRef* const nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!needsShuffle(nodep->varp())) return;
|
||||
AstVar* const varp = getCreateShuffledVariantp(nodep->varp());
|
||||
FileLine* const flp = nodep->fileline();
|
||||
if (AstVarScope* const oldVscp = nodep->varScopep()) {
|
||||
AstVarScope* const vscp = new AstVarScope{flp, oldVscp->scopep(), varp};
|
||||
vscp->trace(oldVscp->isTrace());
|
||||
vscp->optimizeLifePost(oldVscp->optimizeLifePost());
|
||||
nodep->varScopep(vscp);
|
||||
}
|
||||
nodep->fourstateXZPart(nodep->varp()->isFourstateComplement());
|
||||
nodep->varp(varp);
|
||||
if (AstWordSel* const wselp = VN_CAST(nodep->firstAbovep(), WordSel)) {
|
||||
AstNodeExpr* idxp
|
||||
= new AstMul{flp, wselp->bitp()->unlinkFrBack(), new AstConst{flp, 2}};
|
||||
if (nodep->fourstateXZPart()) idxp = new AstAdd{flp, idxp, new AstConst{flp, 1}};
|
||||
idxp = V3Const::constifyEdit(idxp);
|
||||
wselp->bitp(idxp);
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstNode* const nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
explicit FourstateShuffleVisitor(AstNetlist* const netlistp) { iterate(netlistp); }
|
||||
~FourstateShuffleVisitor() override {
|
||||
V3Stats::addStat("Shuffled fourstate variables", m_shuffledVars);
|
||||
}
|
||||
};
|
||||
|
||||
void V3Fourstate::fourstateAll(AstNetlist* const netlistp) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
{ FourstateVisitor{netlistp}; }
|
||||
v3Global.setFourstateHandled();
|
||||
V3Global::dumpCheckGlobalTree("fourstate", 0, dumpTreeEitherLevel() >= 6);
|
||||
}
|
||||
|
||||
void V3Fourstate::fourstateShuffleAll(AstNetlist* const netlistp) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
{ FourstateShuffleVisitor{netlistp}; }
|
||||
v3Global.setFourstateShuffled();
|
||||
V3Global::dumpCheckGlobalTree("fourstateShuffle", 0, dumpTreeEitherLevel() >= 6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,13 @@ class AstNetlist;
|
|||
|
||||
//============================================================================
|
||||
|
||||
#define VALUE_SUFFIX "" // Needs to be empty so C++ api won't change
|
||||
#define XZ_SUFFIX "__Vxz"
|
||||
|
||||
class V3Fourstate final {
|
||||
public:
|
||||
static void fourstateAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
static void fourstateShuffleAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ class V3Global final {
|
|||
bool m_useRandomizeMethods = false; // Need to define randomize() class methods
|
||||
bool m_hasPrintedObjects = false; // Design has format args printed with to_string()
|
||||
bool m_fourstateHandled = false; // There should be no more fourstate values
|
||||
bool m_fourstateShuffled = false; // There should be no more fourstate values
|
||||
uint64_t m_currentHierBlockCost = 0; // Total cost of this hier block, used for scheduling
|
||||
|
||||
// Memory address to short string mapping (for debug)
|
||||
|
|
@ -290,7 +291,9 @@ public:
|
|||
void useCovergroup(bool flag) { m_useCovergroup = flag; }
|
||||
bool useRandomizeMethods() const { return m_useRandomizeMethods; }
|
||||
void setFourstateHandled() { m_fourstateHandled = true; }
|
||||
bool fourstateHandled() const { return !opt.fourstate() || m_fourstateHandled; }
|
||||
bool fourstateHandled() const { return m_fourstateHandled; }
|
||||
void setFourstateShuffled() { m_fourstateShuffled = true; }
|
||||
bool fourstateShuffled() const { return m_fourstateShuffled; }
|
||||
void useRandomizeMethods(bool flag) { m_useRandomizeMethods = flag; }
|
||||
bool hasPrintedObjects() const { return m_hasPrintedObjects; }
|
||||
void hasPrintedObjects(bool flag) { m_hasPrintedObjects = flag; }
|
||||
|
|
|
|||
|
|
@ -222,10 +222,19 @@ class InlineCFuncsVisitor final : public VNVisitor {
|
|||
|
||||
// Clone local variables, add them to the local scope
|
||||
for (AstVar* varp = calleep->varsp(); varp; varp = VN_AS(varp->nextp(), Var)) {
|
||||
AstVar* const newVarp = varp->cloneTree(false);
|
||||
if (varp->isFourstateComplement()) continue;
|
||||
AstVar* const complementp = varp->fourstateComplementp();
|
||||
AstVar* const newVarp
|
||||
= complementp ? varp->cloneWithFourstateComplementp() : varp->cloneTree(false);
|
||||
newVarp->name(varPrefix + varp->name());
|
||||
lscopep->addStmtsp(newVarp);
|
||||
varp->user2p(newVarp);
|
||||
if (complementp) {
|
||||
AstVar* const newComplementp = newVarp->fourstateComplementp();
|
||||
newComplementp->name(varPrefix + complementp->name());
|
||||
lscopep->addStmtsp(newComplementp);
|
||||
complementp->user2p(newComplementp);
|
||||
}
|
||||
}
|
||||
|
||||
// Clone the function body
|
||||
|
|
|
|||
|
|
@ -111,16 +111,30 @@ class LocalizeVisitor final : public VNVisitor {
|
|||
AstVar* const oldVarp = nodep->varp();
|
||||
for (AstCFunc* const funcp : funcps) {
|
||||
// Create the new local variable.
|
||||
const string newName
|
||||
string newName
|
||||
= nodep->scopep() == funcp->scopep()
|
||||
? oldVarp->name()
|
||||
: nodep->scopep()->nameDotless() + "__DOT__" + oldVarp->name();
|
||||
AstVar* const newVarp
|
||||
= new AstVar{oldVarp->fileline(), oldVarp->varType(), newName, oldVarp};
|
||||
AstVar* const newVarp = new AstVar{oldVarp->fileline(), oldVarp->varType(),
|
||||
std::move(newName), oldVarp};
|
||||
newVarp->funcLocal(true);
|
||||
newVarp->noReset(oldVarp->noReset());
|
||||
newVarp->noSubst(oldVarp->noSubst());
|
||||
funcp->addVarsp(newVarp);
|
||||
if (AstVar* complementp = oldVarp->fourstateComplementp()) {
|
||||
string newName
|
||||
= nodep->scopep() == funcp->scopep()
|
||||
? complementp->name()
|
||||
: nodep->scopep()->nameDotless() + "__DOT__" + complementp->name();
|
||||
AstVar* const newVarXZp
|
||||
= new AstVar{complementp->fileline(), complementp->varType(),
|
||||
std::move(newName), complementp};
|
||||
newVarXZp->funcLocal(true);
|
||||
newVarXZp->noReset(complementp->noReset());
|
||||
newVarXZp->noSubst(complementp->noSubst());
|
||||
funcp->addVarsp(newVarXZp);
|
||||
newVarp->fourstateComplementp(newVarXZp);
|
||||
}
|
||||
|
||||
// Fix up all the references within this function
|
||||
const auto er = m_references(funcp).equal_range(nodep);
|
||||
|
|
@ -192,6 +206,8 @@ class LocalizeVisitor final : public VNVisitor {
|
|||
&& !nodep->varp()->sensIfacep() // Not sensitive to an interface
|
||||
&& !nodep->varp()->isVirtIface() // Not interface pointer
|
||||
&& !nodep->varp()->valuep() // Does not have an initializer
|
||||
&& !nodep->varp()->isFourstateComplement() // Don't optimize complements just optimize
|
||||
// a value part
|
||||
) {
|
||||
UINFO(4, "Consider for localization: " << nodep);
|
||||
m_varScopeps.push_back(nodep);
|
||||
|
|
|
|||
|
|
@ -522,6 +522,13 @@ V3Number& V3Number::setValue1() {
|
|||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::setXZFromXZComplement(const V3Number& other) {
|
||||
UASSERT(words() == other.words(), "Width mismatch");
|
||||
UASSERT(!other.isAnyXZ(), "XZ in xz part");
|
||||
for (int i = 1; i < words(); ++i) m_data.num()[i].m_valueX = other.m_data.num()[i].m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void V3Number::setBitX0(int bit) {
|
||||
// Selection beyond bounds after V3Premit needs to have 0s
|
||||
// in upper bits. Contrast to setAllBitsXRemoved which honors xAssign
|
||||
|
|
@ -1167,6 +1174,20 @@ bool V3Number::isAllX() const VL_MT_SAFE {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
bool V3Number::isAll0() const VL_MT_SAFE {
|
||||
if (isDouble() || isString()) return false;
|
||||
for (int i = 0; i < width(); ++i) {
|
||||
if (!bitIs0(i)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool V3Number::isAll1() const VL_MT_SAFE {
|
||||
if (isDouble() || isString()) return false;
|
||||
for (int i = 0; i < width(); ++i) {
|
||||
if (!bitIs1(i)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool V3Number::isEqZero() const VL_MT_SAFE {
|
||||
if (isString()) return m_data.str().empty();
|
||||
for (int i = 0; i < words(); ++i) {
|
||||
|
|
|
|||
|
|
@ -640,6 +640,7 @@ public:
|
|||
V3Number& setAllBits0();
|
||||
V3Number& setAllBits1();
|
||||
V3Number& setValue1();
|
||||
V3Number& setXZFromXZComplement(const V3Number&);
|
||||
// IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc
|
||||
V3Number& setMask(int nbits, int lsb = 0);
|
||||
|
||||
|
|
@ -697,6 +698,8 @@ public:
|
|||
}
|
||||
bool isAllZ() const VL_MT_SAFE;
|
||||
bool isAllX() const VL_MT_SAFE;
|
||||
bool isAll0() const VL_MT_SAFE;
|
||||
bool isAll1() const VL_MT_SAFE;
|
||||
bool isEqZero() const VL_MT_SAFE;
|
||||
bool isNeqZero() const;
|
||||
bool isBitsZero(int msb, int lsb) const;
|
||||
|
|
|
|||
|
|
@ -1054,6 +1054,12 @@ void V3Options::notify() VL_MT_DISABLED {
|
|||
cmdfl->v3warn(E_UNSUPPORTED,
|
||||
"--fourstate is not supported with hierarchical Verilation");
|
||||
}
|
||||
if (systemC()) cmdfl->v3warn(E_UNSUPPORTED, "--fourstate is not supported with --sc");
|
||||
if (!m_xInitialDefault) cmdfl->v3error("--x-initial has no sense with --fourstate");
|
||||
if (!m_xAssignDefault) cmdfl->v3error("--x-assign has no sense with --fourstate");
|
||||
} else if (!m_zero_top_ports.isDefault()) {
|
||||
cmdfl->v3error(
|
||||
"--zero-top-ports and --no-zero-top-ports shall be used only with --fourstate");
|
||||
}
|
||||
|
||||
if (coverage() && savable()) {
|
||||
|
|
@ -1942,6 +1948,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
DECL_OPTION("-waiver-output", Set, &m_waiverOutput);
|
||||
|
||||
DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) {
|
||||
m_xAssignDefault = false;
|
||||
if (!std::strcmp(valp, "0")) {
|
||||
m_xAssign = "0";
|
||||
} else if (!std::strcmp(valp, "1")) {
|
||||
|
|
@ -1957,6 +1964,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
}
|
||||
});
|
||||
DECL_OPTION("-x-initial", CbVal, [this, fl](const char* valp) {
|
||||
m_xInitialDefault = false;
|
||||
if (!std::strcmp(valp, "0")) {
|
||||
m_xInitial = "0";
|
||||
} else if (!std::strcmp(valp, "fast")) {
|
||||
|
|
@ -1975,6 +1983,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
addIncDirUser(parseFileArg(optdir, string{valp}));
|
||||
}).notForRerun();
|
||||
|
||||
DECL_OPTION("-zero-top-ports", OnOff, &m_zero_top_ports).undocumented();
|
||||
|
||||
parser.finalize();
|
||||
|
||||
for (int i = 0; i < argc;) {
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@ private:
|
|||
bool m_vpi = false; // main switch: --vpi
|
||||
bool m_waiverMultiline = false; // main switch: --waiver-multiline
|
||||
bool m_xInitialEdge = false; // main switch: --x-initial-edge
|
||||
VOptionBool m_zero_top_ports{VOptionBool::OPT_DEFAULT_TRUE}; // main switch --zero-top-ports
|
||||
|
||||
int m_assertUnrollLimit = 1024; // main switch: --assert-unroll-limit
|
||||
int m_buildJobs = -1; // main switch: --build-jobs, -j
|
||||
|
|
@ -384,6 +385,8 @@ private:
|
|||
string m_work = "work"; // main switch: --work {libname}
|
||||
string m_xAssign; // main switch: --x-assign
|
||||
string m_xInitial; // main switch: --x-initial
|
||||
bool m_xAssignDefault = true; // whether the value is default of explicitly provided by user
|
||||
bool m_xInitialDefault = true; // whether the value is default of explicitly provided by user
|
||||
|
||||
// Language is now held in FileLine, on a per-node basis. However we still
|
||||
// have a concept of the default language at a global level.
|
||||
|
|
@ -708,6 +711,7 @@ public:
|
|||
bool isWaiverOutput() const { return !m_waiverOutput.empty(); }
|
||||
string xAssign() const { return m_xAssign; }
|
||||
string xInitial() const { return m_xInitial; }
|
||||
VOptionBool zeroTopPorts() const { return m_zero_top_ports; }
|
||||
|
||||
const VStringSet& cppFiles() const { return m_cppFiles; }
|
||||
const VStringList& cFlags() const { return m_cFlags; }
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "V3Premit.h"
|
||||
|
||||
#include "V3Fourstate.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
|
|
@ -308,6 +309,42 @@ class PremitVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
}
|
||||
void visit(AstFourstateExpr* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Consider adding a temp for this expression.
|
||||
if (!m_stmtp) return; // Not under a statement
|
||||
if (nodep->user1SetOnce()) return; // Already processed
|
||||
if (!nodep->valuep()->isWide()) return; // Not wide
|
||||
if (m_assignLhs) return; // This is an lvalue!
|
||||
UASSERT_OBJ(!VN_IS(nodep->firstAbovep(), ArraySel), nodep, "Should have been ignored");
|
||||
// Keep as local temporary.
|
||||
std::string name = "__Vtemp_" + std::to_string(m_tmpVarCnt);
|
||||
std::string nameXz = "__Vtemp_" + std::to_string(++m_tmpVarCnt) + XZ_SUFFIX;
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstVar* const valueVarp
|
||||
= new AstVar{flp, VVarType::STMTTEMP, std::move(name), nodep->valuep()->dtypep()};
|
||||
AstVar* xzVarp
|
||||
= new AstVar{flp, VVarType::STMTTEMP, std::move(nameXz), nodep->xzp()->dtypep()};
|
||||
valueVarp->fourstateComplementp(xzVarp);
|
||||
valueVarp->funcLocal(true);
|
||||
xzVarp->funcLocal(true);
|
||||
valueVarp->noReset(true);
|
||||
xzVarp->noReset(true);
|
||||
m_cfuncp->addVarsp(valueVarp);
|
||||
m_cfuncp->addVarsp(xzVarp);
|
||||
++m_temporaryVarsCreated;
|
||||
|
||||
// Assignment to put before the referencing statement
|
||||
AstAssign* const assignValuep = new AstAssign{
|
||||
flp, new AstVarRef{flp, valueVarp, VAccess::WRITE}, nodep->valuep()->unlinkFrBack()};
|
||||
AstAssign* const assignXZp = new AstAssign{flp, new AstVarRef{flp, xzVarp, VAccess::WRITE},
|
||||
nodep->xzp()->unlinkFrBack()};
|
||||
// Insert before the statement
|
||||
m_stmtp->addHereThisAsNext(assignValuep);
|
||||
m_stmtp->addHereThisAsNext(assignXZp);
|
||||
nodep->valuep(new AstVarRef{flp, valueVarp, VAccess::READ});
|
||||
nodep->xzp(new AstVarRef{flp, xzVarp, VAccess::READ});
|
||||
}
|
||||
void visit(AstRand* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
|
|
|
|||
|
|
@ -1011,12 +1011,20 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
if (targetWidth > exprWidth) {
|
||||
// Extend to match target width
|
||||
AstNodeExpr* const result = new AstExtend{fl, exprp, targetWidth};
|
||||
result->dtypeSetLogicSized(targetWidth, targetSigning);
|
||||
if (exprp->dtypep()->isFourstate()) {
|
||||
result->dtypeSetLogicSized(targetWidth, targetSigning);
|
||||
} else {
|
||||
result->dtypeSetBitSized(targetWidth, targetSigning);
|
||||
}
|
||||
return result;
|
||||
} else if (targetWidth < exprWidth) {
|
||||
// Truncate to match target width
|
||||
AstNodeExpr* const result = new AstSel{fl, exprp, 0, targetWidth};
|
||||
result->dtypeSetLogicSized(targetWidth, targetSigning);
|
||||
if (exprp->dtypep()->isFourstate()) {
|
||||
result->dtypeSetLogicSized(targetWidth, targetSigning);
|
||||
} else {
|
||||
result->dtypeSetBitSized(targetWidth, targetSigning);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
// Width already matches
|
||||
|
|
@ -1964,7 +1972,6 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
AstNodeExpr* indexp = nodep->bitp()->unlinkFrBack(&handle);
|
||||
if (indexp->width() < 32) {
|
||||
AstExtend* const extendp = new AstExtend{fl, indexp, 32};
|
||||
extendp->dtypeSetLogicSized(32, VSigning::UNSIGNED);
|
||||
extendp->user1(true);
|
||||
indexp = extendp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,8 +66,7 @@ class ReloopVisitor final : public VNVisitor {
|
|||
static AstVar* createVarTemp(FileLine* fl, AstCFunc* cfuncp) {
|
||||
UASSERT_OBJ(cfuncp, fl, "Assignment not under a function");
|
||||
const string newvarname{"__Vilp" + std::to_string(cfuncp->user1Inc() + 1)};
|
||||
AstVar* const varp
|
||||
= new AstVar{fl, VVarType::STMTTEMP, newvarname, VFlagLogicPacked{}, 32};
|
||||
AstVar* const varp = new AstVar{fl, VVarType::STMTTEMP, newvarname, VFlagBitPacked{}, 32};
|
||||
cfuncp->addVarsp(varp);
|
||||
return varp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -552,8 +552,9 @@ class TaskVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void connectPort(AstVar* portp, AstArg* argp, const string& namePrefix, AstNode* beginp,
|
||||
bool inlineTask) {
|
||||
AstVarScope* connectPort(AstVar* portp, AstArg* argp, const string& namePrefix,
|
||||
AstNode* beginp, bool inlineTask) {
|
||||
AstVarScope* newvscp = nullptr;
|
||||
AstNodeExpr* pinp = argp->exprp();
|
||||
if (inlineTask) {
|
||||
portp->unlinkFrBack();
|
||||
|
|
@ -574,7 +575,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
+ std::to_string(m_unconVarNum++),
|
||||
portp->dtypep()};
|
||||
m_modp->addStmtsp(varp);
|
||||
AstVarScope* const newvscp = new AstVarScope{pinp->fileline(), m_scopep, varp};
|
||||
newvscp = new AstVarScope{pinp->fileline(), m_scopep, varp};
|
||||
m_scopep->addVarsp(newvscp);
|
||||
AstVarRef* const repp = new AstVarRef{pinp->fileline(), newvscp, VAccess::WRITE};
|
||||
pinp->replaceWith(repp);
|
||||
|
|
@ -619,8 +620,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
} else if (portp->isInout()) {
|
||||
// UINFOTREE(9, pinp, "", "pinrsize-");
|
||||
|
||||
AstVarScope* const newvscp
|
||||
= createVarScope(portp, namePrefix + "__" + portp->shortName());
|
||||
newvscp = createVarScope(portp, namePrefix + "__" + portp->shortName());
|
||||
portp->user2p(newvscp);
|
||||
if (!inlineTask) {
|
||||
pinp->replaceWith(
|
||||
|
|
@ -641,8 +641,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
} else if (portp->isWritable()) {
|
||||
// Even if it's referencing a varref, we still make a temporary
|
||||
// Else task(x,x,x) might produce incorrect results
|
||||
AstVarScope* const newvscp
|
||||
= createVarScope(portp, namePrefix + "__" + portp->shortName());
|
||||
newvscp = createVarScope(portp, namePrefix + "__" + portp->shortName());
|
||||
portp->user2p(newvscp);
|
||||
if (!inlineTask) {
|
||||
pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE});
|
||||
|
|
@ -653,8 +652,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
beginp->addNext(postassp);
|
||||
} else if (inlineTask && portp->isNonOutput()) {
|
||||
// Make input variable
|
||||
AstVarScope* const newvscp
|
||||
= createVarScope(portp, namePrefix + "__" + portp->shortName());
|
||||
newvscp = createVarScope(portp, namePrefix + "__" + portp->shortName());
|
||||
portp->user2p(newvscp);
|
||||
AstAssign* const preassp = connectPortMakeInAssign(pinp, newvscp, false);
|
||||
// Put assignment in FRONT of all other statements
|
||||
|
|
@ -665,6 +663,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
beginp->addNext(preassp);
|
||||
}
|
||||
}
|
||||
return newvscp;
|
||||
}
|
||||
|
||||
bool hasRefArgument(AstNodeFTask* nodep) {
|
||||
|
|
@ -691,10 +690,25 @@ class TaskVisitor final : public VNVisitor {
|
|||
AstNode::user2ClearTree();
|
||||
{
|
||||
const V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp);
|
||||
AstVar* prevFourstateVarp = nullptr;
|
||||
for (const auto& itr : tconnects) {
|
||||
AstVar* const portp = itr.first;
|
||||
AstArg* const argp = itr.second;
|
||||
connectPort(portp, argp, namePrefix, beginp, true);
|
||||
AstVar* varp = nullptr;
|
||||
if (const AstVarScope* const vscp
|
||||
= connectPort(portp, argp, namePrefix, beginp, true)) {
|
||||
varp = vscp->varp();
|
||||
}
|
||||
UASSERT_OBJ(
|
||||
itr.first->isFourstateComplement() == (prevFourstateVarp != nullptr), varp,
|
||||
"Fourstate complements shall be predecessed with fourstate value part");
|
||||
if (itr.first->fourstateComplementp()) {
|
||||
UASSERT_OBJ(varp, itr.first, "Port not needed?");
|
||||
prevFourstateVarp = varp;
|
||||
} else if (prevFourstateVarp) {
|
||||
prevFourstateVarp->fourstateComplementp(varp);
|
||||
prevFourstateVarp = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
UASSERT_OBJ(!refp->argsp(), refp, "Arg wasn't removed by above loop");
|
||||
|
|
|
|||
|
|
@ -207,7 +207,11 @@ class UnknownVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
VL_RESTORER(m_allowXUnique);
|
||||
if (nodep->isParam()) m_allowXUnique = false;
|
||||
if (nodep->isParam()) {
|
||||
m_allowXUnique = false;
|
||||
} else if (m_modp && m_modp->isTop() && nodep->varType() == VVarType::PORT) {
|
||||
nodep->setIsTopLevelPort();
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visitEqNeqCase(AstNodeBiop* nodep) {
|
||||
|
|
@ -551,7 +555,8 @@ public:
|
|||
// CONSTRUCTORS
|
||||
explicit UnknownVisitor(AstNetlist* nodep)
|
||||
: m_lvboundNames{"__Vlvbound"}
|
||||
, m_xrandNames{std::make_unique<V3UniqueNames>(s_xrandPrefix)} {
|
||||
, m_xrandNames{std::make_unique<V3UniqueNames>(s_xrandPrefix)}
|
||||
, m_allowXUnique{!v3Global.opt.fourstate()} {
|
||||
iterate(nodep);
|
||||
}
|
||||
~UnknownVisitor() override { //
|
||||
|
|
|
|||
|
|
@ -1954,13 +1954,15 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstCExprUser* nodep) override {
|
||||
// Give it the size the user wants.
|
||||
if (m_vup && m_vup->prelim()) {
|
||||
nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // We don't care
|
||||
nodep->dtypeSetBitUnsized(32, 1, VSigning::UNSIGNED); // We don't care
|
||||
// All arguments seek their natural sizes
|
||||
userIterateChildren(nodep, WidthVP{SELF, BOTH}.p());
|
||||
}
|
||||
if (m_vup->final()) {
|
||||
AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
|
||||
nodep->dtypep(expDTypep); // Assume user knows the rules; go with the flow
|
||||
nodep->dtypeSetBitUnsized(
|
||||
expDTypep->width(), expDTypep->widthMin(),
|
||||
expDTypep->numeric()); // Assume user knows the rules; go with the flow
|
||||
if (nodep->width() > 64) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $c can't generate wider than 64 bits");
|
||||
}
|
||||
|
|
@ -2092,7 +2094,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
iterateCheckSizedSelf(nodep, "FHS", nodep->fhsp(), SELF, BOTH);
|
||||
// For widthMin, if a 32 bit number, we need a 6 bit number as we need to return '32'.
|
||||
const int widthMin = V3Number::log2b(nodep->lhsp()->width()) + 1;
|
||||
nodep->dtypeSetLogicUnsized(32, widthMin, VSigning::SIGNED);
|
||||
nodep->dtypeSetBitUnsized(32, widthMin, VSigning::SIGNED);
|
||||
}
|
||||
}
|
||||
void visit(AstCountOnes* nodep) override {
|
||||
|
|
@ -2100,7 +2102,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
// For widthMin, if a 32 bit number, we need a 6 bit number as we need to return '32'.
|
||||
const int widthMin = V3Number::log2b(nodep->lhsp()->width()) + 1;
|
||||
nodep->dtypeSetLogicUnsized(32, widthMin, VSigning::SIGNED);
|
||||
nodep->dtypeSetBitUnsized(32, widthMin, VSigning::SIGNED);
|
||||
}
|
||||
}
|
||||
void visit(AstCvtPackString* nodep) override {
|
||||
|
|
|
|||
|
|
@ -174,8 +174,15 @@ class WidthSelVisitor final : public VNVisitor {
|
|||
} else {
|
||||
extendp = new AstExtend{fl, indexp};
|
||||
}
|
||||
extendp->dtypeSetLogicUnsized(
|
||||
32, std::max(V3Number::log2b(elwidth) + 1, indexp->widthMin()), VSigning::UNSIGNED);
|
||||
if (indexp->dtypep()->isFourstate()) {
|
||||
extendp->dtypeSetLogicUnsized(
|
||||
32, std::max(V3Number::log2b(elwidth) + 1, indexp->widthMin()),
|
||||
VSigning::UNSIGNED);
|
||||
} else {
|
||||
extendp->dtypeSetBitUnsized(32,
|
||||
std::max(V3Number::log2b(elwidth) + 1, indexp->widthMin()),
|
||||
VSigning::UNSIGNED);
|
||||
}
|
||||
AstNodeExpr* const mulp
|
||||
= new AstMul{fl, new AstConst{fl, AstConst::Unsized32{}, elwidth},
|
||||
// Extend needed as index might be e.g. 3 bits but constant e.g. 5 bits
|
||||
|
|
|
|||
|
|
@ -565,6 +565,11 @@ static void process() {
|
|||
V3Expand::expandAll(v3Global.rootp());
|
||||
}
|
||||
|
||||
if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly()
|
||||
&& v3Global.opt.fourstate()) {
|
||||
V3Fourstate::fourstateShuffleAll(v3Global.rootp());
|
||||
}
|
||||
|
||||
// Propagate constants across WORDSEL arrayed temporaries
|
||||
if (!v3Global.opt.serializeOnly() && v3Global.opt.fSubst()) {
|
||||
// Constant folding of expanded stuff
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ endif
|
|||
|
||||
######################################################################
|
||||
|
||||
SCENARIOS ?= --vlt --vltmt --dist
|
||||
SCENARIOS ?= --vlt --vltmt --dist --vlt4 --vltmt4
|
||||
DRIVER_HASHSET ?=
|
||||
|
||||
.PHONY: test
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ All_Scenarios = {
|
|||
'xrun': ['linter', 'simulator', 'simulator_st', 'xrun'],
|
||||
'xsim': ['linter', 'simulator', 'simulator_st', 'xsim'],
|
||||
'vlt': ['linter', 'simulator', 'simulator_st', 'vlt_all', 'vlt'],
|
||||
'vlt4': ['linter', 'simulator', 'simulator_st', 'vlt_all', 'vlt'],
|
||||
'vltmt': ['simulator', 'vlt_all', 'vltmt'],
|
||||
'vltmt4': ['simulator', 'vlt_all', 'vltmt'],
|
||||
# yapf: enable
|
||||
}
|
||||
|
||||
|
|
@ -731,11 +733,13 @@ class VlTest:
|
|||
# Make e.g. self.vlt, self.vltmt etc
|
||||
self.vlt = False # Set below also
|
||||
self.vltmt = False # Set below also
|
||||
self.vlt4 = False # Set below also
|
||||
self.vltmt4 = False # Set below also
|
||||
self.xsim = False # Set below also
|
||||
for ascenario in All_Scenarios:
|
||||
self.__dict__[ascenario] = False
|
||||
self.__dict__[scenario] = True
|
||||
self.vlt_all = self.vlt or self.vltmt # Any Verilator scenario
|
||||
self.vlt_all = self.vlt or self.vltmt or self.vlt4 or self.vltmt4 # Any Verilator scenario
|
||||
|
||||
(self.py_filename, self.t_dir) = Runner._py_filename_adjust(self.py_filename, ".")
|
||||
for tdir in Args.test_dirs: # pylint: disable=redefined-outer-name
|
||||
|
|
@ -895,6 +899,9 @@ class VlTest:
|
|||
self.top_filename = re.sub(r'\.py$', '', self.py_filename) + '.' + self.v_suffix
|
||||
self.pli_filename = re.sub(r'\.py$', '', self.py_filename) + '.cpp'
|
||||
self.top_shell_filename = self.obj_dir + "/" + self.vm_prefix + "__top.v"
|
||||
self.twostate_capable = True
|
||||
self.fourstate_capable = True
|
||||
self.fourstate_nowarn = True # This is only a temporary workaround
|
||||
|
||||
def _define_opt_calc(self) -> str:
|
||||
return "--define " if self.xsim else "+define+"
|
||||
|
|
@ -1150,9 +1157,10 @@ class VlTest:
|
|||
verilator_flags += ["--trace-vcd"]
|
||||
if Args.gdbsim or Args.rrsim:
|
||||
verilator_flags += ["-CFLAGS -ggdb -LDFLAGS -ggdb"]
|
||||
verilator_flags += ["--x-assign unique"] # More likely to be buggy
|
||||
if not (param['vlt4'] or param['vltmt4']):
|
||||
verilator_flags += ["--x-assign unique"] # More likely to be buggy
|
||||
|
||||
if param['vltmt']:
|
||||
if param['vltmt'] or param['vltmt4']:
|
||||
verilator_flags += ["--debug-partition"]
|
||||
if param['threads'] >= 0:
|
||||
verilator_flags += ["--threads", str(param['threads'])]
|
||||
|
|
@ -1160,6 +1168,10 @@ class VlTest:
|
|||
verilator_flags += ["--exe"]
|
||||
if param['make_main'] and param['verilator_make_gmake']:
|
||||
verilator_flags += ["../" + self.main_filename]
|
||||
if param['vlt4'] or param['vltmt4']:
|
||||
verilator_flags += ["--fourstate"]
|
||||
if self.fourstate_nowarn:
|
||||
verilator_flags += ["-Wno-FUTURE", "-Wno-CASTFOURSTATE"]
|
||||
|
||||
cmdargs = [
|
||||
"--prefix",
|
||||
|
|
@ -1216,7 +1228,7 @@ class VlTest:
|
|||
if re.search(r'(^|\s)-?-threads\s', checkflags):
|
||||
self.error("Specify threads via 'threads=' argument, not as a command line option")
|
||||
|
||||
if param['threads'] < 0 and param['vltmt']:
|
||||
if param['threads'] < 0 and (param['vltmt'] or param['vltmt4']):
|
||||
param['threads'] = calc_threads(Vltmt_Threads)
|
||||
if not param['context_threads']:
|
||||
param['context_threads'] = param['threads'] if (param['threads'] >= 1) else 1
|
||||
|
|
@ -1358,6 +1370,15 @@ class VlTest:
|
|||
self.skip("Test requires Coroutines; ignore error since not available\n")
|
||||
return
|
||||
|
||||
if not self.twostate_capable and (param['vlt'] or param['vltmt']):
|
||||
self.skip("Test is not twostate capable")
|
||||
return
|
||||
|
||||
if not self.fourstate_capable and (param['vlt4'] or param['vltmt4']):
|
||||
self.skip("Test is not fourstate capable - maybe verilator does not"
|
||||
"support all used features")
|
||||
return
|
||||
|
||||
if self.timing and self.sc and re.search(r'Ubuntu 24.04', distro.name(
|
||||
pretty=True)) and re.search(r'clang', self.cxx_version):
|
||||
self.skip(
|
||||
|
|
@ -1869,6 +1890,11 @@ class VlTest:
|
|||
tee=True,
|
||||
verilator_run=False) -> bool: # Move gcov data to parallel area
|
||||
|
||||
if not self.fourstate_capable and (self.vlt4 or self.vltmt4):
|
||||
self.skip("Test is not fourstate capable - maybe verilator does not"
|
||||
"support all used features")
|
||||
return False
|
||||
|
||||
try:
|
||||
command = ' '.join(cmd)
|
||||
except TypeError:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import vltest_bootstrap
|
|||
|
||||
test.priority(100)
|
||||
test.scenarios('vlt')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_a1_first_cc.v"
|
||||
|
||||
test.leak_check_disable()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
module = re.sub(r'_noinl', '', module)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
test.top_filename = "t/t_altera_lpm.v"
|
||||
module = re.sub(r'.*t_altera_', '', test.name)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile(verilator_flags2=["--stats"])
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile(verilator_flags2=["--stats"])
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile(verilator_flags2=["--stats", test.wno_unopthreads_for_few_cores])
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile(verilator_flags2=["--stats"])
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.fourstate_capable = False
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue