diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index b8332dd..4629634 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -25,7 +25,7 @@ jobs: - name: Setup Verilator uses: veryl-lang/setup-verilator@v1 with: - version: '5.044' + version: '5.050' - name: Run tests run: ./run_regression.sh --coverage diff --git a/fstcpp/fstcpp.h b/fstcpp/fstcpp.h index e17b337..d8d5a9b 100644 --- a/fstcpp/fstcpp.h +++ b/fstcpp/fstcpp.h @@ -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 ' ') ); diff --git a/fstcpp/fstcpp_variable_info.h b/fstcpp/fstcpp_variable_info.h index 0074705..c5b4a4f 100644 --- a/fstcpp/fstcpp_variable_info.h +++ b/fstcpp/fstcpp_variable_info.h @@ -423,18 +423,26 @@ class VariableInfoScalarInt { 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) { - uint64_t v = val[1]; // high bits + // 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(v); - val += 2; + v = val[3]; // high bits + v <<= 32; + v |= val[1]; // low bits + wh.template write(v); } else { - wh.template write(val[0]); - val += 1; + uint64_t v = val[1]; // high bits + v <<= 32; + v |= val[0]; // low bits + wh.template write(v); } + } else { + wh.template write(val[0]); + if (encoding == EncodingType::VERILOG) wh.template write(val[1]); } } @@ -517,7 +525,7 @@ class VariableInfoScalarInt { } else { unsigned val = 0; for (unsigned i = 0; i < num_element; ++i) { - val |= rh.peek(i); + val |= rh.peek(i) << i; } uint64_t delta_time_index = time_index - prev_time_index; prev_time_index = time_index; @@ -525,8 +533,8 @@ class VariableInfoScalarInt { // 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 @@ class VariableInfoScalarInt { 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(), bitwidth); + switch (enc) { + case EncodingType::BINARY: { + h // + .writeLEB128(delta_time_index << 1) + .writeUIntPartialForValueChange(rh.peek(), bitwidth); + } break; + case EncodingType::VERILOG: { + h.writeLEB128((delta_time_index << 1) | 1); + const T val = rh.peek(); + const T xz = rh.peek(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 @@ class VariableInfoScalarInt { 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 @@ class VariableInfoLongInt { 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(std::numeric_limits::max()) << 32, nw); } void emitValueChange(uint64_t current_time_index, const uint64_t val) { @@ -616,12 +649,12 @@ class VariableInfoLongInt { } 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 @@ class VariableInfoLongInt { 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 &buf) const { @@ -663,15 +708,16 @@ class VariableInfoLongInt { break; } case EncodingType::VERILOG: { - for (unsigned word_index = nw; word_index-- > 0;) { - const uint64_t v0 = rh.peek(nw * 0 + word_index); - const uint64_t v1 = rh.peek(nw * 1 + word_index); + for (unsigned word_index = num_words32(); word_index-- > 0;) { + const uint64_t val = rh.peek(word_index); + const uint32_t aval = static_cast(val); + const uint32_t bval = static_cast(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 @@ class VariableInfoLongInt { FST_DCHECK_GT(tail, rh.ptr); const auto time_index = rh.read(); const auto enc = rh.read(); - 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(nw - 1); - // write from nw-1 to 1 - for (unsigned j = nw - 1; j > 0; --j) { - uint64_t lo64 = rh.peek(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(nw - 1); + // write from nw-1 to 1 + for (unsigned j = nw - 1; j > 0; --j) { + uint64_t lo64 = rh.peek(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(j)); + } } - // write 0 - h.writeUIntPartialForValueChange(hi64, remaining); - } else { - // write from nw-1 to 0 - for (unsigned j = nw; j-- > 0;) { - h.writeUIntBE(rh.peek(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(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(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); diff --git a/fstcpp/fstcpp_variable_info.test.cpp b/fstcpp/fstcpp_variable_info.test.cpp index 8558579..3fdab29 100644 --- a/fstcpp/fstcpp_variable_info.test.cpp +++ b/fstcpp/fstcpp_variable_info.test.cpp @@ -55,6 +55,37 @@ TEST(VariableInfoTest, writeInitialBits_Double) { memcpy(&val, buf.data(), sizeof(double)); EXPECT_DOUBLE_EQ(val, 1.0); } + +TEST(VariableInfoTest, writeInitialVerilog_ScalarInt) { + VariableInfo vi{4}; + const uint32_t val[] = {0b1010, 0b0011}; + vi.emitValueChange(0, val, fst::EncodingType::VERILOG); + vi.keepOnlyTheLatestValue(); + vector buf{}; + vi.dumpInitialBits(buf); + EXPECT_EQ(V2S(buf), "10xz"); +} + +TEST(VariableInfoTest, writeInitialVerilog_ScalarInt64) { + VariableInfo vi{64}; + const uint64_t val[] = {0b1010, 0b0011}; + vi.emitValueChange(0, val, fst::EncodingType::VERILOG); + vi.keepOnlyTheLatestValue(); + vector buf{}; + vi.dumpInitialBits(buf); + EXPECT_EQ(V2S(buf), std::string(60, '0') + "10xz"); +} + +TEST(VariableInfoTest, writeInitialVerilog_LongInt) { + VariableInfo vi{70}; + const uint32_t val[] = {0, 0, 0b1010, 0b0011, 0, 0}; + vi.emitValueChange(0, val, fst::EncodingType::VERILOG); + vi.keepOnlyTheLatestValue(); + vector buf{}; + vi.dumpInitialBits(buf); + const string expected{string(34, '0') + "10xz" + string(32, '0')}; + EXPECT_EQ(V2S(buf), expected); +} ///////////////////////////// // dumpValueChanges ///////////////////////////// @@ -119,6 +150,142 @@ TEST(VariableInfoTest, dumpValueChange_LongInt_Binary) { "\x06\x01\x23\x45\x67\x89\x0a\xbc\xde\xf0"s ); } +TEST(VariableInfoTest, dumpValueChange_ScalarInt_1bit_Verilog) { + VariableInfo vi{1}; + uint32_t val[] = {0, 0}; + vi.emitValueChange(1, val, fst::EncodingType::VERILOG); + val[0] = 1; + vi.emitValueChange(2, val, fst::EncodingType::VERILOG); + val[1] = 1; + vi.emitValueChange(3, val, fst::EncodingType::VERILOG); + val[0] = 0; + vi.emitValueChange(4, val, fst::EncodingType::VERILOG); + val[1] = 0; + vi.emitValueChange(5, val, fst::EncodingType::VERILOG); + vector buf{}; + vi.dumpValueChanges(buf); + // Encoding time_index_delta << 2 | (bit << 1) | 0 in binary mode + // (1-0) << 2 | 0b00 + // (2-1) << 2 | 0b10 + // (3-2) << 4 | 0b01 + // (4-3) << 4 | 0b11 + // (5-4) << 2 | 0b00 + EXPECT_EQ(V2S(buf), "\x04\x06\x11\x13\x04"s); +} + +TEST(VariableInfoTest, dumpValueChange_ScalarInt_2bit_Verilog) { + VariableInfo vi{2}; + uint32_t val[] = {0, 0}; + vi.emitValueChange(1, val, fst::EncodingType::VERILOG); + val[1] = 1; + vi.emitValueChange(3, val, fst::EncodingType::VERILOG); + val[1] = 3; + vi.emitValueChange(5, val, fst::EncodingType::VERILOG); + val[1] = 2; + vi.emitValueChange(7, val, fst::EncodingType::VERILOG); + val[0] = 1; + vi.emitValueChange(10, val, fst::EncodingType::VERILOG); + val[1] = 3; + vi.emitValueChange(11, val, fst::EncodingType::VERILOG); + val[1] = 1; + vi.emitValueChange(13, val, fst::EncodingType::VERILOG); + val[1] = 0; + vi.emitValueChange(15, val, fst::EncodingType::VERILOG); + val[0] = 3; + vi.emitValueChange(17, val, fst::EncodingType::VERILOG); + val[1] = 1; + vi.emitValueChange(20, val, fst::EncodingType::VERILOG); + val[1] = 3; + vi.emitValueChange(21, val, fst::EncodingType::VERILOG); + val[1] = 2; + vi.emitValueChange(23, val, fst::EncodingType::VERILOG); + val[0] = 2; + vi.emitValueChange(25, val, fst::EncodingType::VERILOG); + val[1] = 3; + vi.emitValueChange(27, val, fst::EncodingType::VERILOG); + val[1] = 1; + vi.emitValueChange(30, val, fst::EncodingType::VERILOG); + val[1] = 0; + vi.emitValueChange(31, val, fst::EncodingType::VERILOG); + val[0] = 0; + vi.emitValueChange(33, val, fst::EncodingType::VERILOG); + vector buf{}; + vi.dumpValueChanges(buf); + // 1. Varint encoding of (Time_index_delta << 1) | 1 + // 2. Data encoding as chars + EXPECT_EQ(buf, (std::vector{0x03, '0', '0', 0x05, '0', 'z', 0x05, 'z', 'z', + 0x05, 'z', '0', 0x07, 'z', '1', 0x03, 'z', 'x', + 0x05, '0', 'x', 0x05, '0', '1', 0x05, '1', '1', + 0x07, '1', 'x', 0x03, 'x', 'x', 0x05, 'x', '1', + 0x05, 'x', '0', 0x05, 'x', 'z', 0x07, '1', 'z', + 0x03, '1', '0', 0x05, '0', '0'})); +} + +TEST(VariableInfoTest, dumpValueChange_ScalarInt_10bit_Verilog) { + VariableInfo vi{10}; + uint64_t val[] = {0, 0}; + vi.emitValueChange(1, val, fst::EncodingType::VERILOG); + val[0] = 1; + vi.emitValueChange(3, val, fst::EncodingType::VERILOG); + val[1] = 5; + vi.emitValueChange(5, val, fst::EncodingType::VERILOG); + val[0] = 37; + vi.emitValueChange(7, val, fst::EncodingType::VERILOG); + val[1] = 0; + vi.emitValueChange(8, val, fst::EncodingType::VERILOG); + val[0] = 0; + vi.emitValueChange(10, val, fst::EncodingType::VERILOG); + vector buf{}; + vi.dumpValueChanges(buf); + // 1. Varint encoding of Time_index_delta << 1 | 1 since it contains only 0 and 1 + // 2. data encoded as raw bits,aligned with MSB and packed into a whole number of bytes + EXPECT_EQ(buf, (std::vector{0x03, '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + 0x05, '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', + 0x05, '0', '0', '0', '0', '0', '0', '0', 'z', '0', 'x', + 0x05, '0', '0', '0', '0', '1', '0', '0', 'x', '0', 'x', + 0x03, '0', '0', '0', '0', '1', '0', '0', '1', '0', '1', + 0x05, '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'})); +} + +TEST(VariableInfoTest, dumpValueChange_ScalarInt_64bit_Verilog) { + VariableInfo vi{64}; + const uint64_t val[] = {5, 3}; + vi.emitValueChange(1, val, fst::EncodingType::VERILOG); + vector buf{}; + vi.dumpValueChanges(buf); + // 1. Varint encoding of Time_index_delta << 1 | 1 since it contains only 0 and 1 + // 2. data encoded as raw bits,aligned with MSB and packed into a whole number of bytes + EXPECT_EQ(V2S(buf), "\x03"s + std::string(61, '0') + "1zx"); +} + +TEST(VariableInfoTest, dumpValueChange_ScalarInt_64bit_Verilog2) { + VariableInfo vi{64}; + const uint32_t val[] = {5, 3, 0, 0}; + vi.emitValueChange(1, val, fst::EncodingType::VERILOG); + vector buf{}; + vi.dumpValueChanges(buf); + // 1. Varint encoding of Time_index_delta << 1 | 1 since it contains only 0 and 1 + // 2. data encoded as raw bits,aligned with MSB and packed into a whole number of bytes + EXPECT_EQ(V2S(buf), "\x03"s + std::string(61, '0') + "1zx"); +} + +TEST(VariableInfoTest, dumpValueChange_LongInt_Verilog) { + VariableInfo vi{68}; + uint32_t val[] = {0, 0, 0, 0, 0, 0}; + vi.emitValueChange(2, val, fst::EncodingType::VERILOG); + val[2] = 0b0101; + val[3] = 0b0011; + vi.emitValueChange(5, val, fst::EncodingType::VERILOG); + vector buf{}; + vi.dumpValueChanges(buf); + std::vector result(138, '0'); + result[0] = 0x05; + result[69] = 0x07; + result[105] = 'x'; + result[104] = 'z'; + result[103] = '1'; + EXPECT_EQ(buf, result); +} // LCOV_EXCL_START TEST(VariableInfoTest, DISABLED_dumpValueChange_Double_Binary) { diff --git a/fstcpp/fstcpp_writer.cpp b/fstcpp/fstcpp_writer.cpp index 386a761..4a31c3a 100644 --- a/fstcpp/fstcpp_writer.cpp +++ b/fstcpp/fstcpp_writer.cpp @@ -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(*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(*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(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 positions{p_tmp2.first}; + const std::vector positions{std::move(p_tmp2.first)}; const size_t memory_usage{p_tmp2.second}; // 4. Position Section diff --git a/integration_test/setup_runtime.sh b/integration_test/setup_runtime.sh index 233ae68..3a220b9 100755 --- a/integration_test/setup_runtime.sh +++ b/integration_test/setup_runtime.sh @@ -31,17 +31,19 @@ cp -r "$SOURCE_DIR"/*.cpp "$SOURCE_DIR"/*.h "$SOURCE_DIR"/vltstd "$VERILATOR_SHA # Filter files (Whitelisting): Remove files containing _sc _vcd, followed by . or _ rm -rf "$VERILATOR_SHARE"/*_sc[._]* "$VERILATOR_SHARE"/*_vcd[._]* -# Apply patches in verilator_share -echo "=== Applying patches in $VERILATOR_SHARE/ ===" -for patch_file in "$VERILATOR_SHARE"/*.patch; do - if [ -f "$patch_file" ]; then - target="${patch_file%.patch}" - echo "Applying patch: $patch_file -> $target" - # We use -f to force apply even if it seems already applied (e.g. if script rerun) - # But actually, since we just copied fresh files from SOURCE_DIR, they are NOT patched yet. - patch "$target" < "$patch_file" - fi -done +# Apply patches in verilator_share if Verilator is not already using fstcpp +if [ ! -d "${SOURCE_DIR}/fstcpp" ]; then + echo "=== Applying patches in $VERILATOR_SHARE/ ===" + for patch_file in "$VERILATOR_SHARE"/*.patch; do + if [ -f "$patch_file" ]; then + target="${patch_file%.patch}" + echo "Applying patch: $patch_file -> $target" + # We use -f to force apply even if it seems already applied (e.g. if script rerun) + # But actually, since we just copied fresh files from SOURCE_DIR, they are NOT patched yet. + patch "$target" < "$patch_file" + fi + done +fi echo "=== Generating Verilated files for integration tests ===" for test_dir in tests/*; do