Optimize VCD vector zero trimming
This commit is contained in:
parent
6b3e2ce971
commit
008d612dad
|
|
@ -38,8 +38,43 @@
|
||||||
# define VL_HAVE_AVX2 1
|
# define VL_HAVE_AVX2 1
|
||||||
# include <immintrin.h>
|
# include <immintrin.h>
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(__LZCNT__) && !defined(VL_DISABLE_LZCNT)
|
||||||
|
# define VL_HAVE_LZCNT 1
|
||||||
|
# ifndef VL_HAVE_AVX2
|
||||||
|
# include <immintrin.h>
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
VL_ATTR_ALWINLINE int vlIntrinClz32(uint32_t value) {
|
||||||
|
VL_DEBUG_IFDEF(assert(value););
|
||||||
|
#ifdef VL_HAVE_LZCNT
|
||||||
|
return static_cast<int>(_lzcnt_u32(value));
|
||||||
|
#elif (defined(__GNUC__) || defined(__clang__)) && !defined(VL_NO_BUILTINS)
|
||||||
|
return __builtin_clz(value);
|
||||||
|
#else
|
||||||
|
int zeros = 0;
|
||||||
|
uint32_t bit = 1U << 31;
|
||||||
|
while (!(value & bit)) {
|
||||||
|
++zeros;
|
||||||
|
bit >>= 1;
|
||||||
|
}
|
||||||
|
return zeros;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
VL_ATTR_ALWINLINE int vlIntrinClz64(uint64_t value) {
|
||||||
|
VL_DEBUG_IFDEF(assert(value););
|
||||||
|
#if defined(VL_HAVE_LZCNT) && (defined(__x86_64__) || defined(_M_X64))
|
||||||
|
return static_cast<int>(_lzcnt_u64(value));
|
||||||
|
#elif (defined(__GNUC__) || defined(__clang__)) && !defined(VL_NO_BUILTINS)
|
||||||
|
return __builtin_clzll(static_cast<unsigned long long>(value));
|
||||||
|
#else
|
||||||
|
const uint32_t upper = static_cast<uint32_t>(value >> 32);
|
||||||
|
return upper ? vlIntrinClz32(upper) : 32 + vlIntrinClz32(static_cast<uint32_t>(value));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|
|
||||||
|
|
@ -639,46 +639,89 @@ 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;
|
||||||
*wp++ = 'b';
|
*wp++ = 'b';
|
||||||
cvtCDataToStr(wp, newval << (VL_BYTESIZE - bits));
|
CData value = newval << (VL_BYTESIZE - bits);
|
||||||
finishLine(code, wp + bits);
|
if (VL_UNLIKELY(!value)) {
|
||||||
|
*wp++ = '0';
|
||||||
|
finishLine(code, wp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int skip = vlIntrinClz32(value) - (VL_IDATASIZE - VL_BYTESIZE);
|
||||||
|
cvtCDataToStr(wp, value << skip);
|
||||||
|
finishLine(code, wp + bits - skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
*wp++ = 'b';
|
*wp++ = 'b';
|
||||||
cvtSDataToStr(wp, newval << (VL_SHORTSIZE - bits));
|
SData value = newval << (VL_SHORTSIZE - bits);
|
||||||
finishLine(code, wp + bits);
|
if (VL_UNLIKELY(!value)) {
|
||||||
|
*wp++ = '0';
|
||||||
|
finishLine(code, wp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int skip = vlIntrinClz32(value) - (VL_IDATASIZE - VL_SHORTSIZE);
|
||||||
|
cvtSDataToStr(wp, value << skip);
|
||||||
|
finishLine(code, wp + bits - skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
*wp++ = 'b';
|
*wp++ = 'b';
|
||||||
cvtIDataToStr(wp, newval << (VL_IDATASIZE - bits));
|
IData value = newval << (VL_IDATASIZE - bits);
|
||||||
finishLine(code, wp + bits);
|
if (VL_UNLIKELY(!value)) {
|
||||||
|
*wp++ = '0';
|
||||||
|
finishLine(code, wp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int skip = vlIntrinClz32(value);
|
||||||
|
cvtIDataToStr(wp, value << skip);
|
||||||
|
finishLine(code, wp + bits - skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
*wp++ = 'b';
|
*wp++ = 'b';
|
||||||
cvtQDataToStr(wp, newval << (VL_QUADSIZE - bits));
|
QData value = newval << (VL_QUADSIZE - bits);
|
||||||
finishLine(code, wp + bits);
|
if (VL_UNLIKELY(!value)) {
|
||||||
|
*wp++ = '0';
|
||||||
|
finishLine(code, wp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int skip = vlIntrinClz64(value);
|
||||||
|
cvtQDataToStr(wp, value << skip);
|
||||||
|
finishLine(code, wp + bits - skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
VL_ATTR_ALWINLINE
|
VL_ATTR_ALWINLINE
|
||||||
void VerilatedVcdBuffer::emitWData(uint32_t code, WDataInP newval, int bits) {
|
void VerilatedVcdBuffer::emitWData(uint32_t code, WDataInP newval, int bits) {
|
||||||
int words = VL_WORDS_I(bits);
|
|
||||||
char* wp = m_writep;
|
char* wp = m_writep;
|
||||||
*wp++ = 'b';
|
*wp++ = 'b';
|
||||||
// Handle the most significant word
|
|
||||||
|
int word = VL_WORDS_I(bits) - 1;
|
||||||
const int bitsInMSW = VL_BITBIT_E(bits) ? VL_BITBIT_E(bits) : VL_EDATASIZE;
|
const int bitsInMSW = VL_BITBIT_E(bits) ? VL_BITBIT_E(bits) : VL_EDATASIZE;
|
||||||
cvtEDataToStr(wp, newval[--words] << (VL_EDATASIZE - bitsInMSW));
|
int bitsInWord = bitsInMSW;
|
||||||
wp += bitsInMSW;
|
EData value = newval[word] & VL_MASK_E(bitsInMSW);
|
||||||
// Handle the remaining words
|
|
||||||
while (words > 0) {
|
while (!value && word > 0) {
|
||||||
cvtEDataToStr(wp, newval[--words]);
|
value = newval[--word];
|
||||||
|
bitsInWord = VL_EDATASIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VL_UNLIKELY(!value)) {
|
||||||
|
*wp++ = '0';
|
||||||
|
finishLine(code, wp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int skip = vlIntrinClz32(value) - (VL_EDATASIZE - bitsInWord);
|
||||||
|
cvtEDataToStr(wp, value << (VL_EDATASIZE - bitsInWord + skip));
|
||||||
|
wp += bitsInWord - skip;
|
||||||
|
|
||||||
|
while (word > 0) {
|
||||||
|
cvtEDataToStr(wp, newval[--word]);
|
||||||
wp += VL_EDATASIZE;
|
wp += VL_EDATASIZE;
|
||||||
}
|
}
|
||||||
finishLine(code, wp);
|
finishLine(code, wp);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,28 @@
|
||||||
$version Generated by VerilatedVcd $end
|
$version Generated by VerilatedVcd $end
|
||||||
$timescale 1ps $end
|
$timescale 1ps $end
|
||||||
$scope module t $end
|
$scope module t $end
|
||||||
|
$var wire 4 # zero4 [3:0] $end
|
||||||
|
$var wire 4 $ small4 [3:0] $end
|
||||||
|
$var wire 8 % small8 [7:0] $end
|
||||||
|
$var wire 16 & msb16 [15:0] $end
|
||||||
$var wire 32 " sig [31:0] $end
|
$var wire 32 " sig [31:0] $end
|
||||||
|
$var wire 32 ' mid32 [31:0] $end
|
||||||
|
$var wire 64 ( msb64 [63:0] $end
|
||||||
|
$var wire 100 * wide_skip [99:0] $end
|
||||||
|
$var wire 68 . wide_partial [67:0] $end
|
||||||
$upscope $end
|
$upscope $end
|
||||||
$enddefinitions $end
|
$enddefinitions $end
|
||||||
|
|
||||||
|
|
||||||
#0
|
#0
|
||||||
b00000000000000000000000000001010 "
|
b1010 "
|
||||||
|
b0 #
|
||||||
|
b10 $
|
||||||
|
b1 %
|
||||||
|
b1000000000000000 &
|
||||||
|
b10100101 '
|
||||||
|
b1000000000000000000000000000000000000000000000000000000000000000 (
|
||||||
|
b100000000000000000000000000000000 *
|
||||||
|
b100000000000000000000000000000000000000000000000000000000000000000 .
|
||||||
#20
|
#20
|
||||||
b00000000000000000000000000010100 "
|
b10100 "
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,23 @@
|
||||||
|
|
||||||
import vltest_bootstrap
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
|
||||||
test.scenarios('vlt')
|
test.scenarios('vlt')
|
||||||
|
|
||||||
|
verilator_flags2 = ['--binary --trace']
|
||||||
|
if platform.machine().lower() in ("amd64", "x86_64") and os.path.exists("/proc/cpuinfo"):
|
||||||
|
with open("/proc/cpuinfo", encoding="utf-8") as fh:
|
||||||
|
cpuinfo = " " + fh.read().lower() + " "
|
||||||
|
if " avx2 " in cpuinfo and (" lzcnt " in cpuinfo or " abm " in cpuinfo):
|
||||||
|
verilator_flags2 += ["-CFLAGS", "\"-mavx2 -mlzcnt\""]
|
||||||
|
|
||||||
test.compile(
|
test.compile(
|
||||||
verilator_flags=[ # Custom as don't want -cc
|
verilator_flags=[ # Custom as don't want -cc
|
||||||
"-Mdir " + test.obj_dir, "--debug-check"
|
"-Mdir " + test.obj_dir, "--debug-check"
|
||||||
],
|
],
|
||||||
verilator_flags2=['--binary --trace'])
|
verilator_flags2=verilator_flags2)
|
||||||
|
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,16 @@
|
||||||
`define STRINGIFY(x) `"x`"
|
`define STRINGIFY(x) `"x`"
|
||||||
|
|
||||||
module t;
|
module t;
|
||||||
|
logic [3:0] zero4 = 4'b0;
|
||||||
|
logic [3:0] small4 = 4'b0010;
|
||||||
|
logic [7:0] small8 = 8'h01;
|
||||||
|
logic [15:0] msb16 = 16'h8000;
|
||||||
int sig;
|
int sig;
|
||||||
|
logic [31:0] mid32 = 32'h0000_00a5;
|
||||||
|
logic [63:0] msb64 = 64'h8000_0000_0000_0000;
|
||||||
|
logic [99:0] wide_skip = 100'h1_0000_0000;
|
||||||
|
logic [67:0] wide_partial = 68'h2_0000_0000_0000_0000;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
sig = 10;
|
sig = 10;
|
||||||
$dumpfile(`STRINGIFY(`TEST_DUMPFILE));
|
$dumpfile(`STRINGIFY(`TEST_DUMPFILE));
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
-Info: t/t_trace_binary.v:14: $dumpvar ignored, as Verilated without --trace
|
-Info: t/t_trace_binary.v:23: $dumpvar ignored, as Verilated without --trace
|
||||||
*-* All Finished *-*
|
*-* All Finished *-*
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ int main(int argc, char** argv) {
|
||||||
top->clk = !top->clk;
|
top->clk = !top->clk;
|
||||||
top->eval();
|
top->eval();
|
||||||
tfp->dump((unsigned int)(main_time));
|
tfp->dump((unsigned int)(main_time));
|
||||||
|
if (main_time == 200) tfp->flush(); // Ensure rollover with shortened VCD values
|
||||||
++main_time;
|
++main_time;
|
||||||
}
|
}
|
||||||
tfp->close();
|
tfp->close();
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue