Four-state logic squash - signals interleave

Signed-off-by: Igor Zaworski <izaworski@antmicro.com>
This commit is contained in:
Igor Zaworski 2026-04-22 10:19:37 +02:00
parent 3503b9d853
commit 8a24a518c4
2042 changed files with 5748 additions and 1732 deletions

View File

@ -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

View File

@ -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: ''}

View File

@ -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

View File

@ -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"
;;

View File

@ -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`.

View File

@ -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));
} else {
for (int i = 0; i < vw; ++i) owp[i] = un[i];
for (int i = 0; i < vw; ++i) {
owp[i << outputJump] = (un[i] >> s) | (un[i + 1] << (32 - s));
}
for (int i = vw; i < words; ++i) owp[i] = 0;
return owp;
} else {
for (int i = 0; i < vw; ++i) owp[i << outputJump] = un[i];
}
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;
}

View File

@ -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;

View File

@ -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];

View File

@ -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; });

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
};

View File

@ -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;
}
}

View File

@ -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 <>

View File

@ -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;
}
//===================================================================

View File

@ -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];

View File

@ -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);
};

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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;
};

View File

@ -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]"

View File

@ -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,13 +3954,21 @@ public:
if (const AstConst* const constp = VN_CAST(rhsp, Const)) {
if (constp->num().isFourState()
|| (constp->dtypep()->isSigned() && constp->num().isNegative())) {
if (lhsp->dtypep() && !lhsp->dtypep()->isFourstate()) {
dtypeSetBitSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns
} else {
dtypeSetLogicSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns
}
} else {
if (lhsp->dtypep() && !lhsp->dtypep()->isFourstate()) {
dtypeSetBitSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
} else {
dtypeSetLogicSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
}
}
}
}
}
AstReplicate(FileLine* fl, AstNodeExpr* lhsp, uint32_t repCount)
: AstReplicate{fl, lhsp, new AstConst{fl, repCount}} {}
ASTGEN_MEMBERS_AstReplicate;
@ -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} {
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) {
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) {
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();

View File

@ -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

View File

@ -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]";

View File

@ -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);

View File

@ -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};

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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();
}
}
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(");
}
} 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";
return out;
} else {
out += zeroit ? (slow ? "VL_ZERO_RESET_W(" : "VL_ZERO_W(")
// 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";
}
}
} else {
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 += " = ";

View File

@ -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);
}
{ // 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 {
const int width = nodep->num().widthToFit();
putnbs(nodep, "VL_CONST_W_");
puts(cvtToStr(VL_WORDS_I(upWidth)));
puts("X(");
puts(cvtToStr(nodep->widthMin()));
}
emitTVX(assigntop);
puts("(");
puts(cvtToStr(assigntop->width()));
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--) {
puts(", {");
for (int word = 0; word < VL_WORDS_I(width); ++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(")");
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 {

View File

@ -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

View File

@ -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 {
if (!valueVarrefp) {
iterateConst(exprp->valuep());
} else {
putVarRef(valueVarrefp);
}
puts("), (");
if (AstVarRef* const varrefp = VN_CAST(exprp->xzp(), VarRef)) {
putVarRef(varrefp);
} else {
if (!xzVarrefp) {
iterateConst(exprp->xzp());
} else {
putVarRef(xzVarrefp);
}
}
} else if (AstVarRef* const varrefp = VN_CAST(nodep->valuep(), VarRef)) {
putVarRef(varrefp);

View File

@ -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();

View File

@ -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);
}

View File

@ -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

View File

@ -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; }

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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;) {

View File

@ -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; }

View File

@ -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);

View File

@ -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};
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};
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;
}

View File

@ -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;
}

View File

@ -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");

View File

@ -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 { //

View File

@ -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 {

View File

@ -174,8 +174,15 @@ class WidthSelVisitor final : public VNVisitor {
} else {
extendp = new AstExtend{fl, indexp};
}
if (indexp->dtypep()->isFourstate()) {
extendp->dtypeSetLogicUnsized(
32, std::max(V3Number::log2b(elwidth) + 1, indexp->widthMin()), VSigning::UNSIGNED);
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

View File

@ -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

View File

@ -43,7 +43,7 @@ endif
######################################################################
SCENARIOS ?= --vlt --vltmt --dist
SCENARIOS ?= --vlt --vltmt --dist --vlt4 --vltmt4
DRIVER_HASHSET ?=
.PHONY: test

View File

@ -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"]
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:

View File

@ -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()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -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)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile(verilator_flags2=["--stats"])

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('vlt_all')
test.fourstate_capable = False
test.compile(verilator_flags2=["--binary"])

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile(verilator_flags2=["--stats"])

View File

@ -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])

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile(verilator_flags2=["--stats"])

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -10,6 +10,7 @@
import vltest_bootstrap
test.scenarios('simulator')
test.fourstate_capable = False
test.compile()

View File

@ -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