This commit is contained in:
Igor Zaworski 2026-07-02 09:58:57 +02:00 committed by GitHub
commit 067fbef396
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2107 changed files with 11741 additions and 1670 deletions

View File

@ -199,6 +199,13 @@ jobs:
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt-0} - {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt-0}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt-1} - {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt-1}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt-2} - {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt-2}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: dist-vlt4-0}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: dist-vlt4-1}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: dist-vlt4-2}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: dist-vlt4-3}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt4-0}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt4-1}
- {os: ubuntu-26.04, cc: gcc, reloc: 0, suite: vltmt4-2}
test-2604-clang: test-2604-clang:
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }} name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
@ -223,6 +230,13 @@ jobs:
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt-0} - {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt-0}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt-1} - {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt-1}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt-2} - {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt-2}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: dist-vlt4-0}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: dist-vlt4-1}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: dist-vlt4-2}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: dist-vlt4-3}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt4-0}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt4-1}
- {os: ubuntu-26.04, cc: clang, reloc: 0, suite: vltmt4-2}
test-2404-gcc: test-2404-gcc:
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }} name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
@ -247,6 +261,13 @@ jobs:
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-0} - {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-0}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-1} - {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-1}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-2} - {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt-2}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt4-0}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt4-1}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt4-2}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: dist-vlt4-3}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt4-0}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt4-1}
- {os: ubuntu-24.04, cc: gcc, reloc: 0, suite: vltmt4-2}
test-2404-clang: test-2404-clang:
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }} name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
@ -271,6 +292,13 @@ jobs:
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-0} - {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-0}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-1} - {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-1}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-2} - {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt-2}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt4-0}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt4-1}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt4-2}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: dist-vlt4-3}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt4-0}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt4-1}
- {os: ubuntu-24.04, cc: clang, reloc: 0, suite: vltmt4-2}
test-2204-gcc: test-2204-gcc:
name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }} name: Test | ${{ matrix.os }} | ${{ matrix.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
@ -295,6 +323,13 @@ jobs:
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-0} - {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-0}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-1} - {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-1}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-2} - {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt-2}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt4-0}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt4-1}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt4-2}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: dist-vlt4-3}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt4-0}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt4-1}
- {os: ubuntu-22.04, cc: gcc, reloc: 0, suite: vltmt4-2}
lint-py: lint-py:
name: Lint Python name: Lint Python

View File

@ -62,7 +62,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: 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] num: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
include: include:
- {test: coverage-dist, num: ''} - {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 <mode> Assign initial Xs to this value
--x-initial-edge Enable initial X->0 and X->1 edge triggers --x-initial-edge Enable initial X->0 and X->1 edge triggers
-y <dir> Directory to search for modules -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 This is a short summary of the simulation runtime arguments, i.e. for the
final Verilated simulation runtime models. See final Verilated simulation runtime models. See

View File

@ -128,6 +128,27 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
vltmt-2) vltmt-2)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt --driver-clean" DRIVER_HASHSET=--hashset=2/3 "$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) coverage-dist)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist" "$MAKE" -C "$TEST_REGRESS" SCENARIOS="--dist"
;; ;;
@ -191,6 +212,66 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
coverage-vltmt-9) coverage-vltmt-9)
"$MAKE" -C "$TEST_REGRESS" SCENARIOS="--vltmt" DRIVER_HASHSET=--hashset=9/10 "$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 TESTS: $TESTS" fatal "Unknown TESTS: $TESTS"
;; ;;

View File

@ -2380,3 +2380,12 @@ Summary:
user-specified directories. This allows '-y "$(pwd)"' to be used if user-specified directories. This allows '-y "$(pwd)"' to be used if
absolute filenames are desired for error messages instead of relative absolute filenames are desired for error messages instead of relative
filenames. 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

@ -443,6 +443,24 @@ List Of Warnings
in decreased performance. in decreased performance.
.. option:: CASTFOURSTATE
Warns about not supported four-state logic feature.
When two-state logic variant of a feature is fully supported,
an implicit cast to two-state type is made
.. code-block:: sv
:linenos:
:emphasize-lines: 5
module t;
integer fd;
initial begin
$fflush(fd); // <- implicit conversion to two-state value
end
endmodule
.. option:: CDCRSTLOGIC .. option:: CDCRSTLOGIC
Historical, never issued since version 5.008. Historical, never issued since version 5.008.
@ -1346,7 +1364,6 @@ List Of Warnings
:option:`ASCRANGE`. While :option:`LITENDIAN` remains for :option:`ASCRANGE`. While :option:`LITENDIAN` remains for
backwards compatibility, new projects should use :option:`ASCRANGE`. backwards compatibility, new projects should use :option:`ASCRANGE`.
.. option:: MINTYPMAXDLY .. option:: MINTYPMAXDLY
.. code-block:: sv .. code-block:: sv

View File

@ -638,9 +638,29 @@ WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits); outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits);
return outwp; return outwp;
} }
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE { WDataOutP VL_ZERO_RESET_W_T(int obits, WDataOutP outwp) VL_MT_SAFE {
// Not inlined to speed up compilation of slowpath code // 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);
} }
//=========================================================================== //===========================================================================
@ -655,20 +675,39 @@ void _vl_debug_print_w(int lbits, const WDataInP iwp) VL_MT_SAFE {
//=========================================================================== //===========================================================================
// Slow expressions // Slow expressions
WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WDataInP rwp, WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus,
bool is_modulus) VL_MT_SAFE { 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 // See Knuth Algorithm D. Computes u/v = q.r
// This isn't massively tuned, as wide division is rare // This isn't massively tuned, as wide division is rare
// for debug see V3Number version // for debug see V3Number version
// Requires clean input // 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); const int words = VL_WORDS_I(lbits);
for (int i = 0; i < words; ++i) owp[i] = 0;
// Find MSB and check for zero. // Find MSB and check for zero.
const int umsbp1 = VL_MOSTSETBITP1_W(words, lwp); // dividend const int umsbp1 = (lhsJump == 2) ? (lhsOffset ? VL_MOSTSETBITP1_W_X(words, lwp)
const int vmsbp1 = VL_MOSTSETBITP1_W(words, rwp); // divisor : 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. 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 || 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 const int uw = VL_WORDS_I(umsbp1); // aka "m" in the algorithm
@ -679,15 +718,16 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
if (vw == 1) { // Single divisor word breaks rest of algorithm if (vw == 1) { // Single divisor word breaks rest of algorithm
uint64_t k = 0; uint64_t k = 0;
for (int j = uw - 1; j >= 0; --j) { for (int j = uw - 1; j >= 0; --j) {
const uint64_t unw64 = ((k << 32ULL) + static_cast<uint64_t>(lwp[j])); const uint64_t unw64 = ((k << 32ULL) + static_cast<uint64_t>(lwp[j << lhsJump]));
owp[j] = unw64 / static_cast<uint64_t>(rwp[0]); owp[j << outputJump] = unw64 / static_cast<uint64_t>(rwp[0]);
k = unw64 - static_cast<uint64_t>(owp[j]) * static_cast<uint64_t>(rwp[0]); k = unw64
- static_cast<uint64_t>(owp[j << outputJump]) * static_cast<uint64_t>(rwp[0]);
} }
if (is_modulus) { if (is_modulus) {
owp[0] = k; 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 // +1 word as we may shift during normalization
@ -703,16 +743,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) 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 // Copy and shift dividend by same amount; may set new upper word
if (s) { 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; vn[0] = rwp[0] << s;
un[uw] = lwp[uw - 1] >> (32 - s); un[uw] = lwp[(uw - 1) << lhsJump] >> (32 - s);
for (int i = uw - 1; i > 0; --i) un[i] = (lwp[i] << s) | (lwp[i - 1] >> (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; un[0] = lwp[0] << s;
} else { } 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]; vn[0] = rwp[0];
un[uw] = 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]; un[0] = lwp[0];
} }
@ -741,11 +785,11 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
} }
t = un[j + vw] - k; t = un[j + vw] - k;
un[j + vw] = t; un[j + vw] = t;
owp[j] = qhat; // Save quotient digit owp[j << outputJump] = qhat; // Save quotient digit
if (t < 0) { if (t < 0) {
// Over subtracted; correct by adding back // Over subtracted; correct by adding back
owp[j]--; owp[j << outputJump]--;
k = 0; k = 0;
for (int i = 0; i < vw; ++i) { for (int i = 0; i < vw; ++i) {
t = static_cast<uint64_t>(un[i + j]) + static_cast<uint64_t>(vn[i]) + k; t = static_cast<uint64_t>(un[i + j]) + static_cast<uint64_t>(vn[i]) + k;
@ -759,15 +803,17 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
if (is_modulus) { // modulus if (is_modulus) { // modulus
// Need to reverse normalization on copy to output // Need to reverse normalization on copy to output
if (s) { if (s) {
for (int i = 0; i < vw; ++i) owp[i] = (un[i] >> s) | (un[i + 1] << (32 - s)); for (int i = 0; i < vw; ++i) {
owp[i << outputJump] = (un[i] >> s) | (un[i + 1] << (32 - s));
}
} else { } else {
for (int i = 0; i < vw; ++i) owp[i] = un[i]; for (int i = 0; i < vw; ++i) owp[i << outputJump] = un[i];
} }
for (int i = vw; i < words; ++i) owp[i] = 0; for (int i = vw; i < words; ++i) owp[i << outputJump] = 0;
return owp; return resultp;
} }
// division // division
return owp; return resultp;
} }
WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp, WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp,
@ -780,15 +826,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> 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> 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 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) { for (int bit = 0; bit < rbits; ++bit) {
if (bit > 0) { // power = power*power if (bit > 0) { // power = power*power
VL_ASSIGN_W(obits, lastpowstore, powstore); VL_ASSIGN_W_TT(obits, lastpowstore, powstore);
VL_MUL_W(owords, powstore, lastpowstore, lastpowstore); VL_MUL_W_TTT(owords, powstore, lastpowstore, lastpowstore);
} }
if (VL_BITISSET_W(rwp, bit)) { // out *= power if (VL_BITISSET_W(rwp, bit)) { // out *= power
VL_ASSIGN_W(obits, lastoutstore, owp); VL_ASSIGN_W_TT(obits, lastoutstore, owp);
VL_MUL_W(owords, owp, lastoutstore, powstore); VL_MUL_W_TTT(owords, owp, lastoutstore, powstore);
} }
} }
return owp; return owp;
@ -796,7 +842,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, WDataOutP VL_POW_WWQ(int obits, int lbits, int rbits, WDataOutP owp, const WDataInP lwp,
QData rhs) VL_MT_SAFE { QData rhs) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> rhsw; 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); 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 { QData VL_POW_QQW(int, int, int rbits, QData lhs, const WDataInP rwp) VL_MT_SAFE {
@ -817,9 +863,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, WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp,
const WDataInP rwp, bool lsign, bool rsign) VL_MT_SAFE { const WDataInP rwp, bool lsign, bool rsign) VL_MT_SAFE {
// obits==lbits, rbits can be different // 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); 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 EData lor = 0; // 0=all zeros, ~0=all ones, else mix
for (int i = 1; i < (words - 1); ++i) lor |= lwp[i]; for (int i = 1; i < (words - 1); ++i) lor |= lwp[i];
lor |= ((lwp[words - 1] == VL_MASK_E(rbits)) ? ~VL_EUL(0) : 0); lor |= ((lwp[words - 1] == VL_MASK_E(rbits)) ? ~VL_EUL(0) : 0);
@ -832,7 +878,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 (lsign && lor == ~VL_EUL(0) && lwp[0] == ~VL_EUL(0)) { // -1
if (rwp[0] & 1) { // -1^odd=-1 if (rwp[0] & 1) { // -1^odd=-1
return VL_ALLONES_W(obits, owp); return VL_ALLONES_W_T(obits, owp);
} }
// -1^even=1 // -1^even=1
owp[0] = 1; owp[0] = 1;
@ -845,13 +891,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, WDataOutP VL_POWSS_WWQ(int obits, int lbits, int rbits, WDataOutP owp, const WDataInP lwp,
QData rhs, bool lsign, bool rsign) VL_MT_SAFE { QData rhs, bool lsign, bool rsign) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> rhsw; 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); 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, QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, const WDataInP rwp, bool lsign,
bool rsign) VL_MT_SAFE { bool rsign) VL_MT_SAFE {
// Skip check for rhs == 0, as short-circuit doesn't save time // 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 == 0) return 0; // "X"
if (lhs == 1) return 1; if (lhs == 1) return 1;
if (lsign && lhs == VL_MASK_Q(obits)) { // -1 if (lsign && lhs == VL_MASK_Q(obits)) { // -1
@ -880,12 +926,12 @@ double VL_ITOR_D_W(int lbits, const WDataInP lwp) VL_PURE {
return d; return d;
} }
double VL_ISTOR_D_W(int lbits, const WDataInP lwp) VL_MT_SAFE { 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); const int words = VL_WORDS_I(lbits);
VL_DEBUG_IFDEF(assert(words <= VL_MULS_MAX_WORDS);); VL_DEBUG_IFDEF(assert(words <= VL_MULS_MAX_WORDS););
VlWide<VL_MULS_MAX_WORDS + 1> pos; VlWide<VL_MULS_MAX_WORDS + 1> pos;
VL_NEGATE_W(words, pos, lwp); VL_NEGATE_W_TT(words, pos, lwp);
_vl_clean_inplace_w(lbits, pos); _vl_clean_inplace_w_T(lbits, pos);
return -VL_ITOR_D_W(lbits, pos); return -VL_ITOR_D_W(lbits, pos);
} }
@ -898,7 +944,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 // Or (maxdecwidth+7)/8], but can't have more than 4 BCD bits per word
std::vector<EData> bcd(VL_WORDS_I(maxdecwidth)); std::vector<EData> bcd(VL_WORDS_I(maxdecwidth));
WDataOutP bcdp = WDataOutP::external(bcd.data()); 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> tmp(VL_WORDS_I(maxdecwidth));
std::vector<EData> tmp2(VL_WORDS_I(maxdecwidth)); std::vector<EData> tmp2(VL_WORDS_I(maxdecwidth));
WDataOutP tmpp = WDataOutP::external(tmp.data()); WDataOutP tmpp = WDataOutP::external(tmp.data());
@ -911,15 +957,15 @@ std::string VL_DECIMAL_NW(int width, const WDataInP lwp) VL_MT_SAFE {
// Any digits >= 5 need an add 3 (via tmp) // Any digits >= 5 need an add 3 (via tmp)
for (int nibble_bit = 0; nibble_bit < maxdecwidth; nibble_bit += 4) { for (int nibble_bit = 0; nibble_bit < maxdecwidth; nibble_bit += 4) {
if ((VL_BITRSHIFT_W(bcd, nibble_bit) & 0xf) >= 5) { 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); tmp2[VL_BITWORD_E(nibble_bit)] |= VL_EUL(0x3) << VL_BITBIT_E(nibble_bit);
VL_ASSIGN_W(maxdecwidth, tmpp, bcdp); VL_ASSIGN_W_TT(maxdecwidth, tmpp, bcdp);
VL_ADD_W(VL_WORDS_I(maxdecwidth), bcdp, tmpp, tmp2p); VL_ADD_W_TTT(VL_WORDS_I(maxdecwidth), bcdp, tmpp, tmp2p);
} }
} }
// Shift; bcd = bcd << 1 // Shift; bcd = bcd << 1
VL_ASSIGN_W(maxdecwidth, tmpp, bcdp); VL_ASSIGN_W_TT(maxdecwidth, tmpp, bcdp);
VL_SHIFTL_WWI(maxdecwidth, maxdecwidth, 32, bcdp, tmpp, 1); VL_SHIFTL_WWI_TTT(maxdecwidth, maxdecwidth, 32, bcdp, tmpp, 1);
// bcd[0] = lwp[from_bit] // bcd[0] = lwp[from_bit]
if (VL_BITISSET_W(lwp, from_bit)) bcd[0] |= 1; if (VL_BITISSET_W(lwp, from_bit)) bcd[0] |= 1;
} }
@ -951,36 +997,36 @@ std::string _vl_vsformat_time(std::string& tmp, T ld, int timeunit, bool left,
VlWide<w> tmp2; VlWide<w> tmp2;
VlWide<w> tmp3; 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) { if (shift < 0) {
const WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(-shift)); const WDataInP pow10 = VL_EXTEND_WQ_TT(b, 0, tmp1, vl_time_pow10(-shift));
shifted = VL_DIV_WWW(b, tmp2, shifted, pow10); shifted = VL_DIV_WWW_TTT(b, tmp2, shifted, pow10);
} else { } else {
const WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(shift)); const WDataInP pow10 = VL_EXTEND_WQ_TT(b, 0, tmp1, vl_time_pow10(shift));
shifted = VL_MUL_W(w, tmp2, shifted, pow10); shifted = VL_MUL_W_TTT(w, tmp2, shifted, pow10);
} }
const WDataInP fracDigitsPow10 = VL_EXTEND_WQ(b, 0, tmp3, vl_time_pow10(fracDigits)); const WDataInP fracDigitsPow10 = VL_EXTEND_WQ_TT(b, 0, tmp3, vl_time_pow10(fracDigits));
const WDataInP integer = VL_DIV_WWW(b, tmp0, shifted, fracDigitsPow10); const WDataInP integer = VL_DIV_WWW_TTT(b, tmp0, shifted, fracDigitsPow10);
const WDataInP frac = VL_MODDIV_WWW(b, tmp1, shifted, fracDigitsPow10); const WDataInP frac = VL_MODDIV_WWW_TTT(b, tmp1, shifted, fracDigitsPow10);
const WDataInP max64Bit const WDataInP max64Bit
= VL_EXTEND_WQ(b, 0, tmp2, std::numeric_limits<uint64_t>::max()); // breaks shifted = VL_EXTEND_WQ_TT(b, 0, tmp2, std::numeric_limits<uint64_t>::max()); // breaks shifted
if (VL_GT_W(w, integer, max64Bit)) { if (VL_GT_W_TT(w, integer, max64Bit)) {
WDataOutP v = VL_ASSIGN_W(b, tmp3, integer); // breaks fracDigitsPow10 WDataOutP v = VL_ASSIGN_W_TT(b, tmp3, integer); // breaks fracDigitsPow10
VlWide<w> zero; VlWide<w> zero;
VlWide<w> ten; VlWide<w> ten;
VL_ZERO_W(b, zero); VL_ZERO_W_T(b, zero);
VL_EXTEND_WI(b, 0, ten, 10); VL_EXTEND_WI_TT(b, 0, ten, 10);
char buf[128]; // 128B is obviously long enough to represent 128bit integer in decimal char buf[128]; // 128B is obviously long enough to represent 128bit integer in decimal
char* ptr = buf + sizeof(buf) - 1; char* ptr = buf + sizeof(buf) - 1;
*ptr = '\0'; *ptr = '\0';
while (VL_GT_W(w, v, zero)) { while (VL_GT_W_TT(w, v, zero)) {
--ptr; --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)]; *ptr = "0123456789"[VL_SET_QW(mod)];
VlWide<w> divided; VlWide<w> divided;
VL_DIV_WWW(b, divided, v, ten); VL_DIV_WWW_TTT(b, divided, v, ten);
VL_ASSIGN_W(b, v, divided); VL_ASSIGN_W_TT(b, v, divided);
} }
if (!fracDigits) { if (!fracDigits) {
digits = _vl_snprintf_string(tmp, "%s%s", ptr, suffix.c_str()); digits = _vl_snprintf_string(tmp, "%s%s", ptr, suffix.c_str());
@ -1166,7 +1212,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
ld = VL_RTOIROUND_Q_D(real); ld = VL_RTOIROUND_Q_D(real);
strwide.resize(2); strwide.resize(2);
WDataOutP strwidep = WDataOutP::external(strwide.data()); WDataOutP strwidep = WDataOutP::external(strwide.data());
VL_SET_WQ(strwidep, ld); VL_SET_WQ_T(strwidep, ld);
lwp = strwidep; lwp = strwidep;
lbits = 64; lbits = 64;
// Not changint fmt == 'p' to fmt = 'g', as need fmts correct // Not changint fmt == 'p' to fmt = 'g', as need fmts correct
@ -1179,7 +1225,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
ld = VL_VA_ARG_Q_(ap, lbits); ld = VL_VA_ARG_Q_(ap, lbits);
strwide.resize(2); strwide.resize(2);
WDataOutP strwidep = WDataOutP::external(strwide.data()); WDataOutP strwidep = WDataOutP::external(strwide.data());
VL_SET_WQ(strwidep, ld); VL_SET_WQ_T(strwidep, ld);
lwp = strwidep; lwp = strwidep;
lsb = lbits - 1; lsb = lbits - 1;
++argn; // Enum value is followed by the generated name string argument ++argn; // Enum value is followed by the generated name string argument
@ -1207,7 +1253,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
ld = VL_VA_ARG_Q_(ap, lbits); ld = VL_VA_ARG_Q_(ap, lbits);
strwide.resize(2); strwide.resize(2);
WDataOutP strwidep = WDataOutP::external(strwide.data()); WDataOutP strwidep = WDataOutP::external(strwide.data());
VL_SET_WQ(strwidep, ld); VL_SET_WQ_T(strwidep, ld);
lwp = strwidep; lwp = strwidep;
} else { } else {
lwp = WDataInP::external(va_arg(ap, EData*)); lwp = WDataInP::external(va_arg(ap, EData*));
@ -1291,13 +1337,13 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
if (lbits <= VL_QUADSIZE) { if (lbits <= VL_QUADSIZE) {
digits = _vl_snprintf_string( digits = _vl_snprintf_string(
t_tmp, "%" PRId64, 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; append = t_tmp;
} else { } 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)); std::vector<EData> neg(VL_WORDS_I(lbits));
WDataOutP negp = WDataOutP::external(neg.data()); 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); append = "-"s + VL_DECIMAL_NW(lbits, negp);
} else { } else {
append = VL_DECIMAL_NW(lbits, lwp); append = VL_DECIMAL_NW(lbits, lwp);
@ -1372,7 +1418,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
} }
if (widthSet || left) { 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); lsb = (lsb < 1) ? 0 : (lsb - 1);
} }
@ -1527,7 +1573,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, void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, size_t posstart,
size_t posend) VL_MT_SAFE { size_t posend) VL_MT_SAFE {
// Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits. // 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; int lsb = 0;
for (int i = 0, pos = static_cast<int>(posend) - 1; for (int i = 0, pos = static_cast<int>(posend) - 1;
i < obits && pos >= static_cast<int>(posstart); --pos, ++i) { i < obits && pos >= static_cast<int>(posstart); --pos, ++i) {
@ -1648,7 +1694,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
double real = 0; double real = 0;
VlWide<VL_WQ_WORDS_E> qowp; 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() WDataOutP owp = WDataOutP::external((obits <= 64) ? qowp.data()
: static_cast<EData*>(thingp)); : static_cast<EData*>(thingp));
@ -1684,11 +1730,11 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
if (formatAttr == VL_VFORMATATTR_SIGNED) { if (formatAttr == VL_VFORMATATTR_SIGNED) {
QData ld = 0; QData ld = 0;
std::sscanf(t_tmp.c_str(), "%30" PRIu64, &ld); 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) { } else if (formatAttr == VL_VFORMATATTR_UNSIGNED) {
int64_t ld = 0; int64_t ld = 0;
std::sscanf(t_tmp.c_str(), "%30" PRId64, &ld); std::sscanf(t_tmp.c_str(), "%30" PRId64, &ld);
VL_SET_WQ(owp, ld); VL_SET_WQ_T(owp, ld);
} }
break; break;
} }
@ -1706,7 +1752,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
} u; } u;
real = std::strtod(t_tmp.c_str(), nullptr); real = std::strtod(t_tmp.c_str(), nullptr);
u.r = real; u.r = real;
VL_SET_WQ(owp, u.ld); VL_SET_WQ_T(owp, u.ld);
break; break;
} }
case 't': { // Time case 't': { // Time
@ -1720,7 +1766,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
// 0..-15 // 0..-15
const int shift = -userUnits + timeunit; // 0..-15 const int shift = -userUnits + timeunit; // 0..-15
real = std::strtod(t_tmp.c_str(), nullptr) * vl_time_multiplier(-shift); 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; break;
} }
case 'b': { case 'b': {
@ -1807,7 +1853,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
QData* const p = static_cast<QData*>(thingp); QData* const p = static_cast<QData*>(thingp);
*p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp)); *p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp));
} else { } else {
_vl_clean_inplace_w(obits, owp); _vl_clean_inplace_w_T(obits, owp);
} }
} }
} // switch } // switch
@ -2137,7 +2183,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 { IData VL_SSCANF_IQNX(int lbits, QData ld, const std::string& format, int argc, ...) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> fnw; VlWide<VL_WQ_WORDS_E> fnw;
VL_SET_WQ(fnw, ld); VL_SET_WQ_T(fnw, ld);
va_list ap; va_list ap;
va_start(ap, argc); va_start(ap, argc);
@ -2245,7 +2291,7 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
} else { } else {
const WDataOutP datap = WDataOutP::external( const WDataOutP datap = WDataOutP::external(
&(reinterpret_cast<EData*>(memp))[entry * VL_WORDS_I(width)]); &(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)); datap[VL_BITWORD_E(shift)] |= (static_cast<EData>(c) << VL_BITBIT_E(shift));
} }
// Prep for next // Prep for next
@ -2331,7 +2377,7 @@ void VL_STACKTRACE() VL_MT_SAFE {
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE { IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> lhsw; 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); return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw);
} }
IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE { IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE {
@ -2383,12 +2429,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(); const char* const dp = match.c_str() + 1 /*leading + */ + prefix.length();
if (match.empty()) return 0; if (match.empty()) return 0;
VL_ZERO_W(rbits, rwp); VL_ZERO_W_T(rbits, rwp);
switch (std::tolower(fmt)) { switch (std::tolower(fmt)) {
case 'd': { case 'd': {
int64_t lld = 0; int64_t lld = 0;
std::sscanf(dp, "%30" PRId64, &lld); std::sscanf(dp, "%30" PRId64, &lld);
VL_SET_WQ(rwp, lld); VL_SET_WQ_T(rwp, lld);
break; break;
} }
case 'b': _vl_vsss_based(rwp, rbits, 1, dp, 0, std::strlen(dp)); break; case 'b': _vl_vsss_based(rwp, rbits, 1, dp, 0, std::strlen(dp)); break;
@ -2406,25 +2452,25 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
case 'e': { case 'e': {
double temp = 0.F; double temp = 0.F;
std::sscanf(dp, "%le", &temp); 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; break;
} }
case 'f': { case 'f': {
double temp = 0.F; double temp = 0.F;
std::sscanf(dp, "%lf", &temp); 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; break;
} }
case 'g': { case 'g': {
double temp = 0.F; double temp = 0.F;
std::sscanf(dp, "%lg", &temp); 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; break;
} }
default: // Other simulators return 0 in these cases and don't error out default: // Other simulators return 0 in these cases and don't error out
return 0; return 0;
} }
_vl_clean_inplace_w(rbits, rwp); _vl_clean_inplace_w_T(rbits, rwp);
return 1; return 1;
} }
IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_SAFE { IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_SAFE {
@ -2744,7 +2790,7 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
& VL_MASK_Q(m_bits); & VL_MASK_Q(m_bits);
} else { } else {
const WDataOutP datap = WDataOutP::external(reinterpret_cast<EData*>(valuep)); 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)); _vl_shiftl_inplace_w(m_bits, datap, static_cast<IData>(shift));
datap[0] |= value; 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_UINT32: d[0] = *(reinterpret_cast<IData*>(datap)); return;
case VLVT_UINT64: { case VLVT_UINT64: {
VlWide<2> lwp; 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[0] = lwp[0];
d[1] = lwp[1]; d[1] = lwp[1];
break; break;
@ -323,7 +323,7 @@ static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandl
return; return;
case VLVT_UINT64: { case VLVT_UINT64: {
VlWide<2> lwp; 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].aval = lwp[0];
d[0].bval = 0; d[0].bval = 0;
d[1].aval = lwp[1]; d[1].aval = lwp[1];
@ -781,7 +781,7 @@ int svGetTime(const svScope /*scope*/, svTimeVal* time) {
if (VL_UNLIKELY(!time)) return -1; if (VL_UNLIKELY(!time)) return -1;
const QData qtime = VL_TIME_Q(); const QData qtime = VL_TIME_Q();
VlWide<2> itime; VlWide<2> itime;
VL_SET_WQ(itime, qtime); VL_SET_WQ_T(itime, qtime);
time->low = itime[0]; time->low = itime[0];
time->high = itime[1]; time->high = itime[1];
return 0; 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_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 { 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 // 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 { static inline void VL_SET_SVLV_Q(int, svLogicVecVal* owp, const QData ld) VL_MT_SAFE {
VlWide<2> lwp; VlWide<2> lwp;
VL_SET_WQ(lwp, ld); VL_SET_WQ_T(lwp, ld);
owp[0].aval = lwp[0]; owp[0].aval = lwp[0];
owp[0].bval = 0; owp[0].bval = 0;
owp[1].aval = lwp[1]; owp[1].aval = lwp[1];

View File

@ -182,7 +182,7 @@ private:
} }
WDataInP rhswp = WDataInP::external(static_cast<const EData*>(entry.m_rhsDatap)); 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> template <typename T>
@ -260,7 +260,7 @@ private:
} }
void readSel(int lbits, WDataInP valp, WDataOutP reswp, int lsb, int width) const { 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; const int msb = lsb + width - 1;
auto it = std::lower_bound(m_entries.begin(), m_entries.end(), lsb, auto it = std::lower_bound(m_entries.begin(), m_entries.end(), lsb,
[](const Entry& e, int bit) { return e.m_msb < bit; }); [](const Entry& e, int bit) { return e.m_msb < bit; });

View File

@ -383,6 +383,14 @@ void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) {
m_fst->emitValueChange(m_symbolp[code], uint64_t(newval)); m_fst->emitValueChange(m_symbolp[code], uint64_t(newval));
} }
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitLogic(uint32_t code, CData newval, CData newvalXZ) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
m_owner.emitTimeChangeMaybe();
const uint32_t newvals[2] = {static_cast<uint32_t>(newval), static_cast<uint32_t>(newvalXZ)};
m_fst->emitValueChange(m_symbolp[code], newvals, fst::EncodingType::VERILOG);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitCData(uint32_t code, CData newval, int) { void VerilatedFstBuffer::emitCData(uint32_t code, CData newval, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
@ -390,6 +398,14 @@ void VerilatedFstBuffer::emitCData(uint32_t code, CData newval, int) {
m_fst->emitValueChange(m_symbolp[code], newval); m_fst->emitValueChange(m_symbolp[code], newval);
} }
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitFourstateCData(uint32_t code, CData newval, CData newvalXZ, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
m_owner.emitTimeChangeMaybe();
const uint32_t newvals[2] = {static_cast<uint32_t>(newval), static_cast<uint32_t>(newvalXZ)};
m_fst->emitValueChange(m_symbolp[code], newvals, fst::EncodingType::VERILOG);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitSData(uint32_t code, SData newval, int) { void VerilatedFstBuffer::emitSData(uint32_t code, SData newval, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
@ -397,6 +413,14 @@ void VerilatedFstBuffer::emitSData(uint32_t code, SData newval, int) {
m_fst->emitValueChange(m_symbolp[code], newval); m_fst->emitValueChange(m_symbolp[code], newval);
} }
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitFourstateSData(uint32_t code, SData newval, SData newvalXZ, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
m_owner.emitTimeChangeMaybe();
const uint32_t newvals[2] = {static_cast<uint32_t>(newval), static_cast<uint32_t>(newvalXZ)};
m_fst->emitValueChange(m_symbolp[code], newvals, fst::EncodingType::VERILOG);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitIData(uint32_t code, IData newval, int) { void VerilatedFstBuffer::emitIData(uint32_t code, IData newval, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
@ -404,6 +428,14 @@ void VerilatedFstBuffer::emitIData(uint32_t code, IData newval, int) {
m_fst->emitValueChange(m_symbolp[code], newval); m_fst->emitValueChange(m_symbolp[code], newval);
} }
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitFourstateIData(uint32_t code, IData newval, IData newvalXZ, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
m_owner.emitTimeChangeMaybe();
const uint32_t newvals[2] = {newval, newvalXZ};
m_fst->emitValueChange(m_symbolp[code], newvals, fst::EncodingType::VERILOG);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitQData(uint32_t code, QData newval, int) { void VerilatedFstBuffer::emitQData(uint32_t code, QData newval, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
@ -412,12 +444,28 @@ void VerilatedFstBuffer::emitQData(uint32_t code, QData newval, int) {
} }
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitWData(uint32_t code, WDataInP newval, int) { void VerilatedFstBuffer::emitFourstateQData(uint32_t code, QData newval, QData newvalXZ, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
m_owner.emitTimeChangeMaybe();
const uint64_t newvals[2] = {newval, newvalXZ};
m_fst->emitValueChange(m_symbolp[code], newvals, fst::EncodingType::VERILOG);
}
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitWData(uint32_t code, const WDataInP newval, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
m_owner.emitTimeChangeMaybe(); m_owner.emitTimeChangeMaybe();
m_fst->emitValueChange(m_symbolp[code], newval.datap()); m_fst->emitValueChange(m_symbolp[code], newval.datap());
} }
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitFourstateWData(uint32_t code, const WDataInP newval, int) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE
m_owner.emitTimeChangeMaybe();
// call emitValueChange(handle, uint32_t*)
m_fst->emitValueChange(m_symbolp[code], newval);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitDouble(uint32_t code, double newval) { void VerilatedFstBuffer::emitDouble(uint32_t code, double newval) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE VL_DEBUG_IFDEF(assert(m_symbolp[code]);); // LCOV_EXCL_BR_LINE

View File

@ -228,11 +228,17 @@ class VerilatedFstBuffer VL_NOT_FINAL {
// called from only one place (the full* methods), so always inline them. // called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code); VL_ATTR_ALWINLINE void emitEvent(uint32_t code);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval); VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitLogic(uint32_t code, CData newval, CData newvalXZ);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int); VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int);
VL_ATTR_ALWINLINE void emitFourstateCData(uint32_t code, CData newval, CData newvalXZ, int);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int); VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int);
VL_ATTR_ALWINLINE void emitFourstateSData(uint32_t code, SData newval, SData newvalXZ, int);
VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int); VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int);
VL_ATTR_ALWINLINE void emitFourstateIData(uint32_t code, IData newval, IData newvalXZ, int);
VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int); 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 emitWData(uint32_t code, WDataInP newval, int);
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, int);
VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval); 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 { bool VlRandomVar::set(const std::string& idx, const std::string& val) const {
VlWide<VL_WQ_WORDS_E> qowp; VlWide<VL_WQ_WORDS_E> qowp;
VL_SET_WQ(qowp, 0ULL); VL_SET_WQ_T(qowp, 0ULL);
WDataOutP owp = qowp; WDataOutP owp = qowp;
const int obits = width(); const int obits = width();
VlWide<VL_WQ_WORDS_E> qiwp; 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; if (!idx.empty() && !parseSMTNum(64, qiwp, idx)) return false;
const int nidx = qiwp[0]; const int nidx = qiwp[0];
if (obits > VL_QUADSIZE) owp = WDataOutP::external(reinterpret_cast<EData*>(datap(nidx))); 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)); QData* const p = static_cast<QData*>(datap(nidx));
*p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp)); *p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp));
} else { } else {
_vl_clean_inplace_w(obits, owp); _vl_clean_inplace_w_T(obits, owp);
} }
return true; return true;
} }

View File

@ -65,20 +65,23 @@
class VerilatedSaifActivityBit final { class VerilatedSaifActivityBit final {
// MEMBERS // MEMBERS
bool m_lastVal = false; // Last emitted activity bit value bool m_lastVal = false; // Last emitted activity bit value
bool m_lastValXZ = false; // Last emitted activity bit value
uint64_t m_highTime = 0; // Total time when bit was high uint64_t m_highTime = 0; // Total time when bit was high
size_t m_transitions = 0; // Total number of bit transitions size_t m_transitions = 0; // Total number of bit transitions
public: public:
// METHODS // METHODS
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void aggregateVal(uint64_t dt, bool newVal) { void aggregateVal(uint64_t dt, bool newVal, bool newValXZ = false) {
m_transitions += newVal != m_lastVal ? 1 : 0; m_transitions += (newVal != m_lastVal || m_lastValXZ != newValXZ) ? 1 : 0;
m_highTime += m_lastVal ? dt : 0; m_highTime += m_lastVal ? dt : 0;
m_lastVal = newVal; m_lastVal = newVal;
m_lastValXZ = newValXZ;
} }
// ACCESSORS // ACCESSORS
VL_ATTR_ALWINLINE bool bitValue() const { return m_lastVal; } VL_ATTR_ALWINLINE bool bitValue() const { return m_lastVal; }
VL_ATTR_ALWINLINE bool bitValueXZ() const { return m_lastValXZ; }
VL_ATTR_ALWINLINE uint64_t highTime() const { return m_highTime; } VL_ATTR_ALWINLINE uint64_t highTime() const { return m_highTime; }
VL_ATTR_ALWINLINE uint64_t toggleCount() const { return m_transitions; } VL_ATTR_ALWINLINE uint64_t toggleCount() const { return m_transitions; }
}; };
@ -104,6 +107,7 @@ public:
// METHODS // METHODS
VL_ATTR_ALWINLINE void emitBit(uint64_t time, CData newval); VL_ATTR_ALWINLINE void emitBit(uint64_t time, CData newval);
VL_ATTR_ALWINLINE void emitLogic(uint64_t time, CData newval, CData newvalXZ);
template <typename DataType> template <typename DataType>
VL_ATTR_ALWINLINE void emitData(uint64_t time, DataType newval, uint32_t bits) { VL_ATTR_ALWINLINE void emitData(uint64_t time, DataType newval, uint32_t bits) {
@ -117,7 +121,23 @@ public:
updateLastTime(time); updateLastTime(time);
} }
template <typename DataType>
VL_ATTR_ALWINLINE void emitFourstateData(uint64_t time, DataType newval, DataType newvalXZ,
uint32_t bits) {
static_assert(std::is_integral<DataType>::value,
"The emitted value must be of integral type");
const uint64_t dt = time - m_lastTime;
for (size_t i = 0; i < std::min(m_width, bits); ++i) {
m_bits[i].aggregateVal(dt, newval & 1, newvalXZ & 1);
newval >>= 1;
newvalXZ >>= 1;
}
updateLastTime(time);
}
VL_ATTR_ALWINLINE void emitWData(uint64_t time, WDataInP newval, uint32_t bits); VL_ATTR_ALWINLINE void emitWData(uint64_t time, WDataInP newval, 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; } VL_ATTR_ALWINLINE void updateLastTime(uint64_t val) { m_lastTime = val; }
// ACCESSORS // ACCESSORS
@ -229,7 +249,15 @@ void VerilatedSaifActivityVar::emitBit(const uint64_t time, const CData newval)
} }
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedSaifActivityVar::emitWData(const uint64_t time, WDataInP newval, void VerilatedSaifActivityVar::emitLogic(const uint64_t time, const CData newval,
const CData newvalXZ) {
assert(m_lastTime <= time);
m_bits[0].aggregateVal(time - m_lastTime, newval, newvalXZ);
updateLastTime(time);
}
VL_ATTR_ALWINLINE
void VerilatedSaifActivityVar::emitWData(const uint64_t time, const WDataInP newval,
const uint32_t bits) { const uint32_t bits) {
assert(m_lastTime <= time); assert(m_lastTime <= time);
const uint64_t dt = time - m_lastTime; const uint64_t dt = time - m_lastTime;
@ -241,6 +269,20 @@ void VerilatedSaifActivityVar::emitWData(const uint64_t time, WDataInP newval,
updateLastTime(time); updateLastTime(time);
} }
VL_ATTR_ALWINLINE
void VerilatedSaifActivityVar::emitFourstateWData(const uint64_t time, const WDataInP newval,
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) * 2; i += 2) {
const size_t wordIndex = i / VL_EDATASIZE;
m_bits[i].aggregateVal(dt, (newval[wordIndex] >> VL_BITBIT_E(i)) & 1,
(newval[wordIndex | 1] >> VL_BITBIT_E(i)) & 1);
}
updateLastTime(time);
}
VerilatedSaifActivityBit& VerilatedSaifActivityVar::bit(const std::size_t index) { VerilatedSaifActivityBit& VerilatedSaifActivityVar::bit(const std::size_t index) {
assert(index < m_width); assert(index < m_width);
return m_bits[index]; return m_bits[index];
@ -633,6 +675,15 @@ void VerilatedSaifBuffer::emitBit(const uint32_t code, const CData newval) {
activity.emitBit(m_owner.currentTime(), newval); activity.emitBit(m_owner.currentTime(), newval);
} }
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitLogic(uint32_t code, CData newval, CData newvalXZ) {
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.emitLogic(m_owner.currentTime(), newval, newvalXZ);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitCData(const uint32_t code, const CData newval, const int bits) { void VerilatedSaifBuffer::emitCData(const uint32_t code, const CData newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code) assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
@ -642,6 +693,16 @@ void VerilatedSaifBuffer::emitCData(const uint32_t code, const CData newval, con
activity.emitData<CData>(m_owner.currentTime(), newval, bits); activity.emitData<CData>(m_owner.currentTime(), newval, bits);
} }
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitFourstateCData(uint32_t code, CData newval, CData newvalXZ,
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.emitFourstateData<CData>(m_owner.currentTime(), newval, newvalXZ, bits);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitSData(const uint32_t code, const SData newval, const int bits) { void VerilatedSaifBuffer::emitSData(const uint32_t code, const SData newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code) assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
@ -651,6 +712,16 @@ void VerilatedSaifBuffer::emitSData(const uint32_t code, const SData newval, con
activity.emitData<SData>(m_owner.currentTime(), newval, bits); activity.emitData<SData>(m_owner.currentTime(), newval, bits);
} }
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitFourstateSData(uint32_t code, SData newval, SData newvalXZ,
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.emitFourstateData<SData>(m_owner.currentTime(), newval, newvalXZ, bits);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitIData(const uint32_t code, const IData newval, const int bits) { void VerilatedSaifBuffer::emitIData(const uint32_t code, const IData newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code) assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
@ -660,6 +731,16 @@ void VerilatedSaifBuffer::emitIData(const uint32_t code, const IData newval, con
activity.emitData<IData>(m_owner.currentTime(), newval, bits); activity.emitData<IData>(m_owner.currentTime(), newval, bits);
} }
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitFourstateIData(uint32_t code, IData newval, IData newvalXZ,
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.emitFourstateData<IData>(m_owner.currentTime(), newval, newvalXZ, bits);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitQData(const uint32_t code, const QData newval, const int bits) { void VerilatedSaifBuffer::emitQData(const uint32_t code, const QData newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code) assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
@ -670,7 +751,17 @@ void VerilatedSaifBuffer::emitQData(const uint32_t code, const QData newval, con
} }
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitWData(const uint32_t code, WDataInP newval, const int bits) { void VerilatedSaifBuffer::emitFourstateQData(uint32_t code, QData newval, QData newvalXZ,
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.emitFourstateData<QData>(m_owner.currentTime(), newval, newvalXZ, bits);
}
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitWData(const uint32_t code, const WDataInP newval, const int bits) {
assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code) assert(m_owner.m_activityAccumulators.at(m_fidx)->m_activity.count(code)
&& "Activity must be declared earlier"); && "Activity must be declared earlier");
VerilatedSaifActivityVar& activity VerilatedSaifActivityVar& activity
@ -678,6 +769,16 @@ void VerilatedSaifBuffer::emitWData(const uint32_t code, WDataInP newval, const
activity.emitWData(m_owner.currentTime(), newval, bits); activity.emitWData(m_owner.currentTime(), newval, bits);
} }
VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitFourstateWData(const uint32_t code, const WDataInP newval,
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, bits);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedSaifBuffer::emitDouble(const uint32_t code, const double newval) { void VerilatedSaifBuffer::emitDouble(const uint32_t code, const double newval) {
// NOP // NOP

View File

@ -243,11 +243,21 @@ class VerilatedSaifBuffer VL_NOT_FINAL {
// called from only one place (the full* methods), so always inline them. // called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code); VL_ATTR_ALWINLINE void emitEvent(uint32_t code);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval); VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitLogic(uint32_t code, CData newval, CData newvalXZ);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits); VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE void emitFourstateCData(uint32_t code, CData newval, CData newvalXZ,
int bits);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits); VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
VL_ATTR_ALWINLINE void emitFourstateSData(uint32_t code, SData newval, SData newvalXZ,
int bits);
VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits); VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits);
VL_ATTR_ALWINLINE void emitFourstateIData(uint32_t code, IData newval, IData newvalXZ,
int bits);
VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits); VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits);
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 emitWData(uint32_t code, WDataInP newval, int bits);
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, int bits);
VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval); VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval);
}; };

View File

@ -385,11 +385,17 @@ public:
// Write to previous value buffer value and emit trace entry. // Write to previous value buffer value and emit trace entry.
void fullBit(uint32_t* oldp, CData newval); void fullBit(uint32_t* oldp, CData newval);
void fullLogic(uint32_t* oldp, CData newval, CData newvalXZ);
void fullCData(uint32_t* oldp, CData newval, int bits); void fullCData(uint32_t* oldp, CData newval, int bits);
void fullFourstateCData(uint32_t* oldp, CData newval, CData newvalXZ, int bits);
void fullSData(uint32_t* oldp, SData newval, int bits); void fullSData(uint32_t* oldp, SData newval, int bits);
void fullFourstateSData(uint32_t* oldp, SData newval, SData newvalXZ, int bits);
void fullIData(uint32_t* oldp, IData newval, int bits); void fullIData(uint32_t* oldp, IData newval, int bits);
void fullFourstateIData(uint32_t* oldp, IData newval, IData newvalXZ, int bits);
void fullQData(uint32_t* oldp, QData newval, int bits); 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 fullWData(uint32_t* oldp, WDataInP newval, int bits);
void fullFourstateWData(uint32_t* oldp, WDataInP newval, int bits);
void fullDouble(uint32_t* oldp, double newval); void fullDouble(uint32_t* oldp, double newval);
void fullEvent(uint32_t* oldp, const VlEventBase* newvalp); void fullEvent(uint32_t* oldp, const VlEventBase* newvalp);
void fullEventTriggered(uint32_t* oldp); void fullEventTriggered(uint32_t* oldp);
@ -399,32 +405,69 @@ public:
const uint32_t diff = *oldp ^ newval; const uint32_t diff = *oldp ^ newval;
if (VL_UNLIKELY(diff)) fullBit(oldp, newval); if (VL_UNLIKELY(diff)) fullBit(oldp, newval);
} }
VL_ATTR_ALWINLINE void chgLogic(uint32_t* oldp, CData newval, CData newvalXZ) {
CData* oldcp = reinterpret_cast<CData*>(oldp);
const uint32_t diff = (oldcp[0] ^ newval) | (oldcp[1] ^ newvalXZ);
if (VL_UNLIKELY(diff)) fullLogic(oldp, newval, newvalXZ);
}
VL_ATTR_ALWINLINE void chgCData(uint32_t* oldp, CData newval, int bits) { VL_ATTR_ALWINLINE void chgCData(uint32_t* oldp, CData newval, int bits) {
const uint32_t diff = *oldp ^ newval; const uint32_t diff = *oldp ^ newval;
if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits); if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits);
} }
VL_ATTR_ALWINLINE void chgFourstateCData(uint32_t* oldp, CData newval, CData newvalXZ,
int bits) {
CData* oldcp = reinterpret_cast<CData*>(oldp);
const uint32_t diff = (oldcp[0] ^ newval) | (oldcp[1] ^ newvalXZ);
if (VL_UNLIKELY(diff)) fullFourstateCData(oldp, newval, newvalXZ, bits);
}
VL_ATTR_ALWINLINE void chgSData(uint32_t* oldp, SData newval, int bits) { VL_ATTR_ALWINLINE void chgSData(uint32_t* oldp, SData newval, int bits) {
const uint32_t diff = *oldp ^ newval; const uint32_t diff = *oldp ^ newval;
if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits); if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits);
} }
VL_ATTR_ALWINLINE void chgFourstateSData(uint32_t* oldp, SData newval, SData newvalXZ,
int bits) {
SData* oldcp = reinterpret_cast<SData*>(oldp);
const uint32_t diff = (oldcp[0] ^ newval) | (oldcp[1] ^ newvalXZ);
if (VL_UNLIKELY(diff)) fullFourstateSData(oldp, newval, newvalXZ, bits);
}
VL_ATTR_ALWINLINE void chgIData(uint32_t* oldp, IData newval, int bits) { VL_ATTR_ALWINLINE void chgIData(uint32_t* oldp, IData newval, int bits) {
const uint32_t diff = *oldp ^ newval; const uint32_t diff = *oldp ^ newval;
if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits); if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits);
} }
VL_ATTR_ALWINLINE void chgFourstateIData(uint32_t* oldp, IData newval, IData newvalXZ,
int bits) {
IData* oldcp = reinterpret_cast<IData*>(oldp);
const uint32_t diff = (oldcp[0] ^ newval) | (oldcp[1] ^ newvalXZ);
if (VL_UNLIKELY(diff)) fullFourstateIData(oldp, newval, newvalXZ, bits);
}
VL_ATTR_ALWINLINE void chgQData(uint32_t* oldp, QData newval, int bits) { VL_ATTR_ALWINLINE void chgQData(uint32_t* oldp, QData newval, int bits) {
QData old; QData old;
std::memcpy(&old, oldp, sizeof(old)); std::memcpy(&old, oldp, sizeof(old));
const uint64_t diff = old ^ newval; const uint64_t diff = old ^ newval;
if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits); if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits);
} }
VL_ATTR_ALWINLINE void chgWData(uint32_t* oldp, WDataInP newval, int bits) { VL_ATTR_ALWINLINE void chgFourstateQData(uint32_t* oldp, QData newval, QData newvalXZ,
for (int i = 0; i < (bits + 31) / 32; ++i) { int bits) {
QData* oldcp = reinterpret_cast<QData*>(oldp);
const uint32_t diff = (oldcp[0] ^ newval) | (oldcp[1] ^ newvalXZ);
if (VL_UNLIKELY(diff)) fullFourstateQData(oldp, newval, newvalXZ, bits);
}
VL_ATTR_ALWINLINE void chgWData(uint32_t* oldp, const WDataInP newval, int bits) {
for (int i = 0; i < VL_WORDS_I(bits); ++i) {
if (VL_UNLIKELY(oldp[i] ^ newval[i])) { if (VL_UNLIKELY(oldp[i] ^ newval[i])) {
fullWData(oldp, newval, bits); fullWData(oldp, newval, bits);
return; return;
} }
} }
} }
VL_ATTR_ALWINLINE void chgFourstateWData(uint32_t* oldp, const WDataInP newval, int bits) {
for (int i = 0; i < VL_WORDS_I(bits); ++i) {
if (VL_UNLIKELY(oldp[i] ^ newval[i])) {
fullFourstateWData(oldp, newval, bits);
return;
}
}
}
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newvalp) { VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newvalp) {
if (newvalp->isTriggered()) fullEvent(oldp, newvalp); if (newvalp->isTriggered()) fullEvent(oldp, newvalp);
} }

View File

@ -555,6 +555,16 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
emitBit(code, newval); emitBit(code, newval);
} }
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullLogic(uint32_t* oldp, CData newval, CData newvalXZ) {
const uint32_t code = oldp - m_sigs_oldvalp;
CData* oldcp = reinterpret_cast<CData*>(oldp);
oldcp[0] = newval; // Still copy even if not tracing so chg doesn't call full
oldcp[1] = newvalXZ;
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
emitLogic(code, newval, newvalXZ);
}
template <> template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newvalp) { void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newvalp) {
const uint32_t code = oldp - m_sigs_oldvalp; const uint32_t code = oldp - m_sigs_oldvalp;
@ -577,6 +587,17 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullCData(uint32_t* oldp, CData newval, int
emitCData(code, newval, bits); emitCData(code, newval, bits);
} }
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullFourstateCData(uint32_t* oldp, CData newval,
CData newvalXZ, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
CData* oldcp = reinterpret_cast<CData*>(oldp);
oldcp[0] = newval; // Still copy even if not tracing so chg doesn't call full
oldcp[1] = newvalXZ;
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
emitFourstateCData(code, newval, newvalXZ, bits);
}
template <> template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullSData(uint32_t* oldp, SData newval, int bits) { void VerilatedTraceBuffer<VL_BUF_T>::fullSData(uint32_t* oldp, SData newval, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp; const uint32_t code = oldp - m_sigs_oldvalp;
@ -585,6 +606,17 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullSData(uint32_t* oldp, SData newval, int
emitSData(code, newval, bits); emitSData(code, newval, bits);
} }
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullFourstateSData(uint32_t* oldp, SData newval,
SData newvalXZ, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
SData* oldcp = reinterpret_cast<SData*>(oldp);
oldcp[0] = newval; // Still copy even if not tracing so chg doesn't call full
oldcp[1] = newvalXZ;
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
emitFourstateSData(code, newval, newvalXZ, bits);
}
template <> template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullIData(uint32_t* oldp, IData newval, int bits) { void VerilatedTraceBuffer<VL_BUF_T>::fullIData(uint32_t* oldp, IData newval, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp; const uint32_t code = oldp - m_sigs_oldvalp;
@ -593,6 +625,17 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullIData(uint32_t* oldp, IData newval, int
emitIData(code, newval, bits); emitIData(code, newval, bits);
} }
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullFourstateIData(uint32_t* oldp, IData newval,
IData newvalXZ, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
IData* oldcp = reinterpret_cast<IData*>(oldp);
oldcp[0] = newval; // Still copy even if not tracing so chg doesn't call full
oldcp[1] = newvalXZ;
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
emitFourstateIData(code, newval, newvalXZ, bits);
}
template <> template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullQData(uint32_t* oldp, QData newval, int bits) { void VerilatedTraceBuffer<VL_BUF_T>::fullQData(uint32_t* oldp, QData newval, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp; const uint32_t code = oldp - m_sigs_oldvalp;
@ -602,13 +645,33 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullQData(uint32_t* oldp, QData newval, int
} }
template <> template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullWData(uint32_t* oldp, WDataInP newval, int bits) { void VerilatedTraceBuffer<VL_BUF_T>::fullFourstateQData(uint32_t* oldp, QData newval,
QData newvalXZ, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
QData* oldcp = reinterpret_cast<QData*>(oldp);
oldcp[0] = newval; // Still copy even if not tracing so chg doesn't call full
oldcp[1] = newvalXZ;
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
emitFourstateQData(code, newval, newvalXZ, bits);
}
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullWData(uint32_t* oldp, const WDataInP newval, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp; const uint32_t code = oldp - m_sigs_oldvalp;
for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newval[i]; for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newval[i];
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
emitWData(code, newval, bits); emitWData(code, newval, bits);
} }
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullFourstateWData(uint32_t* oldp, const WDataInP newval,
int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
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, bits);
}
template <> template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullDouble(uint32_t* oldp, double newval) { void VerilatedTraceBuffer<VL_BUF_T>::fullDouble(uint32_t* oldp, double newval) {
const uint32_t code = oldp - m_sigs_oldvalp; const uint32_t code = oldp - m_sigs_oldvalp;

View File

@ -95,37 +95,37 @@ struct VlWide final {
return std::memcmp(m_storage, that.m_storage, N_Words * sizeof(EData)) == 0; 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); } 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]; } EData& operator[](size_t index) VL_PURE { return m_storage[index]; }
const EData& operator[](size_t index) const VL_MT_SAFE { return m_storage[index]; } const EData& operator[](size_t index) const VL_PURE { return m_storage[index]; }
VlWide<N_Words>& operator&=(const VlWide& rhs) { 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; return *this;
} }
VlWide<N_Words>& operator|=(const VlWide& rhs) { 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; return *this;
} }
VlWide<N_Words>& operator^=(const VlWide& rhs) { 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; return *this;
} }
VlWide<N_Words>& operator+=(const VlWide& rhs) { 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; return *this;
} }
VlWide<N_Words>& operator*=(const VlWide& rhs) { VlWide<N_Words>& operator*=(const VlWide& rhs) {
VlWide<N_Words> out{}; 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]; for (size_t i = 0; i < N_Words; ++i) m_storage[i] = out.m_storage[i];
return *this; return *this;
} }
// METHODS // METHODS
EData& at(size_t index) 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 { 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; } size_t size() const VL_PURE { return N_Words; }
EData* data() 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 { 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; inline bool operator<(const VlWide<N_Words>& rhs) const VL_PURE;
}; };
@ -169,9 +169,28 @@ public:
// METHODS // METHODS
EData* datap() const VL_PURE { return m_datap; } EData* datap() const VL_PURE { return m_datap; }
operator bool() 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]; } 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+(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+(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"); static_assert(sizeof(WDataOutP) == sizeof(EData*), "WDataOutP should be a single pointer");
@ -208,17 +227,36 @@ public:
// METHODS // METHODS
const EData* datap() const VL_PURE { return m_datap; } const EData* datap() const VL_PURE { return m_datap; }
operator bool() 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]; } 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+(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+(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_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> template <std::size_t N_Words>
bool VlWide<N_Words>::operator<(const VlWide<N_Words>& rhs) const VL_PURE { 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

@ -635,6 +635,18 @@ void VerilatedVcdBuffer::emitBit(uint32_t code, CData newval) {
finishLine(code, wp); finishLine(code, wp);
} }
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitLogic(uint32_t code, CData newval, CData newvalXZ) {
// Don't prefetch suffix as it's a bit too late;
char* wp = m_writep;
if (newval) {
*wp++ = newvalXZ ? 'x' : '1';
} else {
*wp++ = newvalXZ ? 'z' : '0';
}
finishLine(code, wp);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitCData(uint32_t code, CData newval, int bits) { void VerilatedVcdBuffer::emitCData(uint32_t code, CData newval, int bits) {
char* wp = m_writep; char* wp = m_writep;
@ -643,6 +655,19 @@ void VerilatedVcdBuffer::emitCData(uint32_t code, CData newval, int bits) {
finishLine(code, wp + bits); finishLine(code, wp + bits);
} }
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitFourstateCData(uint32_t code, CData newval, CData newvalXZ,
int bits) {
char* wp = m_writep;
*wp++ = 'b';
for (int i = bits - 1; i >= 0; --i) {
const CData mask = 1 << i;
*wp++ = (newvalXZ & mask) ? (newval & mask ? 'x' : 'z')
: ('0' | (static_cast<char>(newval >> i) & 1));
}
finishLine(code, wp);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitSData(uint32_t code, SData newval, int bits) { void VerilatedVcdBuffer::emitSData(uint32_t code, SData newval, int bits) {
char* wp = m_writep; char* wp = m_writep;
@ -651,6 +676,19 @@ void VerilatedVcdBuffer::emitSData(uint32_t code, SData newval, int bits) {
finishLine(code, wp + bits); finishLine(code, wp + bits);
} }
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitFourstateSData(uint32_t code, SData newval, SData newvalXZ,
int bits) {
char* wp = m_writep;
*wp++ = 'b';
for (int i = bits - 1; i >= 0; --i) {
const SData mask = 1 << i;
*wp++ = (newvalXZ & mask) ? (newval & mask ? 'x' : 'z')
: ('0' | (static_cast<char>(newval >> i) & 1));
}
finishLine(code, wp);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitIData(uint32_t code, IData newval, int bits) { void VerilatedVcdBuffer::emitIData(uint32_t code, IData newval, int bits) {
char* wp = m_writep; char* wp = m_writep;
@ -659,6 +697,19 @@ void VerilatedVcdBuffer::emitIData(uint32_t code, IData newval, int bits) {
finishLine(code, wp + bits); finishLine(code, wp + bits);
} }
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitFourstateIData(uint32_t code, IData newval, IData newvalXZ,
int bits) {
char* wp = m_writep;
*wp++ = 'b';
for (int i = bits - 1; i >= 0; --i) {
const IData mask = 1 << i;
*wp++ = (newvalXZ & mask) ? (newval & mask ? 'x' : 'z')
: ('0' | (static_cast<char>(newval >> i) & 1));
}
finishLine(code, wp);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitQData(uint32_t code, QData newval, int bits) { void VerilatedVcdBuffer::emitQData(uint32_t code, QData newval, int bits) {
char* wp = m_writep; char* wp = m_writep;
@ -668,7 +719,20 @@ void VerilatedVcdBuffer::emitQData(uint32_t code, QData newval, int bits) {
} }
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitWData(uint32_t code, WDataInP newval, int bits) { void VerilatedVcdBuffer::emitFourstateQData(uint32_t code, QData newval, QData newvalXZ,
int bits) {
char* wp = m_writep;
*wp++ = 'b';
for (int i = bits - 1; i >= 0; --i) {
const QData mask = 1 << i;
*wp++ = (newvalXZ & mask) ? (newval & mask ? 'x' : 'z')
: ('0' | (static_cast<char>(newval >> i) & 1));
}
finishLine(code, wp);
}
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitWData(uint32_t code, const WDataInP newval, int bits) {
int words = VL_WORDS_I(bits); int words = VL_WORDS_I(bits);
char* wp = m_writep; char* wp = m_writep;
*wp++ = 'b'; *wp++ = 'b';
@ -684,6 +748,32 @@ void VerilatedVcdBuffer::emitWData(uint32_t code, WDataInP newval, int bits) {
finishLine(code, wp); finishLine(code, wp);
} }
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitFourstateWData(uint32_t code, const WDataInP newval, int bits) {
char* wp = m_writep;
*wp++ = 'b';
const int lastIdx = ((bits - 1) / VL_EDATASIZE) << 1;
{
const EData value = newval[lastIdx];
const EData xz = newval[lastIdx | 1];
for (int i = (bits - 1) % VL_EDATASIZE; i >= 0; --i) {
const EData mask = 1 << i;
*wp++ = (xz & mask) ? (value & mask ? 'x' : 'z')
: ('0' | (static_cast<char>(value >> i) & 1));
}
}
for (int w = lastIdx - 2; w >= 0; w -= 2) {
const EData value = newval[w];
const EData xz = newval[w | 1];
for (int i = VL_EDATASIZE - 1; i >= 0; --i) {
const EData mask = 1 << i;
*wp++ = (xz & mask) ? (value & mask ? 'x' : 'z')
: ('0' | (static_cast<char>(value >> i) & 1));
}
}
finishLine(code, wp);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitDouble(uint32_t code, double newval) { void VerilatedVcdBuffer::emitDouble(uint32_t code, double newval) {
char* wp = m_writep; char* wp = m_writep;

View File

@ -247,11 +247,21 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
// called from only one place (the full* methods), so always inline them. // called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code); VL_ATTR_ALWINLINE void emitEvent(uint32_t code);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval); VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitLogic(uint32_t code, CData newval, CData newvalXZ);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits); VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE void emitFourstateCData(uint32_t code, CData newval, CData newvalXZ,
int bits);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits); VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
VL_ATTR_ALWINLINE void emitFourstateSData(uint32_t code, SData newval, SData newvalXZ,
int bits);
VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits); VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits);
VL_ATTR_ALWINLINE void emitFourstateIData(uint32_t code, IData newval, IData newvalXZ,
int bits);
VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits); VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits);
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 emitWData(uint32_t code, WDataInP newval, int bits);
VL_ATTR_ALWINLINE void emitFourstateWData(uint32_t code, WDataInP newval, int bits);
VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval); 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) { if (time_p->type == vpiSimTime) {
const QData qtime = VL_TIME_Q(); const QData qtime = VL_TIME_Q();
VlWide<2> itime; VlWide<2> itime;
VL_SET_WQ(itime, qtime); VL_SET_WQ_T(itime, qtime);
time_p->low = itime[0]; time_p->low = itime[0];
time_p->high = itime[1]; time_p->high = itime[1];
return; return;

View File

@ -104,6 +104,7 @@ set(HEADERS
V3Force.h V3Force.h
V3FsmDetect.h V3FsmDetect.h
V3Fork.h V3Fork.h
V3Fourstate.h
V3FuncOpt.h V3FuncOpt.h
V3FunctionTraits.h V3FunctionTraits.h
V3Gate.h V3Gate.h
@ -280,6 +281,7 @@ set(COMMON_SOURCES
V3Force.cpp V3Force.cpp
V3FsmDetect.cpp V3FsmDetect.cpp
V3Fork.cpp V3Fork.cpp
V3Fourstate.cpp
V3FuncOpt.cpp V3FuncOpt.cpp
V3Gate.cpp V3Gate.cpp
V3Global.cpp V3Global.cpp

View File

@ -282,6 +282,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3Force.o \ V3Force.o \
V3FsmDetect.o \ V3FsmDetect.o \
V3Fork.o \ V3Fork.o \
V3Fourstate.o \
V3Gate.o \ V3Gate.o \
V3HierBlock.o \ V3HierBlock.o \
V3Inline.o \ V3Inline.o \

View File

@ -131,6 +131,19 @@ AstNode::AstNode(VNType t, FileLine* fl)
editCountInc(); 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 { AstNode* AstNode::abovep() const {
// m_headtailp only valid at beginning or end of list // m_headtailp only valid at beginning or end of list
// Avoid supporting at other locations as would require walking // 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. // For 'simple' types we use the global directory. These are all unsized.
// More advanced types land under the module/task/etc // 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 { AstNodeDType* AstNode::findBitDType(int width, int widthMin, VSigning numeric,
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), VBasicDTypeKwd::BIT, bool isShuffledFourstate) const {
width, widthMin, numeric); return v3Global.rootp()->typeTablep()->findLogicBitDType(
fileline(), VBasicDTypeKwd::BIT, width, widthMin, numeric, isShuffledFourstate);
} }
AstNodeDType* AstNode::findLogicDType(int width, int widthMin, VSigning numeric) const { AstNodeDType* AstNode::findLogicDType(int width, int widthMin, VSigning numeric,
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), VBasicDTypeKwd::LOGIC, bool isShuffledFourstate) const {
width, widthMin, numeric); return v3Global.rootp()->typeTablep()->findLogicBitDType(
fileline(), VBasicDTypeKwd::LOGIC, width, widthMin, numeric, isShuffledFourstate);
} }
AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin, AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin, VSigning numeric,
VSigning numeric) const { bool isShuffledFourstate) const {
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), VBasicDTypeKwd::LOGIC, return v3Global.rootp()->typeTablep()->findLogicBitDType(
range, widthMin, numeric); fileline(), VBasicDTypeKwd::LOGIC, range, widthMin, numeric, isShuffledFourstate);
} }
AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin, AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin, VSigning numeric,
VSigning numeric) const { bool isShuffledFourstate) const {
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), VBasicDTypeKwd::BIT, return v3Global.rootp()->typeTablep()->findLogicBitDType(
range, widthMin, numeric); fileline(), VBasicDTypeKwd::BIT, range, widthMin, numeric, isShuffledFourstate);
} }
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) { AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
return v3Global.rootp()->typeTablep()->findInsertSameDType(nodep); return v3Global.rootp()->typeTablep()->findInsertSameDType(nodep);

View File

@ -644,9 +644,9 @@ public:
int widthMinV() const { int widthMinV() const {
return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width(); return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width();
} }
int widthWords() const { return VL_WORDS_I(width()); } int widthWords() const;
bool isQuad() const VL_MT_STABLE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); } bool isQuad() const VL_MT_STABLE;
bool isWide() const VL_MT_STABLE { return (width() > VL_QUADSIZE); } bool isWide() const VL_MT_STABLE;
inline bool isCHandle() const VL_MT_STABLE; inline bool isCHandle() const VL_MT_STABLE;
inline bool isDouble() const VL_MT_STABLE; inline bool isDouble() const VL_MT_STABLE;
inline bool isSigned() const VL_MT_STABLE; inline bool isSigned() const VL_MT_STABLE;
@ -793,18 +793,20 @@ public:
AstNodeDType* findQueueIndexDType() const; AstNodeDType* findQueueIndexDType() const;
AstNodeDType* findStreamDType() const; AstNodeDType* findStreamDType() const;
AstNodeDType* findVoidDType() const; AstNodeDType* findVoidDType() const;
AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const; AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric,
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const; bool isShuffledFourstate = false) const;
AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric,
bool isShuffledFourstate = false) const;
AstNodeDType* findBitOrLogicDType(int width, int widthMin, VSigning numeric, AstNodeDType* findBitOrLogicDType(int width, int widthMin, VSigning numeric,
bool isFourstate) const { bool isFourstate) const {
return isFourstate ? findLogicDType(width, widthMin, numeric) return isFourstate ? findLogicDType(width, widthMin, numeric)
: findBitDType(width, widthMin, numeric); : findBitDType(width, widthMin, numeric);
} }
AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin, AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin, VSigning numeric,
VSigning numeric) const VL_MT_STABLE; bool isShuffledFourstate = false) const VL_MT_STABLE;
AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, VSigning numeric,
VSigning numeric) const VL_MT_STABLE; bool isShuffledFourstate = false) const VL_MT_STABLE;
AstNodeDType* findBasicDType(VBasicDTypeKwd kwd) const; AstNodeDType* findBasicDType(VBasicDTypeKwd kwd, bool isShuffledFourstate = false) const;
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep); static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
static VCastable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, 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 VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
const VSigning m_numeric; // From AstNodeDType: Node is signed const VSigning m_numeric; // From AstNodeDType: Node is signed
const VBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type 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 { bool operator==(const VBasicTypeKey& rhs) const {
return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric 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 { bool operator<(const VBasicTypeKey& rhs) const {
if ((m_width < rhs.m_width)) return true; 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_keyword == rhs.m_keyword)) return false; // lhs > rhs
if ((m_nrange < rhs.m_nrange)) return true; if ((m_nrange < rhs.m_nrange)) return true;
if (!(m_nrange == rhs.m_nrange)) return false; // lhs > rhs if (!(m_nrange == rhs.m_nrange)) return false; // lhs > rhs
if (!m_isShuffledFourstate && rhs.m_isShuffledFourstate) return true;
return false; return false;
} }
VBasicTypeKey(int width, int widthMin, VSigning numeric, VBasicDTypeKwd kwd, VBasicTypeKey(int width, int widthMin, VSigning numeric, VBasicDTypeKwd kwd,
const VNumRange& nrange) const VNumRange& nrange, bool isShuffledFourstate)
: m_width{width} : m_width{width}
, m_widthMin{widthMin} , m_widthMin{widthMin}
, m_nrange{nrange} , m_nrange{nrange}
, m_numeric{numeric} , m_numeric{numeric}
, m_keyword{kwd} {} , m_keyword{kwd}
, m_isShuffledFourstate{isShuffledFourstate} {}
~VBasicTypeKey() = default; ~VBasicTypeKey() = default;
}; };

View File

@ -158,7 +158,9 @@ public:
bool isSigned() const VL_MT_STABLE { return m_numeric.isSigned(); } bool isSigned() const VL_MT_STABLE { return m_numeric.isSigned(); }
bool isNosign() const VL_MT_SAFE { return m_numeric.isNosign(); } bool isNosign() const VL_MT_SAFE { return m_numeric.isNosign(); }
VSigning numeric() const VL_MT_STABLE { return m_numeric; } 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, int widthMin() const VL_MT_STABLE { // If sized, the size,
// if unsized the min digits to represent it // if unsized the min digits to represent it
return m_widthMin ? m_widthMin : m_width; return m_widthMin ? m_widthMin : m_width;
@ -183,6 +185,7 @@ public:
// Represents a C++ LiteralType? (can be constexpr) // Represents a C++ LiteralType? (can be constexpr)
bool isLiteralType() const VL_MT_STABLE; bool isLiteralType() const VL_MT_STABLE;
virtual bool isDynamicallySized() const { return false; } virtual bool isDynamicallySized() const { return false; }
virtual bool isShuffledFourstate() const VL_MT_STABLE { return false; }
private: private:
class CTypeRecursed; class CTypeRecursed;
@ -407,37 +410,47 @@ class AstBasicDType final : public AstNodeDType {
struct Members final { struct Members final {
VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type
VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword) 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 { 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; } m;
// See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned)
public: 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) { : 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) { : 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) { : 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) { : 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) { : 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 m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be
} }
// See also addRange in verilog.y // See also addRange in verilog.y
private: private:
void init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, void init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin,
AstRange* rangep); AstRange* rangep, bool isShuffledFourstate);
public: public:
ASTGEN_MEMBERS_AstBasicDType; ASTGEN_MEMBERS_AstBasicDType;
@ -521,6 +534,7 @@ public:
void cvtRangeConst(); // Convert to smaller representation void cvtRangeConst(); // Convert to smaller representation
bool isCompound() const override { return isString(); } bool isCompound() const override { return isString(); }
bool isIntegralOrPacked() const override { return keyword().isIntNumeric(); } bool isIntegralOrPacked() const override { return keyword().isIntNumeric(); }
bool isShuffledFourstate() const VL_MT_STABLE override { return m.m_isShuffledFourstate; }
}; };
class AstBracketArrayDType final : public AstNodeDType { class AstBracketArrayDType final : public AstNodeDType {
// Associative/Queue/Normal array data type, ie "[dtype_or_expr]" // Associative/Queue/Normal array data type, ie "[dtype_or_expr]"

View File

@ -487,6 +487,8 @@ private:
VSelfPointerText m_selfPointer VSelfPointerText m_selfPointer
= VSelfPointerText{VSelfPointerText::Empty()}; // Output code object = VSelfPointerText{VSelfPointerText::Empty()}; // Output code object
// pointer (e.g.: 'this') // pointer (e.g.: 'this')
bool m_fourstateXZPart : 1; // If references four-state shuffled var true for XZ part and
// false for value part
protected: protected:
AstNodeVarRef(VNType t, FileLine* fl, AstVar* varp, const VAccess& access) AstNodeVarRef(VNType t, FileLine* fl, AstVar* varp, const VAccess& access)
: AstNodeExpr{t, fl} : AstNodeExpr{t, fl}
@ -516,6 +518,8 @@ public:
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
static AstNodeVarRef* varRefLValueRecurse(AstNode* nodep); static AstNodeVarRef* varRefLValueRecurse(AstNode* nodep);
void fourstateXZPart(bool xz) { m_fourstateXZPart = xz; }
bool fourstateXZPart() const { return m_fourstateXZPart; }
}; };
// === Concrete node types ===================================================== // === Concrete node types =====================================================
@ -1675,6 +1679,27 @@ public:
bool sameNode(const AstNode* /*samep*/) const override { return true; } bool sameNode(const AstNode* /*samep*/) const override { return true; }
bool isSystemFunc() const override { return true; } bool isSystemFunc() const override { return true; }
}; };
class AstFourstateExpr final : public AstNodeExpr {
// When AstNode wants a value as an child and that value is a splitted four-state value (so, it
// has value and xz part) this node shall be used to put them both there
// @astgen op1 := valuep : AstNodeExpr // value part of a four-state expression
// @astgen op2 := xzp : AstNodeExpr // xz part of a four-state expression
public:
AstFourstateExpr(FileLine* fl, AstNodeExpr* const valuePartp, AstNodeExpr* const xzPartp)
: ASTGEN_SUPER_FourstateExpr(fl) {
UASSERT_OBJ(valuePartp->width() == xzPartp->width(), this,
"Value and XZ part shall have same width but they have: "
<< valuePartp->width() << " and " << xzPartp->width());
valuep(valuePartp);
xzp(xzPartp);
dtypeSetLogicUnsized(valuePartp->width(), valuePartp->dtypep()->widthMin(),
valuePartp->dtypep()->numeric());
}
ASTGEN_MEMBERS_AstFourstateExpr;
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
};
class AstFuture final : public AstNodeExpr { class AstFuture final : public AstNodeExpr {
// Verilog $future_gclk // Verilog $future_gclk
// @astgen op1 := exprp : AstNodeExpr // @astgen op1 := exprp : AstNodeExpr
@ -3101,7 +3126,7 @@ public:
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opConcat(lhs, rhs); 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)"; } string emitSMT() const override { return "(concat %l %r)"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
@ -3143,7 +3168,7 @@ public:
out.opDiv(lhs, rhs); out.opDiv(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f/ %r)"; } 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)"; } string emitSMT() const override { return "(bvudiv %l %r)"; }
bool emitCheckMaxWords() override { return true; } bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -3186,7 +3211,7 @@ public:
out.opDivS(lhs, rhs); out.opDivS(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f/ %r)"; } 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)"; } string emitSMT() const override { return "(bvsdiv %l %r)"; }
bool emitCheckMaxWords() override { return true; } bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -3221,7 +3246,7 @@ public:
if (v3Global.opt.fourstate()) { if (v3Global.opt.fourstate()) {
V3ERROR_NA_RETURN(""); V3ERROR_NA_RETURN("");
} else { } 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))"; } string emitSMT() const override { return "(__Vbv (= %l %r))"; }
@ -3334,7 +3359,7 @@ public:
out.opGt(lhs, rhs); out.opGt(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f> %r)"; } 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 emitSMT() const override { return "(__Vbv (bvugt %l %r))"; }
string emitSimpleOperator() override { return ">"; } string emitSimpleOperator() override { return ">"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3397,7 +3422,7 @@ public:
out.opGtS(lhs, rhs); out.opGtS(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f> %r)"; } 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 emitSMT() const override { return "(__Vbv (bvsgt %l %r))"; }
string emitSimpleOperator() override { return ""; } string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3419,7 +3444,7 @@ public:
out.opGte(lhs, rhs); out.opGte(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f>= %r)"; } 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 emitSMT() const override { return "(__Vbv (bvuge %l %r))"; }
string emitSimpleOperator() override { return ">="; } string emitSimpleOperator() override { return ">="; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3482,7 +3507,7 @@ public:
out.opGteS(lhs, rhs); out.opGteS(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f>= %r)"; } 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 emitSMT() const override { return "(__Vbv (bvsge %l %r))"; }
string emitSimpleOperator() override { return ""; } string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3504,7 +3529,7 @@ public:
out.opLogAnd(lhs, rhs); out.opLogAnd(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f&& %r)"; } 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 emitSMT() const override { return "(bvand %l %r)"; }
string emitSimpleOperator() override { return "&&"; } string emitSimpleOperator() override { return "&&"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3526,7 +3551,7 @@ public:
out.opLogIf(lhs, rhs); out.opLogIf(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f-> %r)"; } 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 emitSMT() const override { return "(__Vbv (=> (__Vbool %l) (__Vbool %r)))"; }
string emitSimpleOperator() override { return "->"; } string emitSimpleOperator() override { return "->"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3548,7 +3573,7 @@ public:
out.opLogOr(lhs, rhs); out.opLogOr(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f|| %r)"; } 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 emitSMT() const override { return "(bvor %l %r)"; }
string emitSimpleOperator() override { return "||"; } string emitSimpleOperator() override { return "||"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3570,7 +3595,7 @@ public:
out.opLt(lhs, rhs); out.opLt(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f< %r)"; } 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 emitSMT() const override { return "(__Vbv (bvult %l %r))"; }
string emitSimpleOperator() override { return "<"; } string emitSimpleOperator() override { return "<"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3633,7 +3658,7 @@ public:
out.opLtS(lhs, rhs); out.opLtS(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f< %r)"; } 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 emitSMT() const override { return "(__Vbv (bvslt %l %r))"; }
string emitSimpleOperator() override { return ""; } string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3655,7 +3680,7 @@ public:
out.opLte(lhs, rhs); out.opLte(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f<= %r)"; } 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 emitSMT() const override { return "(__Vbv (bvule %l %r))"; }
string emitSimpleOperator() override { return "<="; } string emitSimpleOperator() override { return "<="; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3718,7 +3743,7 @@ public:
out.opLteS(lhs, rhs); out.opLteS(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f<= %r)"; } 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 emitSMT() const override { return "(__Vbv (bvsle %l %r))"; }
string emitSimpleOperator() override { return ""; } string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -3740,7 +3765,7 @@ public:
out.opModDiv(lhs, rhs); out.opModDiv(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f%% %r)"; } 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)"; } string emitSMT() const override { return "(bvurem %l %r)"; }
bool emitCheckMaxWords() override { return true; } bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -3762,7 +3787,7 @@ public:
out.opModDivS(lhs, rhs); out.opModDivS(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f%% %r)"; } 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)"; } string emitSMT() const override { return "(bvsmod %l %r)"; }
bool emitCheckMaxWords() override { return true; } bool emitCheckMaxWords() override { return true; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -3794,7 +3819,7 @@ public:
if (v3Global.opt.fourstate()) { if (v3Global.opt.fourstate()) {
V3ERROR_NA_RETURN(""); V3ERROR_NA_RETURN("");
} else { } else {
return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; return "VL_NEQ_%lq_%lf%rf(%lW, %P, %li, %ri)";
} }
} }
string emitSimpleOperator() override { string emitSimpleOperator() override {
@ -3929,9 +3954,17 @@ public:
if (const AstConst* const constp = VN_CAST(rhsp, Const)) { if (const AstConst* const constp = VN_CAST(rhsp, Const)) {
if (constp->num().isFourState() if (constp->num().isFourState()
|| (constp->dtypep()->isSigned() && constp->num().isNegative())) { || (constp->dtypep()->isSigned() && constp->num().isNegative())) {
dtypeSetLogicSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns if (lhsp->dtypep() && !lhsp->dtypep()->isFourstate()) {
dtypeSetBitSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns
} else {
dtypeSetLogicSized(lhsp->width(), VSigning::UNSIGNED); // V3Width warns
}
} else { } else {
dtypeSetLogicSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED); if (lhsp->dtypep() && !lhsp->dtypep()->isFourstate()) {
dtypeSetBitSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
} else {
dtypeSetLogicSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
}
} }
} }
} }
@ -3943,7 +3976,7 @@ public:
out.opRepl(lhs, rhs); out.opRepl(lhs, rhs);
} }
string emitVerilog() override { return "%f{%r{%k%l}}"; } 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 { string emitSMT() const override {
return "((_ repeat " + cvtToStr(width() / lhsp()->width()) + ") %l)"; return "((_ repeat " + cvtToStr(width() / lhsp()->width()) + ") %l)";
} }
@ -4106,7 +4139,15 @@ public:
: ASTGEN_SUPER_Sel(fl, fromp, lsbp) : ASTGEN_SUPER_Sel(fl, fromp, lsbp)
, m_declElWidth{1} , m_declElWidth{1}
, m_widthConst{bitwidth} { , m_widthConst{bitwidth} {
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED); if (const AstNodeDType* const dtypep = fromp->dtypep()) {
if (dtypep->isFourstate()) {
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED);
} else {
dtypeSetBitSized(bitwidth, VSigning::UNSIGNED);
}
} else {
dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED);
}
} }
AstSel(FileLine* fl, AstNodeExpr* fromp, int lsb, int bitwidth) AstSel(FileLine* fl, AstNodeExpr* fromp, int lsb, int bitwidth)
: ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb)) // Need () constructor : ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb)) // Need () constructor
@ -4122,9 +4163,9 @@ public:
} }
string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { string emitC() override {
return widthConst() == 1 ? "VL_BITSEL_%nq%lq%rqI(%lw, %P, %li, %ri)" return widthConst() == 1 ? "VL_BITSEL_%nq%lq%rqI_%nf%lf%rfT(%lw, %P, %li, %ri)"
: isWide() ? "VL_SEL_%nq%lq%rqI(%nw, %lw, %P, %li, %ri, %nw)" : isWide() ? "VL_SEL_%nq%lq%rqI_%nf%lf%rfT(%nw, %lw, %P, %li, %ri, %nw)"
: "VL_SEL_%nq%lq%rqI(%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)"; } string emitSMT() const override { return "((_ extract %t %r) %l)"; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -4171,7 +4212,7 @@ public:
out.opShiftL(lhs, rhs); out.opShiftL(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f<< %r)"; } 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 emitSMT() const override { return "(bvshl %l %r)"; }
string emitSimpleOperator() override { string emitSimpleOperator() override {
return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<"; return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<";
@ -4188,14 +4229,25 @@ class AstShiftLOvr final : public AstNodeBiop {
public: public:
AstShiftLOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0) AstShiftLOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftLOvr(fl, lhsp, rhsp) { : 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; ASTGEN_MEMBERS_AstShiftLOvr;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftL(lhs, rhs); out.opShiftL(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f<< %r)"; } 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 ""; } string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } bool cleanLhs() const override { return false; }
@ -4226,7 +4278,7 @@ public:
out.opShiftR(lhs, rhs); out.opShiftR(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f>> %r)"; } 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 emitSMT() const override { return "(bvlshr %l %r)"; }
string emitSimpleOperator() override { string emitSimpleOperator() override {
return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>"; return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>";
@ -4244,14 +4296,25 @@ class AstShiftROvr final : public AstNodeBiop {
public: public:
AstShiftROvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0) AstShiftROvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftROvr(fl, lhsp, rhsp) { : 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; ASTGEN_MEMBERS_AstShiftROvr;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftR(lhs, rhs); out.opShiftR(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f>> %r)"; } 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 ""; } string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
@ -4268,7 +4331,18 @@ public:
AstShiftRS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0) AstShiftRS(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) { : ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) {
// Important that widthMin be correct, as opExtend requires it after V3Expand // 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; ASTGEN_MEMBERS_AstShiftRS;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
@ -4276,7 +4350,7 @@ public:
} }
string emitVerilog() override { return "%k(%l %f>>> %r)"; } string emitVerilog() override { return "%k(%l %f>>> %r)"; }
string emitSMT() const override { return "(bvashr %l %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 ""; } string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
@ -4293,14 +4367,25 @@ public:
AstShiftRSOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0) AstShiftRSOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftRSOvr(fl, lhsp, rhsp) { : ASTGEN_SUPER_ShiftRSOvr(fl, lhsp, rhsp) {
// Important that widthMin be correct, as opExtend requires it after V3Expand // 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; ASTGEN_MEMBERS_AstShiftRSOvr;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opShiftRS(lhs, rhs, lhsp()->widthMinV()); out.opShiftRS(lhs, rhs, lhsp()->widthMinV());
} }
string emitVerilog() override { return "%k(%l %f>>> %r)"; } 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 ""; } string emitSimpleOperator() override { return ""; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
@ -4321,7 +4406,7 @@ public:
out.opSub(lhs, rhs); out.opSub(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f- %r)"; } 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 emitSMT() const override { return "(bvsub %l %r)"; }
string emitSimpleOperator() override { return "-"; } string emitSimpleOperator() override { return "-"; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -4394,7 +4479,7 @@ public:
out.opEq(lhs, rhs); out.opEq(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f== %r)"; } 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 emitSMT() const override { return "(__Vbv (= %l %r))"; }
string emitSimpleOperator() override { return "=="; } string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -4415,7 +4500,7 @@ public:
out.opCaseEq(lhs, rhs); out.opCaseEq(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f=== %r)"; } 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 "=="; } string emitSimpleOperator() override { return "=="; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
@ -4496,7 +4581,7 @@ public:
out.opLogEq(lhs, rhs); out.opLogEq(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f<-> %r)"; } 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 emitSMT() const override { return "(bvxnor %l %r)"; }
string emitSimpleOperator() override { return "<->"; } string emitSimpleOperator() override { return "<->"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -4524,7 +4609,7 @@ public:
out.opNeq(lhs, rhs); out.opNeq(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f!= %r)"; } 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 emitSimpleOperator() override { return "!="; }
string emitSMT() const override { return "(__Vbv (not (= %l %r)))"; } string emitSMT() const override { return "(__Vbv (not (= %l %r)))"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -4545,7 +4630,7 @@ public:
out.opCaseNeq(lhs, rhs); out.opCaseNeq(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f!== %r)"; } 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 emitSimpleOperator() override { return "!="; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
@ -4628,7 +4713,7 @@ public:
out.opAdd(lhs, rhs); out.opAdd(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f+ %r)"; } 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 emitSMT() const override { return "(bvadd %l %r)"; }
string emitSimpleOperator() override { return "+"; } string emitSimpleOperator() override { return "+"; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -4670,7 +4755,7 @@ public:
out.opAnd(lhs, rhs); out.opAnd(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f& %r)"; } 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 emitSMT() const override { return "(bvand %l %r)"; }
string emitSimpleOperator() override { return "&"; } string emitSimpleOperator() override { return "&"; }
bool cleanOut() const override { V3ERROR_NA_RETURN(false); } bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
@ -4692,7 +4777,7 @@ public:
out.opMul(lhs, rhs); out.opMul(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f* %r)"; } 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 emitSMT() const override { return "(bvmul %l %r)"; }
string emitSimpleOperator() override { return "*"; } string emitSimpleOperator() override { return "*"; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -4735,7 +4820,7 @@ public:
out.opMulS(lhs, rhs); out.opMulS(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f* %r)"; } 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 emitSMT() const override { return "(bvmul %l %r)"; }
string emitSimpleOperator() override { return ""; } string emitSimpleOperator() override { return ""; }
bool emitCheckMaxWords() override { return true; } bool emitCheckMaxWords() override { return true; }
@ -4759,7 +4844,7 @@ public:
out.opOr(lhs, rhs); out.opOr(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f| %r)"; } 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 emitSMT() const override { return "(bvor %l %r)"; }
string emitSimpleOperator() override { return "|"; } string emitSimpleOperator() override { return "|"; }
bool cleanOut() const override { V3ERROR_NA_RETURN(false); } bool cleanOut() const override { V3ERROR_NA_RETURN(false); }
@ -4781,7 +4866,7 @@ public:
out.opXor(lhs, rhs); out.opXor(lhs, rhs);
} }
string emitVerilog() override { return "%k(%l %f^ %r)"; } 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 emitSMT() const override { return "(bvxor %l %r)"; }
string emitSimpleOperator() override { return "^"; } string emitSimpleOperator() override { return "^"; }
bool cleanOut() const override { return false; } // Lclean && Rclean bool cleanOut() const override { return false; } // Lclean && Rclean
@ -4969,7 +5054,7 @@ public:
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opAssign(lhs); 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 cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } bool cleanLhs() const override { return false; }
bool cleanRhs() const override { return false; } bool cleanRhs() const override { return false; }
@ -5198,7 +5283,7 @@ class AstInferredDisable final : public AstNodeTermop {
public: public:
explicit AstInferredDisable(FileLine* fl) explicit AstInferredDisable(FileLine* fl)
: ASTGEN_SUPER_InferredDisable(fl) { : ASTGEN_SUPER_InferredDisable(fl) {
dtypeSetLogicSized(1, VSigning::UNSIGNED); dtypeSetBitSized(1, VSigning::UNSIGNED);
} }
ASTGEN_MEMBERS_AstInferredDisable; ASTGEN_MEMBERS_AstInferredDisable;
string emitVerilog() override { return "%f$inferred_disable"; } string emitVerilog() override { return "%f$inferred_disable"; }
@ -5267,7 +5352,7 @@ public:
out.opAssign(lhs.isNeqZero() ? rhs : ths); out.opAssign(lhs.isNeqZero() ? rhs : ths);
} }
string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; } 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)"; } string emitSMT() const override { return "(ite (__Vbool %l) %r %t)"; }
bool cleanOut() const override { return false; } // clean if e1 & e2 clean bool cleanOut() const override { return false; } // clean if e1 & e2 clean
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
@ -5504,6 +5589,7 @@ public:
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
string emitVerilog() override { return "(%l)"; } string emitVerilog() override { return "(%l)"; }
string emitC() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSMT() const override { return "%l"; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
bool cleanLhs() const override { return false; } bool cleanLhs() const override { return false; }
bool sizeMattersLhs() const override { return false; } bool sizeMattersLhs() const override { return false; }
@ -5549,12 +5635,20 @@ public:
: ASTGEN_SUPER_Extend(fl, lhsp) {} : ASTGEN_SUPER_Extend(fl, lhsp) {}
AstExtend(FileLine* fl, AstNodeExpr* lhsp, int width) AstExtend(FileLine* fl, AstNodeExpr* lhsp, int width)
: ASTGEN_SUPER_Extend(fl, lhsp) { : ASTGEN_SUPER_Extend(fl, lhsp) {
dtypeSetLogicSized(width, VSigning::UNSIGNED); if (const AstNodeDType* const dtypep = lhsp->dtypep()) {
if (dtypep->isFourstate()) {
dtypeSetLogicSized(width, VSigning::UNSIGNED);
} else {
dtypeSetBitSized(width, VSigning::UNSIGNED);
}
} else {
dtypeSetLogicSized(width, VSigning::UNSIGNED);
}
} }
ASTGEN_MEMBERS_AstExtend; ASTGEN_MEMBERS_AstExtend;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); }
string emitVerilog() override { return "%l"; } 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 { string emitSMT() const override {
return "((_ zero_extend " + cvtToStr(width() - lhsp()->width()) + ") %l)"; return "((_ zero_extend " + cvtToStr(width() - lhsp()->width()) + ") %l)";
} }
@ -5574,14 +5668,22 @@ public:
AstExtendS(FileLine* fl, AstNodeExpr* lhsp, int width) AstExtendS(FileLine* fl, AstNodeExpr* lhsp, int width)
// Important that widthMin be correct, as opExtend requires it after V3Expand // Important that widthMin be correct, as opExtend requires it after V3Expand
: ASTGEN_SUPER_ExtendS(fl, lhsp) { : ASTGEN_SUPER_ExtendS(fl, lhsp) {
dtypeSetLogicSized(width, VSigning::UNSIGNED); if (const AstNodeDType* const dtypep = lhsp->dtypep()) {
if (dtypep->isFourstate()) {
dtypeSetLogicSized(width, VSigning::UNSIGNED);
} else {
dtypeSetBitSized(width, VSigning::UNSIGNED);
}
} else {
dtypeSetLogicSized(width, VSigning::UNSIGNED);
}
} }
ASTGEN_MEMBERS_AstExtendS; ASTGEN_MEMBERS_AstExtendS;
void numberOperate(V3Number& out, const V3Number& lhs) override { void numberOperate(V3Number& out, const V3Number& lhs) override {
out.opExtendS(lhs, lhsp()->widthMinV()); out.opExtendS(lhs, lhsp()->widthMinV());
} }
string emitVerilog() override { return "%l"; } 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 { string emitSMT() const override {
return "((_ sign_extend " + cvtToStr(width() - lhsp()->width()) + ") %l)"; return "((_ sign_extend " + cvtToStr(width() - lhsp()->width()) + ") %l)";
} }
@ -5727,7 +5829,7 @@ public:
ASTGEN_MEMBERS_AstLogNot; ASTGEN_MEMBERS_AstLogNot;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); }
string emitVerilog() override { return "%f(! %l)"; } 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 emitSMT() const override { return "(__Vbv (not (__Vbool %l)))"; }
string emitSimpleOperator() override { return "!"; } string emitSimpleOperator() override { return "!"; }
bool cleanOut() const override { return true; } bool cleanOut() const override { return true; }
@ -5747,7 +5849,7 @@ public:
ASTGEN_MEMBERS_AstMostSetBitP1; ASTGEN_MEMBERS_AstMostSetBitP1;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opMostSetBitP1(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opMostSetBitP1(lhs); }
string emitVerilog() override { return "%f$mostsetbitp1(%l)"; } 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 cleanOut() const override { return true; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; } bool sizeMattersLhs() const override { return false; }
@ -5778,7 +5880,7 @@ public:
ASTGEN_MEMBERS_AstNegate; ASTGEN_MEMBERS_AstNegate;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegate(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegate(lhs); }
string emitVerilog() override { return "%f(- %l)"; } 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 emitSMT() const override { return "(bvneg %l)"; }
string emitSimpleOperator() override { return "-"; } string emitSimpleOperator() override { return "-"; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -5812,7 +5914,7 @@ public:
ASTGEN_MEMBERS_AstNot; ASTGEN_MEMBERS_AstNot;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNot(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNot(lhs); }
string emitVerilog() override { return "%f(~ %l)"; } 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 emitSMT() const override { return "(bvnot %l)"; }
string emitSimpleOperator() override { return "~"; } string emitSimpleOperator() override { return "~"; }
bool cleanOut() const override { return false; } bool cleanOut() const override { return false; }
@ -6004,7 +6106,7 @@ public:
ASTGEN_MEMBERS_AstRedAnd; ASTGEN_MEMBERS_AstRedAnd;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); }
string emitVerilog() override { return "%f(& %l)"; } 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 cleanOut() const override { return true; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; } bool sizeMattersLhs() const override { return false; }
@ -6019,7 +6121,7 @@ public:
ASTGEN_MEMBERS_AstRedOr; ASTGEN_MEMBERS_AstRedOr;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); }
string emitVerilog() override { return "%f(| %l)"; } 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 cleanOut() const override { return true; }
bool cleanLhs() const override { return true; } bool cleanLhs() const override { return true; }
bool sizeMattersLhs() const override { return false; } bool sizeMattersLhs() const override { return false; }
@ -6034,7 +6136,7 @@ public:
ASTGEN_MEMBERS_AstRedXor; ASTGEN_MEMBERS_AstRedXor;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); } void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); }
string emitVerilog() override { return "%f(^ %l)"; } 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 cleanOut() const override { return false; }
bool cleanLhs() const override { bool cleanLhs() const override {
const int w = lhsp()->width(); const int w = lhsp()->width();

View File

@ -1960,11 +1960,12 @@ public:
ASTGEN_MEMBERS_AstTypeTable; ASTGEN_MEMBERS_AstTypeTable;
bool maybePointedTo() const override VL_MT_SAFE { return true; } bool maybePointedTo() const override VL_MT_SAFE { return true; }
void cloneRelink() override { V3ERROR_NA; } // Not cloneable 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, 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, AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, const VNumRange& range,
int widthMin, VSigning numeric); int widthMin, VSigning numeric, bool isShuffledFourstate);
AstBasicDType* findCreateSameDType(AstBasicDType& node); AstBasicDType* findCreateSameDType(AstBasicDType& node);
AstBasicDType* findInsertSameDType(AstBasicDType* nodep); AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
AstConstraintRefDType* findConstraintRefDType(FileLine* fl); AstConstraintRefDType* findConstraintRefDType(FileLine* fl);
@ -2117,6 +2118,8 @@ class AstVar final : public AstNode {
// @astgen op4 := attrsp : List[AstNode] // Attributes during early parse // @astgen op4 := attrsp : List[AstNode] // Attributes during early parse
// @astgen ptr := m_sensIfacep : Optional[AstIface] // Interface type to which reads from this // @astgen ptr := m_sensIfacep : Optional[AstIface] // Interface type to which reads from this
// var are sensitive // var are sensitive
// @astgen ptr := m_fourstateComplementp : Optional[AstVar] // Set in four-state value part -
// points to an xz part
string m_name; // Name of variable string m_name; // Name of variable
string m_origName; // Original name before dot addition string m_origName; // Original name before dot addition
@ -2126,6 +2129,8 @@ class AstVar final : public AstNode {
VDirection m_declDirection; // Declared direction input/output etc VDirection m_declDirection; // Declared direction input/output etc
VLifetime m_lifetime; // Lifetime VLifetime m_lifetime; // Lifetime
VRandAttr m_rand; // Randomizability of this variable (rand, randc, etc) VRandAttr m_rand; // Randomizability of this variable (rand, randc, etc)
VBasicDTypeKwd
m_fourstateOriginalDTypeKwd; // Original dtype of a four-state var - before splitting
int m_pinNum = 0; // For JSON, if non-zero the connection pin number int m_pinNum = 0; // For JSON, if non-zero the connection pin number
bool m_ansi : 1; // Params or pins declared in the module header, rather than the body bool m_ansi : 1; // Params or pins declared in the module header, rather than the body
bool m_declTyped : 1; // Declared as type (for dedup check) bool m_declTyped : 1; // Declared as type (for dedup check)
@ -2190,7 +2195,10 @@ class AstVar final : public AstNode {
bool m_isStdRandomizeArg : 1; // Argument variable created for std::randomize (__Varg*) bool m_isStdRandomizeArg : 1; // Argument variable created for std::randomize (__Varg*)
bool m_processQueue : 1; // Process queue variable bool m_processQueue : 1; // Process queue variable
bool m_mtaskCacheLineAlign : 1; // Start MTask affinity group on a cache line 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() { void init() {
m_fourstateOriginalDTypeKwd = VBasicDTypeKwd::UNKNOWN;
m_ansi = false; m_ansi = false;
m_declTyped = false; m_declTyped = false;
m_tristate = false; m_tristate = false;
@ -2254,6 +2262,8 @@ class AstVar final : public AstNode {
m_isStdRandomizeArg = false; m_isStdRandomizeArg = false;
m_processQueue = false; m_processQueue = false;
m_mtaskCacheLineAlign = false; m_mtaskCacheLineAlign = false;
m_isFourstateComplement = false;
m_isTopLevelPort = false;
} }
public: public:
@ -2356,6 +2366,36 @@ public:
void ansi(bool flag) { m_ansi = flag; } void ansi(bool flag) { m_ansi = flag; }
void declTyped(bool flag) { m_declTyped = flag; } void declTyped(bool flag) { m_declTyped = flag; }
void sensIfacep(AstIface* nodep) { m_sensIfacep = nodep; } void sensIfacep(AstIface* nodep) { m_sensIfacep = nodep; }
void fourstateComplementp(AstVar* const varp) {
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 attrFileDescr(bool flag) { m_fileDescr = flag; }
void attrScBv(bool flag) { m_attrScBv = flag; } void attrScBv(bool flag) { m_attrScBv = flag; }
void attrScBigUint(bool flag) { m_attrScBigUint = flag; } void attrScBigUint(bool flag) { m_attrScBigUint = flag; }
@ -2565,6 +2605,7 @@ public:
&& !noCReset() && !(basicp() && basicp()->isEvent()); && !noCReset() && !(basicp() && basicp()->isEvent());
} }
static AstVar* scVarRecurse(AstNode* nodep); static AstVar* scVarRecurse(AstNode* nodep);
const char* broken() const override;
}; };
class AstVarScope final : public AstNode { class AstVarScope final : public AstNode {
// A particular scoped usage of a variable // A particular scoped usage of a variable

View File

@ -1297,8 +1297,10 @@ class AstTraceDecl final : public AstNodeStmt {
const VNumRange m_arrayRange; // Property of var the trace details const VNumRange m_arrayRange; // Property of var the trace details
const VVarType m_varType; // Type of variable (for localparam vs. param) const VVarType m_varType; // Type of variable (for localparam vs. param)
const VDirection m_declDirection; // Declared direction input/output etc const VDirection m_declDirection; // Declared direction input/output etc
const VBasicDTypeKwd m_dtypeKwd; // dtype keyword of traced signal
const bool m_inDtypeFunc; // Trace decl inside type init function const bool m_inDtypeFunc; // Trace decl inside type init function
int m_codeInc{0}; // Code increment for type int m_codeInc{0}; // Code increment for type
public: public:
AstTraceDecl(FileLine* fl, const string& showname, AstTraceDecl(FileLine* fl, const string& showname,
AstVar* varp, // For input/output state etc AstVar* varp, // For input/output state etc
@ -1310,6 +1312,7 @@ public:
, m_arrayRange{arrayRange} , m_arrayRange{arrayRange}
, m_varType{varp->varType()} , m_varType{varp->varType()}
, m_declDirection{varp->declDirection()} , m_declDirection{varp->declDirection()}
, m_dtypeKwd{varp->fourstateOriginalDTypeKwd()}
, m_inDtypeFunc{inDtypeFunc} { , m_inDtypeFunc{inDtypeFunc} {
dtypeFrom(valuep); dtypeFrom(valuep);
this->valuep(valuep); this->valuep(valuep);
@ -1335,12 +1338,15 @@ public:
if (m_codeInc) { return m_codeInc; } if (m_codeInc) { return m_codeInc; }
return (m_arrayRange.ranged() ? m_arrayRange.elements() : 1) return (m_arrayRange.ranged() ? m_arrayRange.elements() : 1)
* valuep()->dtypep()->widthWords() * valuep()->dtypep()->widthWords()
* (1 + VN_IS(valuep(), FourstateExpr)) // Fourstate variables take twice
// as much space as they are wide
* (VL_EDATASIZE / 32); // A code is always 32-bits * (VL_EDATASIZE / 32); // A code is always 32-bits
} }
const VNumRange& bitRange() const { return m_bitRange; } const VNumRange& bitRange() const { return m_bitRange; }
const VNumRange& arrayRange() const { return m_arrayRange; } const VNumRange& arrayRange() const { return m_arrayRange; }
VVarType varType() const { return m_varType; } VVarType varType() const { return m_varType; }
VDirection declDirection() const { return m_declDirection; } VDirection declDirection() const { return m_declDirection; }
VBasicDTypeKwd dtypeKwd() const { return m_dtypeKwd; }
AstCCall* dtypeCallp() const { return m_dtypeCallp; } AstCCall* dtypeCallp() const { return m_dtypeCallp; }
void dtypeCallp(AstCCall* const callp) { m_dtypeCallp = callp; } void dtypeCallp(AstCCall* const callp) { m_dtypeCallp = callp; }
AstTraceDecl* dtypeDeclp() const { return m_dtypeDeclp; } AstTraceDecl* dtypeDeclp() const { return m_dtypeDeclp; }

View File

@ -199,11 +199,12 @@ void AstAddrOfCFunc::dump(std::ostream& str) const {
} }
void AstBasicDType::init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, 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 // wantwidth=0 means figure it out, but if a widthmin is >=0
// we allow width 0 so that {{0{x}},y} works properly // we allow width 0 so that {{0{x}},y} works properly
// wantwidthmin=-1: default, use wantwidth if it is non-zero // wantwidthmin=-1: default, use wantwidth if it is non-zero
m.m_keyword = kwd; m.m_keyword = kwd;
m.m_isShuffledFourstate = isShuffledFourstate;
// Implicitness: // "parameter X" is implicit and sized from initial // Implicitness: // "parameter X" is implicit and sized from initial
// value, "parameter reg x" not // value, "parameter reg x" not
if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) { if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) {
@ -1026,6 +1027,15 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
return nullptr; 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, const AstNodeDType* AstNodeDType::skipRefIterp(bool skipConst, bool skipEnum,
bool assertOn) const VL_MT_STABLE { bool assertOn) const VL_MT_STABLE {
static constexpr int MAX_TYPEDEF_DEPTH = 1000; 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, // 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 // and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) 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) { if (bdtypep->keyword() == VBasicDTypeKwd::CHARPTR) {
info.m_type = "const char*"; info.m_type = "const char*";
@ -1249,6 +1260,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
info.m_type = "VlStdRandomizer"; info.m_type = "VlStdRandomizer";
} else if (bdtypep->isEvent()) { } else if (bdtypep->isEvent()) {
info.m_type = v3Global.assignsEvents() ? "VlAssignableEvent" : "VlEvent"; 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 } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec; info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) { } else if (dtypep->widthMin() <= 16) {
@ -1257,8 +1270,6 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
info.m_type = "IData" + bitvec; info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) { } else if (dtypep->isQuad()) {
info.m_type = "QData" + bitvec; 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. // CData, SData, IData, QData or VlWide are packed type.
const bool packedType = VString::startsWith(info.m_type, "CData") const bool packedType = VString::startsWith(info.m_type, "CData")
@ -1604,32 +1615,34 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
return m_voidp; 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 // 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 // map for this same node. Also adds this new node to the detailed map
if (!m_basicps[kwd]) { if (!m_basicps[kwd]) {
AstBasicDType basic{fl, kwd}; AstBasicDType basic{fl, kwd, VSigning::NOSIGN, isShuffledFourstate};
m_basicps[kwd] = findCreateSameDType(basic); m_basicps[kwd] = findCreateSameDType(basic);
} }
return m_basicps[kwd]; return m_basicps[kwd];
} }
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width, AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width,
int widthMin, VSigning numeric) { int widthMin, VSigning numeric,
AstBasicDType basic{fl, kwd, numeric, width, widthMin}; bool isShuffledFourstate) {
AstBasicDType basic{fl, kwd, numeric, width, widthMin, isShuffledFourstate};
return findCreateSameDType(basic); return findCreateSameDType(basic);
} }
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
const VNumRange& range, int widthMin, const VNumRange& range, int widthMin,
VSigning numeric) { VSigning numeric, bool isShuffledFourstate) {
AstBasicDType basic{fl, kwd, numeric, range, widthMin}; AstBasicDType basic{fl, kwd, numeric, range, widthMin, isShuffledFourstate};
return findCreateSameDType(basic); return findCreateSameDType(basic);
} }
AstBasicDType* AstTypeTable::findCreateSameDType(AstBasicDType& node) { AstBasicDType* AstTypeTable::findCreateSameDType(AstBasicDType& node) {
const VBasicTypeKey key{node.width(), node.widthMin(), node.numeric(), node.keyword(), const VBasicTypeKey key{node.width(), node.widthMin(), node.numeric(),
node.nrange()}; node.keyword(), node.nrange(), node.isShuffledFourstate()};
AstBasicDType*& entryr = m_detailedMap[key]; AstBasicDType*& entryr = m_detailedMap[key];
if (!entryr) { if (!entryr) {
entryr = node.cloneTree(false); entryr = node.cloneTree(false);
@ -1641,8 +1654,8 @@ AstBasicDType* AstTypeTable::findCreateSameDType(AstBasicDType& node) {
// cppcheck-suppress duplInheritedMember // cppcheck-suppress duplInheritedMember
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) { AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
const VBasicTypeKey key{nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(), const VBasicTypeKey key{nodep->width(), nodep->widthMin(), nodep->numeric(),
nodep->nrange()}; nodep->keyword(), nodep->nrange(), nodep->isShuffledFourstate()};
auto pair = m_detailedMap.emplace(key, nodep); auto pair = m_detailedMap.emplace(key, nodep);
if (pair.second) nodep->generic(true); if (pair.second) nodep->generic(true);
// No addTypesp; the upper function that called new() is responsible for adding // 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 { void AstBasicDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str); this->AstNodeDType::dump(str);
str << " kwd=" << keyword().ascii(); str << " kwd=" << keyword().ascii();
if (isShuffledFourstate()) str << " [SHUFFLED4STATE]";
if (isRanged() && !rangep()) str << " range=[" << left() << ":" << right() << "]"; if (isRanged() && !rangep()) str << " range=[" << left() << ":" << right() << "]";
} }
void AstBasicDType::dumpJson(std::ostream& str) const { void AstBasicDType::dumpJson(std::ostream& str) const {
@ -3285,6 +3299,10 @@ void AstVar::dump(std::ostream& str) const {
} else if (isFuncLocal()) { } else if (isFuncLocal()) {
str << " [FUNC]"; str << " [FUNC]";
} }
if (const AstVar* const varp = fourstateComplementp()) {
str << " [COMPL=" << nodeAddr(varp) << "]";
}
if (isFourstateComplement()) str << " [4STATECOMPL]";
if (hasUserInit()) str << " [UINIT]"; if (hasUserInit()) str << " [UINIT]";
if (icoMaybeWritten()) str << " [ICOMAYBEWRITTEN]"; if (icoMaybeWritten()) str << " [ICOMAYBEWRITTEN]";
if (isDpiOpenArray()) str << " [DPIOPENA]"; if (isDpiOpenArray()) str << " [DPIOPENA]";

View File

@ -3709,6 +3709,16 @@ class ConstVisitor final : public VNVisitor {
if (!m_doNConst) return; if (!m_doNConst) return;
const AstBasicDType* const bdtypep = VN_CAST(nodep->dtypep()->skipRefp(), BasicDType); const AstBasicDType* const bdtypep = VN_CAST(nodep->dtypep()->skipRefp(), BasicDType);
if (!bdtypep) return; 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; if (!bdtypep->isZeroInit()) return;
AstConst* const newp = new AstConst{nodep->fileline(), V3Number{nodep, bdtypep}}; AstConst* const newp = new AstConst{nodep->fileline(), V3Number{nodep, bdtypep}};
UINFO(9, "CRESET(0) => CONST(0) " << nodep); UINFO(9, "CRESET(0) => CONST(0) " << nodep);
@ -3846,8 +3856,9 @@ class ConstVisitor final : public VNVisitor {
nodep->condp(new AstLogNot{condp->fileline(), nodep->condp(new AstLogNot{condp->fileline(),
condp}); // LogNot, as C++ optimization also possible condp}); // LogNot, as C++ optimization also possible
nodep->addThensp(elsesp); nodep->addThensp(elsesp);
} else if (((VN_IS(nodep->condp(), Not) && nodep->condp()->width() == 1) } else if ((!v3Global.opt.fourstate() || v3Global.fourstateHandled())
|| VN_IS(nodep->condp(), LogNot)) && ((VN_IS(nodep->condp(), Not) && nodep->condp()->width() == 1)
|| VN_IS(nodep->condp(), LogNot))
&& nodep->thensp() && nodep->elsesp()) { && nodep->thensp() && nodep->elsesp()) {
UINFO(4, "IF(NOT {x}) => IF(x) swapped if/else" << nodep); UINFO(4, "IF(NOT {x}) => IF(x) swapped if/else" << nodep);
AstNodeExpr* const condp AstNodeExpr* const condp
@ -3859,7 +3870,8 @@ class ConstVisitor final : public VNVisitor {
ifp->branchPred(nodep->branchPred().invert()); ifp->branchPred(nodep->branchPred().invert());
nodep->replaceWith(ifp); nodep->replaceWith(ifp);
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (ifSameAssign(nodep)) { } else if ((!v3Global.opt.fourstate() || v3Global.fourstateHandled())
&& ifSameAssign(nodep)) {
UINFO(4, UINFO(4,
"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})"); "IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})");
AstNodeAssign* const thensp = VN_AS(nodep->thensp(), NodeAssign); AstNodeAssign* const thensp = VN_AS(nodep->thensp(), NodeAssign);

View File

@ -489,8 +489,12 @@ class DeadVisitor final : public VNVisitor {
retry = false; retry = false;
for (std::vector<AstVar*>::iterator it = m_varsp.begin(); it != m_varsp.end(); ++it) { for (std::vector<AstVar*>::iterator it = m_varsp.begin(); it != m_varsp.end(); ++it) {
AstVar* const varp = *it; AstVar* const varp = *it;
if (!varp) continue; if (!varp || varp->isFourstateComplement()) continue;
if (varp->user1() == 0) { if (varp->user1() == 0) {
if (AstVar* const varComplementp = varp->fourstateComplementp()) {
if (varComplementp->user1() != 0) continue;
deleting(varComplementp);
}
UINFO(4, " Dead " << varp); UINFO(4, " Dead " << varp);
if (varp->dtypep()) varp->dtypep()->user1Inc(-1); if (varp->dtypep()) varp->dtypep()->user1Inc(-1);
deleting(varp); deleting(varp);

View File

@ -489,6 +489,76 @@ class DelayedVisitor final : public VNVisitor {
return varscp; 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' // 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) { AstVarScope* createTemp(FileLine* flp, AstScope* scopep, const std::string& name, int width) {
AstNodeDType* const dtypep = scopep->findBitDType(width, width, VSigning::UNSIGNED); AstNodeDType* const dtypep = scopep->findBitDType(width, width, VSigning::UNSIGNED);
@ -591,8 +661,7 @@ class DelayedVisitor final : public VNVisitor {
FileLine* const flp = vscp->fileline(); FileLine* const flp = vscp->fileline();
AstScope* const scopep = vscp->scopep(); AstScope* const scopep = vscp->scopep();
// Create the shadow variable // Create the shadow variable
const std::string name = "__Vdly__" + vscp->varp()->shortName(); AstVarScope* const shadowVscp = createTemp("__Vdly__", vscp, vscp->dtypep());
AstVarScope* const shadowVscp = createTemp(flp, scopep, name, vscp->dtypep());
vscpInfo.shadowVariableKit().vscp = shadowVscp; vscpInfo.shadowVariableKit().vscp = shadowVscp;
// Mark both for V3LifePsot // Mark both for V3LifePsot
vscp->optimizeLifePost(true); vscp->optimizeLifePost(true);
@ -631,12 +700,10 @@ class DelayedVisitor final : public VNVisitor {
FileLine* const flp = vscp->fileline(); FileLine* const flp = vscp->fileline();
AstScope* const scopep = vscp->scopep(); AstScope* const scopep = vscp->scopep();
// Create the shadow variable // Create the shadow variable
const std::string shadowName = "__Vdly__" + vscp->varp()->shortName(); AstVarScope* const shadowVscp = createTemp("__Vdly__", vscp, vscp->dtypep());
AstVarScope* const shadowVscp = createTemp(flp, scopep, shadowName, vscp->dtypep());
vscpInfo.shadowVarMaskedKit().vscp = shadowVscp; vscpInfo.shadowVarMaskedKit().vscp = shadowVscp;
// Create the makk variable // Create the makk variable
const std::string maskName = "__VdlyMask__" + vscp->varp()->shortName(); AstVarScope* const maskVscp = createTemp("__VdlyMask__", vscp, vscp->dtypep());
AstVarScope* const maskVscp = createTemp(flp, scopep, maskName, vscp->dtypep());
maskVscp->varp()->setIgnorePostWrite(); maskVscp->varp()->setIgnorePostWrite();
vscpInfo.shadowVarMaskedKit().maskp = maskVscp; vscpInfo.shadowVarMaskedKit().maskp = maskVscp;
// Create the AstActive for the Post logic // Create the AstActive for the Post logic
@ -742,7 +809,7 @@ class DelayedVisitor final : public VNVisitor {
if (!reuseTheFlag) { if (!reuseTheFlag) {
// Create new flag // 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 // Set the flag at the original NBA
nodep->addHereThisAsNext( // nodep->addHereThisAsNext( //
new AstAssign{flp, new AstVarRef{flp, flagVscp, VAccess::WRITE}, 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); = captureLhs(scopep, nodep, nodep->lhsp()->unlinkFrBack(), baseName);
// Create new flag // Create new flag
AstVarScope* const flagVscp = createTemp(flp, scopep, "__VdlySet" + baseName, 1); AstVarScope* const flagVscp = createTemp("__VdlySet", vscp, 1, &vscpInfo);
flagVscp->varp()->setIgnorePostWrite(); flagVscp->varp()->setIgnorePostWrite();
// Set the flag at the original NBA // Set the flag at the original NBA
nodep->addHereThisAsNext( // nodep->addHereThisAsNext( //
@ -850,8 +917,7 @@ class DelayedVisitor final : public VNVisitor {
auto* const cqDTypep auto* const cqDTypep
= new AstNBACommitQueueDType{flp, vscp->dtypep()->skipRefp(), N_Partial}; = new AstNBACommitQueueDType{flp, vscp->dtypep()->skipRefp(), N_Partial};
v3Global.rootp()->typeTablep()->addTypesp(cqDTypep); v3Global.rootp()->typeTablep()->addTypesp(cqDTypep);
const std::string name = "__VdlyCommitQueue" + vscp->varp()->shortName(); AstVarScope* const queueVscp = createTemp("__VdlyCommitQueue", vscp, cqDTypep);
AstVarScope* const queueVscp = createTemp(flp, scopep, name, cqDTypep);
queueVscp->varp()->noReset(true); queueVscp->varp()->noReset(true);
queueVscp->varp()->setIgnorePostWrite(); queueVscp->varp()->setIgnorePostWrite();
vscpInfo.valueQueueKit().vscp = queueVscp; vscpInfo.valueQueueKit().vscp = queueVscp;
@ -1198,9 +1264,7 @@ class DelayedVisitor final : public VNVisitor {
AstNode* newp = cstmtp; AstNode* newp = cstmtp;
if (nodep->isDelayed()) { if (nodep->isDelayed()) {
const AstVarRef* const vrefp = VN_AS(eventp, VarRef); const AstVarRef* const vrefp = VN_AS(eventp, VarRef);
const std::string newvarname = "__Vdly__" + vrefp->varp()->shortName(); AstVarScope* const dlyvscp = createTemp("__Vdly__", vrefp->varScopep(), 1);
AstVarScope* const dlyvscp
= createTemp(flp, vrefp->varScopep()->scopep(), newvarname, 1);
const auto dlyRef = [=](VAccess access) { // const auto dlyRef = [=](VAccess access) { //
return new AstVarRef{flp, dlyvscp, access}; return new AstVarRef{flp, dlyvscp, access};

View File

@ -77,7 +77,7 @@ class DfgDataType final {
// METHODS // METHODS
static AstNodeDType* canonicalPackedDType(uint32_t width) { 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) { static AstNodeDType* canonicalArrayDType(uint32_t size, const DfgDataType& elemType) {
AstNodeDType* const elemDTypep = elemType.m_astDtypep; AstNodeDType* const elemDTypep = elemType.m_astDtypep;

View File

@ -54,7 +54,7 @@ template <>
AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeExpr*>( // AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeExpr*>( //
const DfgCountOnes* vtxp, AstNodeExpr* op1) { const DfgCountOnes* vtxp, AstNodeExpr* op1) {
AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1}; AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1};
nodep->dtypeSetLogicSized(vtxp->width(), VSigning::UNSIGNED); nodep->dtypeSetBitSized(vtxp->width(), VSigning::UNSIGNED);
return nodep; return nodep;
} }

View File

@ -41,6 +41,16 @@ class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitorConst {
} }
protected: 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 // VISITORS
void visit(AstInitArray* nodep) override { void visit(AstInitArray* nodep) override {
VL_RESTORER(m_unpackedWord); 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. // and write out appropriate text.
// %n* node // %n* node
// %nq emitIQW on the [node] // %nq emitIQW on the [node]
// %nf data format T/V/X
// %nw width in bits // %nw width in bits
// %nW width in words // %nW width in words
// %ni iterate // %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 // %t* thsp - if appropriate, then second char as above
// %k Potential line break // %k Potential line break
// %P Wide temporary name // %P Wide temporary name
// %p* Wide temporary - if appropriate, then second char as above
// , Commas suppressed if the previous field is suppressed // , Commas suppressed if the previous field is suppressed
string out; string out;
putnbs(nodep, ""); putnbs(nodep, "");
@ -128,6 +130,16 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
needComma = true; 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; break;
default: nodep->v3fatalSrc("Unknown emitOperator format code: %" << pos[0]); 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); emitIQW(detailp);
} }
break; break;
case 'f':
putOut();
emitTVX(detailp);
break;
case 'w': case 'w':
commaOut(); commaOut();
out += cvtToStr(detailp->widthMin()); out += cvtToStr(detailp->widthMin());
needComma = true; needComma = true;
break; break;
case 'W': case 'W':
if (lhsp->isWide()) { if (detailp->isWide()) {
commaOut(); 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; needComma = true;
} else if (VN_IS(lhsp, StreamR)) { } else if (VN_IS(lhsp, StreamR)) {
commaOut(); 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, string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
const string& varNameProtected, AstNodeDType* dtypep, const string& varNameProtected, AstNodeDType* dtypep,
int depth, const string& suffix, const AstNode* valuep) { int depth, const string& suffix, const AstNode* valuep) {
@ -617,8 +645,47 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = "; out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = ";
out += cvtToStr(constp->num().edataWord(w)) + "U;\n"; out += cvtToStr(constp->num().edataWord(w)) + "U;\n";
} }
} else if (v3Global.opt.fourstate() && dtypep->isShuffledFourstate()) {
const std::string& reset = slow ? "RESET_" : "";
if (v3Global.opt.zeroTopPorts().isTrue() && varp->isTopLevelPort()) {
// Instead of using VL_ZERO_RESET_W V and X we just use T and pretend the
// signal is twice as wide. this way we resets whole thing and sets to zero at
// once. We can do that because of the four-state internal representation
out += "VL_ZERO_" + reset + "W_T(";
out += cvtToStr(dtypep->widthMin() * 2);
out += ", " + varNameProtected + suffix;
out += ");\n";
} else if (varp->varType().isNet() || isModulePort(varp)) {
out += "VL_ZERO_" + reset + "W_V(";
out += cvtToStr(dtypep->widthMin());
out += ", " + varNameProtected + suffix;
out += ");\n";
out += "VL_ALLONES_" + reset + "W_X(";
out += cvtToStr(dtypep->widthMin());
out += ", " + varNameProtected + suffix;
out += ");\n";
} else {
// The same as above we can do a trick and use the internal representation to
// set everything up in one go but this time it is important to clear the
// result
out += "VL_ALLONES_" + reset + "W_T(";
out += cvtToStr(dtypep->widthWords() * VL_EDATASIZE);
out += ", " + varNameProtected + suffix;
out += ");\n";
if ((dtypep->widthMin() & VL_SIZEBITS_E) != 0) {
// Need cleaning
out += "_vl_clean_inplace_w_V(";
out += cvtToStr(dtypep->widthMin());
out += ", " + varNameProtected + suffix;
out += ");\n";
out += "_vl_clean_inplace_w_X(";
out += cvtToStr(dtypep->widthMin());
out += ", " + varNameProtected + suffix;
out += ");\n";
}
}
} else { } else {
out += zeroit ? (slow ? "VL_ZERO_RESET_W(" : "VL_ZERO_W(") out += zeroit ? (slow ? "VL_ZERO_RESET_W_T(" : "VL_ZERO_W_T(")
: (varp->isXTemp() ? "VL_SCOPED_RAND_RESET_ASSIGN_W(" : (varp->isXTemp() ? "VL_SCOPED_RAND_RESET_ASSIGN_W("
: "VL_SCOPED_RAND_RESET_W("); : "VL_SCOPED_RAND_RESET_W(");
out += cvtToStr(dtypep->widthMin()); out += cvtToStr(dtypep->widthMin());
@ -645,6 +712,16 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
UASSERT_OBJ(constp, varp, "non-const initializer for variable"); UASSERT_OBJ(constp, varp, "non-const initializer for variable");
out += cvtToStr(constp->num().edataWord(0)) + "U;\n"; out += cvtToStr(constp->num().edataWord(0)) + "U;\n";
out += ";\n"; out += ";\n";
} else if (v3Global.opt.fourstate() && varp->isFourstateConstruct()) {
V3Number xNum{varp->fileline(), varp->width(), 0};
if (!(v3Global.opt.zeroTopPorts().isTrue() && varp->isTopLevelPort())
&& (varp->isFourstateComplement()
|| !(varp->varType().isNet() || isModulePort(varp)))) {
xNum.setAllBits1();
}
out += " = ";
out += xNum.emitC();
out += ";\n";
} else if (zeroit) { } else if (zeroit) {
out += " = 0;\n"; out += " = 0;\n";
} else { } else {

View File

@ -30,9 +30,6 @@
#include <unordered_set> #include <unordered_set>
#include <vector> #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 // Emit lazy forward declarations
@ -299,58 +296,23 @@ public:
return; return;
} }
int upWidth = nodep->num().widthToFit(); const int width = nodep->num().widthToFit();
int chunks = 0; putnbs(nodep, "VL_CONST_W_");
if (upWidth > EMITC_NUM_CONSTW * VL_EDATASIZE) { emitTVX(assigntop);
// Output e.g. 8 words in groups of e.g. 8 puts("(");
chunks = (upWidth - 1) / (EMITC_NUM_CONSTW * VL_EDATASIZE); puts(cvtToStr(assigntop->width()));
upWidth %= (EMITC_NUM_CONSTW * VL_EDATASIZE); puts(",");
if (upWidth == 0) upWidth = (EMITC_NUM_CONSTW * VL_EDATASIZE); if (!assigntop->selfPointer().isEmpty()) {
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
} }
{ // Upper e.g. 8 words puts(assigntop->varp()->nameProtect());
if (chunks) { puts(", {");
putnbs(nodep, "VL_CONSTHI_W_"); for (int word = 0; word < VL_WORDS_I(width); ++word) {
puts(cvtToStr(VL_WORDS_I(upWidth))); // Only 32 bits - llx + long long here just to appease CPP format warning
puts("X("); if (word) puts(",");
puts(cvtToStr(nodep->widthMin())); ofp()->printf("0x%08" PRIx64, static_cast<uint64_t>(nodep->num().edataWord(word)));
puts(",");
puts(cvtToStr(chunks * EMITC_NUM_CONSTW * VL_EDATASIZE));
} else {
putnbs(nodep, "VL_CONST_W_");
puts(cvtToStr(VL_WORDS_I(upWidth)));
puts("X(");
puts(cvtToStr(nodep->widthMin()));
}
puts(",");
if (!assigntop->selfPointer().isEmpty()) {
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
for (int word = VL_WORDS_I(upWidth) - 1; word >= 0; word--) {
// Only 32 bits - llx + long long here just to appease CPP format warning
ofp()->printf(",0x%08" PRIx64, static_cast<uint64_t>(nodep->num().edataWord(
word + chunks * EMITC_NUM_CONSTW)));
}
puts(")");
}
for (chunks--; chunks >= 0; chunks--) {
puts(";\n");
putbs("VL_CONSTLO_W_");
puts(cvtToStr(EMITC_NUM_CONSTW));
puts("X(");
puts(cvtToStr(chunks * EMITC_NUM_CONSTW * VL_EDATASIZE));
puts(",");
if (!assigntop->selfPointer().isEmpty()) {
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
for (int word = EMITC_NUM_CONSTW - 1; word >= 0; word--) {
// Only 32 bits - llx + long long here just to appease CPP format warning
ofp()->printf(",0x%08" PRIx64, static_cast<uint64_t>(nodep->num().edataWord(
word + chunks * EMITC_NUM_CONSTW)));
}
puts(")");
} }
puts("})");
} }
void emitNodesWithText(AstNode* nodesp, bool useSelfForThis, bool tracking, void emitNodesWithText(AstNode* nodesp, bool useSelfForThis, bool tracking,
@ -609,6 +571,9 @@ public:
putnbs(nodep, "VL_ASSIGNSEL_"); putnbs(nodep, "VL_ASSIGNSEL_");
emitIQW(selp->fromp()); emitIQW(selp->fromp());
emitIQW(nodep->rhsp()); emitIQW(nodep->rhsp());
puts("_");
emitTVX(selp->fromp());
emitTVX(nodep->rhsp());
puts("("); puts("(");
putns(selp->fromp(), cvtToStr(selp->fromp()->widthMin()) + ", "); putns(selp->fromp(), cvtToStr(selp->fromp()->widthMin()) + ", ");
puts(cvtToStr(nodep->widthMin()) + ", "); puts(cvtToStr(nodep->widthMin()) + ", ");
@ -694,8 +659,10 @@ public:
m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef); m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef);
paren = false; paren = false;
} else if (nodep->isWide() && !unpackDtp && !VN_IS(nodep->rhsp(), Const)) { } else if (nodep->isWide() && !unpackDtp && !VN_IS(nodep->rhsp(), Const)) {
putnbs(nodep, "VL_ASSIGN_W("); putnbs(nodep, "VL_ASSIGN_W_");
puts(cvtToStr(nodep->widthMin()) + ", "); emitTVX(nodep->lhsp());
emitTVX(nodep->rhsp());
puts("(" + cvtToStr(nodep->widthMin()) + ", ");
iterateAndNextConstNull(nodep->lhsp()); iterateAndNextConstNull(nodep->lhsp());
puts(", "); puts(", ");
} else if (VN_IS(nodep->lhsp()->dtypep()->skipRefp(), QueueDType) } else if (VN_IS(nodep->lhsp()->dtypep()->skipRefp(), QueueDType)
@ -1792,7 +1759,6 @@ public:
} }
void visit(AstConst* nodep) override { // void visit(AstConst* nodep) override { //
if (m_wideTempRefp && nodep->isWide()) { if (m_wideTempRefp && nodep->isWide()) {
UASSERT_OBJ(m_wideTempRefp, nodep, "Wide Constant w/ no temp");
emitConstantW(nodep, m_wideTempRefp); emitConstantW(nodep, m_wideTempRefp);
m_wideTempRefp = nullptr; // We used it, fail if set it a second time m_wideTempRefp = nullptr; // We used it, fail if set it a second time
} else { } else {

View File

@ -442,7 +442,9 @@ class EmitCHeader final : public EmitCConstInit {
puts(getfunc ? "VL_ASSIGNSEL_" : "VL_SELASSIGN_"); puts(getfunc ? "VL_ASSIGNSEL_" : "VL_SELASSIGN_");
puts(lhstype->charIQWN()); puts(lhstype->charIQWN());
puts(rhstype->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) { if (getfunc) {
puts(std::to_string(rhstype->width()) + ", "); // Number of copy bits puts(std::to_string(rhstype->width()) + ", "); // Number of copy bits
puts(off + ", "); // LHS offset puts(off + ", "); // LHS offset

View File

@ -740,8 +740,9 @@ class EmitCTrace final : public EmitCFunc {
void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) { void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) {
// Note: Both VTraceType::CHANGE and VTraceType::FULL use the 'full' methods // Note: Both VTraceType::CHANGE and VTraceType::FULL use the 'full' methods
const std::string func = nodep->traceType() == VTraceType::CHANGE ? "chg" : "full"; std::string func = nodep->traceType() == VTraceType::CHANGE ? "chg" : "full";
bool emitWidth = true; bool emitWidth = true;
const bool isFourstate = VN_IS(nodep->valuep(), FourstateExpr);
string stype; string stype;
if (nodep->dtypep()->basicp()->isDouble()) { if (nodep->dtypep()->basicp()->isDouble()) {
stype = "Double"; stype = "Double";
@ -759,10 +760,14 @@ class EmitCTrace final : public EmitCFunc {
} else if (nodep->dtypep()->basicp()->isEvent()) { } else if (nodep->dtypep()->basicp()->isEvent()) {
stype = "Event"; stype = "Event";
emitWidth = false; emitWidth = false;
} else if (isFourstate) {
stype = "Logic";
emitWidth = false;
} else { } else {
stype = "Bit"; stype = "Bit";
emitWidth = false; emitWidth = false;
} }
if (isFourstate && stype != "Logic") func += "Fourstate";
putns(nodep, "bufp->" + func + stype); putns(nodep, "bufp->" + func + stype);
const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords());
@ -781,8 +786,8 @@ class EmitCTrace final : public EmitCFunc {
} }
void emitTraceValue(const AstTraceInc* nodep, int arrayindex) { void emitTraceValue(const AstTraceInc* nodep, int arrayindex) {
if (AstVarRef* const varrefp = VN_CAST(nodep->valuep(), VarRef)) { auto putVarRef = [this, nodep, arrayindex](AstVarRef* const varrefp) {
const AstVar* const varp = varrefp->varp(); AstVar* const varp = varrefp->varp();
if (varp->isEvent()) puts("&"); if (varp->isEvent()) puts("&");
puts("("); puts("(");
if (emitTraceIsScBigUint(nodep)) { if (emitTraceIsScBigUint(nodep)) {
@ -801,12 +806,39 @@ class EmitCTrace final : public EmitCFunc {
puts(")"); puts(")");
} }
puts(")"); puts(")");
};
puts("(");
if (AstFourstateExpr* const exprp = VN_CAST(nodep->valuep(), FourstateExpr)) {
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 (!xzVarrefp) {
iterateConst(exprp->xzp());
} else {
putVarRef(xzVarrefp);
}
}
} else if (AstVarRef* const varrefp = VN_CAST(nodep->valuep(), VarRef)) {
putVarRef(varrefp);
} else { } else {
puts("("); puts("(");
iterateConst(nodep->valuep()); iterateConst(nodep->valuep());
emitTraceIndex(nodep, arrayindex); emitTraceIndex(nodep, arrayindex);
puts(")"); puts(")");
} }
puts(")");
} }
void emitTraceIndex(const AstTraceInc* const nodep, int arrayindex) { void emitTraceIndex(const AstTraceInc* const nodep, int arrayindex) {

View File

@ -639,6 +639,13 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
iterateConst(nodep->exprp()); iterateConst(nodep->exprp());
puts(";\n"); puts(";\n");
} }
void visit(AstFourstateExpr* const nodep) override {
puts("Four-state expression: (Value part: ");
iterateConst(nodep->valuep());
puts(", XZ part:");
iterateConst(nodep->xzp());
puts(")");
}
// Nodes involing AstText // Nodes involing AstText
void visit(AstText* nodep) override { void visit(AstText* nodep) override {

View File

@ -90,6 +90,7 @@ public:
CASEWITHX, // Case with X values CASEWITHX, // Case with X values
CASEX, // Casex CASEX, // Casex
CASTCONST, // Cast is constant CASTCONST, // Cast is constant
CASTFOURSTATE, // Implicit logic (between 2/4 state logic)
CDCRSTLOGIC, // Logic in async reset path. Historical, never issued. CDCRSTLOGIC, // Logic in async reset path. Historical, never issued.
CLKDATA, // Clock used as data. Historical, never issued. CLKDATA, // Clock used as data. Historical, never issued.
CMPCONST, // Comparison is constant due to limited range CMPCONST, // Comparison is constant due to limited range
@ -226,24 +227,24 @@ public:
" EC_FIRST_WARN", "ALWCOMBORDER", "ALWNEVER", "ASCRANGE", "ASSIGNDLY", "ASSIGNEQEXPR", " EC_FIRST_WARN", "ALWCOMBORDER", "ALWNEVER", "ASCRANGE", "ASSIGNDLY", "ASSIGNEQEXPR",
"ASSIGNIN", "BADSTDPRAGMA", "BADVLTPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "ASSIGNIN", "BADSTDPRAGMA", "BADVLTPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ",
"BSSPACE", "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "BSSPACE", "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST",
"CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CASTFOURSTATE", "CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY",
"CONTASSREG", "COVERIGN", "DECLFILENAME", "DEFOVERRIDE", "DEFPARAM", "DEPRECATED", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN", "DECLFILENAME", "DEFOVERRIDE", "DEFPARAM",
"ENCAPSULATED", "ENDLABEL", "ENUMITEMWIDTH", "ENUMVALUE", "EOFNEWLINE", "FINALDLY", "DEPRECATED", "ENCAPSULATED", "ENDLABEL", "ENUMITEMWIDTH", "ENUMVALUE", "EOFNEWLINE",
"FSMMULTI", "FUNCTIMECTL", "FUTURE", "GENCLK", "GENUNNAMED", "HIERBLOCK", "HIERPARAM", "FINALDLY", "FSMMULTI", "FUNCTIMECTL", "FUTURE", "GENCLK", "GENUNNAMED", "HIERBLOCK",
"IEEEMAYDEPRECATE", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "HIERPARAM", "IEEEMAYDEPRECATE", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH",
"IMPLICITSTATIC", "IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP",
"INSECURE", "INSIDETRUE", "LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP", "INITIALDLY", "INSECURE", "INSIDETRUE", "LATCH", "LITENDIAN", "MINTYPMAXDLY",
"MODMISSING", "MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", "MISINDENT", "MODDUP", "MODMISSING", "MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOEFFECT",
"NORETURN", "NOTREDOP", "NULLPORT", "PARAMNODEFAULT", "PINCONNECTEMPTY", "PINMISSING", "NOLATCH", "NONSTD", "NORETURN", "NOTREDOP", "NULLPORT", "PARAMNODEFAULT",
"PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PREPROCZERO", "PROCASSINIT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL",
"PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "PROTOTYPEMIS", "RANDC", "REALCVT", "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED",
"REDEFMACRO", "RISEFALLDLY", "SELRANGE", "SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "PROTOTYPEMIS", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE",
"SPLITVAR", "STATICVAR", "STMTDLY", "SUPERNFIRST", "SYMRSVDWORD", "SYNCASYNCNET", "SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "SPLITVAR", "STATICVAR", "STMTDLY",
"TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "SUPERNFIRST", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN",
"UNPACKED", "UNSATCONSTR", "UNSIGNED", "UNUSED", "UNUSEDGENVAR", "UNUSEDLOOP", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSATCONSTR", "UNSIGNED", "UNUSED",
"UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", "UNUSEDGENVAR", "UNUSEDLOOP", "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL",
"VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "USERINFO", "USERWARN", "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT",
"WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", " MAX"}; "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", " MAX"};
return names[m_e]; return names[m_e];
} }
// Warnings that default to off // Warnings that default to off

View File

@ -937,7 +937,7 @@ class ExpandVisitor final : public VNVisitor {
if (lhswidth == 1) { if (lhswidth == 1) {
newp = new AstNegate{fl, lhsp->cloneTreePure(true)}; newp = new AstNegate{fl, lhsp->cloneTreePure(true)};
// Replicate always unsigned // Replicate always unsigned
newp->dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); newp->dtypeSetBitSized(VL_EDATASIZE, VSigning::UNSIGNED);
} else { } else {
newp = newAstWordSelClone(lhsp, w); newp = newAstWordSelClone(lhsp, w);
FileLine* const rfl = rhsp->fileline(); FileLine* const rfl = rhsp->fileline();

2529
src/V3Fourstate.cpp Normal file

File diff suppressed because it is too large Load Diff

36
src/V3Fourstate.h Normal file
View File

@ -0,0 +1,36 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Four-state logic handler
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of either the GNU Lesser General Public License Version 3
// or the Perl Artistic License Version 2.0.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#ifndef VERILATOR_V3FOURSTATE_METHOD_H_
#define VERILATOR_V3FOURSTATE_METHOD_H_
#include "config_build.h"
#include "verilatedos.h"
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

@ -135,6 +135,8 @@ class V3Global final {
bool m_useCovergroup = false; // Has covergroup declarations bool m_useCovergroup = false; // Has covergroup declarations
bool m_useRandomizeMethods = false; // Need to define randomize() class methods bool m_useRandomizeMethods = false; // Need to define randomize() class methods
bool m_hasPrintedObjects = false; // Design has format args printed with to_string() 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 uint64_t m_currentHierBlockCost = 0; // Total cost of this hier block, used for scheduling
// Memory address to short string mapping (for debug) // Memory address to short string mapping (for debug)
@ -224,6 +226,10 @@ public:
bool useCovergroup() const { return m_useCovergroup; } bool useCovergroup() const { return m_useCovergroup; }
void useCovergroup(bool flag) { m_useCovergroup = flag; } void useCovergroup(bool flag) { m_useCovergroup = flag; }
bool useRandomizeMethods() const { return m_useRandomizeMethods; } bool useRandomizeMethods() const { return m_useRandomizeMethods; }
void setFourstateHandled() { m_fourstateHandled = true; }
bool fourstateHandled() const { return m_fourstateHandled; }
void setFourstateShuffled() { m_fourstateShuffled = true; }
bool fourstateShuffled() const { return m_fourstateShuffled; }
void useRandomizeMethods(bool flag) { m_useRandomizeMethods = flag; } void useRandomizeMethods(bool flag) { m_useRandomizeMethods = flag; }
bool hasPrintedObjects() const { return m_hasPrintedObjects; } bool hasPrintedObjects() const { return m_hasPrintedObjects; }
void hasPrintedObjects(bool flag) { m_hasPrintedObjects = flag; } 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 // Clone local variables, add them to the local scope
for (AstVar* varp = calleep->varsp(); varp; varp = VN_AS(varp->nextp(), Var)) { 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()); newVarp->name(varPrefix + varp->name());
lscopep->addStmtsp(newVarp); lscopep->addStmtsp(newVarp);
varp->user2p(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 // Clone the function body

View File

@ -111,16 +111,30 @@ class LocalizeVisitor final : public VNVisitor {
AstVar* const oldVarp = nodep->varp(); AstVar* const oldVarp = nodep->varp();
for (AstCFunc* const funcp : funcps) { for (AstCFunc* const funcp : funcps) {
// Create the new local variable. // Create the new local variable.
const string newName string newName
= nodep->scopep() == funcp->scopep() = nodep->scopep() == funcp->scopep()
? oldVarp->name() ? oldVarp->name()
: nodep->scopep()->nameDotless() + "__DOT__" + oldVarp->name(); : nodep->scopep()->nameDotless() + "__DOT__" + oldVarp->name();
AstVar* const newVarp AstVar* const newVarp = new AstVar{oldVarp->fileline(), oldVarp->varType(),
= new AstVar{oldVarp->fileline(), oldVarp->varType(), newName, oldVarp}; std::move(newName), oldVarp};
newVarp->funcLocal(true); newVarp->funcLocal(true);
newVarp->noReset(oldVarp->noReset()); newVarp->noReset(oldVarp->noReset());
newVarp->noSubst(oldVarp->noSubst()); newVarp->noSubst(oldVarp->noSubst());
funcp->addVarsp(newVarp); 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 // Fix up all the references within this function
const auto er = m_references(funcp).equal_range(nodep); 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()->sensIfacep() // Not sensitive to an interface
&& !nodep->varp()->isVirtIface() // Not interface pointer && !nodep->varp()->isVirtIface() // Not interface pointer
&& !nodep->varp()->valuep() // Does not have an initializer && !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); UINFO(4, "Consider for localization: " << nodep);
m_varScopeps.push_back(nodep); m_varScopeps.push_back(nodep);

View File

@ -522,6 +522,13 @@ V3Number& V3Number::setValue1() {
return *this; 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) { void V3Number::setBitX0(int bit) {
// Selection beyond bounds after V3Premit needs to have 0s // Selection beyond bounds after V3Premit needs to have 0s
// in upper bits. Contrast to setAllBitsXRemoved which honors xAssign // in upper bits. Contrast to setAllBitsXRemoved which honors xAssign
@ -1167,6 +1174,20 @@ bool V3Number::isAllX() const VL_MT_SAFE {
} }
return true; 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 { bool V3Number::isEqZero() const VL_MT_SAFE {
if (isString()) return m_data.str().empty(); if (isString()) return m_data.str().empty();
for (int i = 0; i < words(); ++i) { for (int i = 0; i < words(); ++i) {
@ -1339,6 +1360,16 @@ V3Number& V3Number::opBitsOne(const V3Number& lhs) { // 1->1, 0/X/Z->0
} }
return *this; return *this;
} }
V3Number& V3Number::opBitsOneX(const V3Number& lhs) {
// op i, L(lhs) bit return
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
setZero();
for (int bit = 0; bit < width(); ++bit) {
if (lhs.bitIs1(bit) || lhs.bitIsX(bit)) setBit(bit, 1);
}
return *this;
}
V3Number& V3Number::opBitsXZ(const V3Number& lhs) { // 0/1->1, X/Z->0 V3Number& V3Number::opBitsXZ(const V3Number& lhs) { // 0/1->1, X/Z->0
// op i, L(lhs) bit return // op i, L(lhs) bit return
NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_OP_ARGS1(lhs);

View File

@ -640,6 +640,7 @@ public:
V3Number& setAllBits0(); V3Number& setAllBits0();
V3Number& setAllBits1(); V3Number& setAllBits1();
V3Number& setValue1(); V3Number& setValue1();
V3Number& setXZFromXZComplement(const V3Number&);
// IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc
V3Number& setMask(int nbits, int lsb = 0); V3Number& setMask(int nbits, int lsb = 0);
@ -697,6 +698,8 @@ public:
} }
bool isAllZ() const VL_MT_SAFE; bool isAllZ() const VL_MT_SAFE;
bool isAllX() 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 isEqZero() const VL_MT_SAFE;
bool isNeqZero() const; bool isNeqZero() const;
bool isBitsZero(int msb, int lsb) const; bool isBitsZero(int msb, int lsb) const;
@ -744,6 +747,7 @@ public:
// "this" is the output, as we need the output width before some computations // "this" is the output, as we need the output width before some computations
V3Number& opBitsNonXZ(const V3Number& lhs); // 0/1->1, X/Z->0 V3Number& opBitsNonXZ(const V3Number& lhs); // 0/1->1, X/Z->0
V3Number& opBitsOne(const V3Number& lhs); // 1->1, 0/X/Z->0 V3Number& opBitsOne(const V3Number& lhs); // 1->1, 0/X/Z->0
V3Number& opBitsOneX(const V3Number& lhs); // 1/X->1, 0/Z->0
V3Number& opBitsXZ(const V3Number& lhs); // 0/1->0, X/Z->1 V3Number& opBitsXZ(const V3Number& lhs); // 0/1->0, X/Z->1
V3Number& opBitsZ(const V3Number& lhs); // Z->1, 0/1/X->0 V3Number& opBitsZ(const V3Number& lhs); // Z->1, 0/1/X->0
// //

View File

@ -1054,6 +1054,15 @@ void V3Options::notify() VL_MT_DISABLED {
cmdfl->v3warn(E_UNSUPPORTED, cmdfl->v3warn(E_UNSUPPORTED,
"--fourstate is not supported with hierarchical Verilation"); "--fourstate is not supported with hierarchical Verilation");
} }
if (traceEnabledFst()) {
cmdfl->v3warn(E_UNSUPPORTED, "--fourstate is not supported with fst trace");
}
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()) { if (coverage() && savable()) {
@ -1942,6 +1951,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
DECL_OPTION("-waiver-output", Set, &m_waiverOutput); DECL_OPTION("-waiver-output", Set, &m_waiverOutput);
DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) { DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) {
m_xAssignDefault = false;
if (!std::strcmp(valp, "0")) { if (!std::strcmp(valp, "0")) {
m_xAssign = "0"; m_xAssign = "0";
} else if (!std::strcmp(valp, "1")) { } else if (!std::strcmp(valp, "1")) {
@ -1957,6 +1967,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
} }
}); });
DECL_OPTION("-x-initial", CbVal, [this, fl](const char* valp) { DECL_OPTION("-x-initial", CbVal, [this, fl](const char* valp) {
m_xInitialDefault = false;
if (!std::strcmp(valp, "0")) { if (!std::strcmp(valp, "0")) {
m_xInitial = "0"; m_xInitial = "0";
} else if (!std::strcmp(valp, "fast")) { } else if (!std::strcmp(valp, "fast")) {
@ -1975,6 +1986,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
addIncDirUser(parseFileArg(optdir, string{valp})); addIncDirUser(parseFileArg(optdir, string{valp}));
}).notForRerun(); }).notForRerun();
DECL_OPTION("-zero-top-ports", OnOff, &m_zero_top_ports).undocumented();
parser.finalize(); parser.finalize();
for (int i = 0; i < argc;) { for (int i = 0; i < argc;) {

View File

@ -311,6 +311,7 @@ private:
bool m_vpi = false; // main switch: --vpi bool m_vpi = false; // main switch: --vpi
bool m_waiverMultiline = false; // main switch: --waiver-multiline bool m_waiverMultiline = false; // main switch: --waiver-multiline
bool m_xInitialEdge = false; // main switch: --x-initial-edge 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_assertUnrollLimit = 1024; // main switch: --assert-unroll-limit
int m_buildJobs = -1; // main switch: --build-jobs, -j int m_buildJobs = -1; // main switch: --build-jobs, -j
@ -384,6 +385,8 @@ private:
string m_work = "work"; // main switch: --work {libname} string m_work = "work"; // main switch: --work {libname}
string m_xAssign; // main switch: --x-assign string m_xAssign; // main switch: --x-assign
string m_xInitial; // main switch: --x-initial 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 // 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. // have a concept of the default language at a global level.
@ -708,6 +711,7 @@ public:
bool isWaiverOutput() const { return !m_waiverOutput.empty(); } bool isWaiverOutput() const { return !m_waiverOutput.empty(); }
string xAssign() const { return m_xAssign; } string xAssign() const { return m_xAssign; }
string xInitial() const { return m_xInitial; } string xInitial() const { return m_xInitial; }
VOptionBool zeroTopPorts() const { return m_zero_top_ports; }
const VStringSet& cppFiles() const { return m_cppFiles; } const VStringSet& cppFiles() const { return m_cppFiles; }
const VStringList& cFlags() const { return m_cFlags; } const VStringList& cFlags() const { return m_cFlags; }

View File

@ -28,6 +28,7 @@
#include "V3Premit.h" #include "V3Premit.h"
#include "V3Fourstate.h"
#include "V3Stats.h" #include "V3Stats.h"
#include "V3UniqueNames.h" #include "V3UniqueNames.h"
@ -308,6 +309,42 @@ class PremitVisitor final : public VNVisitor {
iterateChildren(nodep); iterateChildren(nodep);
checkNode(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 { void visit(AstRand* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
checkNode(nodep); checkNode(nodep);

View File

@ -1011,12 +1011,20 @@ class ConstraintExprVisitor final : public VNVisitor {
if (targetWidth > exprWidth) { if (targetWidth > exprWidth) {
// Extend to match target width // Extend to match target width
AstNodeExpr* const result = new AstExtend{fl, exprp, targetWidth}; AstNodeExpr* const result = new AstExtend{fl, exprp, targetWidth};
result->dtypeSetLogicSized(targetWidth, targetSigning); if (exprp->dtypep()->isFourstate()) {
result->dtypeSetLogicSized(targetWidth, targetSigning);
} else {
result->dtypeSetBitSized(targetWidth, targetSigning);
}
return result; return result;
} else if (targetWidth < exprWidth) { } else if (targetWidth < exprWidth) {
// Truncate to match target width // Truncate to match target width
AstNodeExpr* const result = new AstSel{fl, exprp, 0, targetWidth}; AstNodeExpr* const result = new AstSel{fl, exprp, 0, targetWidth};
result->dtypeSetLogicSized(targetWidth, targetSigning); if (exprp->dtypep()->isFourstate()) {
result->dtypeSetLogicSized(targetWidth, targetSigning);
} else {
result->dtypeSetBitSized(targetWidth, targetSigning);
}
return result; return result;
} else { } else {
// Width already matches // Width already matches
@ -1964,7 +1972,6 @@ class ConstraintExprVisitor final : public VNVisitor {
AstNodeExpr* indexp = nodep->bitp()->unlinkFrBack(&handle); AstNodeExpr* indexp = nodep->bitp()->unlinkFrBack(&handle);
if (indexp->width() < 32) { if (indexp->width() < 32) {
AstExtend* const extendp = new AstExtend{fl, indexp, 32}; AstExtend* const extendp = new AstExtend{fl, indexp, 32};
extendp->dtypeSetLogicSized(32, VSigning::UNSIGNED);
extendp->user1(true); extendp->user1(true);
indexp = extendp; indexp = extendp;
} }

View File

@ -66,8 +66,7 @@ class ReloopVisitor final : public VNVisitor {
static AstVar* createVarTemp(FileLine* fl, AstCFunc* cfuncp) { static AstVar* createVarTemp(FileLine* fl, AstCFunc* cfuncp) {
UASSERT_OBJ(cfuncp, fl, "Assignment not under a function"); UASSERT_OBJ(cfuncp, fl, "Assignment not under a function");
const string newvarname{"__Vilp" + std::to_string(cfuncp->user1Inc() + 1)}; const string newvarname{"__Vilp" + std::to_string(cfuncp->user1Inc() + 1)};
AstVar* const varp AstVar* const varp = new AstVar{fl, VVarType::STMTTEMP, newvarname, VFlagBitPacked{}, 32};
= new AstVar{fl, VVarType::STMTTEMP, newvarname, VFlagLogicPacked{}, 32};
cfuncp->addVarsp(varp); cfuncp->addVarsp(varp);
return varp; return varp;
} }

View File

@ -246,10 +246,40 @@ private:
= [this, flp, senp]() { return new AstVarRef{flp, getPrev(senp), VAccess::READ}; }; = [this, flp, senp]() { return new AstVarRef{flp, getPrev(senp), VAccess::READ}; };
const auto lsb = [=](AstNodeExpr* opp) { return new AstSel{flp, opp, 0, 1}; }; const auto lsb = [=](AstNodeExpr* opp) { return new AstSel{flp, opp, 0, 1}; };
// Four-state expression handlers
AstFourstateExpr* const fourstateExpr = VN_CAST(senp, FourstateExpr);
auto currValp = [this, fourstateExpr]() { return getCurr(fourstateExpr->valuep()); };
auto currXZp = [this, fourstateExpr]() { return getCurr(fourstateExpr->xzp()); };
auto prevValp = [this, fourstateExpr, flp]() {
return new AstVarRef{flp, getPrev(fourstateExpr->valuep()), VAccess::READ};
};
auto prevXZp = [this, fourstateExpr, flp]() {
return new AstVarRef{flp, getPrev(fourstateExpr->xzp()), VAccess::READ};
};
// All event signals should be 1-bit at this point // All event signals should be 1-bit at this point
switch (senItemp->edgeType()) { switch (senItemp->edgeType()) {
case VEdgeType::ET_CHANGED: case VEdgeType::ET_CHANGED:
case VEdgeType::ET_HYBRID: // case VEdgeType::ET_HYBRID: //
if (fourstateExpr) {
if (VN_IS(senp->dtypep()->skipRefp(), UnpackArrayDType)) {
AstCMethodHard* const resultValp
= new AstCMethodHard{flp, prevp(), VCMethod::UNPACKED_NEQ, currValp()};
AstCMethodHard* const resultXZp
= new AstCMethodHard{flp, prevp(), VCMethod::UNPACKED_NEQ, currXZp()};
resultValp->dtypeSetBit();
resultXZp->dtypeSetBit();
return {wrapExprWithNullCheck(flp, new AstOr{flp, resultValp, resultXZp},
baseClassRefp),
true};
}
return {wrapExprWithNullCheck(
flp,
lsb(new AstOr{flp, new AstXor{flp, prevValp(), currValp()},
new AstXor{flp, prevXZp(), currXZp()}}),
baseClassRefp),
true};
}
if (VN_IS(senp->dtypep()->skipRefp(), UnpackArrayDType)) { if (VN_IS(senp->dtypep()->skipRefp(), UnpackArrayDType)) {
// operand order reversed to avoid calling neq() method on non-VlUnpacked type, see // operand order reversed to avoid calling neq() method on non-VlUnpacked type, see
// issue #5125 // issue #5125
@ -261,15 +291,46 @@ private:
return {wrapExprWithNullCheck(flp, new AstNeq{flp, currp(), prevp()}, baseClassRefp), return {wrapExprWithNullCheck(flp, new AstNeq{flp, currp(), prevp()}, baseClassRefp),
true}; true};
case VEdgeType::ET_BOTHEDGE: // case VEdgeType::ET_BOTHEDGE: //
if (fourstateExpr) {
return {wrapExprWithNullCheck(
flp,
lsb(new AstOr{flp, new AstXor{flp, currXZp(), prevXZp()},
new AstAnd{flp, new AstNot{flp, prevXZp()},
new AstXor{flp, currValp(), prevValp()}}}),
baseClassRefp),
false};
}
return { return {
wrapExprWithNullCheck(flp, lsb(new AstXor{flp, currp(), prevp()}), baseClassRefp), wrapExprWithNullCheck(flp, lsb(new AstXor{flp, currp(), prevp()}), baseClassRefp),
false}; false};
case VEdgeType::ET_POSEDGE: // case VEdgeType::ET_POSEDGE: //
if (fourstateExpr) {
return {wrapExprWithNullCheck(
flp,
lsb(new AstAnd{
flp,
new AstAnd{flp, new AstOr{flp, currValp(), currXZp()},
new AstOr{flp, prevXZp(), new AstNot{flp, prevValp()}}},
new AstNot{flp, new AstAnd{flp, prevXZp(), currXZp()}}}),
baseClassRefp),
false};
}
return {wrapExprWithNullCheck(flp, return {wrapExprWithNullCheck(flp,
lsb(new AstAnd{flp, currp(), new AstNot{flp, prevp()}}), lsb(new AstAnd{flp, currp(), new AstNot{flp, prevp()}}),
baseClassRefp), baseClassRefp),
false}; false};
case VEdgeType::ET_NEGEDGE: // case VEdgeType::ET_NEGEDGE: //
if (fourstateExpr) {
return {wrapExprWithNullCheck(
flp,
lsb(new AstAnd{
flp,
new AstAnd{flp, new AstOr{flp, prevValp(), prevXZp()},
new AstOr{flp, currXZp(), new AstNot{flp, currValp()}}},
new AstNot{flp, new AstAnd{flp, prevXZp(), currXZp()}}}),
baseClassRefp),
false};
}
return {wrapExprWithNullCheck(flp, return {wrapExprWithNullCheck(flp,
lsb(new AstAnd{flp, new AstNot{flp, currp()}, prevp()}), lsb(new AstAnd{flp, new AstNot{flp, currp()}, prevp()}),
baseClassRefp), baseClassRefp),
@ -293,6 +354,9 @@ private:
return {wrapExprWithNullCheck(flp, callp, baseClassRefp), false}; return {wrapExprWithNullCheck(flp, callp, baseClassRefp), false};
} }
case VEdgeType::ET_TRUE: // case VEdgeType::ET_TRUE: //
if (fourstateExpr) {
return {lsb(new AstAnd{flp, currValp(), new AstNot{flp, currXZp()}}), false};
}
return {currp(), false}; return {currp(), false};
case VEdgeType::ET_INITIAL_NBA: // case VEdgeType::ET_INITIAL_NBA: //
return {new AstConst{flp, AstConst::BitFalse{}}, true}; return {new AstConst{flp, AstConst::BitFalse{}}, true};

View File

@ -553,8 +553,9 @@ class TaskVisitor final : public VNVisitor {
} }
} }
void connectPort(AstVar* portp, AstArg* argp, const string& namePrefix, AstNode* beginp, AstVarScope* connectPort(AstVar* portp, AstArg* argp, const string& namePrefix,
bool inlineTask) { AstNode* beginp, bool inlineTask) {
AstVarScope* newvscp = nullptr;
AstNodeExpr* pinp = argp->exprp(); AstNodeExpr* pinp = argp->exprp();
if (inlineTask) { if (inlineTask) {
portp->unlinkFrBack(); portp->unlinkFrBack();
@ -575,7 +576,7 @@ class TaskVisitor final : public VNVisitor {
+ std::to_string(m_unconVarNum++), + std::to_string(m_unconVarNum++),
portp->dtypep()}; portp->dtypep()};
m_modp->addStmtsp(varp); 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); m_scopep->addVarsp(newvscp);
AstVarRef* const repp = new AstVarRef{pinp->fileline(), newvscp, VAccess::WRITE}; AstVarRef* const repp = new AstVarRef{pinp->fileline(), newvscp, VAccess::WRITE};
pinp->replaceWith(repp); pinp->replaceWith(repp);
@ -620,8 +621,7 @@ class TaskVisitor final : public VNVisitor {
} else if (portp->isInout()) { } else if (portp->isInout()) {
// UINFOTREE(9, pinp, "", "pinrsize-"); // UINFOTREE(9, pinp, "", "pinrsize-");
AstVarScope* const newvscp newvscp = createVarScope(portp, namePrefix + "__" + portp->shortName());
= createVarScope(portp, namePrefix + "__" + portp->shortName());
portp->user2p(newvscp); portp->user2p(newvscp);
if (!inlineTask) { if (!inlineTask) {
pinp->replaceWith( pinp->replaceWith(
@ -642,8 +642,7 @@ class TaskVisitor final : public VNVisitor {
} else if (portp->isWritable()) { } else if (portp->isWritable()) {
// Even if it's referencing a varref, we still make a temporary // Even if it's referencing a varref, we still make a temporary
// Else task(x,x,x) might produce incorrect results // Else task(x,x,x) might produce incorrect results
AstVarScope* const newvscp newvscp = createVarScope(portp, namePrefix + "__" + portp->shortName());
= createVarScope(portp, namePrefix + "__" + portp->shortName());
portp->user2p(newvscp); portp->user2p(newvscp);
if (!inlineTask) { if (!inlineTask) {
pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE}); pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE});
@ -654,8 +653,7 @@ class TaskVisitor final : public VNVisitor {
beginp->addNext(postassp); beginp->addNext(postassp);
} else if (inlineTask && portp->isNonOutput()) { } else if (inlineTask && portp->isNonOutput()) {
// Make input variable // Make input variable
AstVarScope* const newvscp newvscp = createVarScope(portp, namePrefix + "__" + portp->shortName());
= createVarScope(portp, namePrefix + "__" + portp->shortName());
portp->user2p(newvscp); portp->user2p(newvscp);
AstAssign* const preassp = connectPortMakeInAssign(pinp, newvscp, false); AstAssign* const preassp = connectPortMakeInAssign(pinp, newvscp, false);
// Put assignment in FRONT of all other statements // Put assignment in FRONT of all other statements
@ -666,6 +664,7 @@ class TaskVisitor final : public VNVisitor {
beginp->addNext(preassp); beginp->addNext(preassp);
} }
} }
return newvscp;
} }
bool hasRefArgument(AstNodeFTask* nodep) { bool hasRefArgument(AstNodeFTask* nodep) {
@ -692,10 +691,25 @@ class TaskVisitor final : public VNVisitor {
AstNode::user2ClearTree(); AstNode::user2ClearTree();
{ {
const V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp); const V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp);
AstVar* prevFourstateVarp = nullptr;
for (const auto& itr : tconnects) { for (const auto& itr : tconnects) {
AstVar* const portp = itr.first; AstVar* const portp = itr.first;
AstArg* const argp = itr.second; 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"); UASSERT_OBJ(!refp->argsp(), refp, "Arg wasn't removed by above loop");

View File

@ -230,8 +230,11 @@ class TraceDeclVisitor final : public VNVisitor {
FileLine& fileline() const { return m_vscp ? *m_vscp->fileline() : *m_cellp->fileline(); } FileLine& fileline() const { return m_vscp ? *m_vscp->fileline() : *m_cellp->fileline(); }
}; };
std::vector<TraceEntry> m_entries; // Trace entries under current scope std::vector<TraceEntry> m_entries; // Trace entries under current scope
std::map<const AstVar*, AstVarScope*>
m_varxzToVscp; // Map from variable with xz part to its variable scope
AstVarScope* m_traVscp = nullptr; // Current AstVarScope we are constructing AstTraceDecls for AstVarScope* m_traVscp = nullptr; // Current AstVarScope we are constructing AstTraceDecls for
AstNodeExpr* m_traValuep = nullptr; // Value expression for current signal AstNodeExpr* m_traValuep = nullptr; // Value expression for current signal
AstNodeExpr* m_traValueXZp = nullptr; // ValueXZ expression for current signal
string m_traName; // Name component for current signal string m_traName; // Name component for current signal
VDouble0 m_statSigs; // Statistic tracking VDouble0 m_statSigs; // Statistic tracking
@ -334,6 +337,10 @@ class TraceDeclVisitor final : public VNVisitor {
} }
FileLine* const flp = m_traVscp->fileline(); FileLine* const flp = m_traVscp->fileline();
AstNodeExpr* valuep = m_traValuep->cloneTree(false); AstNodeExpr* valuep = m_traValuep->cloneTree(false);
if (m_traValueXZp) {
valuep = new AstFourstateExpr{m_traVscp->fileline(), valuep,
m_traValueXZp->cloneTree(false)};
}
const bool validOffset = m_offset != std::numeric_limits<uint32_t>::max(); const bool validOffset = m_offset != std::numeric_limits<uint32_t>::max();
AstTraceDecl* const newp AstTraceDecl* const newp
= new AstTraceDecl{flp, m_traName, m_traVscp->varp(), valuep, = new AstTraceDecl{flp, m_traName, m_traVscp->varp(), valuep,
@ -685,6 +692,12 @@ class TraceDeclVisitor final : public VNVisitor {
// traversal. // traversal.
m_traValuep m_traValuep
= new AstVarRef{m_traVscp->fileline(), m_traVscp, VAccess::READ}; = new AstVarRef{m_traVscp->fileline(), m_traVscp, VAccess::READ};
if (AstVar* const complementp
= m_traVscp->varp()->fourstateComplementp()) {
m_traValueXZp
= new AstVarRef{m_traVscp->fileline(),
m_varxzToVscp.at(complementp), VAccess::READ};
}
// Recurse into data type of the signal. The visit methods will add // Recurse into data type of the signal. The visit methods will add
// AstTraceDecls. // AstTraceDecls.
iterate(m_traVscp->varp()->dtypep()->skipRefToEnump()); iterate(m_traVscp->varp()->dtypep()->skipRefToEnump());
@ -694,6 +707,10 @@ class TraceDeclVisitor final : public VNVisitor {
// Note: Sometimes VL_DANGLING is a no-op, but we have assertions // Note: Sometimes VL_DANGLING is a no-op, but we have assertions
// on m_traValuep being nullptr, so make sure it is. // on m_traValuep being nullptr, so make sure it is.
m_traValuep = nullptr; m_traValuep = nullptr;
if (m_traValueXZp) {
VL_DO_DANGLING(m_traValueXZp->deleteTree(), m_traValueXZp);
m_traValueXZp = nullptr;
}
} }
} }
} else { } else {
@ -795,8 +812,12 @@ class TraceDeclVisitor final : public VNVisitor {
if (nodep->varp()->isParam() && VN_IS(nodep->scopep()->modp(), Package)) return; if (nodep->varp()->isParam() && VN_IS(nodep->scopep()->modp(), Package)) return;
} }
// Add to traced signal list if (nodep->varp()->isFourstateComplement()) {
m_entries.emplace_back(m_currScopep, nodep); m_varxzToVscp.emplace(nodep->varp(), nodep);
} else {
// Add to traced signal list
m_entries.emplace_back(m_currScopep, nodep);
}
} }
// VISITORS - Data types when tracing // VISITORS - Data types when tracing

View File

@ -207,7 +207,11 @@ class UnknownVisitor final : public VNVisitor {
} }
void visit(AstVar* nodep) override { void visit(AstVar* nodep) override {
VL_RESTORER(m_allowXUnique); 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); iterateChildren(nodep);
} }
void visitEqNeqCase(AstNodeBiop* nodep) { void visitEqNeqCase(AstNodeBiop* nodep) {
@ -394,7 +398,7 @@ class UnknownVisitor final : public VNVisitor {
void visit(AstSel* nodep) override { void visit(AstSel* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
if (!nodep->user1SetOnce()) { if (!v3Global.opt.fourstate() && !nodep->user1SetOnce()) {
// Guard against reading/writing past end of bit vector array // Guard against reading/writing past end of bit vector array
const AstNode* const basefromp = AstArraySel::baseFromp(nodep, true); const AstNode* const basefromp = AstArraySel::baseFromp(nodep, true);
bool lvalue = false; bool lvalue = false;
@ -551,7 +555,8 @@ public:
// CONSTRUCTORS // CONSTRUCTORS
explicit UnknownVisitor(AstNetlist* nodep) explicit UnknownVisitor(AstNetlist* nodep)
: m_lvboundNames{"__Vlvbound"} : 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); iterate(nodep);
} }
~UnknownVisitor() override { // ~UnknownVisitor() override { //

View File

@ -1071,7 +1071,8 @@ class WidthVisitor final : public VNVisitor {
const bool inParameterizedTemplate const bool inParameterizedTemplate
= m_modep && (m_modep->dead() || m_modep->parameterizedTemplate()); = m_modep && (m_modep->dead() || m_modep->parameterizedTemplate());
if (VN_IS(nodep->lsbp(), Const) && nodep->msbConst() < nodep->lsbConst()) { if (!v3Global.opt.fourstate() && VN_IS(nodep->lsbp(), Const)
&& nodep->msbConst() < nodep->lsbConst()) {
// Likely impossible given above width check // Likely impossible given above width check
nodep->v3warn(E_UNSUPPORTED, nodep->v3warn(E_UNSUPPORTED,
"Unsupported: left < right of bit extract: " // LCOV_EXCL_LINE "Unsupported: left < right of bit extract: " // LCOV_EXCL_LINE
@ -1145,22 +1146,24 @@ class WidthVisitor final : public VNVisitor {
UINFO(1, " Related node: " << nodep); UINFO(1, " Related node: " << nodep);
} }
if (lrefp) UINFO(9, " Select extend lrefp " << lrefp); if (lrefp) UINFO(9, " Select extend lrefp " << lrefp);
if (lrefp && lrefp->access().isWriteOrRW()) { if (!v3Global.opt.fourstate()) {
// lvarref[X] = ..., the expression assigned is too wide if (lrefp && lrefp->access().isWriteOrRW()) {
// WTF to do // lvarref[X] = ..., the expression assigned is too wide
// Don't change the width of this lhsp, instead propagate up // WTF to do
// to upper assign/expression the correct width // Don't change the width of this lhsp, instead propagate up
AstNodeDType* const subDTypep // to upper assign/expression the correct width
= nodep->findLogicDType(width, width, nodep->fromp()->dtypep()->numeric()); AstNodeDType* const subDTypep = nodep->findLogicDType(
widthCheckSized(nodep, "errorless...", nodep->fromp(), subDTypep, EXTEND_EXP, width, width, nodep->fromp()->dtypep()->numeric());
false /*noerror*/); widthCheckSized(nodep, "errorless...", nodep->fromp(), subDTypep,
} else { EXTEND_EXP, false /*noerror*/);
// Extend it } else {
const int extendTo = nodep->msbConst() + 1; // Extend it
AstNodeDType* const subDTypep = nodep->findLogicDType( const int extendTo = nodep->msbConst() + 1;
extendTo, extendTo, nodep->fromp()->dtypep()->numeric()); AstNodeDType* const subDTypep = nodep->findLogicDType(
widthCheckSized(nodep, "errorless...", nodep->fromp(), subDTypep, EXTEND_EXP, extendTo, extendTo, nodep->fromp()->dtypep()->numeric());
false /*noerror*/); widthCheckSized(nodep, "errorless...", nodep->fromp(), subDTypep,
EXTEND_EXP, false /*noerror*/);
}
} }
} }
// iterate FINAL is two blocks above // iterate FINAL is two blocks above
@ -1168,7 +1171,7 @@ class WidthVisitor final : public VNVisitor {
// If we have a width problem with GENERATE etc, this will reduce // If we have a width problem with GENERATE etc, this will reduce
// it down and mask it, so we have no chance of finding a real // it down and mask it, so we have no chance of finding a real
// error in the future. So don't do this for them. // error in the future. So don't do this for them.
if (!m_doGenerate) { if (!v3Global.opt.fourstate() && !m_doGenerate) {
// lsbp() must be self-determined, however for performance // lsbp() must be self-determined, however for performance
// we want the select to be truncated to fit within the // we want the select to be truncated to fit within the
// maximum select range, e.g. turn Xs outside of the select // maximum select range, e.g. turn Xs outside of the select
@ -1908,13 +1911,15 @@ class WidthVisitor final : public VNVisitor {
void visit(AstCExprUser* nodep) override { void visit(AstCExprUser* nodep) override {
// Give it the size the user wants. // Give it the size the user wants.
if (m_vup && m_vup->prelim()) { 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 // All arguments seek their natural sizes
userIterateChildren(nodep, WidthVP{SELF, BOTH}.p()); userIterateChildren(nodep, WidthVP{SELF, BOTH}.p());
} }
if (m_vup->final()) { if (m_vup->final()) {
AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); 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) { if (nodep->width() > 64) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $c can't generate wider than 64 bits"); nodep->v3warn(E_UNSUPPORTED, "Unsupported: $c can't generate wider than 64 bits");
} }
@ -2046,7 +2051,7 @@ class WidthVisitor final : public VNVisitor {
iterateCheckSizedSelf(nodep, "FHS", nodep->fhsp(), SELF, BOTH); 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'. // 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; 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 { void visit(AstCountOnes* nodep) override {
@ -2054,7 +2059,7 @@ class WidthVisitor final : public VNVisitor {
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); 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'. // 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; 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 { void visit(AstCvtPackString* nodep) override {

View File

@ -278,9 +278,6 @@ private:
void visit(AstCastWrap* nodep) override { void visit(AstCastWrap* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
editDType(nodep); editDType(nodep);
UINFO(6, " Replace " << nodep << " w/ " << nodep->lhsp());
nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
void visit(AstConstraint* nodep) override { void visit(AstConstraint* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
@ -557,3 +554,19 @@ void V3WidthCommit::widthCommit(AstNetlist* nodep) {
{ WidthCommitVisitor{nodep}; } // Destruct before checking { WidthCommitVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTreeEitherLevel() >= 6); V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTreeEitherLevel() >= 6);
} }
void V3WidthCommit::widthCommitClean(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ":");
{
std::vector<AstCastWrap*> castWrapsToDelete;
v3Global.rootp()->foreach([&castWrapsToDelete](AstCastWrap* nodep) {
UINFO(6, " Replace " << nodep << " w/ " << nodep->lhsp());
castWrapsToDelete.push_back(nodep);
});
for (AstCastWrap* const nodep : castWrapsToDelete) {
nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
V3Global::dumpCheckGlobalTree("widthcommit_clean", 0, dumpTreeEitherLevel() >= 6);
}

View File

@ -42,6 +42,7 @@ public:
// Final step... Mark all widths as equal // Final step... Mark all widths as equal
static void widthCommit(AstNetlist* nodep) VL_MT_DISABLED; static void widthCommit(AstNetlist* nodep) VL_MT_DISABLED;
static void widthCommitClean(AstNetlist* nodep) VL_MT_DISABLED;
}; };
//###################################################################### //######################################################################

View File

@ -174,8 +174,15 @@ class WidthSelVisitor final : public VNVisitor {
} else { } else {
extendp = new AstExtend{fl, indexp}; extendp = new AstExtend{fl, indexp};
} }
extendp->dtypeSetLogicUnsized( if (indexp->dtypep()->isFourstate()) {
32, std::max(V3Number::log2b(elwidth) + 1, indexp->widthMin()), VSigning::UNSIGNED); extendp->dtypeSetLogicUnsized(
32, std::max(V3Number::log2b(elwidth) + 1, indexp->widthMin()),
VSigning::UNSIGNED);
} else {
extendp->dtypeSetBitUnsized(32,
std::max(V3Number::log2b(elwidth) + 1, indexp->widthMin()),
VSigning::UNSIGNED);
}
AstNodeExpr* const mulp AstNodeExpr* const mulp
= new AstMul{fl, new AstConst{fl, AstConst::Unsized32{}, elwidth}, = 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 // Extend needed as index might be e.g. 3 bits but constant e.g. 5 bits

View File

@ -57,6 +57,7 @@
#include "V3File.h" #include "V3File.h"
#include "V3Force.h" #include "V3Force.h"
#include "V3Fork.h" #include "V3Fork.h"
#include "V3Fourstate.h"
#include "V3FsmDetect.h" #include "V3FsmDetect.h"
#include "V3FuncOpt.h" #include "V3FuncOpt.h"
#include "V3Gate.h" #include "V3Gate.h"
@ -301,6 +302,8 @@ static void process() {
// No more AstGenBlocks after this // No more AstGenBlocks after this
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
if (v3Global.opt.fourstate()) V3Fourstate::fourstateAll(v3Global.rootp());
V3WidthCommit::widthCommitClean(v3Global.rootp());
// Expand inouts, stage 2 // Expand inouts, stage 2
// Also simplify pin connections to always be AssignWs in prep for V3Unknown // Also simplify pin connections to always be AssignWs in prep for V3Unknown
V3Tristate::tristateAll(v3Global.rootp()); V3Tristate::tristateAll(v3Global.rootp());
@ -561,6 +564,11 @@ static void process() {
V3Expand::expandAll(v3Global.rootp()); V3Expand::expandAll(v3Global.rootp());
} }
if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly()
&& v3Global.opt.fourstate()) {
V3Fourstate::fourstateShuffleAll(v3Global.rootp());
}
// Propagate constants across WORDSEL arrayed temporaries // Propagate constants across WORDSEL arrayed temporaries
if (!v3Global.opt.serializeOnly() && v3Global.opt.fSubst()) { if (!v3Global.opt.serializeOnly() && v3Global.opt.fSubst()) {
// Constant folding of expanded stuff // Constant folding of expanded stuff

View File

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

View File

@ -44,7 +44,9 @@ All_Scenarios = {
'xrun': ['linter', 'simulator', 'simulator_st', 'xrun'], 'xrun': ['linter', 'simulator', 'simulator_st', 'xrun'],
'xsim': ['linter', 'simulator', 'simulator_st', 'xsim'], 'xsim': ['linter', 'simulator', 'simulator_st', 'xsim'],
'vlt': ['linter', 'simulator', 'simulator_st', 'vlt_all', 'vlt'], 'vlt': ['linter', 'simulator', 'simulator_st', 'vlt_all', 'vlt'],
'vlt4': ['linter', 'simulator', 'simulator_st', 'vlt_all', 'vlt'],
'vltmt': ['simulator', 'vlt_all', 'vltmt'], 'vltmt': ['simulator', 'vlt_all', 'vltmt'],
'vltmt4': ['simulator', 'vlt_all', 'vltmt'],
# yapf: enable # yapf: enable
} }
@ -731,11 +733,13 @@ class VlTest:
# Make e.g. self.vlt, self.vltmt etc # Make e.g. self.vlt, self.vltmt etc
self.vlt = False # Set below also self.vlt = False # Set below also
self.vltmt = 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 self.xsim = False # Set below also
for ascenario in All_Scenarios: for ascenario in All_Scenarios:
self.__dict__[ascenario] = False self.__dict__[ascenario] = False
self.__dict__[scenario] = True 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, ".") (self.py_filename, self.t_dir) = Runner._py_filename_adjust(self.py_filename, ".")
for tdir in Args.test_dirs: # pylint: disable=redefined-outer-name 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.top_filename = re.sub(r'\.py$', '', self.py_filename) + '.' + self.v_suffix
self.pli_filename = re.sub(r'\.py$', '', self.py_filename) + '.cpp' self.pli_filename = re.sub(r'\.py$', '', self.py_filename) + '.cpp'
self.top_shell_filename = self.obj_dir + "/" + self.vm_prefix + "__top.v" 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: def _define_opt_calc(self) -> str:
return "--define " if self.xsim else "+define+" return "--define " if self.xsim else "+define+"
@ -1150,9 +1157,10 @@ class VlTest:
verilator_flags += ["--trace-vcd"] verilator_flags += ["--trace-vcd"]
if Args.gdbsim or Args.rrsim: if Args.gdbsim or Args.rrsim:
verilator_flags += ["-CFLAGS -ggdb -LDFLAGS -ggdb"] verilator_flags += ["-CFLAGS -ggdb -LDFLAGS -ggdb"]
verilator_flags += ["--x-assign unique"] # More likely to be buggy if not (param['vlt4'] or param['vltmt4']):
verilator_flags += ["--x-assign unique"] # More likely to be buggy
if param['vltmt']: if param['vltmt'] or param['vltmt4']:
verilator_flags += ["--debug-partition"] verilator_flags += ["--debug-partition"]
if param['threads'] >= 0: if param['threads'] >= 0:
verilator_flags += ["--threads", str(param['threads'])] verilator_flags += ["--threads", str(param['threads'])]
@ -1160,6 +1168,10 @@ class VlTest:
verilator_flags += ["--exe"] verilator_flags += ["--exe"]
if param['make_main'] and param['verilator_make_gmake']: if param['make_main'] and param['verilator_make_gmake']:
verilator_flags += ["../" + self.main_filename] 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 = [ cmdargs = [
"--prefix", "--prefix",
@ -1216,7 +1228,7 @@ class VlTest:
if re.search(r'(^|\s)-?-threads\s', checkflags): if re.search(r'(^|\s)-?-threads\s', checkflags):
self.error("Specify threads via 'threads=' argument, not as a command line option") 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) param['threads'] = calc_threads(Vltmt_Threads)
if not param['context_threads']: if not param['context_threads']:
param['context_threads'] = param['threads'] if (param['threads'] >= 1) else 1 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") self.skip("Test requires Coroutines; ignore error since not available\n")
return 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( 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): pretty=True)) and re.search(r'clang', self.cxx_version):
self.skip( self.skip(
@ -1869,6 +1890,11 @@ class VlTest:
tee=True, tee=True,
verilator_run=False) -> bool: # Move gcov data to parallel area 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: try:
command = ' '.join(cmd) command = ' '.join(cmd)
except TypeError: except TypeError:

View File

@ -15,6 +15,7 @@ import vltest_bootstrap
test.priority(100) test.priority(100)
test.scenarios('vlt') test.scenarios('vlt')
test.fourstate_capable = False
test.top_filename = "t/t_a1_first_cc.v" test.top_filename = "t/t_a1_first_cc.v"
test.leak_check_disable() test.leak_check_disable()

View File

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

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('linter') test.scenarios('linter')
test.fourstate_capable = False
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename) test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)

View File

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

View File

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

View File

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

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('linter') test.scenarios('linter')
test.fourstate_capable = False
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename) test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)
module = re.sub(r'_noinl', '', module) module = re.sub(r'_noinl', '', module)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

@ -10,6 +10,7 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('vlt_all') test.scenarios('vlt_all')
test.fourstate_capable = False
test.top_filename = "t/t_altera_lpm.v" test.top_filename = "t/t_altera_lpm.v"
module = re.sub(r'.*t_altera_', '', test.name) module = re.sub(r'.*t_altera_', '', test.name)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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