mirror of
https://github.com/verilator/verilator.git
synced 2026-08-29 01:13:53 +02:00
@@ -90,7 +90,7 @@ static inline constexpr unsigned bitPerEncodedBit(EncodingType type) {
|
||||
[[maybe_unused]]
|
||||
static const char* kEncodedBitToCharTable = (
|
||||
"01" // Binary
|
||||
"xzhu" // Verilog
|
||||
"zxhu" // Verilog
|
||||
"wl-? " // Vhdl (padded with ' ')
|
||||
);
|
||||
|
||||
|
||||
@@ -423,18 +423,26 @@ public:
|
||||
|
||||
void emitValueChange(uint64_t current_time_index, const uint32_t *val, EncodingType encoding) {
|
||||
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
||||
for (unsigned i = 0; i < bitPerEncodedBit(encoding); ++i) {
|
||||
// C++17: replace this with if constexpr
|
||||
if (sizeof(T) == 8) {
|
||||
// C++17: replace this with if constexpr
|
||||
if (sizeof(T) == 8) {
|
||||
if (encoding == EncodingType::VERILOG) {
|
||||
uint64_t v = val[2]; // high bits
|
||||
v <<= 32;
|
||||
v |= val[0]; // low bits
|
||||
wh.template write<uint64_t>(v);
|
||||
v = val[3]; // high bits
|
||||
v <<= 32;
|
||||
v |= val[1]; // low bits
|
||||
wh.template write<uint64_t>(v);
|
||||
} else {
|
||||
uint64_t v = val[1]; // high bits
|
||||
v <<= 32;
|
||||
v |= val[0]; // low bits
|
||||
wh.template write<uint64_t>(v);
|
||||
val += 2;
|
||||
} else {
|
||||
wh.template write<T>(val[0]);
|
||||
val += 1;
|
||||
}
|
||||
} else {
|
||||
wh.template write<T>(val[0]);
|
||||
if (encoding == EncodingType::VERILOG) wh.template write<T>(val[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,7 +525,7 @@ public:
|
||||
} else {
|
||||
unsigned val = 0;
|
||||
for (unsigned i = 0; i < num_element; ++i) {
|
||||
val |= rh.peek<T>(i);
|
||||
val |= rh.peek<T>(i) << i;
|
||||
}
|
||||
uint64_t delta_time_index = time_index - prev_time_index;
|
||||
prev_time_index = time_index;
|
||||
@@ -525,8 +533,8 @@ public:
|
||||
// clang-format off
|
||||
case 0: delta_time_index = (delta_time_index<<2) | (0<<1) | 0; break; // '0'
|
||||
case 1: delta_time_index = (delta_time_index<<2) | (1<<1) | 0; break; // '1'
|
||||
case 2: delta_time_index = (delta_time_index<<4) | (0<<1) | 1; break; // 'X'
|
||||
case 3: delta_time_index = (delta_time_index<<4) | (1<<1) | 1; break; // 'Z'
|
||||
case 2: delta_time_index = (delta_time_index<<4) | (1<<1) | 1; break; // 'Z'
|
||||
case 3: delta_time_index = (delta_time_index<<4) | (0<<1) | 1; break; // 'X'
|
||||
// Not supporting VHDL now
|
||||
// LCOV_EXCL_START
|
||||
case 4: delta_time_index = (delta_time_index<<4) | (2<<1) | 1; break; // 'H'
|
||||
@@ -556,13 +564,29 @@ public:
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
FST_CHECK(enc == EncodingType::BINARY); // TODO
|
||||
const bool has_non_binary = enc != EncodingType::BINARY;
|
||||
const uint64_t delta_time_index = time_index - prev_time_index;
|
||||
prev_time_index = time_index;
|
||||
h //
|
||||
.writeLEB128((delta_time_index << 1) | has_non_binary)
|
||||
.writeUIntPartialForValueChange(rh.peek<T>(), bitwidth);
|
||||
switch (enc) {
|
||||
case EncodingType::BINARY: {
|
||||
h //
|
||||
.writeLEB128(delta_time_index << 1)
|
||||
.writeUIntPartialForValueChange(rh.peek<T>(), bitwidth);
|
||||
} break;
|
||||
case EncodingType::VERILOG: {
|
||||
h.writeLEB128((delta_time_index << 1) | 1);
|
||||
const T val = rh.peek<T>();
|
||||
const T xz = rh.peek<T>(1);
|
||||
for (int j = bitwidth; j > 0;) {
|
||||
--j;
|
||||
h.writeUIntBE(
|
||||
kEncodedBitToCharTable[(((xz >> j) << 1) & 2) | ((val >> j) & 1)]
|
||||
);
|
||||
}
|
||||
} break;
|
||||
[[unlikely]] case EncodingType::VHDL: {
|
||||
FST_FAIL_STRING("VHDL format is unsupported with wide values");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
rh.skip(num_byte);
|
||||
}
|
||||
@@ -573,16 +597,26 @@ public:
|
||||
class VariableInfoLongInt {
|
||||
VariableInfo &info;
|
||||
unsigned num_words() const { return (info.bitwidth() + 63) / 64; }
|
||||
unsigned num_words32() const { return (info.bitwidth() + 31) / 32; }
|
||||
|
||||
public:
|
||||
VariableInfoLongInt(VariableInfo &info_) : info(info_) {}
|
||||
|
||||
public:
|
||||
size_t computeBytesNeededNoHeader(EncodingType encoding) const {
|
||||
switch (encoding) {
|
||||
case EncodingType::BINARY:
|
||||
return num_words() * sizeof(uint64_t);
|
||||
case EncodingType::VERILOG:
|
||||
return num_words32() * sizeof(uint32_t) * 2;
|
||||
[[unlikely]] case EncodingType::VHDL:
|
||||
FST_FAIL_STRING("VHDL format is unsupported with wide values");
|
||||
}
|
||||
FST_UNREACHABLE;
|
||||
}
|
||||
|
||||
size_t computeBytesNeeded(EncodingType encoding) const {
|
||||
return (
|
||||
kEmitTimeIndexAndEncodingSize +
|
||||
num_words() * sizeof(uint64_t) * bitPerEncodedBit(encoding)
|
||||
);
|
||||
return kEmitTimeIndexAndEncodingSize + computeBytesNeededNoHeader(encoding);
|
||||
}
|
||||
|
||||
EmitWriterHelper emitValueChangeCommonPart(uint64_t current_time_index, EncodingType encoding) {
|
||||
@@ -600,13 +634,12 @@ public:
|
||||
|
||||
public:
|
||||
void construct() {
|
||||
const size_t nw = num_words();
|
||||
const size_t nw = num_words32();
|
||||
info.resize(computeBytesNeeded(EncodingType::VERILOG));
|
||||
EmitWriterHelper wh(info.data_ptr());
|
||||
wh //
|
||||
.writeTimeIndexAndEncoding(0, EncodingType::VERILOG)
|
||||
.fill(uint64_t(0), nw)
|
||||
.fill(uint64_t(-1), nw);
|
||||
.fill(static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) << 32, nw);
|
||||
}
|
||||
|
||||
void emitValueChange(uint64_t current_time_index, const uint64_t val) {
|
||||
@@ -616,12 +649,12 @@ public:
|
||||
}
|
||||
|
||||
void emitValueChange(uint64_t current_time_index, const uint32_t *val, EncodingType encoding) {
|
||||
const unsigned nw32 = (info.bitwidth() + 31) / 32;
|
||||
const unsigned bpb = bitPerEncodedBit(encoding);
|
||||
const unsigned nw32 = num_words32();
|
||||
|
||||
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
||||
|
||||
for (unsigned i = 0; i < bpb; ++i) {
|
||||
switch (encoding) {
|
||||
case EncodingType::BINARY: {
|
||||
for (unsigned j = 0; j < nw32 / 2; ++j) {
|
||||
uint64_t v = val[1]; // high bits
|
||||
v <<= 32;
|
||||
@@ -634,13 +667,25 @@ public:
|
||||
wh.write(v);
|
||||
val += 1;
|
||||
}
|
||||
} break;
|
||||
case EncodingType::VERILOG: {
|
||||
for (unsigned j = 0; j < nw32; ++j) {
|
||||
uint64_t v = val[1]; // high bits
|
||||
v <<= 32;
|
||||
v |= val[0]; // low bits
|
||||
wh.write(v);
|
||||
val += 2;
|
||||
}
|
||||
} break;
|
||||
[[unlikely]] case EncodingType::VHDL:
|
||||
FST_FAIL_STRING("VHDL format is unsupported with wide values");
|
||||
}
|
||||
}
|
||||
|
||||
void emitValueChange(uint64_t current_time_index, const uint64_t *val, EncodingType encoding) {
|
||||
const unsigned nw_encoded = num_words() * bitPerEncodedBit(encoding);
|
||||
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
|
||||
wh.write(val, nw_encoded);
|
||||
FST_CHECK(encoding == EncodingType::BINARY);
|
||||
wh.write(val, num_words());
|
||||
}
|
||||
|
||||
void dumpInitialBits(std::vector<uint8_t> &buf) const {
|
||||
@@ -663,15 +708,16 @@ public:
|
||||
break;
|
||||
}
|
||||
case EncodingType::VERILOG: {
|
||||
for (unsigned word_index = nw; word_index-- > 0;) {
|
||||
const uint64_t v0 = rh.peek<uint64_t>(nw * 0 + word_index);
|
||||
const uint64_t v1 = rh.peek<uint64_t>(nw * 1 + word_index);
|
||||
for (unsigned word_index = num_words32(); word_index-- > 0;) {
|
||||
const uint64_t val = rh.peek<uint64_t>(word_index);
|
||||
const uint32_t aval = static_cast<uint32_t>(val);
|
||||
const uint32_t bval = static_cast<uint32_t>(val >> 32);
|
||||
const unsigned num_bit =
|
||||
(word_index * 64 + 64 > info.bitwidth()) ? (info.bitwidth() % 64) : 64;
|
||||
(word_index * 32 + 32 > info.bitwidth()) ? (info.bitwidth() % 32) : 32;
|
||||
for (unsigned bit_index = num_bit; bit_index-- > 0;) {
|
||||
const bool b0 = ((v0 >> bit_index) & uint64_t(1));
|
||||
const bool b1 = ((v1 >> bit_index) & uint64_t(1));
|
||||
const char c = kEncodedBitToCharTable[(b1 << 1) | b0];
|
||||
const bool a = ((aval >> bit_index) & 1);
|
||||
const bool b = ((bval >> bit_index) & 1);
|
||||
const char c = kEncodedBitToCharTable[(b << 1) | a];
|
||||
buf.push_back(c);
|
||||
}
|
||||
}
|
||||
@@ -717,33 +763,58 @@ public:
|
||||
FST_DCHECK_GT(tail, rh.ptr);
|
||||
const auto time_index = rh.read<uint64_t>();
|
||||
const auto enc = rh.read<EncodingType>();
|
||||
const auto num_element = bitPerEncodedBit(enc);
|
||||
const auto num_byte = num_element * nw * sizeof(uint64_t);
|
||||
const auto num_byte = computeBytesNeededNoHeader(enc);
|
||||
if (first) {
|
||||
// Note: [0] is initial value, which is already dumped in dumpInitialBits()
|
||||
first = false;
|
||||
} else {
|
||||
FST_CHECK(enc == EncodingType::BINARY); // TODO
|
||||
const bool has_non_binary = enc != EncodingType::BINARY;
|
||||
const uint64_t delta_time_index = time_index - prev_time_index;
|
||||
prev_time_index = time_index;
|
||||
h.writeLEB128((delta_time_index << 1) | has_non_binary);
|
||||
if (bitwidth % 64 != 0) {
|
||||
const unsigned remaining = bitwidth % 64;
|
||||
uint64_t hi64 = rh.peek<uint64_t>(nw - 1);
|
||||
// write from nw-1 to 1
|
||||
for (unsigned j = nw - 1; j > 0; --j) {
|
||||
uint64_t lo64 = rh.peek<uint64_t>(j - 1);
|
||||
h.writeUIntBE((hi64 << (64 - remaining)) | (lo64 >> remaining));
|
||||
hi64 = lo64;
|
||||
switch (enc) {
|
||||
case EncodingType::BINARY: {
|
||||
h.writeLEB128((delta_time_index << 1));
|
||||
if (bitwidth % 64 != 0) {
|
||||
const unsigned remaining = bitwidth % 64;
|
||||
uint64_t hi64 = rh.peek<uint64_t>(nw - 1);
|
||||
// write from nw-1 to 1
|
||||
for (unsigned j = nw - 1; j > 0; --j) {
|
||||
uint64_t lo64 = rh.peek<uint64_t>(j - 1);
|
||||
h.writeUIntBE((hi64 << (64 - remaining)) | (lo64 >> remaining));
|
||||
hi64 = lo64;
|
||||
}
|
||||
// write 0
|
||||
h.writeUIntPartialForValueChange(hi64, remaining);
|
||||
} else {
|
||||
// write from nw-1 to 0
|
||||
for (unsigned j = nw; j-- > 0;) {
|
||||
h.writeUIntBE(rh.peek<uint64_t>(j));
|
||||
}
|
||||
}
|
||||
// write 0
|
||||
h.writeUIntPartialForValueChange(hi64, remaining);
|
||||
} else {
|
||||
// write from nw-1 to 0
|
||||
for (unsigned j = nw; j-- > 0;) {
|
||||
h.writeUIntBE(rh.peek<uint64_t>(j));
|
||||
} break;
|
||||
case EncodingType::VERILOG: {
|
||||
h.writeLEB128((delta_time_index << 1) | 1);
|
||||
const int fullWords = (bitwidth / 32);
|
||||
if (int j = bitwidth % 32) {
|
||||
const uint64_t val = rh.peek<uint64_t>(fullWords);
|
||||
while (j > 0) {
|
||||
--j;
|
||||
const uint64_t v = val >> j;
|
||||
h.writeUIntBE(kEncodedBitToCharTable[((v >> 31) & 2) | (v & 1)]);
|
||||
}
|
||||
}
|
||||
for (size_t i = fullWords; i > 0;) {
|
||||
--i;
|
||||
const uint64_t val = rh.peek<uint64_t>(i);
|
||||
for (int j = 32; j > 0;) {
|
||||
--j;
|
||||
const uint64_t v = val >> j;
|
||||
h.writeUIntBE(kEncodedBitToCharTable[((v >> 31) & 2) | (v & 1)]);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
[[unlikely]] case EncodingType::VHDL: {
|
||||
FST_FAIL_STRING("VHDL format is unsupported with wide values");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
rh.skip(num_byte);
|
||||
|
||||
@@ -268,26 +268,55 @@ void Writer::emitValueChange(Handle handle, const char *val) {
|
||||
|
||||
// For normal integer handles, const char* is "01xz..." (1B per bit)
|
||||
const uint32_t bitwidth{var_info.bitwidth()};
|
||||
const bool hasXZ = // Detects A-Z and a-z but not 0-9 and NOT `-` `?`
|
||||
(std::accumulate(val, val + bitwidth, 0, [](int a, char b) { return a | b; }) & (1 << 6)) !=
|
||||
0;
|
||||
FST_DCHECK_NE(bitwidth, 0);
|
||||
|
||||
val += bitwidth;
|
||||
const unsigned num_words{(bitwidth + 63) / 64};
|
||||
m_packed_value_buffer_.assign(num_words, 0);
|
||||
m_packed_value_buffer_.assign(num_words << (hasXZ ? 1 : 0), 0);
|
||||
for (unsigned i = 0; i < num_words; ++i) {
|
||||
const char *start{val - std::min((i + 1) * 64, bitwidth)};
|
||||
const char *end{val - 64 * i};
|
||||
m_packed_value_buffer_[i] = 0;
|
||||
for (const char *p = start; p < end; ++p) {
|
||||
// No checking for invalid characters, follow original C implementation
|
||||
m_packed_value_buffer_[i] <<= 1;
|
||||
m_packed_value_buffer_[i] |= static_cast<uint64_t>(*p - '0');
|
||||
if (hasXZ) {
|
||||
const size_t j = i << 1;
|
||||
m_packed_value_buffer_[j] <<= 1;
|
||||
m_packed_value_buffer_[j | 1] <<= 1;
|
||||
switch (*p) {
|
||||
case '0':
|
||||
break;
|
||||
case '1': {
|
||||
m_packed_value_buffer_[i] |= 1;
|
||||
} break;
|
||||
case 'X':
|
||||
case 'x': {
|
||||
m_packed_value_buffer_[i] |= 1;
|
||||
} // FALLTHROUGH
|
||||
case 'Z':
|
||||
case 'z': {
|
||||
m_packed_value_buffer_[j | 1] |= 1;
|
||||
} break;
|
||||
[[unlikely]] default: { FST_FAIL_STRING("Unexpected char"); } break;
|
||||
}
|
||||
} else {
|
||||
m_packed_value_buffer_[i] <<= 1;
|
||||
m_packed_value_buffer_[i] |= static_cast<uint64_t>(*p - '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bitwidth <= 64) {
|
||||
if (bitwidth <= 64 && !hasXZ) {
|
||||
emitValueChange(handle, m_packed_value_buffer_.front());
|
||||
} else {
|
||||
emitValueChange(handle, m_packed_value_buffer_.data(), EncodingType::BINARY);
|
||||
emitValueChange(
|
||||
handle,
|
||||
m_packed_value_buffer_.data(),
|
||||
hasXZ ? EncodingType::VERILOG : EncodingType::BINARY
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,7 +634,7 @@ void detail::ValueChangeData::writeEncodedPositions(
|
||||
}
|
||||
|
||||
// encode as signed (value << 1) | 1 and write as signed LEB128
|
||||
h.writeLEB128Signed((value_to_encode << 1) | 1);
|
||||
h.writeLEB128Signed((static_cast<uint64_t>(value_to_encode) << 1) | 1);
|
||||
|
||||
++i;
|
||||
}
|
||||
@@ -695,7 +724,7 @@ void Writer::flushValueChangeDataConstPart_(
|
||||
(void)count;
|
||||
return std::make_pair(positions, memory_usage);
|
||||
}();
|
||||
const std::vector<int64_t> positions{p_tmp2.first};
|
||||
const std::vector<int64_t> positions{std::move(p_tmp2.first)};
|
||||
const size_t memory_usage{p_tmp2.second};
|
||||
|
||||
// 4. Position Section
|
||||
|
||||
Reference in New Issue
Block a user