From 1c9263a25b4a3fc0ab3286262305f42e3acb2bdb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 5 Sep 2022 15:20:08 -0400 Subject: [PATCH 01/25] Commentary --- docs/guide/simulating.rst | 6 +++--- test_regress/t/t_EXAMPLE.v | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index 01dd7f844..7209a0a19 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -7,9 +7,9 @@ Simulating (Verilated-Model Runtime) ************************************ -This section describes items related to simulating, that using a Verilated -model's executable. For the runtime arguments to a simulated model, see -:ref:`Simulation Runtime Arguments`. +This section describes items related to simulating, that is, the use of a +Verilated model's executable. For the runtime arguments to a simulated +model, see :ref:`Simulation Runtime Arguments`. .. _Benchmarking & Optimization: diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index 0e3a9b428..236e0f85d 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -13,7 +13,7 @@ // please note it here, otherwise:** // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2022 by ____YOUR_NAME_HERE____. +// any use, without warranty, 2022 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 module t(/*AUTOARG*/ From 1af046986d3aeb1daa7d0f96e9c17a46fe214d5f Mon Sep 17 00:00:00 2001 From: Mladen Slijepcevic <77167949+mslijepc@users.noreply.github.com> Date: Tue, 6 Sep 2022 00:42:12 +0200 Subject: [PATCH 02/25] Fix thread saftey in SystemC VL_ASSIGN_SBW/WSB (#3494) (#3513). --- docs/CONTRIBUTORS | 1 + include/verilated_funcs.h | 46 ++++-- test_regress/t/t_var_sc_bv.cpp | 220 +++++++++++++++++++++++++++++ test_regress/t/t_var_sc_bv.pl | 24 ++++ test_regress/t/t_var_sc_bv.v | 246 +++++++++++++++++++++++++++++++++ 5 files changed, 522 insertions(+), 15 deletions(-) create mode 100644 test_regress/t/t_var_sc_bv.cpp create mode 100755 test_regress/t/t_var_sc_bv.pl create mode 100644 test_regress/t/t_var_sc_bv.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 9c10dbb6f..83ab9f830 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -82,6 +82,7 @@ Michael Killough Michaël Lefebvre Mike Popoloski Miodrag Milanović +Mladen Slijepcevic Morten Borup Petersen Mostafa Gamal Nandu Raj diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index a7c3fcc73..acba15530 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -446,14 +446,21 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE { { (vvar) = VL_CLEAN_QQ((obits), (obits), (svar).read().to_uint64()); } #define VL_ASSIGN_WSB(obits, owp, svar) \ { \ - const int words = VL_WORDS_I(obits); \ - sc_biguint<(obits)> _butemp = (svar).read(); \ - for (int i = 0; i < words; ++i) { \ - int msb = ((i + 1) * VL_IDATASIZE) - 1; \ - msb = (msb >= (obits)) ? ((obits)-1) : msb; \ - (owp)[i] = _butemp.range(msb, i * VL_IDATASIZE).to_uint(); \ - } \ - (owp)[words - 1] &= VL_MASK_E(obits); \ + const int words = VL_WORDS_I(obits); \ + sc_biguint<(obits)> _butemp = (svar).read(); \ + uint32_t* chunk = _butemp.get_raw(); \ + int32_t lsb = 0; \ + while (lsb < obits - BITS_PER_DIGIT) { \ + const uint32_t data = *chunk; \ + ++chunk; \ + _vl_insert_WI(owp.data(), data, lsb+BITS_PER_DIGIT-1, lsb); \ + lsb += BITS_PER_DIGIT; \ + } \ + if (lsb < obits) { \ + const uint32_t msb_data = *chunk; \ + _vl_insert_WI(owp.data(), msb_data, obits-1, lsb); \ + } \ + (owp)[words - 1] &= VL_MASK_E(obits); \ } // Copying verilog format from systemc integers and bit vectors. @@ -492,15 +499,24 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE { { (svar).write(rd); } #define VL_ASSIGN_SBQ(obits, svar, rd) \ { (svar).write(rd); } +#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT #define VL_ASSIGN_SBW(obits, svar, rwp) \ { \ - sc_biguint<(obits)> _butemp; \ - for (int i = 0; i < VL_WORDS_I(obits); ++i) { \ - int msb = ((i + 1) * VL_IDATASIZE) - 1; \ - msb = (msb >= (obits)) ? ((obits)-1) : msb; \ - _butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \ - } \ - (svar).write(_butemp); \ + sc_biguint<(obits)> _butemp; \ + int32_t lsb = 0; \ + uint32_t* chunk = _butemp.get_raw(); \ + while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \ + static_assert(std::is_same::value, "IData and EData missmatch"); \ + const uint32_t data = VL_SEL_IWII(lsb+VL_SC_BITS_PER_DIGIT+1, (rwp).data(), lsb, VL_SC_BITS_PER_DIGIT); \ + *chunk = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \ + ++chunk; \ + lsb += VL_SC_BITS_PER_DIGIT; \ + } \ + if (lsb < (obits)) { \ + const uint32_t msb_data = VL_SEL_IWII((obits)+1, (rwp).data(), lsb, (obits) - lsb); \ + *chunk = msb_data & VL_MASK_E((obits) - lsb); \ + } \ + (svar).write(_butemp); \ } //=================================================================== diff --git a/test_regress/t/t_var_sc_bv.cpp b/test_regress/t/t_var_sc_bv.cpp new file mode 100644 index 000000000..d8324bf2f --- /dev/null +++ b/test_regress/t/t_var_sc_bv.cpp @@ -0,0 +1,220 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +#include VM_PREFIX_INCLUDE + +VM_PREFIX* tb = nullptr; +bool pass = true; + +double sc_time_stamp() { return 0; } + +void compare_signals(const sc_signal>& ls, const sc_signal>& rs) { + if (ls.read() != rs.read()) { + pass &= false; + VL_PRINTF("%%Error: Data missmatch in signals %s and %s\n", ls.name(), rs.name()); + } +} + +void compareWls(int obits, WDataInP const lwp, WDataInP const rwp) { + const int words = VL_WORDS_I(obits); + bool same = true; + + for (int i = 0; (i < (words - 1)); ++i) { + if (lwp[i] != rwp[i]) { same = false; } + } + if ((lwp[words - 1] & VL_MASK_E(obits)) != (rwp[words - 1] & VL_MASK_E(obits))) { + same = false; + } + + if (!same) { + pass &= false; + VL_PRINTF("%%Error: There is a difference in VlWide variable %d bits wide\n", obits); + } +} + +// old macro which is correct but has MT issue with range +#define VL_ASSIGN_SBW_MT_ISSUE(obits, svar, rwp) \ + { \ + sc_biguint<(obits)> _butemp; \ + for (int i = 0; i < VL_WORDS_I(obits); ++i) { \ + int msb = ((i + 1) * VL_IDATASIZE) - 1; \ + msb = (msb >= (obits)) ? ((obits)-1) : msb; \ + _butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \ + } \ + (svar).write(_butemp); \ + } + +#ifdef SYSTEMC_VERSION +int sc_main(int, char**) +#else +int main() +#endif +{ + Verilated::debug(0); + tb = new VM_PREFIX("tb"); + + VlWide<8> /*255:0*/ input_var; + VlWide<8> /*255:0*/ out_var; + + // msb is always set to F not to be false positive on checking equality + input_var.m_storage[0] = 0xF2341234; + input_var.m_storage[1] = 0xFEADBEEF; + input_var.m_storage[2] = 0xF5A5A5A5; + input_var.m_storage[3] = 0xF1B2C3D4; + input_var.m_storage[4] = 0xFFFFFFFF; + input_var.m_storage[5] = 0xFAAABBBB; + input_var.m_storage[6] = 0xF000AAAA; + input_var.m_storage[7] = 0xF0101010; + +#ifdef SYSTEMC_VERSION + // clang-format off + sc_signal> SC_NAMED(i_29_s), SC_NAMED(i_29_old_s), SC_NAMED(o_29_s), SC_NAMED(o_29_old_s), + SC_NAMED(i_30_s), SC_NAMED(i_30_old_s), SC_NAMED(o_30_s), SC_NAMED(o_30_old_s), + SC_NAMED(i_31_s), SC_NAMED(i_31_old_s), SC_NAMED(o_31_s), SC_NAMED(o_31_old_s), + SC_NAMED(i_32_s), SC_NAMED(i_32_old_s), SC_NAMED(o_32_s), SC_NAMED(o_32_old_s), + SC_NAMED(i_59_s), SC_NAMED(i_59_old_s), SC_NAMED(o_59_s), SC_NAMED(o_59_old_s), + SC_NAMED(i_60_s), SC_NAMED(i_60_old_s), SC_NAMED(o_60_s), SC_NAMED(o_60_old_s), + SC_NAMED(i_62_s), SC_NAMED(i_62_old_s), SC_NAMED(o_62_s), SC_NAMED(o_62_old_s), + SC_NAMED(i_64_s), SC_NAMED(i_64_old_s), SC_NAMED(o_64_s), SC_NAMED(o_64_old_s), + SC_NAMED(i_119_s), SC_NAMED(i_119_old_s), SC_NAMED(o_119_s), SC_NAMED(o_119_old_s), + SC_NAMED(i_120_s), SC_NAMED(i_120_old_s), SC_NAMED(o_120_s), SC_NAMED(o_120_old_s), + SC_NAMED(i_121_s), SC_NAMED(i_121_old_s), SC_NAMED(o_121_s), SC_NAMED(o_121_old_s), + SC_NAMED(i_127_s), SC_NAMED(i_127_old_s), SC_NAMED(o_127_s), SC_NAMED(o_127_old_s), + SC_NAMED(i_128_s), SC_NAMED(i_128_old_s), SC_NAMED(o_128_s), SC_NAMED(o_128_old_s), + SC_NAMED(i_255_s), SC_NAMED(i_255_old_s), SC_NAMED(o_255_s), SC_NAMED(o_255_old_s), + SC_NAMED(i_256_s), SC_NAMED(i_256_old_s), SC_NAMED(o_256_s), SC_NAMED(o_256_old_s); + + + tb->i_29(i_29_s); tb->i_29_old(i_29_old_s); tb->o_29(o_29_s); tb->o_29_old(o_29_old_s); + tb->i_30(i_30_s); tb->i_30_old(i_30_old_s); tb->o_30(o_30_s); tb->o_30_old(o_30_old_s); + tb->i_31(i_31_s); tb->i_31_old(i_31_old_s); tb->o_31(o_31_s); tb->o_31_old(o_31_old_s); + tb->i_32(i_32_s); tb->i_32_old(i_32_old_s); tb->o_32(o_32_s); tb->o_32_old(o_32_old_s); + tb->i_59(i_59_s); tb->i_59_old(i_59_old_s); tb->o_59(o_59_s); tb->o_59_old(o_59_old_s); + tb->i_60(i_60_s); tb->i_60_old(i_60_old_s); tb->o_60(o_60_s); tb->o_60_old(o_60_old_s); + tb->i_62(i_62_s); tb->i_62_old(i_62_old_s); tb->o_62(o_62_s); tb->o_62_old(o_62_old_s); + tb->i_64(i_64_s); tb->i_64_old(i_64_old_s); tb->o_64(o_64_s); tb->o_64_old(o_64_old_s); + tb->i_119(i_119_s); tb->i_119_old(i_119_old_s); tb->o_119(o_119_s); tb->o_119_old(o_119_old_s); + tb->i_120(i_120_s); tb->i_120_old(i_120_old_s); tb->o_120(o_120_s); tb->o_120_old(o_120_old_s); + tb->i_121(i_121_s); tb->i_121_old(i_121_old_s); tb->o_121(o_121_s); tb->o_121_old(o_121_old_s); + tb->i_127(i_127_s); tb->i_127_old(i_127_old_s); tb->o_127(o_127_s); tb->o_127_old(o_127_old_s); + tb->i_128(i_128_s); tb->i_128_old(i_128_old_s); tb->o_128(o_128_s); tb->o_128_old(o_128_old_s); + tb->i_255(i_255_s); tb->i_255_old(i_255_old_s); tb->o_255(o_255_s); tb->o_255_old(o_255_old_s); + tb->i_256(i_256_s); tb->i_256_old(i_256_old_s); tb->o_256(o_256_s); tb->o_256_old(o_256_old_s); + + // clang-format on + +#endif + +// clang-format off +#ifdef SYSTEMC_VERSION + sc_start(1, SC_NS); +#else + tb->eval(); +#endif + // This testcase is testing multi-thread safe VL_ASSIGN_SBW and VL_ASSIGN_WSB macros. + // Testbench is assigning different number of bits from VlWide input_var variable to different inputs. + // Values around multiple of 30 (i.e. BITS_PER_DIGIT defined in SystemC sc_nbdefs.h) are tested with the special care, since + // it is the value by which the data_ptr of sc_biguint underlying data type is increased by (and not expected 32, as width of uint32_t). + // Correctness of the output is compared against the 'old' macro, which is correct but has multi-threaded issue since it's using range function. + // Second part is testing VL_ASSIGN_WSB in a reverse way, it is reading signals from the previous test, + // and comparing the output with (fraction) of VlWide input_var variable. + + // clang-format on + VL_ASSIGN_SBW(29, i_29_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(29, i_29_old_s, input_var); + VL_ASSIGN_SBW(30, i_30_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(30, i_30_old_s, input_var); + VL_ASSIGN_SBW(31, i_31_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(31, i_31_old_s, input_var); + VL_ASSIGN_SBW(32, i_32_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(32, i_32_old_s, input_var); + VL_ASSIGN_SBW(59, i_59_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(59, i_59_old_s, input_var); + VL_ASSIGN_SBW(60, i_60_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(60, i_60_old_s, input_var); + VL_ASSIGN_SBW(62, i_62_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(62, i_62_old_s, input_var); + VL_ASSIGN_SBW(64, i_64_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(64, i_64_old_s, input_var); + VL_ASSIGN_SBW(119, i_119_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(119, i_119_old_s, input_var); + VL_ASSIGN_SBW(120, i_120_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(120, i_120_old_s, input_var); + VL_ASSIGN_SBW(121, i_121_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(121, i_121_old_s, input_var); + VL_ASSIGN_SBW(127, i_127_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(127, i_127_old_s, input_var); + VL_ASSIGN_SBW(128, i_128_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(128, i_128_old_s, input_var); + VL_ASSIGN_SBW(255, i_255_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(255, i_255_old_s, input_var); + VL_ASSIGN_SBW(256, i_256_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(256, i_256_old_s, input_var); + +#ifdef SYSTEMC_VERSION + sc_start(1, SC_NS); +#else + tb->eval(); +#endif + compare_signals(o_29_s, o_29_old_s); + compare_signals(o_30_s, o_30_old_s); + compare_signals(o_31_s, o_31_old_s); + compare_signals(o_32_s, o_32_old_s); + compare_signals(o_59_s, o_59_old_s); + compare_signals(o_60_s, o_60_old_s); + compare_signals(o_62_s, o_62_old_s); + compare_signals(o_64_s, o_64_old_s); + compare_signals(o_119_s, o_119_old_s); + compare_signals(o_120_s, o_120_old_s); + compare_signals(o_121_s, o_121_old_s); + compare_signals(o_127_s, o_127_old_s); + compare_signals(o_128_s, o_128_old_s); + compare_signals(o_255_s, o_255_old_s); + compare_signals(o_256_s, o_256_old_s); + + //////////////////////////////// + + VL_ASSIGN_WSB(29, out_var, o_29_s); + compareWls(29, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(30, out_var, o_30_s); + compareWls(30, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(31, out_var, o_31_s); + compareWls(31, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(32, out_var, o_32_s); + compareWls(32, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(59, out_var, o_59_s); + compareWls(59, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(60, out_var, o_60_s); + compareWls(60, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(62, out_var, o_62_s); + compareWls(62, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(64, out_var, o_64_s); + compareWls(64, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(119, out_var, o_119_s); + compareWls(119, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(120, out_var, o_120_s); + compareWls(120, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(121, out_var, o_121_s); + compareWls(121, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(127, out_var, o_127_s); + compareWls(127, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(128, out_var, o_128_s); + compareWls(128, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(255, out_var, o_255_s); + compareWls(255, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(256, out_var, o_256_s); + compareWls(256, input_var.data(), out_var.data()); + + tb->final(); + VL_DO_DANGLING(delete tb, tb); + + if (pass) { + VL_PRINTF("*-* All Finished *-*\n"); + } else { + vl_fatal(__FILE__, __LINE__, "top", "Unexpected results from test\n"); + } + return 0; +} diff --git a/test_regress/t/t_var_sc_bv.pl b/test_regress/t/t_var_sc_bv.pl new file mode 100755 index 000000000..0091e49f0 --- /dev/null +++ b/test_regress/t/t_var_sc_bv.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe $Self->{t_dir}/t_var_sc_bv.cpp --sc -fno-inline"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_sc_bv.v b/test_regress/t/t_var_sc_bv.v new file mode 100644 index 000000000..d3164ee09 --- /dev/null +++ b/test_regress/t/t_var_sc_bv.v @@ -0,0 +1,246 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2008 by Lane Brooks. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Outputs + o_29,o_29_old, + o_30,o_30_old, + o_31,o_31_old, + o_32,o_32_old, + o_59,o_59_old, + o_60,o_60_old, + o_62,o_62_old, + o_64,o_64_old, + o_119,o_119_old, + o_120,o_120_old, + o_121,o_121_old, + o_127,o_127_old, + o_128,o_128_old, + o_255,o_255_old, + o_256,o_256_old, + // Inputs + i_29,i_29_old, + i_30,i_30_old, + i_31,i_31_old, + i_32,i_32_old, + i_59,i_59_old, + i_60,i_60_old, + i_62,i_62_old, + i_64,i_64_old, + i_119,i_119_old, + i_120,i_120_old, + i_121,i_121_old, + i_127,i_127_old, + i_128,i_128_old, + i_255,i_255_old, + i_256,i_256_old + ); + input [255:0] i_29; + output wire [255:0] o_29; + input [255:0] i_29_old; + output wire [255:0] o_29_old; + input [255:0] i_30; + output wire [255:0] o_30; + input [255:0] i_30_old; + output wire [255:0] o_30_old; + input [255:0] i_31; + output wire [255:0] o_31; + input [255:0] i_31_old; + output wire [255:0] o_31_old; + input [255:0] i_32; + output wire [255:0] o_32; + input [255:0] i_32_old; + output wire [255:0] o_32_old; + input [255:0] i_59; + output wire [255:0] o_59; + input [255:0] i_59_old; + output wire [255:0] o_59_old; + input [255:0] i_60; + output wire [255:0] o_60; + input [255:0] i_60_old; + output wire [255:0] o_60_old; + input [255:0] i_62; + output wire [255:0] o_62; + input [255:0] i_62_old; + output wire [255:0] o_62_old; + input [255:0] i_64; + output wire [255:0] o_64; + input [255:0] i_64_old; + output wire [255:0] o_64_old; + input [255:0] i_119; + output wire [255:0] o_119; + input [255:0] i_119_old; + output wire [255:0] o_119_old; + input [255:0] i_120; + output wire [255:0] o_120; + input [255:0] i_120_old; + output wire [255:0] o_120_old; + input [255:0] i_121; + output wire [255:0] o_121; + input [255:0] i_121_old; + output wire [255:0] o_121_old; + input [255:0] i_127; + output wire [255:0] o_127; + input [255:0] i_127_old; + output wire [255:0] o_127_old; + input [255:0] i_128; + output wire [255:0] o_128; + input [255:0] i_128_old; + output wire [255:0] o_128_old; + input [255:0] i_255; + output wire [255:0] o_255; + input [255:0] i_255_old; + output wire [255:0] o_255_old; + input [255:0] i_256; + output wire [255:0] o_256; + input [255:0] i_256_old; + output wire [255:0] o_256_old; + + sub sub (.*); +endmodule + +module sub (/*AUTOARG*/ + // Outputs + o_29,o_29_old, + o_30,o_30_old, + o_31,o_31_old, + o_32,o_32_old, + o_59,o_59_old, + o_60,o_60_old, + o_62,o_62_old, + o_64,o_64_old, + o_119,o_119_old, + o_120,o_120_old, + o_121,o_121_old, + o_127,o_127_old, + o_128,o_128_old, + o_255,o_255_old, + o_256,o_256_old, + // Inputs + i_29,i_29_old, + i_30,i_30_old, + i_31,i_31_old, + i_32,i_32_old, + i_59,i_59_old, + i_60,i_60_old, + i_62,i_62_old, + i_64,i_64_old, + i_119,i_119_old, + i_120,i_120_old, + i_121,i_121_old, + i_127,i_127_old, + i_128,i_128_old, + i_255,i_255_old, + i_256,i_256_old + ); + + input [255:0] i_29; + output wire [255:0] o_29; + input [255:0] i_29_old; + output wire [255:0] o_29_old; + input [255:0] i_30; + output wire [255:0] o_30; + input [255:0] i_30_old; + output wire [255:0] o_30_old; + input [255:0] i_31; + output wire [255:0] o_31; + input [255:0] i_31_old; + output wire [255:0] o_31_old; + input [255:0] i_32; + output wire [255:0] o_32; + input [255:0] i_32_old; + output wire [255:0] o_32_old; + input [255:0] i_59; + output wire [255:0] o_59; + input [255:0] i_59_old; + output wire [255:0] o_59_old; + input [255:0] i_60; + output wire [255:0] o_60; + input [255:0] i_60_old; + output wire [255:0] o_60_old; + input [255:0] i_62; + output wire [255:0] o_62; + input [255:0] i_62_old; + output wire [255:0] o_62_old; + input [255:0] i_64; + output wire [255:0] o_64; + input [255:0] i_64_old; + output wire [255:0] o_64_old; + input [255:0] i_119; + output wire [255:0] o_119; + input [255:0] i_119_old; + output wire [255:0] o_119_old; + input [255:0] i_120; + output wire [255:0] o_120; + input [255:0] i_120_old; + output wire [255:0] o_120_old; + input [255:0] i_121; + output wire [255:0] o_121; + input [255:0] i_121_old; + output wire [255:0] o_121_old; + input [255:0] i_127; + output wire [255:0] o_127; + input [255:0] i_127_old; + output wire [255:0] o_127_old; + input [255:0] i_128; + output wire [255:0] o_128; + input [255:0] i_128_old; + output wire [255:0] o_128_old; + input [255:0] i_255; + output wire [255:0] o_255; + input [255:0] i_255_old; + output wire [255:0] o_255_old; + input [255:0] i_256; + output wire [255:0] o_256; + input [255:0] i_256_old; + output wire [255:0] o_256_old; + + assign o_29 = i_29; + assign o_29_old = i_29_old; + + assign o_30 = i_30; + assign o_30_old = i_30_old; + + assign o_31 = i_31; + assign o_31_old = i_31_old; + + assign o_32 = i_32; + assign o_32_old = i_32_old; + + assign o_59 = i_59; + assign o_59_old = i_59_old; + + assign o_60 = i_60; + assign o_60_old = i_60_old; + + assign o_62 = i_62; + assign o_62_old = i_62_old; + + assign o_64 = i_64; + assign o_64_old = i_64_old; + + assign o_119 = i_119; + assign o_119_old = i_119_old; + + assign o_120 = i_120; + assign o_120_old = i_120_old; + + assign o_121 = i_121; + assign o_121_old = i_121_old; + + assign o_127 = i_127; + assign o_127_old = i_127_old; + + assign o_128 = i_128; + assign o_128_old = i_128_old; + + assign o_255 = i_255; + assign o_255_old = i_255_old; + + assign o_256 = i_256; + assign o_256_old = i_256_old; + +endmodule From e94cdcf29c22fac332ca42fc711d0e186e7d8369 Mon Sep 17 00:00:00 2001 From: github action Date: Mon, 5 Sep 2022 22:43:09 +0000 Subject: [PATCH 03/25] Apply 'make format' --- include/verilated_funcs.h | 63 ++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index acba15530..8bcef8019 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -446,21 +446,21 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE { { (vvar) = VL_CLEAN_QQ((obits), (obits), (svar).read().to_uint64()); } #define VL_ASSIGN_WSB(obits, owp, svar) \ { \ - const int words = VL_WORDS_I(obits); \ - sc_biguint<(obits)> _butemp = (svar).read(); \ - uint32_t* chunk = _butemp.get_raw(); \ - int32_t lsb = 0; \ - while (lsb < obits - BITS_PER_DIGIT) { \ - const uint32_t data = *chunk; \ - ++chunk; \ - _vl_insert_WI(owp.data(), data, lsb+BITS_PER_DIGIT-1, lsb); \ - lsb += BITS_PER_DIGIT; \ - } \ - if (lsb < obits) { \ - const uint32_t msb_data = *chunk; \ - _vl_insert_WI(owp.data(), msb_data, obits-1, lsb); \ - } \ - (owp)[words - 1] &= VL_MASK_E(obits); \ + const int words = VL_WORDS_I(obits); \ + sc_biguint<(obits)> _butemp = (svar).read(); \ + uint32_t* chunk = _butemp.get_raw(); \ + int32_t lsb = 0; \ + while (lsb < obits - BITS_PER_DIGIT) { \ + const uint32_t data = *chunk; \ + ++chunk; \ + _vl_insert_WI(owp.data(), data, lsb + BITS_PER_DIGIT - 1, lsb); \ + lsb += BITS_PER_DIGIT; \ + } \ + if (lsb < obits) { \ + const uint32_t msb_data = *chunk; \ + _vl_insert_WI(owp.data(), msb_data, obits - 1, lsb); \ + } \ + (owp)[words - 1] &= VL_MASK_E(obits); \ } // Copying verilog format from systemc integers and bit vectors. @@ -499,24 +499,25 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE { { (svar).write(rd); } #define VL_ASSIGN_SBQ(obits, svar, rd) \ { (svar).write(rd); } -#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT +#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT #define VL_ASSIGN_SBW(obits, svar, rwp) \ { \ - sc_biguint<(obits)> _butemp; \ - int32_t lsb = 0; \ - uint32_t* chunk = _butemp.get_raw(); \ - while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \ - static_assert(std::is_same::value, "IData and EData missmatch"); \ - const uint32_t data = VL_SEL_IWII(lsb+VL_SC_BITS_PER_DIGIT+1, (rwp).data(), lsb, VL_SC_BITS_PER_DIGIT); \ - *chunk = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \ - ++chunk; \ - lsb += VL_SC_BITS_PER_DIGIT; \ - } \ - if (lsb < (obits)) { \ - const uint32_t msb_data = VL_SEL_IWII((obits)+1, (rwp).data(), lsb, (obits) - lsb); \ - *chunk = msb_data & VL_MASK_E((obits) - lsb); \ - } \ - (svar).write(_butemp); \ + sc_biguint<(obits)> _butemp; \ + int32_t lsb = 0; \ + uint32_t* chunk = _butemp.get_raw(); \ + while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \ + static_assert(std::is_same::value, "IData and EData missmatch"); \ + const uint32_t data = VL_SEL_IWII(lsb + VL_SC_BITS_PER_DIGIT + 1, (rwp).data(), lsb, \ + VL_SC_BITS_PER_DIGIT); \ + *chunk = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \ + ++chunk; \ + lsb += VL_SC_BITS_PER_DIGIT; \ + } \ + if (lsb < (obits)) { \ + const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \ + *chunk = msb_data & VL_MASK_E((obits)-lsb); \ + } \ + (svar).write(_butemp); \ } //=================================================================== From 361cef463372fdef59b8c1e2245de47988dac5b6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 7 Sep 2022 21:48:52 -0400 Subject: [PATCH 04/25] Fix pylint warnings. --- Makefile.in | 2 +- bin/verilator_difftree | 2 +- bin/verilator_gantt | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index fc9b6b1a9..6903e37f9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -391,7 +391,7 @@ yapf: FLAKE8 = flake8 FLAKE8_FLAGS = \ --extend-exclude=fastcov.py \ - --ignore=E123,E129,E251,E501,W503,W504,E701 + --ignore=E123,E129,E251,E402,E501,W503,W504,E701 PYLINT = pylint PYLINT_FLAGS = --disable=R0801 diff --git a/bin/verilator_difftree b/bin/verilator_difftree index 3e8315691..d7c65a28e 100755 --- a/bin/verilator_difftree +++ b/bin/verilator_difftree @@ -38,7 +38,7 @@ def diff_dir(a, b): anyfile = False for base in sorted(files.keys()): - if (not 'a' in files[base]) or (not 'b' in files[base]): + if ('a' not in files[base]) or ('b' not in files[base]): continue a = files[base]['a'] b = files[base]['b'] diff --git a/bin/verilator_gantt b/bin/verilator_gantt index 616af30dc..03a7a16af 100755 --- a/bin/verilator_gantt +++ b/bin/verilator_gantt @@ -149,7 +149,8 @@ def report(): for thread in Threads: # Make potentially multiple characters per column for start in Threads[thread]: - if not Threads[thread][start]: continue + if not Threads[thread][start]: + continue cpu = Threads[thread][start]['cpu'] elapsed = Threads[thread][start]['end'] - start if cpu not in Global['cpus']: From 5a1bcf97946cc683beb0186b3a752e981370d1ab Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 7 Sep 2022 22:04:57 -0400 Subject: [PATCH 05/25] Tests: Add lint-py checker --- Makefile.in | 2 +- test_regress/t/t_dist_lint_py.pl | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_dist_lint_py.pl diff --git a/Makefile.in b/Makefile.in index 6903e37f9..08271b047 100644 --- a/Makefile.in +++ b/Makefile.in @@ -394,7 +394,7 @@ FLAKE8_FLAGS = \ --ignore=E123,E129,E251,E402,E501,W503,W504,E701 PYLINT = pylint -PYLINT_FLAGS = --disable=R0801 +PYLINT_FLAGS = --score=n --disable=R0801 lint-py: -$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS) diff --git a/test_regress/t/t_dist_lint_py.pl b/test_regress/t/t_dist_lint_py.pl new file mode 100755 index 000000000..b0af4f6e6 --- /dev/null +++ b/test_regress/t/t_dist_lint_py.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(dist => 1); + +my $root = ".."; + +if (!-r "$root/.git") { + skip("Not in a git repository"); +} else { + my $cmd = "cd $root && make lint-py"; + my $out = `$cmd`; + my $first; + foreach my $line (split /\n+/, $out) { + next if $line =~ /^---/; + next if $line =~ /^flake8/; + next if $line =~ /^pylint/; + print "$line\n"; + if (!defined $first) { + $first = $line; + error("lint-py failed: ", $first); + } + } +} + +ok(1); +1; From 42283150d7847954ff0c359cfc71834adadd4368 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 7 Sep 2022 22:13:02 -0400 Subject: [PATCH 06/25] Actions: Use 22.04 for contrib action --- .github/workflows/contributor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/contributor.yml b/.github/workflows/contributor.yml index 627d00ab3..bbc00ce97 100644 --- a/.github/workflows/contributor.yml +++ b/.github/workflows/contributor.yml @@ -11,7 +11,7 @@ on: jobs: Test: name: "'docs/CONTRIBUTORS' was signed" - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - run: test_regress/t/t_dist_contributors.pl From 9a27004ae547757579a87734fd4bc4a26f90589a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 7 Sep 2022 22:49:09 -0400 Subject: [PATCH 07/25] Github actions: Avoid cpan cert expirations. --- ci/ci-install.bash | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/ci-install.bash b/ci/ci-install.bash index 4f61f06c4..576b39974 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -19,6 +19,9 @@ set -x cd $(dirname "$0")/.. +# Avoid occasional cpan failures "Issued certificate has expired." +export PERL_LWP_SSL_VERIFY_HOSTNAME=0 + fatal() { echo "ERROR: $(basename "$0"): $1" >&2; exit 1; } From 249feaae7ca78da5295c25a8aca565bbc41d8d1f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 7 Sep 2022 22:59:32 -0400 Subject: [PATCH 08/25] Tests: Remove lint-py, need ci package. --- test_regress/t/t_dist_lint_py.pl | 34 -------------------------------- 1 file changed, 34 deletions(-) delete mode 100755 test_regress/t/t_dist_lint_py.pl diff --git a/test_regress/t/t_dist_lint_py.pl b/test_regress/t/t_dist_lint_py.pl deleted file mode 100755 index b0af4f6e6..000000000 --- a/test_regress/t/t_dist_lint_py.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env perl -if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# Copyright 2022 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -scenarios(dist => 1); - -my $root = ".."; - -if (!-r "$root/.git") { - skip("Not in a git repository"); -} else { - my $cmd = "cd $root && make lint-py"; - my $out = `$cmd`; - my $first; - foreach my $line (split /\n+/, $out) { - next if $line =~ /^---/; - next if $line =~ /^flake8/; - next if $line =~ /^pylint/; - print "$line\n"; - if (!defined $first) { - $first = $line; - error("lint-py failed: ", $first); - } - } -} - -ok(1); -1; From 45d622e4bc3ceb8922aa60af2612806028b5309a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 8 Sep 2022 11:06:44 -0400 Subject: [PATCH 09/25] Github actions: Avoid cpan cert expirations. --- ci/ci-install.bash | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/ci-install.bash b/ci/ci-install.bash index 576b39974..2e7325cea 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -21,6 +21,7 @@ cd $(dirname "$0")/.. # Avoid occasional cpan failures "Issued certificate has expired." export PERL_LWP_SSL_VERIFY_HOSTNAME=0 +echo "check_certificate = off" >> ~/.wgetrc fatal() { echo "ERROR: $(basename "$0"): $1" >&2; exit 1; From 47e64535d6d3e1069e6acebfa828030f66e527c5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 11 Sep 2022 12:25:44 -0400 Subject: [PATCH 10/25] Commentary --- src/V3Waiver.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp index 42d222fe8..41a07c1ff 100644 --- a/src/V3Waiver.cpp +++ b/src/V3Waiver.cpp @@ -6,9 +6,10 @@ // //************************************************************************* // -// Copyright 2020 by Wilson Snyder. 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. +// Copyright 2020-2022 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // //************************************************************************* From 47262cd4ecc81eac363350f70085dada72ecd60b Mon Sep 17 00:00:00 2001 From: Gustav Svensk Date: Sun, 11 Sep 2022 18:33:31 +0200 Subject: [PATCH 11/25] Fix arguments in non-static method call (#3547) (#3582) --- src/V3Width.cpp | 1 + test_regress/t/t_class_method_str_literal.pl | 21 +++++++++++++++ test_regress/t/t_class_method_str_literal.v | 28 ++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100755 test_regress/t/t_class_method_str_literal.pl create mode 100644 test_regress/t/t_class_method_str_literal.v diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a9f784e06..9b85d5c12 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3218,6 +3218,7 @@ private: nodep->dtypeFrom(ftaskp); nodep->classOrPackagep(classp); if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + processFTaskRefArgs(nodep); } return; } diff --git a/test_regress/t/t_class_method_str_literal.pl b/test_regress/t/t_class_method_str_literal.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_class_method_str_literal.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_method_str_literal.v b/test_regress/t/t_class_method_str_literal.v new file mode 100644 index 000000000..3e5e9225d --- /dev/null +++ b/test_regress/t/t_class_method_str_literal.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + +class T; + function automatic void print_str(input string a_string); + $display(a_string); + endfunction + + static function automatic void static_print_str(input string a_string); + $display(a_string); + endfunction +endclass + + +initial begin + T t_c = new; + t_c.print_str("function though member"); + t_c.static_print_str("static function through member"); + T::static_print_str("static function through class"); + $write("*-* All Finished *-*\n"); + $finish; +end +endmodule From 752f425025d6ad36815ca181667aba4c9e8ea8fa Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 11 Sep 2022 13:05:13 -0400 Subject: [PATCH 12/25] Tests: Process/Semaphore/Mailbox testing (all fail until supported) --- src/V3Width.cpp | 2 +- test_regress/t/t_mailbox.out | 6 ++++-- test_regress/t/t_mailbox.v | 2 +- test_regress/t/t_mailbox_bad.out | 6 ++++++ test_regress/t/t_mailbox_bad.pl | 22 ++++++++++++++++++++++ test_regress/t/t_mailbox_bad.v | 17 +++++++++++++++++ test_regress/t/t_process.v | 8 ++++---- test_regress/t/t_process_bad.out | 10 ++++++++++ test_regress/t/t_process_bad.pl | 22 ++++++++++++++++++++++ test_regress/t/t_process_bad.v | 20 ++++++++++++++++++++ test_regress/t/t_semaphore.out | 3 +++ test_regress/t/t_semaphore.v | 8 +++++++- test_regress/t/t_semaphore_bad.out | 7 +++++++ test_regress/t/t_semaphore_bad.pl | 22 ++++++++++++++++++++++ test_regress/t/t_semaphore_bad.v | 17 +++++++++++++++++ 15 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 test_regress/t/t_mailbox_bad.out create mode 100755 test_regress/t/t_mailbox_bad.pl create mode 100644 test_regress/t/t_mailbox_bad.v create mode 100644 test_regress/t/t_process_bad.out create mode 100755 test_regress/t/t_process_bad.pl create mode 100644 test_regress/t/t_process_bad.v create mode 100644 test_regress/t/t_semaphore_bad.out create mode 100755 test_regress/t/t_semaphore_bad.pl create mode 100644 test_regress/t/t_semaphore_bad.v diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 9b85d5c12..7fdbf20f0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -538,7 +538,7 @@ private: || VN_IS(vdtypep, DynArrayDType) // || VN_IS(vdtypep, QueueDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Concatenation to form " - << vdtypep->prettyDTypeNameQ() << "data type"); + << vdtypep->prettyDTypeNameQ() << " data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); diff --git a/test_regress/t/t_mailbox.out b/test_regress/t/t_mailbox.out index 5a7cc1581..4d5432212 100644 --- a/test_regress/t/t_mailbox.out +++ b/test_regress/t/t_mailbox.out @@ -1,4 +1,6 @@ %Error: t/t_mailbox.v:20:4: Can't find typedef: 'mailbox' - 20 | mailbox m; + 20 | mailbox #(int) m; | ^~~~~~~ -%Error: Exiting due to +%Error: Internal Error: t/t_mailbox.v:20:14: ../V3LinkDot.cpp:#: Pin not under instance? + 20 | mailbox #(int) m; + | ^~~ diff --git a/test_regress/t/t_mailbox.v b/test_regress/t/t_mailbox.v index 21eadf323..06ea1f834 100644 --- a/test_regress/t/t_mailbox.v +++ b/test_regress/t/t_mailbox.v @@ -17,7 +17,7 @@ // endclass module t(/*AUTOARG*/); - mailbox m; + mailbox #(int) m; int msg; int out; diff --git a/test_regress/t/t_mailbox_bad.out b/test_regress/t/t_mailbox_bad.out new file mode 100644 index 000000000..4d5432212 --- /dev/null +++ b/test_regress/t/t_mailbox_bad.out @@ -0,0 +1,6 @@ +%Error: t/t_mailbox.v:20:4: Can't find typedef: 'mailbox' + 20 | mailbox #(int) m; + | ^~~~~~~ +%Error: Internal Error: t/t_mailbox.v:20:14: ../V3LinkDot.cpp:#: Pin not under instance? + 20 | mailbox #(int) m; + | ^~~ diff --git a/test_regress/t/t_mailbox_bad.pl b/test_regress/t/t_mailbox_bad.pl new file mode 100755 index 000000000..8de551634 --- /dev/null +++ b/test_regress/t/t_mailbox_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t_mailbox.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_mailbox_bad.v b/test_regress/t/t_mailbox_bad.v new file mode 100644 index 000000000..a8bcb84fc --- /dev/null +++ b/test_regress/t/t_mailbox_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + mailbox #(int) m; + + initial begin + m = new(4); + if (m.bad_method() != 0) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_process.v b/test_regress/t/t_process.v index f6ee27bac..0d495ab17 100644 --- a/test_regress/t/t_process.v +++ b/test_regress/t/t_process.v @@ -6,16 +6,16 @@ // Methods defined by IEEE: // class process; -// enum state { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED }; +// enum state { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED }; // UVM uses KILLED, FINISHED // static function process self(); // function state status(); // function void kill(); // task await(); // Warn as unsupported (no UVM library use) // function void suspend(); // Warn as unsupported (no UVM library use) // function void resume(); // Warn as unsupported (no UVM library use) -// function void srandom( int seed ); // Just ignore? -// function string get_randstate(); // Just ignore? -// function void set_randstate( string state ); // Just ignore? +// function void srandom( int seed ); // Operate on all proceses for now? +// function string get_randstate(); // Operate on all proceses for now? +// function void set_randstate( string state ); // Operate on all proceses for now? // endclass module t(/*AUTOARG*/); diff --git a/test_regress/t/t_process_bad.out b/test_regress/t/t_process_bad.out new file mode 100644 index 000000000..a4ada3778 --- /dev/null +++ b/test_regress/t/t_process_bad.out @@ -0,0 +1,10 @@ +%Error: t/t_process.v:22:4: Can't find typedef: 'process' + 22 | process p; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_process.v:26:20: Unsupported: 'process' + 26 | p = process::self(); + | ^~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link + 26 | p = process::self(); + | ^~~~~~~ diff --git a/test_regress/t/t_process_bad.pl b/test_regress/t/t_process_bad.pl new file mode 100755 index 000000000..7be24ae56 --- /dev/null +++ b/test_regress/t/t_process_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t_process.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_process_bad.v b/test_regress/t/t_process_bad.v new file mode 100644 index 000000000..d32afb72b --- /dev/null +++ b/test_regress/t/t_process_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + process p; + + initial begin + if (p != null) $stop; + p = process::self(); + if (p.bad_method() != 0) $stop; + + p.bad_method_2(); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_semaphore.out b/test_regress/t/t_semaphore.out index 21345fd35..76d60e04d 100644 --- a/test_regress/t/t_semaphore.out +++ b/test_regress/t/t_semaphore.out @@ -1,4 +1,7 @@ %Error: t/t_semaphore.v:17:4: Can't find typedef: 'semaphore' 17 | semaphore s; | ^~~~~~~~~ +%Error: t/t_semaphore.v:18:4: Can't find typedef: 'semaphore' + 18 | semaphore s2; + | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_semaphore.v b/test_regress/t/t_semaphore.v index 322a8541a..bc229ad75 100644 --- a/test_regress/t/t_semaphore.v +++ b/test_regress/t/t_semaphore.v @@ -13,8 +13,9 @@ // endclass module t(/*AUTOARG*/); - //From UVM: + // From UVM: semaphore s; + semaphore s2; int msg; initial begin @@ -30,6 +31,7 @@ module t(/*AUTOARG*/); s.put(2); if (s.try_get(2) <= 0) $stop; +`ifndef VERILATOR fork begin #10; // So later then get() starts below @@ -42,6 +44,10 @@ module t(/*AUTOARG*/); s.get(); end join +`endif + + s2 = new; + if (s2.try_get() != 0) $stop; $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_semaphore_bad.out b/test_regress/t/t_semaphore_bad.out new file mode 100644 index 000000000..76d60e04d --- /dev/null +++ b/test_regress/t/t_semaphore_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_semaphore.v:17:4: Can't find typedef: 'semaphore' + 17 | semaphore s; + | ^~~~~~~~~ +%Error: t/t_semaphore.v:18:4: Can't find typedef: 'semaphore' + 18 | semaphore s2; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_semaphore_bad.pl b/test_regress/t/t_semaphore_bad.pl new file mode 100755 index 000000000..92483cce2 --- /dev/null +++ b/test_regress/t/t_semaphore_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t_semaphore.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_semaphore_bad.v b/test_regress/t/t_semaphore_bad.v new file mode 100644 index 000000000..68e6ee38b --- /dev/null +++ b/test_regress/t/t_semaphore_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + semaphore s; + + initial begin + s = new(4); + if (s.bad_method() != 0) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 9b2266f68cc1b4f7b936d293b3f6ca6da3e1307e Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Mon, 12 Sep 2022 17:59:14 +0200 Subject: [PATCH 13/25] Internals: Remove usage of global state in V3EmitCFunc (#3615). No functional change intended. --- src/V3EmitCFunc.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 9d863c7e5..27af5ad6a 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -36,18 +36,20 @@ constexpr int EMITC_NUM_CONSTW = 8; class EmitCLazyDecls final : public VNVisitor { // NODE STATE/TYPES - // AstNode::user2() -> bool. Already emitted decl for symbols. - const VNUser2InUse m_inuser2; + // None allowed to support threaded emitting // MEMBERS std::unordered_set m_emittedManually; // Set of names already declared manually. EmitCBaseVisitor& m_emitter; // For access to file output bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic) + std::set m_emitted; // -> in set. Already emitted decl for symbols. // METHODS + bool declaredOnce(AstNode* nodep) { return m_emitted.insert(nodep).second; } + void lazyDeclare(AstCFunc* funcp) { // Already declared in this compilation unit - if (funcp->user2SetOnce()) return; + if (!declaredOnce(funcp)) return; // Check if this kind of function is lazily declared if (!(funcp->isMethod() && funcp->isLoose()) && !funcp->dpiImportPrototype()) return; // Already declared manually @@ -58,7 +60,7 @@ class EmitCLazyDecls final : public VNVisitor { } void lazyDeclareConstPoolVar(AstVar* varp) { - if (varp->user2SetOnce()) return; // Already declared + if (!declaredOnce(varp)) return; // Already declared const string nameProtect = m_emitter.topClassName() + "__ConstPool__" + varp->nameProtect(); m_emitter.puts("extern const "); @@ -106,8 +108,8 @@ public: m_emitter.puts(suffix); m_emitter.ensureNewLine(); } - void declared(AstCFunc* nodep) { nodep->user2SetOnce(); } - void reset() { AstNode::user2ClearTree(); } + void declared(AstCFunc* nodep) { m_emitted.insert(nodep); } + void reset() { m_emitted.clear(); } }; //###################################################################### From 4d49db48a39fccdb5c29c87d5c3f06405f62a27f Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Mon, 12 Sep 2022 18:00:41 +0200 Subject: [PATCH 14/25] Internals: Remove usage of user1 from EmitCTrace (#3617). No Functional change intended. --- src/V3EmitCImp.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 9bea7b2c0..b31e30b88 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -551,14 +551,13 @@ public: class EmitCTrace final : EmitCFunc { // NODE STATE/TYPES - // Cleared on netlist - // AstNode::user1() -> int. Enum number - const VNUser1InUse m_inuser1; + // None allowed to support threaded emitting // MEMBERS const bool m_slow; // Making slow file int m_enumNum = 0; // Enumeration number (whole netlist) V3UniqueNames m_uniqueNames; // For generating unique file names + std::unordered_map m_enumNumMap; // EnumDType to enumeration number // METHODS void openNextOutputFile() { @@ -710,10 +709,10 @@ class EmitCTrace final : EmitCFunc { // Skip over refs-to-refs, but stop before final ref so can get data type name // Alternatively back in V3Width we could push enum names from upper typedefs if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) { - int enumNum = enump->user1(); + int enumNum = m_enumNumMap[enump]; if (!enumNum) { enumNum = ++m_enumNum; - enump->user1(enumNum); + m_enumNumMap[enump] = enumNum; int nvals = 0; puts("{\n"); puts("const char* " + protect("__VenumItemNames") + "[]\n"); From 08b6bdddf9e2f54ec36d1fcbe212521ed28ebc7c Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 12 Sep 2022 17:21:27 +0100 Subject: [PATCH 15/25] Update default --mod-prefix when --prefix is repeated Fixes #3603 --- src/V3Options.cpp | 5 +--- test_regress/t/t_flag_prefix.pl | 49 +++++++++++++++++++++++++++++++++ test_regress/t/t_flag_prefix.v | 35 +++++++++++++++++++++++ 3 files changed, 85 insertions(+), 4 deletions(-) create mode 100755 test_regress/t/t_flag_prefix.pl create mode 100755 test_regress/t/t_flag_prefix.v diff --git a/src/V3Options.cpp b/src/V3Options.cpp index d88f6df3c..e1f194e8b 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1270,10 +1270,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-pins-uint8", OnOff, &m_pinsUint8); DECL_OPTION("-pipe-filter", Set, &m_pipeFilter); DECL_OPTION("-pp-comments", OnOff, &m_ppComments); - DECL_OPTION("-prefix", CbVal, [this](const char* valp) { - m_prefix = valp; - if (m_modPrefix == "") m_modPrefix = m_prefix; - }); + DECL_OPTION("-prefix", Set, &m_prefix); DECL_OPTION("-private", CbCall, [this]() { m_public = false; }); DECL_OPTION("-prof-c", OnOff, &m_profC); DECL_OPTION("-prof-cfuncs", CbCall, [this]() { m_profC = m_profCFuncs = true; }); diff --git a/test_regress/t/t_flag_prefix.pl b/test_regress/t/t_flag_prefix.pl new file mode 100755 index 000000000..adcce742d --- /dev/null +++ b/test_regress/t/t_flag_prefix.pl @@ -0,0 +1,49 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Geza Lore. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--prefix t_flag_prefix", # should be overridden + "--prefix Vprefix", + "--exe", "--main", "--stats", "--build"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + +execute( + check_finished => 1, + executable => "$Self->{obj_dir}/Vprefix", + ); + +sub check_files { + foreach my $path (glob("$Self->{obj_dir}/*")) { + my $filename = substr $path, ((length $Self->{obj_dir}) + 1); + next if ($filename =~ /^.*\.log$/); + if ($filename =~ /t_flag_prefix/) { + error("bad filename $filename"); + next; + } + next if ($filename =~ /^(.*\.(o|a)|Vprefix)$/); + my $fh = IO::File->new("<$path") or error("$! $filenme"); + while (defined(my $line = $fh->getline)) { + $line =~ s/--prefix V?t_flag_prefix//g; + $line =~ s/obj_vlt\/t_flag_prefix//g; + $line =~ s/t\/t_flag_prefix\.v//g; + error("bad line in $filename: $line") if $line =~ /t_flag_prefix/; + } + } +} + +check_files(); + +ok(1); +1; diff --git a/test_regress/t/t_flag_prefix.v b/test_regress/t/t_flag_prefix.v new file mode 100755 index 000000000..00634520b --- /dev/null +++ b/test_regress/t/t_flag_prefix.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t; + sub sub(); +endmodule + +module sub; + // no_inline_module, so it goes into separate file + /* verilator no_inline_module */ + + // Goes into const pool which is separate file + wire bit [255:0] C = {32'h1111_1111, + 32'h2222_2222, + 32'h3333_3333, + 32'h4444_4444, + 32'h5555_5555, + 32'h6666_6666, + 32'h7777_7777, + 32'h8888_8888}; + + initial begin + // Note: Base index via $c to prevent optimization + $display("0x%32x", C[$c(0*32)+:32]); + $display("0x%32x", C[$c(2*32)+:32]); + $display("0x%32x", C[$c(4*32)+:32]); + $display("0x%32x", C[$c(6*32)+:32]); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 81fe35ee2e71ee8db894bb7e6bf5a490b2fdbb71 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Sep 2022 18:03:47 -0400 Subject: [PATCH 16/25] Fix typedef'ed class conversion to boolean (#3616). --- Changes | 3 ++- src/V3Width.cpp | 12 ++++++------ test_regress/t/t_class1.v | 6 ++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Changes b/Changes index 5cae1fc1c..202e279c2 100644 --- a/Changes +++ b/Changes @@ -13,7 +13,8 @@ Verilator 4.227 devel **Minor:** -Fix crash in gate optimization of circular logic (#3543). [Bill Flynn] +* Fix crash in gate optimization of circular logic (#3543). [Bill Flynn] +* Fix typedef'ed class conversion to boolean (#3616). [Aleksander Kiryk] Verilator 4.226 2022-08-31 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 7fdbf20f0..081fc526e 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5808,7 +5808,8 @@ private: "Node has no type"); // Perhaps forgot to do a prelim visit on it? // // For DOUBLE under a logical op, add implied test against zero, never a warning - if (underp && underp->isDouble()) { + AstNodeDType* const underVDTypep = underp ? underp->dtypep()->skipRefp() : nullptr; + if (underp && underVDTypep->isDouble()) { UINFO(6, " spliceCvtCmpD0: " << underp << endl); VNRelinker linker; underp->unlinkFrBack(&linker); @@ -5816,13 +5817,12 @@ private: = new AstNeqD(nodep->fileline(), underp, new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0)); linker.relink(newp); - } else if (VN_IS(underp->dtypep(), ClassRefDType) - || (VN_IS(underp->dtypep(), BasicDType) - && VN_AS(underp->dtypep(), BasicDType)->keyword() - == VBasicDTypeKwd::CHANDLE)) { + } else if (VN_IS(underVDTypep, ClassRefDType) + || (VN_IS(underVDTypep, BasicDType) + && VN_AS(underVDTypep, BasicDType)->keyword() == VBasicDTypeKwd::CHANDLE)) { // Allow warning-free "if (handle)" VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed - } else if (!underp->dtypep()->basicp()) { + } else if (!underVDTypep->basicp()) { nodep->v3error("Logical operator " << nodep->prettyTypeName() << " expects a non-complex data type on the " << side << "."); diff --git a/test_regress/t/t_class1.v b/test_regress/t/t_class1.v index b584c5be6..c10125c51 100644 --- a/test_regress/t/t_class1.v +++ b/test_regress/t/t_class1.v @@ -12,14 +12,20 @@ class Cls; endclass : Cls module t (/*AUTOARG*/); + typedef Cls Cls2; + initial begin Cls c; + Cls2 c2; if (c != null) $stop; if (c) $stop; + if (c2) $stop; $display("Display: null = \"%p\"", c); // null c = new; + c2 = new; if (c == null) $stop; if (!c) $stop; + if (!c2) $stop; $display("Display: newed = \"%p\"", c); // '{imembera:0, imemberb:0} c.imembera = 10; c.imemberb = 20; From 93a044f587cec70d67e2ee2dbebdc632843f5e41 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Tue, 13 Sep 2022 18:15:34 +0200 Subject: [PATCH 17/25] Internals: Rework addFilesp towards parallel emit (#3620). No functional change intended. --- src/V3EmitCBase.cpp | 4 ++-- src/V3EmitCBase.h | 2 +- src/V3EmitCImp.cpp | 45 ++++++++++++++++++++++++++++++++------------- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 1e3e9383f..40198fa76 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -57,11 +57,11 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod return name; } -AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source) { +AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source, bool add) { AstCFile* const cfilep = new AstCFile(v3Global.rootp()->fileline(), filename); cfilep->slow(slow); cfilep->source(source); - v3Global.rootp()->addFilesp(cfilep); + if (add) v3Global.rootp()->addFilesp(cfilep); return cfilep; } diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 66b954f35..2451cfdfc 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -100,7 +100,7 @@ public: && (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon } - static AstCFile* newCFile(const string& filename, bool slow, bool source); + static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true); string cFuncArgs(const AstCFunc* nodep); void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index b31e30b88..988a8b7fd 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -148,6 +148,7 @@ class EmitCImp final : EmitCFunc { const std::set* m_requiredHeadersp; // Header files required by output file std::string m_subFileName; // substring added to output filenames V3UniqueNames m_uniqueNames; // For generating unique file names + std::deque& m_cfilesr; // cfiles generated by this emit // METHODS void openNextOutputFile(const std::set& headers, const string& subFileName) { @@ -160,7 +161,8 @@ class EmitCImp final : EmitCFunc { // Unfortunately we have some lint checks here, so we can't just skip processing. // We should move them to a different stage. const string filename = VL_DEV_NULL; - newCFile(filename, /* slow: */ m_slow, /* source: */ true); + m_cfilesr.push_back( + newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false)); m_ofp = new V3OutCFile(filename); } else { string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp); @@ -170,7 +172,8 @@ class EmitCImp final : EmitCFunc { } if (m_slow) filename += "__Slow"; filename += ".cpp"; - newCFile(filename, /* slow: */ m_slow, /* source: */ true); + m_cfilesr.push_back( + newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false)); m_ofp = v3Global.opt.systemC() ? new V3OutScFile(filename) : new V3OutCFile(filename); } @@ -522,9 +525,10 @@ class EmitCImp final : EmitCFunc { EmitCFunc::visit(nodep); } - explicit EmitCImp(const AstNodeModule* modp, bool slow) + explicit EmitCImp(const AstNodeModule* modp, bool slow, std::deque& cfilesr) : m_fileModp{modp} - , m_slow{slow} { + , m_slow{slow} + , m_cfilesr{cfilesr} { UINFO(5, " Emitting implementation of " << prefixNameProtect(modp) << endl); m_modp = modp; @@ -543,7 +547,9 @@ class EmitCImp final : EmitCFunc { virtual ~EmitCImp() override = default; public: - static void main(const AstNodeModule* modp, bool slow) { EmitCImp{modp, slow}; } + static void main(const AstNodeModule* modp, bool slow, std::deque& cfilesr) { + EmitCImp{modp, slow, cfilesr}; + } }; //###################################################################### @@ -558,6 +564,7 @@ class EmitCTrace final : EmitCFunc { int m_enumNum = 0; // Enumeration number (whole netlist) V3UniqueNames m_uniqueNames; // For generating unique file names std::unordered_map m_enumNumMap; // EnumDType to enumeration number + std::deque& m_cfilesr; // cfiles generated by this emit // METHODS void openNextOutputFile() { @@ -572,8 +579,9 @@ class EmitCTrace final : EmitCFunc { if (m_slow) filename += "__Slow"; filename += ".cpp"; - AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/); + AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/, false /*add*/); cfilep->support(true); + m_cfilesr.push_back(cfilep); if (optSystemC()) { m_ofp = new V3OutScFile(filename); @@ -862,8 +870,9 @@ class EmitCTrace final : EmitCFunc { } } - explicit EmitCTrace(AstNodeModule* modp, bool slow) - : m_slow{slow} { + explicit EmitCTrace(AstNodeModule* modp, bool slow, std::deque& cfilesr) + : m_slow{slow} + , m_cfilesr{cfilesr} { m_modp = modp; // Open output file openNextOutputFile(); @@ -877,7 +886,9 @@ class EmitCTrace final : EmitCFunc { virtual ~EmitCTrace() override = default; public: - static void main(AstNodeModule* modp, bool slow) { EmitCTrace{modp, slow}; } + static void main(AstNodeModule* modp, bool slow, std::deque& cfilesr) { + EmitCTrace{modp, slow, cfilesr}; + } }; //###################################################################### @@ -887,19 +898,27 @@ void V3EmitC::emitcImp() { UINFO(2, __FUNCTION__ << ": " << endl); // Make parent module pointers available. const EmitCParentModule emitCParentModule; + std::list> cfiles; // Process each module in turn for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) { if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage const AstNodeModule* const modp = VN_AS(nodep, NodeModule); - EmitCImp::main(modp, /* slow: */ true); - EmitCImp::main(modp, /* slow: */ false); + cfiles.emplace_back(); + EmitCImp::main(modp, /* slow: */ true, cfiles.back()); + cfiles.emplace_back(); + EmitCImp::main(modp, /* slow: */ false, cfiles.back()); } // Emit trace routines (currently they can only exist in the top module) if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) { - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true); - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false); + cfiles.emplace_back(); + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true, cfiles.back()); + cfiles.emplace_back(); + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false, cfiles.back()); + } + for (const auto& collr : cfiles) { + for (const auto cfilep : collr) v3Global.rootp()->addFilesp(cfilep); } } From 25644844299af8f987ffdea7aa4859ff00c37065 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 13 Sep 2022 15:57:22 +0100 Subject: [PATCH 18/25] astgen: Rewrite in a more OOP way, in preparation for extensions Rely less on strings and represent AstNode classes as a 'class Node', with all associated properties kept together, rather than distributed over multiple dictionaries or constructed at retrieval time. No functional change intended. --- src/astgen | 362 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 203 insertions(+), 159 deletions(-) diff --git a/src/astgen b/src/astgen index 44529a0e4..f8860dce0 100755 --- a/src/astgen +++ b/src/astgen @@ -8,9 +8,125 @@ import re import sys # from pprint import pprint, pformat -Types = [] -Classes = {} -Children = {} + +class Node: + def __init__(self, name, superClass): + self._name = name + self._superClass = superClass + self._subClasses = [] # Initially list, but tuple after completion + self._allSuperClasses = None # Computed on demand after completion + self._allSubClasses = None # Computed on demand after completion + self._typeId = None # Concrete type identifier number for leaf classes + self._typeIdMin = None # Lowest type identifier number for class + self._typeIdMax = None # Highest type identifier number for class + + @property + def name(self): + return self._name + + @property + def superClass(self): + return self._superClass + + @property + def isCompleted(self): + return isinstance(self._subClasses, tuple) + + # Pre completion methods + def addSubClass(self, subClass): + assert not self.isCompleted + self._subClasses.append(subClass) + + # Computes derived properties over entire class hierarchy. + # No more changes to the hierarchy are allowed once this was called + def complete(self, typeId=0): + assert not self.isCompleted + # Sort sub-classes and convert to tuple, which marks completion + self._subClasses = tuple(sorted(self._subClasses, + key=lambda _: _.name)) + # Leaves + if self.isLeaf: + self._typeId = typeId + return typeId + 1 + + # Non-leaves + for subClass in self._subClasses: + typeId = subClass.complete(typeId) + return typeId + + # Post completion methods + @property + def subClasses(self): + assert self.isCompleted + return self._subClasses + + @property + def isRoot(self): + assert self.isCompleted + return self.superClass is None + + @property + def isLeaf(self): + assert self.isCompleted + return not self.subClasses + + @property + def allSuperClasses(self): + assert self.isCompleted + if self._allSuperClasses is None: + if self.superClass is None: + self._allSuperClasses = () + else: + self._allSuperClasses = self.superClass.allSuperClasses + ( + self.superClass, ) + return self._allSuperClasses + + @property + def allSubClasses(self): + assert self.isCompleted + if self._allSubClasses is None: + if self.isLeaf: + self._allSubClasses = () + else: + self._allSubClasses = self.subClasses + tuple( + _ for subClass in self.subClasses + for _ in subClass.allSubClasses) + return self._allSubClasses + + @property + def typeId(self): + assert self.isCompleted + assert self.isLeaf + return self._typeId + + @property + def typeIdMin(self): + assert self.isCompleted + if self.isLeaf: + return self.typeId + if self._typeIdMin is None: + self._typeIdMin = min(_.typeIdMin for _ in self.allSubClasses) + return self._typeIdMin + + @property + def typeIdMax(self): + assert self.isCompleted + if self.isLeaf: + return self.typeId + if self._typeIdMax is None: + self._typeIdMax = max(_.typeIdMax for _ in self.allSubClasses) + return self._typeIdMax + + def isSubClassOf(self, other): + assert self.isCompleted + if self is other: + return True + return self in other.allSubClasses + + +Nodes = {} +SortedNodes = None + ClassRefs = {} Stages = {} @@ -111,7 +227,7 @@ class Cpt: self.error("Can't parse from function: " + func) typen = match.group(1) subnodes = match.group(2) - if not subclasses_of(typen): + if Nodes[typen].isRoot: self.error("Unknown AstNode typen: " + typen + ": in " + func) mif = "" @@ -166,7 +282,7 @@ class Cpt: elif match_skip: typen = match_skip.group(1) self.tree_skip_visit[typen] = 1 - if typen not in Classes: + if typen not in Nodes: self.error("Unknown node type: " + typen) else: @@ -296,12 +412,13 @@ class Cpt: self.print( " // Bottom class up, as more simple transforms are generally better\n" ) - for typen in sorted(Classes.keys()): + for node in SortedNodes: out_for_type_sc = [] out_for_type = [] - bases = subclasses_of(typen) - bases.append(typen) - for base in bases: + classes = list(node.allSuperClasses) + classes.append(node) + for base in classes: + base = base.name if base not in self.treeop: continue for typefunc in self.treeop[base]: @@ -328,23 +445,23 @@ class Cpt: if len(out_for_type_sc) > 0: # Short-circuited types self.print( " // Generated by astgen with short-circuiting\n" + - " virtual void visit(Ast" + typen + + " virtual void visit(Ast" + node.name + "* nodep) override {\n" + " iterateAndNextNull(nodep->lhsp());\n" + "".join(out_for_type_sc)) if out_for_type[0]: self.print(" iterateAndNextNull(nodep->rhsp());\n") - if is_subclass_of(typen, "NodeTriop"): + if node.isSubClassOf(Nodes["NodeTriop"]): self.print( " iterateAndNextNull(nodep->thsp());\n") self.print("".join(out_for_type) + " }\n") elif len(out_for_type) > 0: # Other types with something to print - skip = typen in self.tree_skip_visit + skip = node.name in self.tree_skip_visit gen = "Gen" if skip else "" override = "" if skip else " override" self.print( " // Generated by astgen\n" + " virtual void visit" + - gen + "(Ast" + typen + "* nodep)" + override + " {\n" + + gen + "(Ast" + node.name + "* nodep)" + override + " {\n" + ("" if skip else " iterateChildren(nodep);\n") + ''.join(out_for_type) + " }\n") @@ -368,11 +485,13 @@ def read_types(filename): if re.search(r'Ast', supern) or classn == "AstNode": classn = re.sub(r'^Ast', '', classn) supern = re.sub(r'^Ast', '', supern) - Classes[classn] = supern - if supern != '': - if supern not in Children: - Children[supern] = {} - Children[supern][classn] = 1 + if supern: + superClass = Nodes[supern] + node = Node(classn, superClass) + Nodes[supern].addSubClass(node) + else: + node = Node(classn, None) + Nodes[classn] = node def read_stages(filename): @@ -424,37 +543,6 @@ def open_file(filename): return fh -def subclasses_of(typen): - cllist = [] - subclass = Classes[typen] - while True: - if subclass not in Classes: - break - cllist.append(subclass) - subclass = Classes[subclass] - - cllist.reverse() - return cllist - - -def children_of(typen): - cllist = [] - todo = [] - todo.append(typen) - while len(todo) != 0: - subclass = todo.pop(0) - if subclass in Children: - for child in sorted(Children[subclass].keys()): - todo.append(child) - cllist.append(child) - - return cllist - - -def is_subclass_of(typen, what): - return typen == what or (typen in children_of(what)) - - # --------------------------------------------------------------------- @@ -468,20 +556,19 @@ def write_report(filename): fh.write(" " + classn + "\n") fh.write("\nClasses:\n") - for typen in sorted(Classes.keys()): - fh.write(" class Ast%-17s\n" % typen) + for node in SortedNodes: + fh.write(" class Ast%-17s\n" % node.name) fh.write(" parent: ") - for subclass in subclasses_of(typen): - if subclass != 'Node': - fh.write("Ast%-12s " % subclass) + for superClass in node.allSuperClasses: + if not superClass.isRoot: + fh.write("Ast%-12s " % superClass.name) fh.write("\n") fh.write(" childs: ") - for subclass in children_of(typen): - if subclass != 'Node': - fh.write("Ast%-12s " % subclass) + for subClass in node.allSubClasses: + fh.write("Ast%-12s " % subClass.name) fh.write("\n") - if ("Ast" + typen) in ClassRefs: # pylint: disable=superfluous-parens - refs = ClassRefs["Ast" + typen] + if ("Ast" + node.name) in ClassRefs: # pylint: disable=superfluous-parens + refs = ClassRefs["Ast" + node.name] fh.write(" newed: ") for stage in sorted(refs['newed'].keys(), key=lambda val: Stages[val] @@ -500,27 +587,27 @@ def write_report(filename): def write_classes(filename): with open_file(filename) as fh: fh.write("class AstNode;\n") - for typen in sorted(Classes.keys()): - fh.write("class Ast%-17s // " % (typen + ";")) - for subclass in subclasses_of(typen): - fh.write("Ast%-12s " % subclass) + for node in SortedNodes: + fh.write("class Ast%-17s // " % (node.name + ";")) + for superClass in node.allSuperClasses: + fh.write("Ast%-12s " % superClass.name) fh.write("\n") def write_visitor_decls(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - if typen != "Node": - fh.write("virtual void visit(Ast" + typen + "*);\n") + for node in SortedNodes: + if not node.isRoot: + fh.write("virtual void visit(Ast" + node.name + "*);\n") def write_visitor_defns(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - if typen != "Node": - base = Classes[typen] - fh.write("void VNVisitor::visit(Ast" + typen + - "* nodep) { visit(static_cast(nodep)); }\n") @@ -528,75 +615,51 @@ def write_impl(filename): with open_file(filename) as fh: fh.write("\n") fh.write("// For internal use. They assume argument is not nullptr.\n") - for typen in sorted(Classes.keys()): + for node in SortedNodes: fh.write("template<> inline bool AstNode::privateTypeTest(const AstNode* nodep) { ") - if typen == "Node": + node.name + ">(const AstNode* nodep) { ") + if node.isRoot: fh.write("return true; ") else: fh.write("return ") - if re.search(r'^Node', typen): + if not node.isLeaf: fh.write( "static_cast(nodep->type()) >= static_cast(VNType::first" - + typen + ") && ") + + node.name + ") && ") fh.write( "static_cast(nodep->type()) <= static_cast(VNType::last" - + typen + "); ") + + node.name + "); ") else: - fh.write("nodep->type() == VNType::at" + typen + "; ") + fh.write("nodep->type() == VNType::at" + node.name + "; ") fh.write("}\n") -def write_type_enum(fh, typen, idx, processed, kind, indent): - # Skip this if it has already been processed - if typen in processed: - return idx - # Mark processed - processed[typen] = 1 - - # The last used index - last = None - - if not re.match(r'^Node', typen): - last = idx - if kind == "concrete-enum": - fh.write(" " * (indent * 4) + "at" + typen + " = " + str(idx) + - ",\n") - elif kind == "concrete-ascii": - fh.write(" " * (indent * 4) + "\"" + typen.upper() + "\",\n") - idx += 1 - elif kind == "abstract-enum": - fh.write(" " * (indent * 4) + "first" + typen + " = " + str(idx) + - ",\n") - - if typen in Children: - for child in sorted(Children[typen].keys()): - (idx, last) = write_type_enum(fh, child, idx, processed, kind, - indent) - - if re.match(r'^Node', typen) and kind == "abstract-enum": - fh.write(" " * (indent * 4) + "last" + typen + " = " + str(last) + - ",\n") - - return [idx, last] - - def write_types(filename): with open_file(filename) as fh: fh.write(" enum en : uint16_t {\n") - (final, ignored) = write_type_enum( # pylint: disable=W0612 - fh, "Node", 0, {}, "concrete-enum", 2) - fh.write(" _ENUM_END = " + str(final) + "\n") + for node in sorted(filter(lambda _: _.isLeaf, SortedNodes), + key=lambda _: _.typeId): + fh.write(" at" + node.name + " = " + str(node.typeId) + + ",\n") + fh.write(" _ENUM_END = " + str(Nodes["Node"].typeIdMax + 1) + + "\n") fh.write(" };\n") fh.write(" enum bounds : uint16_t {\n") - write_type_enum(fh, "Node", 0, {}, "abstract-enum", 2) + for node in sorted(filter(lambda _: not _.isLeaf, SortedNodes), + key=lambda _: _.typeIdMin): + fh.write(" first" + node.name + " = " + + str(node.typeIdMin) + ",\n") + fh.write(" last" + node.name + " = " + str(node.typeIdMax) + + ",\n") fh.write(" _BOUNDS_END\n") fh.write(" };\n") fh.write(" const char* ascii() const {\n") fh.write(" static const char* const names[_ENUM_END + 1] = {\n") - write_type_enum(fh, "Node", 0, {}, "concrete-ascii", 3) + for node in sorted(filter(lambda _: _.isLeaf, SortedNodes), + key=lambda _: _.typeId): + fh.write(" \"" + node.name.upper() + "\",\n") fh.write(" \"_ENUM_END\"\n") fh.write(" };\n") fh.write(" return names[m_e];\n") @@ -605,45 +668,21 @@ def write_types(filename): def write_yystype(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - fh.write("Ast{t}* {m}p;\n".format(t=typen, - m=typen[0].lower() + typen[1:])) + for node in SortedNodes: + fh.write("Ast{t}* {m}p;\n".format(t=node.name, + m=node.name[0].lower() + + node.name[1:])) def write_macros(filename): with open_file(filename) as fh: - typen = "None" - base = "None" - - in_filename = "V3AstNodes.h" - ifile = Args.I + "/" + in_filename - with open(ifile) as ifh: - for (lineno, line) in enumerate(ifh, 1): - # Drop expanded macro definitions - but keep empty line so compiler - # message locations are accurate - line = re.sub(r'^\s*#(define|undef)\s+ASTGEN_.*$', '', line) - - # Track current node type and base class - match = re.search( - r'\s*class\s*Ast(\S+)\s*(final|VL_NOT_FINAL)?\s*:\s*(public)?\s*(AstNode\S*)', - line) - if match: - typen = match.group(1) - base = match.group(4) - if not typen.startswith("Node"): - macro = "#define ASTGEN_SUPER_{t}(...) {b}(VNType::at{t}, __VA_ARGS__)\n" \ - .format(b=base, t=typen) - fh.write(macro) - - match = re.search(r"ASTGEN_SUPER_(\w+)", line) - if match: - if typen != match.group(1): - print(( - "V3AstNodes.h:{l} ERROR: class Ast{t} calls wrong superclass " - + - "constructor macro (should call ASTGEN_SUPER_{t})" - ).format(l=lineno, t=typen)) - sys.exit(1) + for node in SortedNodes: + # Only care about leaf classes + if not node.isLeaf: + continue + fh.write( + "#define ASTGEN_SUPER_{t}(...) Ast{b}(VNType::at{t}, __VA_ARGS__)\n" + .format(t=node.name, b=node.superClass.name)) ###################################################################### @@ -673,19 +712,24 @@ Args = parser.parse_args() read_types(Args.I + "/V3Ast.h") read_types(Args.I + "/V3AstNodes.h") -for typen in sorted(Classes.keys()): + +# Compute derived properties over the whole AstNode hierarchy +Nodes["Node"].complete() + +SortedNodes = tuple(map(lambda _: Nodes[_], sorted(Nodes.keys()))) + +for node in SortedNodes: # Check all leaves are not AstNode* and non-leaves are AstNode* - children = children_of(typen) - if re.match(r'^Node', typen): - if len(children) == 0: + if re.match(r'^Node', node.name): + if node.isLeaf: sys.exit( "%Error: Final AstNode subclasses must not be named AstNode*: Ast" - + typen) + + node.name) else: - if len(children) != 0: + if not node.isLeaf: sys.exit( "%Error: Non-final AstNode subclasses must be named AstNode*: Ast" - + typen) + + node.name) read_stages(Args.I + "/Verilator.cpp") From ae466b170361af49beac5c827638fbec9a3ab6e2 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 14 Sep 2022 13:37:51 +0200 Subject: [PATCH 19/25] Internals: Improve Verilation peak memory usage in V3Subst (#3512). --- src/V3Subst.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index ef7562ac5..ce43a7fd0 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -359,6 +359,13 @@ private: } virtual void visit(AstVar*) override {} virtual void visit(AstConst*) override {} + virtual void visit(AstModule* nodep) override { + ++m_ops; + if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA; + iterateChildren(nodep); + // Reduce peak memory usage by reclaiming the edited AstNodes + doDeletes(); + } virtual void visit(AstNode* nodep) override { m_ops++; if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA; From a3c58d7b70b45e42b3b43db5da5a1fecb8d3db59 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 14 Sep 2022 13:39:27 +0200 Subject: [PATCH 20/25] Support IEEE constant signal strengths (#3601). --- src/V3Ast.h | 30 ++++ src/V3AstNodes.cpp | 4 + src/V3AstNodes.h | 24 +++ src/V3Const.cpp | 1 + src/V3LinkLValue.cpp | 8 + src/V3ParseGrammar.cpp | 10 +- src/V3ParseImp.cpp | 9 +- src/V3ParseImp.h | 2 + src/V3Tristate.cpp | 147 ++++++++++++++++++ src/verilog.l | 16 +- src/verilog.y | 111 +++++++++---- test_regress/t/t_strength_assignments.pl | 21 +++ test_regress/t/t_strength_assignments.v | 38 +++++ test_regress/t/t_strength_bufif1.out | 5 + test_regress/t/t_strength_bufif1.pl | 19 +++ test_regress/t/t_strength_bufif1.v | 17 ++ test_regress/t/t_strength_highz.out | 14 ++ test_regress/t/t_strength_highz.pl | 19 +++ test_regress/t/t_strength_highz.v | 19 +++ .../t/t_strength_strong1_strong1_bad.out | 4 + .../t/t_strength_strong1_strong1_bad.pl | 19 +++ .../t/t_strength_strong1_strong1_bad.v | 13 ++ test_regress/t/t_weak_nor_strong_assign.pl | 21 +++ test_regress/t/t_weak_nor_strong_assign.v | 18 +++ 24 files changed, 550 insertions(+), 39 deletions(-) create mode 100755 test_regress/t/t_strength_assignments.pl create mode 100644 test_regress/t/t_strength_assignments.v create mode 100644 test_regress/t/t_strength_bufif1.out create mode 100755 test_regress/t/t_strength_bufif1.pl create mode 100644 test_regress/t/t_strength_bufif1.v create mode 100644 test_regress/t/t_strength_highz.out create mode 100755 test_regress/t/t_strength_highz.pl create mode 100644 test_regress/t/t_strength_highz.v create mode 100644 test_regress/t/t_strength_strong1_strong1_bad.out create mode 100755 test_regress/t/t_strength_strong1_strong1_bad.pl create mode 100644 test_regress/t/t_strength_strong1_strong1_bad.v create mode 100755 test_regress/t/t_weak_nor_strong_assign.pl create mode 100644 test_regress/t/t_weak_nor_strong_assign.v diff --git a/src/V3Ast.h b/src/V3Ast.h index 9e50846cd..6e455ef1c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -732,6 +732,10 @@ public: return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR); } + bool isNet() const { + return (m_e == WIRE || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 + || m_e == SUPPLY0 || m_e == SUPPLY1); + } bool isContAssignable() const { // In Verilog, always ok in SystemVerilog return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 @@ -975,6 +979,32 @@ inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) { return os << rhs.ascii(); } +//###################################################################### + +class VStrength final { +public: + enum en : uint8_t { HIGHZ, SMALL, MEDIUM, WEAK, LARGE, PULL, STRONG, SUPPLY }; + enum en m_e; + + inline VStrength(en strengthLevel) + : m_e(strengthLevel) {} + explicit inline VStrength(int _e) + : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + + operator en() const { return m_e; } + const char* ascii() const { + static const char* const names[] + = {"highz", "small", "medium", "weak", "large", "pull", "strong", "supply"}; + return names[m_e]; + } +}; +inline bool operator==(const VStrength& lhs, const VStrength& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VStrength& lhs, VStrength::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VStrength::en lhs, const VStrength& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VStrength& rhs) { + return os << rhs.ascii(); +} + //###################################################################### // VNumRange - Structure containing numeric range information // See also AstRange, which is a symbolic version of this diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index f8a409247..d534622e5 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1786,6 +1786,10 @@ void AstSenItem::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << edgeType().ascii() << "]"; } +void AstStrengthSpec::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " (" << m_s0.ascii() << ", " << m_s1.ascii() << ")"; +} void AstParseRef::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << expect().ascii() << "]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index cef18db50..b5724847b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -290,6 +290,23 @@ public: virtual bool same(const AstNode* /*samep*/) const override { return true; } }; +class AstStrengthSpec final : public AstNode { +private: + VStrength m_s0; // Drive 0 strength + VStrength m_s1; // Drive 1 strength + +public: + AstStrengthSpec(FileLine* fl, VStrength s0, VStrength s1) + : ASTGEN_SUPER_StrengthSpec(fl) + , m_s0{s0} + , m_s1{s1} {} + + ASTNODE_NODE_FUNCS(StrengthSpec) + VStrength strength0() { return m_s0; } + VStrength strength1() { return m_s1; } + virtual void dump(std::ostream& str) const override; +}; + class AstGatePin final : public AstNodeMath { // Possibly expand a gate primitive input pin value to match the range of the gate primitive public: @@ -2094,6 +2111,7 @@ private: bool m_isRand : 1; // Random variable bool m_isConst : 1; // Table contains constant data bool m_isContinuously : 1; // Ever assigned continuously (for force/release) + bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic) bool m_isPulldown : 1; // Tri0 bool m_isPullup : 1; // Tri1 @@ -2134,6 +2152,7 @@ private: m_isRand = false; m_isConst = false; m_isContinuously = false; + m_hasStrengthAssignment = false; m_isStatic = false; m_isPulldown = false; m_isPullup = false; @@ -2297,6 +2316,8 @@ public: void isIfaceParent(bool flag) { m_isIfaceParent = flag; } void funcLocal(bool flag) { m_funcLocal = flag; } void funcReturn(bool flag) { m_funcReturn = flag; } + void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; } + bool hasStrengthAssignment() { return m_hasStrengthAssignment; } void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } bool isDpiOpenArray() const { return m_isDpiOpenArray; } bool isHideLocal() const { return m_isHideLocal; } @@ -2330,6 +2351,7 @@ public: bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); } bool isIfaceParent() const { return m_isIfaceParent; } bool isSignal() const { return varType().isSignal(); } + bool isNet() const { return varType().isNet(); } bool isTemp() const { return varType().isTemp(); } bool isToggleCoverable() const { return ((isIO() || isSignal()) @@ -3630,6 +3652,8 @@ public: AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignW) + AstStrengthSpec* strengthSpecp() const { return VN_AS(op4p(), StrengthSpec); } + void strengthSpecp(AstStrengthSpec* const strengthSpecp) { setOp4p((AstNode*)strengthSpecp); } virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignW(this->fileline(), lhsp, rhsp); } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 096510af1..2c5f10f7b 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2853,6 +2853,7 @@ private: if (m_wremove && !m_params && m_doNConst && m_modp && operandConst(nodep->rhsp()) && !VN_AS(nodep->rhsp(), Const)->num().isFourState() && varrefp // Don't do messes with BITREFs/ARRAYREFs + && !varrefp->varp()->hasStrengthAssignment() // Strengths are resolved in V3Tristate && !varrefp->varp()->valuep() // Not already constified && !varrefp->varScopep()) { // Not scoped (or each scope may have different initial // value) diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 0e8f4ed65..a05407d37 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -37,6 +37,7 @@ private: // STATE bool m_setContinuously = false; // Set that var has some continuous assignment + bool m_setStrengthSpecified = false; // Set that var has assignment with strength specified. VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside @@ -51,6 +52,9 @@ private: if (nodep->varp()) { if (nodep->access().isWriteOrRW() && m_setContinuously) { nodep->varp()->isContinuously(true); + // Strength may only be specified in continuous assignment, + // so it is needed to check only if m_setContinuously is true + if (m_setStrengthSpecified) nodep->varp()->hasStrengthAssignment(true); } if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) { nodep->v3warn(ASSIGNIN, @@ -78,9 +82,13 @@ private: { m_setRefLvalue = VAccess::WRITE; m_setContinuously = VN_IS(nodep, AssignW) || VN_IS(nodep, AssignAlias); + if (AstAssignW* assignwp = VN_CAST(nodep, AssignW)) { + if (assignwp->strengthSpecp()) m_setStrengthSpecified = true; + } iterateAndNextNull(nodep->lhsp()); m_setRefLvalue = VAccess::NOCHANGE; m_setContinuously = false; + m_setStrengthSpecified = false; iterateAndNextNull(nodep->rhsp()); } } diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 8e95d13c8..66670338e 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -84,9 +84,13 @@ AstArg* V3ParseGrammar::argWrapList(AstNode* nodep) { } AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { - return new AstAssignW( - fileline, new AstVarRef(fileline, name, VAccess::WRITE), - new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0"))); + AstAssignW* assignp + = new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE}, + new AstConst{fileline, AstConst::StringToParse{}, (value ? "'1" : "'0")}}; + AstStrengthSpec* strengthSpecp + = new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY}; + assignp->strengthSpecp(strengthSpecp); + return assignp; } AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) { diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 924a5062b..8a1481323 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -398,8 +398,7 @@ void V3ParseImp::tokenPipeline() { const int nexttok = nexttokp->token; yylval = curValue; // Now potentially munge the current token - if (token == '(' - && (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) { + if (token == '(' && isStrengthToken(nexttok)) { token = yP_PAR__STRENGTH; } else if (token == ':') { if (nexttok == yBEGIN) { @@ -483,6 +482,12 @@ void V3ParseImp::tokenPipeline() { // effectively returns yylval } +bool V3ParseImp::isStrengthToken(int tok) { + return tok == ygenSTRENGTH || tok == ySUPPLY0 || tok == ySUPPLY1 || tok == ySTRONG0 + || tok == ySTRONG1 || tok == yPULL0 || tok == yPULL1 || tok == yWEAK0 || tok == yWEAK1 + || tok == yHIGHZ0 || tok == yHIGHZ1; +} + void V3ParseImp::tokenPipelineSym() { // If an id, change the type based on symbol table // Note above sometimes converts yGLOBAL to a yaID__LEX diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index c5cf4bd36..54a241365 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -121,6 +121,7 @@ struct V3ParseBisonYYSType { V3ErrorCode::en errcodeen; VAttrType::en attrtypeen; VLifetime::en lifetime; + VStrength::en strength; #include "V3Ast__gen_yystype.h" }; @@ -216,6 +217,7 @@ public: } int lexKwdLastState() const { return m_lexKwdLast; } static const char* tokenName(int tok); + static bool isStrengthToken(int tok); void ppPushText(const string& text) { m_ppBuffers.push_back(text); diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index b5e983978..733d4ad74 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -55,6 +55,33 @@ // duplicating vars and logic that is common between each instance of a // module. // +// +// Another thing done in this phase is signal strength handling. +// Currently they are only supported in assignments and only in case when the strongest assignment +// has constant with all bits equal on the RHS. It is the case when they can be statically +// resolved. +// +// Static resolution is done in the following way: +// - The assignment of value 0 (size may be greater than 1), that has greatest strength (the +// one corresponding to 0) of all other assignments of 0, has to be found. +// - The same is done for value '1 and strength corresponding to value 1. +// - The greater of these two strengths is chosen. If they are equal the one that corresponds +// to 1 is taken as the greatest. +// - All assignments, that have strengths weaker or equal to the one that was found before, are +// removed. They are the assignments with constants on the RHS and also all assignments that have +// both strengths non-greater that the one was found, because they are weaker no matter what is on +// RHS. +// +// All assignments that are stronger than the one with strongest constant are left as they are. +// +// There is a possible problem with equally strong assignments, because multiple assignments with +// the same strength, but different values should result in x value, but these values are +// unsupported. +// +// Singal strength can also be used in simple logic gates parsed as assignments (see verilog.y), +// but these gates are then either removed (if they are weaker than the strongest constant) or +// handled as the gates witout signal strengths are handled now. In other words, gate with greater +// strength won't properly overwrite weaker driver. //************************************************************************* #include "config_build.h" @@ -340,6 +367,8 @@ class TristateVisitor final : public TristateBaseVisitor { // TYPES using RefVec = std::vector; using VarMap = std::unordered_map; + using Assigns = std::vector; + using VarToAssignsMap = std::map; enum : uint8_t { U2_GRAPHING = 1, // bit[0] if did m_graphing visit U2_NONGRAPH = 2, // bit[1] if did !m_graphing visit @@ -352,6 +381,7 @@ class TristateVisitor final : public TristateBaseVisitor { AstNodeModule* m_modp = nullptr; // Current module AstCell* m_cellp = nullptr; // current cell VarMap m_lhsmap; // Tristate left-hand-side driver map + VarToAssignsMap m_assigns; // Assigns in current module int m_unique = 0; bool m_alhs = false; // On LHS of assignment const AstNode* m_logicp = nullptr; // Current logic being built @@ -636,6 +666,117 @@ class TristateVisitor final : public TristateBaseVisitor { nodep->addStmtp(assp); } + void addToAssignmentList(AstAssignW* nodep) { + if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) { + if (varRefp->varp()->isNet()) { + m_assigns[varRefp->varp()].push_back(nodep); + } else if (nodep->strengthSpecp()) { + if (!varRefp->varp()->isNet()) + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Signal strengths are unsupported " + "on the following variable type: " + << varRefp->varp()->varType()); + + nodep->strengthSpecp()->unlinkFrBack()->deleteTree(); + } + } else if (nodep->strengthSpecp()) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Assignments with signal strength with LHS of type: " + << nodep->lhsp()->prettyTypeName()); + } + } + + uint8_t getStrength(AstAssignW* const nodep, bool value) { + if (AstStrengthSpec* const strengthSpec = nodep->strengthSpecp()) { + return value ? strengthSpec->strength1() : strengthSpec->strength0(); + } + return VStrength::STRONG; // default strength is strong + } + + bool assignmentOfValueOnAllBits(AstAssignW* const nodep, bool value) { + if (AstConst* const constp = VN_CAST(nodep->rhsp(), Const)) { + const V3Number num = constp->num(); + return value ? num.isEqAllOnes() : num.isEqZero(); + } + return false; + } + + AstAssignW* getStrongestAssignmentOfValue(const Assigns& assigns, bool value) { + auto maxIt = std::max_element( + assigns.begin(), assigns.end(), [&](AstAssignW* ap, AstAssignW* bp) { + bool valuesOnRhsA = assignmentOfValueOnAllBits(ap, value); + bool valuesOnRhsB = assignmentOfValueOnAllBits(bp, value); + if (!valuesOnRhsA) return valuesOnRhsB; + if (!valuesOnRhsB) return false; + return getStrength(ap, value) < getStrength(bp, value); + }); + // If not all assignments have const with all bits equal to value on the RHS, + // std::max_element will return one of them anyway, so it has to be checked before + // returning + return assignmentOfValueOnAllBits(*maxIt, value) ? *maxIt : nullptr; + } + + void removeWeakerAssignments(Assigns& assigns) { + // Weaker assignments are these assignments that can't change the final value of the net. + // If the value of the RHS is known, only strength corresponding to its value is taken into + // account. Assignments of constants that have bits both 0 and 1 are skipped here, because + // it would involve handling parts of bits separately. + + // First, the strongest assignment, that has value on the RHS consisting of only 1 or only + // 0, has to be found. + AstAssignW* const strongest0p = getStrongestAssignmentOfValue(assigns, 0); + AstAssignW* const strongest1p = getStrongestAssignmentOfValue(assigns, 1); + AstAssignW* strongestp = nullptr; + uint8_t greatestKnownStrength = 0; + const auto getIfStrongest = [&](AstAssignW* const strongestCandidatep, bool value) { + if (!strongestCandidatep) return; + uint8_t strength = getStrength(strongestCandidatep, value); + if (strength >= greatestKnownStrength) { + greatestKnownStrength = strength; + strongestp = strongestCandidatep; + } + }; + getIfStrongest(strongest0p, 0); + getIfStrongest(strongest1p, 1); + + if (strongestp) { + // Then all weaker assignments can be safely removed. + // Assignments of the same strength are also removed, because duplicates aren't needed. + // One problem is with 2 assignments of different values and equal strengths. It should + // result in assignment of x value, but these values aren't supported now. + auto removedIt + = std::remove_if(assigns.begin(), assigns.end(), [&](AstAssignW* assignp) { + if (assignp == strongestp) return false; + const uint8_t strength0 = getStrength(assignp, 0); + const uint8_t strength1 = getStrength(assignp, 1); + const bool toRemove = (strength0 <= greatestKnownStrength + && strength1 <= greatestKnownStrength) + || (strength0 <= greatestKnownStrength + && assignmentOfValueOnAllBits(assignp, 0)) + || (strength1 <= greatestKnownStrength + && assignmentOfValueOnAllBits(assignp, 1)); + if (toRemove) { + // Don't propagate tristate if its assignment is removed. + TristateVertex* const vertexp + = reinterpret_cast(assignp->rhsp()->user5p()); + if (vertexp) vertexp->isTristate(false); + VL_DO_DANGLING(pushDeletep(assignp->unlinkFrBack()), assignp); + return true; + } + return false; + }); + assigns.erase(removedIt, assigns.end()); + } + } + + void resolveMultipleNetAssignments() { + for (auto& varpAssigns : m_assigns) { + if (varpAssigns.second.size() > 1) { + // first the static resolution is tried + removeWeakerAssignments(varpAssigns.second); + } + } + } + // VISITORS virtual void visit(AstConst* nodep) override { UINFO(9, dbgState() << nodep << endl); @@ -889,6 +1030,8 @@ class TristateVisitor final : public TristateBaseVisitor { void visitAssign(AstNodeAssign* nodep) { if (m_graphing) { + if (AstAssignW* assignWp = VN_CAST(nodep, AssignW)) addToAssignmentList(assignWp); + if (nodep->user2() & U2_GRAPHING) return; VL_RESTORER(m_logicp); m_logicp = nodep; @@ -1373,6 +1516,7 @@ class TristateVisitor final : public TristateBaseVisitor { VL_RESTORER(m_graphing); VL_RESTORER(m_unique); VL_RESTORER(m_lhsmap); + VL_RESTORER(m_assigns); // Not preserved, needs pointer instead: TristateGraph origTgraph = m_tgraph; UASSERT_OBJ(m_tgraph.empty(), nodep, "Unsupported: NodeModule under NodeModule"); { @@ -1382,6 +1526,7 @@ class TristateVisitor final : public TristateBaseVisitor { m_unique = 0; m_logicp = nullptr; m_lhsmap.clear(); + m_assigns.clear(); m_modp = nodep; // Walk the graph, finding all variables and tristate constructs { @@ -1389,6 +1534,8 @@ class TristateVisitor final : public TristateBaseVisitor { iterateChildren(nodep); m_graphing = false; } + // resolve multiple net assignments and signal strengths + resolveMultipleNetAssignments(); // Use graph to find tristate signals m_tgraph.graphWalk(nodep); // Build the LHS drivers map for this module diff --git a/src/verilog.l b/src/verilog.l index c3eb40f4c..a3cc59ef6 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -325,8 +325,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "forever" { FL; return yFOREVER; } "fork" { FL; return yFORK; } "function" { FL; return yFUNCTION; } - "highz0" { FL; return ygenSTRENGTH; } - "highz1" { FL; return ygenSTRENGTH; } + "highz0" { FL; return yHIGHZ0; } + "highz1" { FL; return yHIGHZ1; } "if" { FL; return yIF; } "initial" { FL; return yINITIAL; } "inout" { FL; return yINOUT; } @@ -350,8 +350,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "pmos" { FL; return yPMOS; } "posedge" { FL; return yPOSEDGE; } "primitive" { FL; return yPRIMITIVE; } - "pull0" { FL; return ygenSTRENGTH; } - "pull1" { FL; return ygenSTRENGTH; } + "pull0" { FL; return yPULL0; } + "pull1" { FL; return yPULL1; } "pulldown" { FL; return yPULLDOWN; } "pullup" { FL; return yPULLUP; } "rcmos" { FL; return yRCMOS; } @@ -369,8 +369,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "small" { FL; return ygenSTRENGTH; } "specify" { FL; return ySPECIFY; } "specparam" { FL; return ySPECPARAM; } - "strong0" { FL; return ygenSTRENGTH; } - "strong1" { FL; return ygenSTRENGTH; } + "strong0" { FL; return ySTRONG0; } + "strong1" { FL; return ySTRONG1; } "supply0" { FL; return ySUPPLY0; } "supply1" { FL; return ySUPPLY1; } "table" { FL; yy_push_state(TABLE); return yTABLE; } @@ -388,8 +388,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "vectored" { FL; return yVECTORED; } "wait" { FL; return yWAIT; } "wand" { FL; return yWAND; } - "weak0" { FL; return ygenSTRENGTH; } - "weak1" { FL; return ygenSTRENGTH; } + "weak0" { FL; return yWEAK0; } + "weak1" { FL; return yWEAK1; } "while" { FL; return yWHILE; } "wire" { FL; return yWIRE; } "wor" { FL; return yWOR; } diff --git a/src/verilog.y b/src/verilog.y index 3d77c680b..161fe8f67 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -40,6 +40,13 @@ #define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg) #define GATEUNSUP(fl, tok) \ { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); } +#define STRENGTHUNSUP(nodep) \ + { \ + if (nodep) { \ + BBUNSUP((nodep->fileline()), "Unsupported: Strength specifier on this gate type"); \ + nodep->deleteTree(); \ + } \ + } #define PRIMDLYUNSUP(nodep) \ { \ if (nodep) { \ @@ -68,6 +75,7 @@ public: AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration AstNode* m_netDelayp = nullptr; // Pointer to delay for next signal declaration + AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration AstNodeModule* m_modp = nullptr; // Last module for timeunits bool m_pinAnsi = false; // In ANSI port list FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations @@ -172,6 +180,7 @@ public: m_varDTypep = dtypep; } void setNetDelay(AstNode* netDelayp) { m_netDelayp = netDelayp; } + void setNetStrength(AstStrengthSpec* netStrengthp) { m_netStrengthp = netStrengthp; } void pinPush() { m_pinStack.push(m_pinNum); m_pinNum = 1; @@ -291,6 +300,15 @@ int V3ParseGrammar::s_modTypeImpNum = 0; if (nodep) nodep->deleteTree(); \ } +#define APPLY_STRENGTH_TO_LIST(beginp, strengthSpecNodep, typeToCast) \ + { \ + if (AstStrengthSpec* specp = VN_CAST(strengthSpecNodep, StrengthSpec)) \ + for (auto* nodep = beginp; nodep; nodep = nodep->nextp()) { \ + auto* const assignp = VN_AS(nodep, typeToCast); \ + assignp->strengthSpecp(nodep == beginp ? specp : specp->cloneTree(false)); \ + } \ + } + static void ERRSVKWD(FileLine* fileline, const string& tokname) { static int toldonce = 0; fileline->v3error( @@ -544,6 +562,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yGLOBAL__CLOCKING "global-then-clocking" %token yGLOBAL__ETC "global" %token yGLOBAL__LEX "global-in-lex" +%token yHIGHZ0 "highz0" +%token yHIGHZ1 "highz1" %token yIF "if" %token yIFF "iff" //UNSUP %token yIGNORE_BINS "ignore_bins" @@ -598,6 +618,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yPROGRAM "program" %token yPROPERTY "property" %token yPROTECTED "protected" +%token yPULL0 "pull0" +%token yPULL1 "pull1" %token yPULLDOWN "pulldown" %token yPULLUP "pullup" %token yPURE "pure" @@ -635,6 +657,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token ySTATIC__LEX "static-in-lex" %token ySTRING "string" //UNSUP %token ySTRONG "strong" +%token ySTRONG0 "strong0" +%token ySTRONG1 "strong1" %token ySTRUCT "struct" %token ySUPER "super" %token ySUPPLY0 "supply0" @@ -688,6 +712,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) //UNSUP %token yWAIT_ORDER "wait_order" %token yWAND "wand" //UNSUP %token yWEAK "weak" +%token yWEAK0 "weak0" +%token yWEAK1 "weak1" %token yWHILE "while" //UNSUP %token yWILDCARD "wildcard" %token yWIRE "wire" @@ -1718,11 +1744,18 @@ parameter_port_declarationTypeFrontE: // IEEE: parameter_port_declaration w/o as ; net_declaration: // IEEE: net_declaration - excluding implict - net_declarationFront netSigList ';' { $$ = $2; } + net_declarationFront netSigList ';' + { $$ = $2; + if (GRAMMARP->m_netStrengthp) { + VL_DO_CLEAR(delete GRAMMARP->m_netStrengthp, GRAMMARP->m_netStrengthp = nullptr); + }} ; net_declarationFront: // IEEE: beginning of net_declaration - net_declRESET net_type strengthSpecE net_scalaredE net_dataTypeE { VARDTYPE_NDECL($5); } + net_declRESET net_type driveStrengthE net_scalaredE net_dataTypeE + { VARDTYPE_NDECL($5); + GRAMMARP->setNetStrength(VN_CAST($3, StrengthSpec)); + } //UNSUP net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(x); } ; @@ -2425,9 +2458,10 @@ module_common_item: // ==IEEE: module_common_item ; continuous_assign: // IEEE: continuous_assign - yASSIGN strengthSpecE delayE assignList ';' + yASSIGN driveStrengthE delayE assignList ';' { $$ = $4; + APPLY_STRENGTH_TO_LIST($$, $2, AssignW); if ($3) for (auto* nodep = $$; nodep; nodep = nodep->nextp()) { auto* const assignp = VN_AS(nodep, NodeAssign); @@ -2726,6 +2760,7 @@ netSig: // IEEE: net_decl_assignment - one element from | netId sigAttrListE '=' expr { $$ = VARDONEA($1, *$1, nullptr, $2); auto* const assignp = new AstAssignW{$3, new AstVarRef{$1, *$1, VAccess::WRITE}, $4}; + if (GRAMMARP->m_netStrengthp) assignp->strengthSpecp(GRAMMARP->m_netStrengthp->cloneTree(false)); if ($$->delayp()) assignp->addTimingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3 $$->addNext(assignp); } | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1,*$1, $2, $3); } @@ -4718,18 +4753,30 @@ stream_expressionOrDataType: // IEEE: from streaming_concatenation // Gate declarations gateDecl: - yBUF delayE gateBufList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOT delayE gateNotList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yAND delayE gateAndList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNAND delayE gateNandList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yOR delayE gateOrList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOR delayE gateNorList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yXOR delayE gateXorList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yXNOR delayE gateXnorList ';' { $$ = $3; PRIMDLYUNSUP($2); } + yBUF driveStrengthE delayE gateBufList ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yBUFIF0 driveStrengthE delayE gateBufif0List ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yBUFIF1 driveStrengthE delayE gateBufif1List ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yNOT driveStrengthE delayE gateNotList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yNOTIF0 driveStrengthE delayE gateNotif0List ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yNOTIF1 driveStrengthE delayE gateNotif1List ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yAND driveStrengthE delayE gateAndList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yNAND driveStrengthE delayE gateNandList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yOR driveStrengthE delayE gateOrList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yNOR driveStrengthE delayE gateNorList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yXOR driveStrengthE delayE gateXorList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yXNOR driveStrengthE delayE gateXnorList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } | yPULLUP delayE gatePullupList ';' { $$ = $3; PRIMDLYUNSUP($2); } | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; PRIMDLYUNSUP($2); } | yNMOS delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif1, as don't have strengths yet @@ -4901,21 +4948,33 @@ gatePinExpr: expr { $$ = GRAMMARP->createGatePin($1); } ; -// This list is also hardcoded in VParseLex.l -strength: // IEEE: strength0+strength1 - plus HIGHZ/SMALL/MEDIUM/LARGE - ygenSTRENGTH { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - | ySUPPLY0 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - | ySUPPLY1 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } +strength0: + ySUPPLY0 { $$ = VStrength::SUPPLY; } + | ySTRONG0 { $$ = VStrength::STRONG; } + | yPULL0 { $$ = VStrength::PULL; } + | yWEAK0 { $$ = VStrength::WEAK; } ; -strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty - /* empty */ { } - | strengthSpec { } +strength1: + ySUPPLY1 { $$ = VStrength::SUPPLY; } + | ySTRONG1 { $$ = VStrength::STRONG; } + | yPULL1 { $$ = VStrength::PULL; } + | yWEAK1 { $$ = VStrength::WEAK; } ; -strengthSpec: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty - yP_PAR__STRENGTH strength ')' { } - | yP_PAR__STRENGTH strength ',' strength ')' { } +driveStrengthE: + /* empty */ { $$ = nullptr; } + | driveStrength { $$ = $1; } + ; + + +driveStrength: + yP_PAR__STRENGTH strength0 ',' strength1 ')' { $$ = new AstStrengthSpec{$1, $2, $4}; } + | yP_PAR__STRENGTH strength1 ',' strength0 ')' { $$ = new AstStrengthSpec{$1, $4, $2}; } + | yP_PAR__STRENGTH strength0 ',' yHIGHZ1 ')' { BBUNSUP($4, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH strength1 ',' yHIGHZ0 ')' { BBUNSUP($4, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH yHIGHZ0 ',' strength1 ')' { BBUNSUP($2, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH yHIGHZ1 ',' strength0 ')' { BBUNSUP($2, "Unsupported: highz strength"); } ; //************************************************ diff --git a/test_regress/t/t_strength_assignments.pl b/test_regress/t/t_strength_assignments.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_strength_assignments.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_assignments.v b/test_regress/t/t_strength_assignments.v new file mode 100644 index 000000000..8344adbdd --- /dev/null +++ b/test_regress/t/t_strength_assignments.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire a; + assign (weak0, weak1) a = 1; + assign (weak0, supply1) a = 1; + assign (strong0, strong1) a = 0; + + wire (weak0, weak1) b = 1; + assign (strong0, strong1) b = 0; + + wire [1:0] c; + assign (weak0, supply1) c = '1; + assign (supply0, pull1) c = '1; + assign (strong0, strong1) c = '0; + + supply0 d; + assign (strong0, strong1) d = 1; + + wire (supply0, supply1) e = 'z; + assign (weak0, weak1) e = 1; + + always begin + if (a && !b && c === '1 && !d && e) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $write("Error: a = %b, b = %b, c = %b, d = %b, e = %b ", a, b, c, d, e); + $write("expected: a = 1, b = 0, c = 11, d = 0, e = 1\n"); + $stop; + end + end +endmodule diff --git a/test_regress/t/t_strength_bufif1.out b/test_regress/t/t_strength_bufif1.out new file mode 100644 index 000000000..0ac300369 --- /dev/null +++ b/test_regress/t/t_strength_bufif1.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_strength_bufif1.v:9:11: Unsupported: Strength specifier on this gate type + 9 | bufif1 (strong0, strong1) (a, 1'b1, 1'b1); + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_strength_bufif1.pl b/test_regress/t/t_strength_bufif1.pl new file mode 100755 index 000000000..35c0dfe5b --- /dev/null +++ b/test_regress/t/t_strength_bufif1.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_bufif1.v b/test_regress/t/t_strength_bufif1.v new file mode 100644 index 000000000..0a78b107c --- /dev/null +++ b/test_regress/t/t_strength_bufif1.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire a; + bufif1 (strong0, strong1) (a, 1'b1, 1'b1); + + always begin + if (a) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_strength_highz.out b/test_regress/t/t_strength_highz.out new file mode 100644 index 000000000..06f32f6e9 --- /dev/null +++ b/test_regress/t/t_strength_highz.out @@ -0,0 +1,14 @@ +%Error-UNSUPPORTED: t/t_strength_highz.v:8:17: Unsupported: highz strength + 8 | wire (weak0, highz1) a = 1; + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_strength_highz.v:9:19: Unsupported: highz strength + 9 | wire (strong1, highz0) b = 0; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_strength_highz.v:10:10: Unsupported: highz strength + 10 | wire (highz0, pull1) c = 0; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_strength_highz.v:11:10: Unsupported: highz strength + 11 | wire (highz1, supply0) d = 1; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_strength_highz.pl b/test_regress/t/t_strength_highz.pl new file mode 100755 index 000000000..48bf31461 --- /dev/null +++ b/test_regress/t/t_strength_highz.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_highz.v b/test_regress/t/t_strength_highz.v new file mode 100644 index 000000000..340723aba --- /dev/null +++ b/test_regress/t/t_strength_highz.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire (weak0, highz1) a = 1; + wire (strong1, highz0) b = 0; + wire (highz0, pull1) c = 0; + wire (highz1, supply0) d = 1; + + always begin + if (a === 1'bz && b === 1'bz && c === 1'bz && d === 1'bz) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_strength_strong1_strong1_bad.out b/test_regress/t/t_strength_strong1_strong1_bad.out new file mode 100644 index 000000000..b1e299714 --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_strength_strong1_strong1_bad.v:8:19: syntax error, unexpected strong1 + 8 | wire (strong1, strong1) a = 1; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_strength_strong1_strong1_bad.pl b/test_regress/t/t_strength_strong1_strong1_bad.pl new file mode 100755 index 000000000..19ba90d40 --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_strong1_strong1_bad.v b/test_regress/t/t_strength_strong1_strong1_bad.v new file mode 100644 index 000000000..ab84216cc --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire (strong1, strong1) a = 1; + initial begin + $stop; + end + +endmodule diff --git a/test_regress/t/t_weak_nor_strong_assign.pl b/test_regress/t/t_weak_nor_strong_assign.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_weak_nor_strong_assign.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_weak_nor_strong_assign.v b/test_regress/t/t_weak_nor_strong_assign.v new file mode 100644 index 000000000..a3811ca71 --- /dev/null +++ b/test_regress/t/t_weak_nor_strong_assign.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire a; + nor (pull0, weak1) n1(a, 0, 0); + assign (strong0, weak1) a = 0; + + always begin + if (!a) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From 7aa01625d833461abc45c1c9a9c6da6a88cb80d5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 14 Sep 2022 08:15:42 -0400 Subject: [PATCH 21/25] Commentary: Changes update --- Changes | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 202e279c2..e2a1c13a8 100644 --- a/Changes +++ b/Changes @@ -13,7 +13,11 @@ Verilator 4.227 devel **Minor:** +* Support IEEE constant signal strengths (#3601). [Ryszard Rozak/Antmicro] +* Fix thread saftey in SystemC VL_ASSIGN_SBW/WSB (#3494) (#3513). [Mladen Slijepcevic] * Fix crash in gate optimization of circular logic (#3543). [Bill Flynn] +* Fix arguments in non-static method call (#3547) (#3582). [Gustav Svensk] +* Fix default --mod-prefix when --prefix is repeated (#3603). [Geza Lore] * Fix typedef'ed class conversion to boolean (#3616). [Aleksander Kiryk] @@ -34,7 +38,7 @@ Verilator 4.226 2022-08-31 * Fix incorrect tristate logic (#3399) [shareefj, Vighnesh Iyer] * Fix incorrect bit op tree optimization (#3470). [algrobman] * Fix bisonpre for MSYS2 (#3471). -* Fix max memory usage (#3483). [Kamil Rakoczy] +* Fix max memory usage (#3483). [Kamil Rakoczy/Antmicro] * Fix empty string arguments to display (#3484). [Grulfen] * Fix table misoptimizing away display (#3488). [Stefan Post] * Fix unique_ptr memory header for MinGW64 (#3493). @@ -45,7 +49,7 @@ Verilator 4.226 2022-08-31 * Fix segfault exporting non-existant package (#3535). * Fix void-cast queue pop_front or pop_back (#3542) (#3364). [Drew Ranck] * Fix case statement comparing string literal (#3544). [Gustav Svensk] -* Fix === with some tristate constants (#3551). [Ryszard Rozak] +* Fix === with some tristate constants (#3551). [Ryszard Rozak/Antmicro] * Fix converting subclasses to string (#3552). [Arkadiusz Kozdra/Antmicro] * Fix --hierarchical with order-based pin connections (#3583) (#3585). [Kelin9298] From 9efd64ab9804258f4c34b4ddafc7438ad5f5fe89 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 14 Sep 2022 20:13:28 -0400 Subject: [PATCH 22/25] Commentary --- Changes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changes b/Changes index e2a1c13a8..5502f48a7 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,12 @@ contributors that suggested a given feature are shown in []. Thanks! Verilator 4.227 devel ========================== +**Announcement:** + +* The next release is anticipated primere Verilator Version 5. Please + consider beta-testing the github 'develop-v5' branch, which will soon + merge into the github 'master' branch (#3383). + **Minor:** * Support IEEE constant signal strengths (#3601). [Ryszard Rozak/Antmicro] From 75fd71d7e5523a2eb8f841618981743c74a39563 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 14 Sep 2022 20:18:40 -0400 Subject: [PATCH 23/25] Add --main to generate main() C++ (previously was experimental only) (#3265). --- Changes | 1 + bin/verilator | 1 + docs/guide/exe_verilator.rst | 9 +++++++++ src/V3Options.cpp | 17 ++++++++++------- src/V3Options.h | 3 ++- test_regress/t/t_flag_main.pl | 3 +++ 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Changes b/Changes index 5502f48a7..d0f057a5e 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,7 @@ Verilator 4.227 devel **Minor:** * Support IEEE constant signal strengths (#3601). [Ryszard Rozak/Antmicro] +* Add --main to generate main() C++ (previously was experimental only). * Fix thread saftey in SystemC VL_ASSIGN_SBW/WSB (#3494) (#3513). [Mladen Slijepcevic] * Fix crash in gate optimization of circular logic (#3543). [Bill Flynn] * Fix arguments in non-static method call (#3547) (#3582). [Gustav Svensk] diff --git a/bin/verilator b/bin/verilator index 62f7be232..74c5b49c6 100755 --- a/bin/verilator +++ b/bin/verilator @@ -343,6 +343,7 @@ detailed descriptions of these arguments. --lint-only Lint, but do not make output --make Generate scripts for specified build tool -MAKEFLAGS Arguments to pass to make during --build + --main Generate C++ main() --max-num-width Maximum number width (default: 64K) --Mdir Name of output object directory --MMD Create .d dependency files diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 0348c4db2..8d2ccda86 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -709,6 +709,15 @@ Summary: (e.g. ``-MAKEFLAGS -l -MAKEFLAGS -k``). Use of this option should not be required for simple builds using the host toolchain. +.. option:: --main + + Generates a top-level C++ main() file that supports parsing arguments, + but does not drive any inputs. This is sufficient to use for top-level + SystemVerilog designs that has no inputs, and does not need the C++ to + do any time advancement. + + Implies :vlopt:`--cc` if no other output mode was provided. + .. option:: --max-num-width Set the maximum number literal width (e.g. in 1024'd22 this it the diff --git a/src/V3Options.cpp b/src/V3Options.cpp index e1f194e8b..474cc3e57 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -435,6 +435,11 @@ string V3Options::allArgsStringForHierBlock(bool forTop) const { return out; } +void V3Options::ccSet() { // --cc + m_outFormatOk = true; + m_systemC = false; +} + //###################################################################### // File searching @@ -719,9 +724,10 @@ bool V3Options::systemCFound() { // V3 Options notification methods void V3Options::notify() { - FileLine* const cmdfl = new FileLine(FileLine::commandLineFilename()); - // Notify that all arguments have been passed and final modification can be made. + FileLine* const cmdfl = new FileLine{FileLine::commandLineFilename()}; + + if (!outFormatOk() && v3Global.opt.main()) ccSet(); // --main implies --cc if not provided if (!outFormatOk() && !cdc() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) { v3fatal("verilator: Need --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, " "--xml-only or --E option"); @@ -1002,10 +1008,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-build", Set, &m_build); DECL_OPTION("-CFLAGS", CbVal, callStrSetter(&V3Options::addCFlags)); - DECL_OPTION("-cc", CbCall, [this]() { - m_outFormatOk = true; - m_systemC = false; - }); + DECL_OPTION("-cc", CbCall, [this]() { ccSet(); }); DECL_OPTION("-cdc", OnOff, &m_cdc); DECL_OPTION("-clk", CbVal, callStrSetter(&V3Options::addClocker)); DECL_OPTION("-no-clk", CbVal, callStrSetter(&V3Options::addNoClocker)); @@ -1175,7 +1178,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_makeDir = valp; addIncDirFallback(m_makeDir); // Need to find generated files there too }); - DECL_OPTION("-main", OnOff, &m_main).undocumented(); // Future + DECL_OPTION("-main", OnOff, &m_main); DECL_OPTION("-make", CbVal, [this, fl](const char* valp) { if (!strcmp(valp, "cmake")) { m_cmake = true; diff --git a/src/V3Options.h b/src/V3Options.h index 8637277bb..190d4c7ab 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -410,8 +410,9 @@ public: void addNoClocker(const string& signame); void addVFile(const string& filename); void addForceInc(const string& filename); - void notify(); bool available() const { return m_available; } + void ccSet(); + void notify(); // ACCESSORS (options) bool preprocOnly() const { return m_preprocOnly; } diff --git a/test_regress/t/t_flag_main.pl b/test_regress/t/t_flag_main.pl index 381004460..57041562f 100755 --- a/test_regress/t/t_flag_main.pl +++ b/test_regress/t/t_flag_main.pl @@ -11,6 +11,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags => [# Custom as don't want -cc + "-Mdir $Self->{obj_dir}", + "--debug-check", ], verilator_flags2 => ['--exe --build --main'], verilator_make_cmake => 0, verilator_make_gmake => 0, From d85b90905456870a12dd6dc63a37c64347ec4456 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 14 Sep 2022 21:10:19 -0400 Subject: [PATCH 24/25] Internals: Use std:: for mem and str functions. --- examples/make_protect_lib/sim_main.cpp | 2 +- examples/make_tracing_sc/sc_main.cpp | 2 +- src/V3Ast.cpp | 8 ++--- src/V3Ast.h | 5 +-- src/V3Begin.cpp | 2 +- src/V3EmitCModel.cpp | 2 +- src/V3EmitCSyms.cpp | 2 +- src/V3File.cpp | 10 +++--- src/V3File.h | 4 +-- src/V3FileLine.cpp | 4 +-- src/V3LinkDot.cpp | 2 +- src/V3Number.cpp | 16 +++++----- src/V3OptionParser.cpp | 8 ++--- src/V3Options.cpp | 39 ++++++++++++------------ src/V3Os.cpp | 2 +- src/V3ParseImp.cpp | 10 +++--- src/V3PreLex.l | 4 +-- src/V3PreProc.cpp | 16 +++++----- src/V3String.cpp | 4 +-- src/V3Width.cpp | 2 +- src/verilog.l | 2 +- test_regress/driver.pl | 2 +- test_regress/t/TestCheck.h | 2 +- test_regress/t/TestSimulator.h | 6 ++-- test_regress/t/t_dpi_arg_inout_type.cpp | 16 +++++----- test_regress/t/t_dpi_arg_input_type.cpp | 8 ++--- test_regress/t/t_dpi_arg_output_type.cpp | 8 ++--- test_regress/t/t_dpi_export_c.cpp | 7 +++-- test_regress/t/t_dpi_result_type.cpp | 8 ++--- test_regress/t/t_dpi_string_c.cpp | 2 +- test_regress/t/t_dpi_var.cpp | 4 +-- test_regress/t/t_sc_names.cpp | 2 +- test_regress/t/t_scope_map.cpp | 2 +- test_regress/t/t_vpi_get.cpp | 2 +- test_regress/t/t_vpi_module.cpp | 6 ++-- test_regress/t/t_vpi_param.cpp | 2 +- test_regress/t/t_vpi_unimpl.cpp | 2 +- test_regress/t/t_vpi_var.cpp | 6 ++-- 38 files changed, 118 insertions(+), 113 deletions(-) diff --git a/examples/make_protect_lib/sim_main.cpp b/examples/make_protect_lib/sim_main.cpp index b3096b4c5..fefcb0c5a 100644 --- a/examples/make_protect_lib/sim_main.cpp +++ b/examples/make_protect_lib/sim_main.cpp @@ -32,7 +32,7 @@ int main(int argc, char** argv, char** env) { // When tracing, the contents of the secret module will not be seen VerilatedVcdC* tfp = nullptr; const char* flag = contextp->commandArgsPlusMatch("trace"); - if (flag && 0 == strcmp(flag, "+trace")) { + if (flag && 0 == std::strcmp(flag, "+trace")) { contextp->traceEverOn(true); VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n"); tfp = new VerilatedVcdC; diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp index 93861ceea..3d3cb1392 100644 --- a/examples/make_tracing_sc/sc_main.cpp +++ b/examples/make_tracing_sc/sc_main.cpp @@ -89,7 +89,7 @@ int sc_main(int argc, char* argv[]) { // and if at run time passed the +trace argument, turn on tracing VerilatedVcdSc* tfp = nullptr; const char* flag = Verilated::commandArgsPlusMatch("trace"); - if (flag && 0 == strcmp(flag, "+trace")) { + if (flag && 0 == std::strcmp(flag, "+trace")) { cout << "Enabling waves into logs/vlt_dump.vcd...\n"; tfp = new VerilatedVcdSc; top->trace(tfp, 99); // Trace 99 levels of hierarchy diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 2f1467f03..7694e1e69 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -165,22 +165,22 @@ string AstNode::prettyName(const string& namein) { continue; } if (pos[0] == '_' && pos[1] == '_') { // Short-circuit - if (0 == strncmp(pos, "__BRA__", 7)) { + if (0 == std::strncmp(pos, "__BRA__", 7)) { pretty += "["; pos += 7; continue; } - if (0 == strncmp(pos, "__KET__", 7)) { + if (0 == std::strncmp(pos, "__KET__", 7)) { pretty += "]"; pos += 7; continue; } - if (0 == strncmp(pos, "__DOT__", 7)) { + if (0 == std::strncmp(pos, "__DOT__", 7)) { pretty += "."; pos += 7; continue; } - if (0 == strncmp(pos, "__PVT__", 7)) { + if (0 == std::strncmp(pos, "__PVT__", 7)) { pretty += ""; pos += 7; continue; diff --git a/src/V3Ast.h b/src/V3Ast.h index 6e455ef1c..bb945564c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -467,8 +467,9 @@ public: return names[m_e]; } static void selfTest() { - UASSERT(0 == strcmp(VBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), "SelfTest: Enum mismatch"); - UASSERT(0 == strcmp(VBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), + UASSERT(0 == std::strcmp(VBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), + "SelfTest: Enum mismatch"); + UASSERT(0 == std::strcmp(VBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), "SelfTest: Enum mismatch"); } inline VBasicDTypeKwd() diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 0e4176739..6a40e1233 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -85,7 +85,7 @@ private: string::size_type pos; while ((pos = dottedname.find("__DOT__")) != string::npos) { const string ident = dottedname.substr(0, pos); - dottedname = dottedname.substr(pos + strlen("__DOT__")); + dottedname = dottedname.substr(pos + std::strlen("__DOT__")); if (nodep->name() != "") { m_displayScope = dot(m_displayScope, ident); m_namedScope = dot(m_namedScope, ident); diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 28687c19c..c8dc7b521 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -565,7 +565,7 @@ class EmitCModel final : public EmitCFunc { // Some hackery to locate handle__V for trace_init_task // Considered a pragma on the handle, but that still doesn't help us attach it here string handle = funcp->name(); - const size_t wr_len = strlen("__Vdpiimwrap_"); + const size_t wr_len = std::strlen("__Vdpiimwrap_"); UASSERT_OBJ(handle.substr(0, wr_len) == "__Vdpiimwrap_", funcp, "Strange trace_init_task function name"); handle = "vlSymsp->TOP." + handle.substr(wr_len); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 5193bd7e6..2bff31190 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -211,7 +211,7 @@ class EmitCSyms final : EmitCBaseVisitor { const string::size_type dpos = whole.rfind("__DOT__"); if (dpos != string::npos) { scpName = whole.substr(0, dpos); - varBase = whole.substr(dpos + strlen("__DOT__")); + varBase = whole.substr(dpos + std::strlen("__DOT__")); } else { varBase = whole; } diff --git a/src/V3File.cpp b/src/V3File.cpp index 57452b969..c4adf58bc 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -94,7 +94,7 @@ class V3FileDependImp final { const string fn = filename(); const int err = stat(fn.c_str(), &m_stat); if (err != 0) { - memset(&m_stat, 0, sizeof(m_stat)); + std::memset(&m_stat, 0, sizeof(m_stat)); m_stat.st_mtime = 1; m_exists = false; // Not an error... This can occur due to `line directives in the .vpp files @@ -389,7 +389,7 @@ private: if (!m_pidExited && waitpid(m_pid, &m_pidStatus, hang ? 0 : WNOHANG)) { UINFO(1, "--pipe-filter: Exited, status " << m_pidStatus << " exit=" << WEXITSTATUS(m_pidStatus) << " err" - << strerror(errno) << endl); + << std::strerror(errno) << endl); m_readEof = true; m_pidExited = true; } @@ -495,7 +495,7 @@ private: constexpr int P_WR = 1; if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) { - v3fatal("--pipe-filter: Can't pipe: " << strerror(errno)); + v3fatal("--pipe-filter: Can't pipe: " << std::strerror(errno)); } if (fd_stdin[P_RD] <= 2 || fd_stdin[P_WR] <= 2 || fd_stdout[P_RD] <= 2 || fd_stdout[P_WR] <= 2) { @@ -507,7 +507,7 @@ private: UINFO(1, "--pipe-filter: /bin/sh -c " << command << endl); const pid_t pid = fork(); - if (pid < 0) v3fatal("--pipe-filter: fork failed: " << strerror(errno)); + if (pid < 0) v3fatal("--pipe-filter: fork failed: " << std::strerror(errno)); if (pid == 0) { // Child UINFO(6, "In child\n"); close(fd_stdin[P_WR]); @@ -518,7 +518,7 @@ private: execl("/bin/sh", "sh", "-c", command.c_str(), static_cast(nullptr)); // Don't use v3fatal, we don't share the common structures any more - fprintf(stderr, "--pipe-filter: exec failed: %s\n", strerror(errno)); + fprintf(stderr, "--pipe-filter: exec failed: %s\n", std::strerror(errno)); _exit(1); } else { // Parent UINFO(6, "In parent, child pid " << pid << " stdin " << fd_stdin[P_WR] << "->" diff --git a/src/V3File.h b/src/V3File.h index 309f136c9..95b29eb8d 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -224,7 +224,7 @@ private: std::size_t len = strlen(str); std::size_t availableBytes = WRITE_BUFFER_SIZE_BYTES - m_usedBytes; while (VL_UNLIKELY(len >= availableBytes)) { - memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes); + std::memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes); m_usedBytes = WRITE_BUFFER_SIZE_BYTES; writeBlock(); str += availableBytes; @@ -232,7 +232,7 @@ private: availableBytes = WRITE_BUFFER_SIZE_BYTES; } if (len > 0) { - memcpy(m_bufferp->data() + m_usedBytes, str, len); + std::memcpy(m_bufferp->data() + m_usedBytes, str, len); m_usedBytes += len; } } diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 6b7b2e58b..0d9705c82 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -185,7 +185,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { const char* const ln = textp; while (*textp && !isspace(*textp)) textp++; if (isdigit(*ln)) { - lineno(atoi(ln)); + lineno(std::atoi(ln)); } else { fail = true; } @@ -207,7 +207,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { // Grab level while (*textp && (isspace(*textp) || *textp == '"')) textp++; if (isdigit(*textp)) { - enterExitRef = atoi(textp); + enterExitRef = std::atoi(textp); if (enterExitRef >= 3) fail = true; } else { enterExitRef = 0; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 02e6b439b..493beaf4d 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -919,7 +919,7 @@ class LinkDotFindVisitor final : public VNVisitor { string::size_type pos; if ((pos = dottedname.rfind("__DOT__")) != string::npos) { const string dotted = dottedname.substr(0, pos); - const string ident = dottedname.substr(pos + strlen("__DOT__")); + const string ident = dottedname.substr(pos + std::strlen("__DOT__")); string baddot; VSymEnt* okSymp; aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, dotted, baddot, okSymp); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index d7473cd29..81b059442 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -156,14 +156,15 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) } value_startp = cp; - if (atoi(widthn.c_str())) { - if (atoi(widthn.c_str()) < 0 || atoi(widthn.c_str()) > v3Global.opt.maxNumWidth()) { + if (std::atoi(widthn.c_str())) { + if (std::atoi(widthn.c_str()) < 0 + || std::atoi(widthn.c_str()) > v3Global.opt.maxNumWidth()) { // atoi might convert large number to negative, so can't tell which v3error("Unsupported: Width of number exceeds implementation limit: " << sourcep << " (IEEE 1800-2017 6.9.1)"); width(v3Global.opt.maxNumWidth(), true); } else { - width(atoi(widthn.c_str()), true); + width(std::atoi(widthn.c_str()), true); } } } else { @@ -278,7 +279,8 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) } } else { // Convert bin/octal number to hex - for (const char* cp = value_startp + strlen(value_startp) - 1; cp >= value_startp; cp--) { + for (const char* cp = value_startp + std::strlen(value_startp) - 1; cp >= value_startp; + cp--) { if (*cp != '_' && *cp != '0' && obit >= width()) { v3error("Too many digits for " << width() << " bit number: " << sourcep); break; @@ -698,7 +700,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { if (fmtsize != "0") str += ' '; } } - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, ' ', left, str); return str; } @@ -747,7 +749,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { } const bool zeropad = fmtsize.length() > 0 && fmtsize[0] == '0'; // fmtsize might have changed since we parsed the %fmtsize - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, (zeropad ? '0' : ' '), left, str); return str; } @@ -802,7 +804,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { return str; } case '@': { // Packed string - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, ' ', left, toString()); return str; } diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp index 308a26e10..8035916e7 100644 --- a/src/V3OptionParser.cpp +++ b/src/V3OptionParser.cpp @@ -130,8 +130,8 @@ V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { for (auto&& act : m_pimpl->m_options) { if (act.second->isFOnOffAllowed()) { // Find starts with "-fno" if (const char* const nop - = VString::startsWith(optp, "-fno-") ? (optp + strlen("-fno-")) : nullptr) { - if (act.first.substr(strlen("-f"), std::string::npos) + = VString::startsWith(optp, "-fno-") ? (optp + std::strlen("-fno-")) : nullptr) { + if (act.first.substr(std::strlen("-f"), std::string::npos) == nop) { // [-f]opt = [-fno-]opt return act.second.get(); } @@ -139,7 +139,7 @@ V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { } if (act.second->isOnOffAllowed()) { // Find starts with "-no" if (const char* const nop - = VString::startsWith(optp, "-no") ? (optp + strlen("-no")) : nullptr) { + = VString::startsWith(optp, "-no") ? (optp + std::strlen("-no")) : nullptr) { if (act.first == nop || act.first == (std::string{"-"} + nop)) { return act.second.get(); } @@ -206,7 +206,7 @@ void V3OptionParser::finalize() { m_pimpl->m_spellCheck.pushCandidate(opt.first); if (opt.second->isFOnOffAllowed()) { m_pimpl->m_spellCheck.pushCandidate( - "-fno-" + opt.first.substr(strlen("-f"), std::string::npos)); + "-fno-" + opt.first.substr(std::strlen("-f"), std::string::npos)); } if (opt.second->isOnOffAllowed()) m_pimpl->m_spellCheck.pushCandidate("-no" + opt.first); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 474cc3e57..0580fdac4 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -908,8 +908,8 @@ void V3Options::parseOpts(FileLine* fl, int argc, char** argv) { //====================================================================== bool V3Options::suffixed(const string& sw, const char* arg) { - if (strlen(arg) > sw.length()) return false; - return (0 == strcmp(sw.c_str() + sw.length() - strlen(arg), arg)); + if (std::strlen(arg) > sw.length()) return false; + return (0 == std::strcmp(sw.c_str() + sw.length() - std::strlen(arg), arg)); } void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv) { @@ -1019,15 +1019,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-comp-limit-parens", Set, &m_compLimitParens).undocumented(); DECL_OPTION("-comp-limit-syms", CbVal, [](int val) { VName::maxLength(val); }).undocumented(); DECL_OPTION("-compiler", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "clang")) { + if (!std::strcmp(valp, "clang")) { m_compLimitBlocks = 80; // limit unknown m_compLimitMembers = 64; // soft limit, has slowdown bug as of clang++ 3.8 m_compLimitParens = 240; // controlled by -fbracket-depth, which defaults to 256 - } else if (!strcmp(valp, "gcc")) { + } else if (!std::strcmp(valp, "gcc")) { m_compLimitBlocks = 0; // Bug free m_compLimitMembers = 64; // soft limit, has slowdown bug as of g++ 7.1 m_compLimitParens = 240; // Unlimited, but generate same code as for clang - } else if (!strcmp(valp, "msvc")) { + } else if (!std::strcmp(valp, "msvc")) { m_compLimitBlocks = 80; // 128, but allow some room m_compLimitMembers = 0; // probably ok, and AFAIK doesn't support anon structs m_compLimitParens = 80; // 128, but allow some room @@ -1180,9 +1180,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char }); DECL_OPTION("-main", OnOff, &m_main); DECL_OPTION("-make", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "cmake")) { + if (!std::strcmp(valp, "cmake")) { m_cmake = true; - } else if (!strcmp(valp, "gmake")) { + } else if (!std::strcmp(valp, "gmake")) { m_gmake = true; } else { fl->v3fatal("Unknown --make system specified: '" << valp << "'"); @@ -1329,13 +1329,13 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char if (m_threads < 0) fl->v3fatal("--threads must be >= 0: " << valp); }); DECL_OPTION("-threads-dpi", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "all")) { + if (!std::strcmp(valp, "all")) { m_threadsDpiPure = true; m_threadsDpiUnpure = true; - } else if (!strcmp(valp, "none")) { + } else if (!std::strcmp(valp, "none")) { m_threadsDpiPure = false; m_threadsDpiUnpure = false; - } else if (!strcmp(valp, "pure")) { + } else if (!std::strcmp(valp, "pure")) { m_threadsDpiPure = true; m_threadsDpiUnpure = false; } else { @@ -1470,13 +1470,13 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-waiver-output", Set, &m_waiverOutput); DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "0")) { + if (!std::strcmp(valp, "0")) { m_xAssign = "0"; - } else if (!strcmp(valp, "1")) { + } else if (!std::strcmp(valp, "1")) { m_xAssign = "1"; - } else if (!strcmp(valp, "fast")) { + } else if (!std::strcmp(valp, "fast")) { m_xAssign = "fast"; - } else if (!strcmp(valp, "unique")) { + } else if (!std::strcmp(valp, "unique")) { m_xAssign = "unique"; } else { fl->v3fatal("Unknown setting for --x-assign: '" @@ -1485,11 +1485,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } }); DECL_OPTION("-x-initial", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "0")) { + if (!std::strcmp(valp, "0")) { m_xInitial = "0"; - } else if (!strcmp(valp, "fast")) { + } else if (!std::strcmp(valp, "fast")) { m_xInitial = "fast"; - } else if (!strcmp(valp, "unique")) { + } else if (!std::strcmp(valp, "unique")) { m_xInitial = "unique"; } else { fl->v3fatal("Unknown setting for --x-initial: '" @@ -1511,11 +1511,12 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char for (int i = 0; i < argc;) { UINFO(9, " Option: " << argv[i] << endl); - if (!strcmp(argv[i], "-j") || !strcmp(argv[i], "--j")) { // Allow gnu -- switches + if (!std::strcmp(argv[i], "-j") + || !std::strcmp(argv[i], "--j")) { // Allow gnu -- switches ++i; m_buildJobs = 0; // Unlimited parallelism if (i < argc && isdigit(argv[i][0])) { - m_buildJobs = atoi(argv[i]); + m_buildJobs = std::atoi(argv[i]); if (m_buildJobs <= 0) { fl->v3error("-j accepts positive integer, but '" << argv[i] << "' is passed"); } diff --git a/src/V3Os.cpp b/src/V3Os.cpp index c410c6735..2abc200c0 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -347,7 +347,7 @@ int V3Os::system(const string& command) { const int ret = ::system(command.c_str()); if (VL_UNCOVERABLE(ret == -1)) { v3fatal("Failed to execute command:" // LCOV_EXCL_LINE - << command << " " << strerror(errno)); + << command << " " << std::strerror(errno)); return -1; // LCOV_EXCL_LINE } else { UASSERT(WIFEXITED(ret), "system(" << command << ") returned unexpected value of " << ret); diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 8a1481323..1d2832ce5 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -150,8 +150,8 @@ void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnO void V3ParseImp::lexVerilatorCmtBad(FileLine* fl, const char* textp) { string cmtparse = textp; - if (cmtparse.substr(0, strlen("/*verilator")) == "/*verilator") { - cmtparse.replace(0, strlen("/*verilator"), ""); + if (cmtparse.substr(0, std::strlen("/*verilator")) == "/*verilator") { + cmtparse.replace(0, std::strlen("/*verilator"), ""); } while (isspace(cmtparse[0])) cmtparse.replace(0, 1, ""); string cmtname; @@ -178,14 +178,14 @@ void V3ParseImp::lexErrorPreprocDirective(FileLine* fl, const char* textp) { } string V3ParseImp::lexParseTag(const char* textp) { - string tmp = textp + strlen("/*verilator tag "); + string tmp = textp + std::strlen("/*verilator tag "); string::size_type pos; if ((pos = tmp.rfind("*/")) != string::npos) tmp.erase(pos); return tmp; } double V3ParseImp::lexParseTimenum(const char* textp) { - const size_t length = strlen(textp); + const size_t length = std::strlen(textp); char* const strgp = new char[length + 1]; char* dp = strgp; const char* sp = textp; @@ -234,7 +234,7 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) { m_ppBuffers.push_front(remainder); // Put back remainder for next time len = (max_size - got); } - memcpy(buf + got, front.c_str(), len); + std::memcpy(buf + got, front.c_str(), len); got += len; } if (debug() >= 9) { diff --git a/src/V3PreLex.l b/src/V3PreLex.l index bfe69e7c7..a83a55db9 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -126,7 +126,7 @@ bom [\357\273\277] if (LEXP->m_protBytes > 0) { LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "multiple `pragma protected encoding sections"); } - res = sscanf(yytext + strlen("encoding"), " = (enctype = \"%15[A-Za-z0-9]\", line_length = %d, bytes = %d)", &enctype[0], &LEXP->m_protLength, &LEXP->m_protBytes); + res = sscanf(yytext + std::strlen("encoding"), " = (enctype = \"%15[A-Za-z0-9]\", line_length = %d, bytes = %d)", &enctype[0], &LEXP->m_protLength, &LEXP->m_protBytes); if (res == 0) LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "`pragma protected encoding must have an \"enctype\" field"); LEXP->m_encType = !VL_STRCASECMP(enctype, "uuencode") ? Enctype::UUENCODE : @@ -242,7 +242,7 @@ bom [\357\273\277] "`__LINE__" { FL_FWDC; static char buf[25]; VL_SNPRINTF(buf, 25, "%d", LEXP->curFilelinep()->lastLineno()); - yytext = buf; yyleng = strlen(yytext); + yytext = buf; yyleng = std::strlen(yytext); return VP_TEXT; } /* Pass-through strings */ diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 59ba4398b..0cf66dc24 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -395,7 +395,7 @@ string V3PreProcImp::commentCleanup(const string& text) { } bool V3PreProcImp::commentTokenMatch(string& cmdr, const char* strg) { - int len = strlen(strg); + int len = std::strlen(strg); if (VString::startsWith(cmdr, strg) && (cmdr[len] == '\0' || isspace(cmdr[len]))) { if (isspace(cmdr[len])) len++; cmdr = cmdr.substr(len); @@ -425,27 +425,27 @@ void V3PreProcImp::comment(const string& text) { bool synth = false; bool vlcomment = false; if ((cp[0] == 'v' || cp[0] == 'V') && VString::startsWith(cp + 1, "erilator")) { - cp += strlen("verilator"); + cp += std::strlen("verilator"); if (*cp == '_') { fileline()->v3error("Extra underscore in meta-comment;" " use /*verilator {...}*/ not /*verilator_{...}*/"); } vlcomment = true; } else if (VString::startsWith(cp, "synopsys")) { - cp += strlen("synopsys"); + cp += std::strlen("synopsys"); synth = true; if (*cp == '_') { fileline()->v3error("Extra underscore in meta-comment;" " use /*synopsys {...}*/ not /*synopsys_{...}*/"); } } else if (VString::startsWith(cp, "cadence")) { - cp += strlen("cadence"); + cp += std::strlen("cadence"); synth = true; } else if (VString::startsWith(cp, "pragma")) { - cp += strlen("pragma"); + cp += std::strlen("pragma"); synth = true; } else if (VString::startsWith(cp, "ambit synthesis")) { - cp += strlen("ambit synthesis"); + cp += std::strlen("ambit synthesis"); synth = true; } else { return; @@ -478,7 +478,7 @@ void V3PreProcImp::comment(const string& text) { string::size_type pos; if ((pos = cmd.find("public_flat_rw")) != string::npos) { // "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)" - cmd = cmd.substr(pos + strlen("public_flat_rw")); + cmd = cmd.substr(pos + std::strlen("public_flat_rw")); while (isspace(cmd[0])) cmd = cmd.substr(1); if (!printed) insertUnreadback("/*verilator public_flat_rw*/ " + cmd + " /**/"); } else { @@ -1593,7 +1593,7 @@ string V3PreProcImp::getline() { if (isEof()) return ""; const char* rtnp; bool gotEof = false; - while (nullptr == (rtnp = strchr(m_lineChars.c_str(), '\n')) && !gotEof) { + while (nullptr == (rtnp = std::strchr(m_lineChars.c_str(), '\n')) && !gotEof) { string buf; const int tok = getFinalToken(buf /*ref*/); if (debug() >= 5) { diff --git a/src/V3String.cpp b/src/V3String.cpp index 9d20bd078..1a42ee2e7 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -150,7 +150,7 @@ double VString::parseDouble(const string& str, bool* successp) { char* endp = strgp; const double d = strtod(strgp, &endp); const size_t parsed_len = endp - strgp; - if (parsed_len != strlen(strgp)) { + if (parsed_len != std::strlen(strgp)) { if (successp) *successp = false; } VL_DO_DANGLING(delete[] strgp, strgp); @@ -402,7 +402,7 @@ void VHashSha256::selfTest() { string VName::dehash(const string& in) { static const char VHSH[] = "__Vhsh"; - static const size_t DOT_LEN = strlen("__DOT__"); + static const size_t DOT_LEN = std::strlen("__DOT__"); std::string dehashed; // Need to split 'in' into components separated by __DOT__, 'last_dot_pos' diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 081fc526e..a784b3024 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5963,7 +5963,7 @@ private: } if ((VN_IS(nodep, Add) && underp->width() == 1 && underp->isOne()) || (VN_IS(nodep, Sub) && underp->width() == 1 && underp->isOne() - && 0 == strcmp(side, "RHS"))) { + && 0 == std::strcmp(side, "RHS"))) { // "foo + 1'b1", or "foo - 1'b1" are very common, people assume // they extend correctly warnOn = false; diff --git a/src/verilog.l b/src/verilog.l index a3cc59ef6..46f612ef4 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -1004,7 +1004,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} return yaT_RESETALL; } // Rest handled by preproc "`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`timescale"{ws}+[^\n\r]* { FL; PARSEP->lexTimescaleParse(yylval.fl, - yytext + strlen("`timescale")); + yytext + std::strlen("`timescale")); FL_BRK; } "`unconnected_drive"{ws}+"pull0" { FL; return yaT_UNCONNECTED_PULL0; } "`unconnected_drive"{ws}+"pull1" { FL; return yaT_UNCONNECTED_PULL1; } diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 22a2a67f8..fe0bd9498 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1845,7 +1845,7 @@ sub _make_main { if ($self->{savable}) { $fh->print(" const char* save_time_strp = contextp->commandArgsPlusMatch(\"save_time=\");\n"); - $fh->print(" unsigned int save_time = !save_time_strp[0] ? 0 : atoi(save_time_strp+strlen(\"+save_time=\"));\n"); + $fh->print(" unsigned int save_time = !save_time_strp[0] ? 0 : std::atoi(save_time_strp + std::strlen(\"+save_time=\"));\n"); $fh->print(" const char* save_restore_strp = contextp->commandArgsPlusMatch(\"save_restore=\");\n"); $fh->print(" unsigned int save_restore = !save_restore_strp[0] ? 0 : 1;\n"); } diff --git a/test_regress/t/TestCheck.h b/test_regress/t/TestCheck.h index ac42dde3b..2f8cf2283 100644 --- a/test_regress/t/TestCheck.h +++ b/test_regress/t/TestCheck.h @@ -34,7 +34,7 @@ static const bool verbose = false; #define TEST_CHECK_EQ(got, exp) TEST_CHECK(got, exp, ((got) == (exp))); #define TEST_CHECK_NE(got, exp) TEST_CHECK(got, exp, ((got) != (exp))); -#define TEST_CHECK_CSTR(got, exp) TEST_CHECK(got, exp, 0 == strcmp((got), (exp))); +#define TEST_CHECK_CSTR(got, exp) TEST_CHECK(got, exp, 0 == std::strcmp((got), (exp))); #define TEST_CHECK_HEX_EQ(got, exp) \ do { \ diff --git a/test_regress/t/TestSimulator.h b/test_regress/t/TestSimulator.h index 6272887d8..c25304f6e 100644 --- a/test_regress/t/TestSimulator.h +++ b/test_regress/t/TestSimulator.h @@ -28,13 +28,13 @@ private: public: TestSimulator() { vpi_get_vlog_info(&m_info); - if (0 == strcmp(m_info.product, "Verilator")) { + if (0 == std::strcmp(m_info.product, "Verilator")) { m_simulators.verilator = true; - } else if (0 == strcmp(m_info.product, "Verilator")) { + } else if (0 == std::strcmp(m_info.product, "Verilator")) { m_simulators.icarus = true; } else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", - strlen("Chronologic Simulation VCS"))) { + std::strlen("Chronologic Simulation VCS"))) { m_simulators.vcs = true; } else { printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n", __FILE__, diff --git a/test_regress/t/t_dpi_arg_inout_type.cpp b/test_regress/t/t_dpi_arg_inout_type.cpp index a5c346d8f..f5b109b39 100644 --- a/test_regress/t/t_dpi_arg_inout_type.cpp +++ b/test_regress/t/t_dpi_arg_inout_type.cpp @@ -168,10 +168,10 @@ void i_string(const char** x) { static int n = 0; printf("i_string %d\n", n); if (n++ % 2 == 0) { - if (strcmp(*x, "Hello") != 0) stop(); + if (std::strcmp(*x, "Hello") != 0) stop(); *x = "Good"; } else { - if (strcmp(*x, "World") != 0) stop(); + if (std::strcmp(*x, "World") != 0) stop(); *x = "Bye"; } } @@ -296,10 +296,10 @@ void i_string_t(const char** x) { static int n = 0; printf("i_string_t %d\n", n); if (n++ % 2 == 0) { - if (strcmp(*x, "World") != 0) stop(); + if (std::strcmp(*x, "World") != 0) stop(); *x = "Bye"; } else { - if (strcmp(*x, "Hello") != 0) stop(); + if (std::strcmp(*x, "Hello") != 0) stop(); *x = "Good"; } } @@ -962,10 +962,10 @@ void check_exports() { e_string(&x_string); if ((n % 2) == 0) { if (x_chandle) stop(); - if (strcmp(x_string, "Hello") != 0) stop(); + if (std::strcmp(x_string, "Hello") != 0) stop(); } else { if (x_chandle) stop(); - if (strcmp(x_string, "World") != 0) stop(); + if (std::strcmp(x_string, "World") != 0) stop(); } x_bit = n % 2; @@ -1045,10 +1045,10 @@ void check_exports() { e_string_t(&x_string_t); if ((n % 2) == 0) { if (x_chandle_t != NULL) stop(); - if (strcmp(x_string_t, "World") != 0) stop(); + if (std::strcmp(x_string_t, "World") != 0) stop(); } else { if (x_chandle_t != NULL) stop(); - if (strcmp(x_string_t, "Hello") != 0) stop(); + if (std::strcmp(x_string_t, "Hello") != 0) stop(); } x_bit_t = n % 2; diff --git a/test_regress/t/t_dpi_arg_input_type.cpp b/test_regress/t/t_dpi_arg_input_type.cpp index 1593e1dfc..ee7f56d79 100644 --- a/test_regress/t/t_dpi_arg_input_type.cpp +++ b/test_regress/t/t_dpi_arg_input_type.cpp @@ -155,9 +155,9 @@ void i_string(const char* i) { static int n = 0; printf("i_string %d\n", n); if (n++ % 2 == 0) { - if (strcmp(i, "World") != 0) stop(); + if (std::strcmp(i, "World") != 0) stop(); } else { - if (strcmp(i, "Hello") != 0) stop(); + if (std::strcmp(i, "Hello") != 0) stop(); } } @@ -266,9 +266,9 @@ void i_string_t(const char* i) { static int n = 0; printf("i_string_t %d\n", n); if (n++ % 2 == 0) { - if (strcmp(i, "World") != 0) stop(); + if (std::strcmp(i, "World") != 0) stop(); } else { - if (strcmp(i, "Hello") != 0) stop(); + if (std::strcmp(i, "Hello") != 0) stop(); } } diff --git a/test_regress/t/t_dpi_arg_output_type.cpp b/test_regress/t/t_dpi_arg_output_type.cpp index cf127ee6e..b8eda4a74 100644 --- a/test_regress/t/t_dpi_arg_output_type.cpp +++ b/test_regress/t/t_dpi_arg_output_type.cpp @@ -711,9 +711,9 @@ void check_exports() { e_string(&x_string); if ((n % 2) == 0) { - if (strcmp(x_string, "Hello") != 0) stop(); + if (std::strcmp(x_string, "Hello") != 0) stop(); } else { - if (strcmp(x_string, "World") != 0) stop(); + if (std::strcmp(x_string, "World") != 0) stop(); } e_bit(&x_bit); @@ -772,9 +772,9 @@ void check_exports() { e_string_t(&x_string_t); if ((n % 2) == 0) { - if (strcmp(x_string_t, "Hello") != 0) stop(); + if (std::strcmp(x_string_t, "Hello") != 0) stop(); } else { - if (strcmp(x_string_t, "World") != 0) stop(); + if (std::strcmp(x_string_t, "World") != 0) stop(); } e_bit_t(&x_bit_t); diff --git a/test_regress/t/t_dpi_export_c.cpp b/test_regress/t/t_dpi_export_c.cpp index da9fee221..8b60a1c66 100644 --- a/test_regress/t/t_dpi_export_c.cpp +++ b/test_regress/t/t_dpi_export_c.cpp @@ -115,9 +115,10 @@ int dpix_run_tests() { #ifndef CADENCE // Unimplemented; how hard is it? printf("svDpiVersion: %s\n", svDpiVersion()); - CHECK_RESULT( - bool, - strcmp(svDpiVersion(), "1800-2005") == 0 || strcmp(svDpiVersion(), "P1800-2005") == 0, 1); + CHECK_RESULT(bool, + std::strcmp(svDpiVersion(), "1800-2005") == 0 + || std::strcmp(svDpiVersion(), "P1800-2005") == 0, + 1); #endif CHECK_RESULT(int, dpix_int123(), 0x123); diff --git a/test_regress/t/t_dpi_result_type.cpp b/test_regress/t/t_dpi_result_type.cpp index a0d7b3cb5..bc8314a15 100644 --- a/test_regress/t/t_dpi_result_type.cpp +++ b/test_regress/t/t_dpi_result_type.cpp @@ -303,9 +303,9 @@ void check_exports() { #endif if (e_chandle()) stop(); if ((n % 2) == 0) { - if (strcmp(e_string(), "Hello") != 0) stop(); + if (std::strcmp(e_string(), "Hello") != 0) stop(); } else { - if (strcmp(e_string(), "World") != 0) stop(); + if (std::strcmp(e_string(), "World") != 0) stop(); } if (e_bit() != (n % 2)) stop(); if (e_logic() != !(n % 2)) stop(); @@ -327,9 +327,9 @@ void check_exports() { #endif if (e_chandle_t()) stop(); if ((n % 2) == 0) { - if (strcmp(e_string_t(), "Hello") != 0) stop(); + if (std::strcmp(e_string_t(), "Hello") != 0) stop(); } else { - if (strcmp(e_string_t(), "World") != 0) stop(); + if (std::strcmp(e_string_t(), "World") != 0) stop(); } if (e_bit_t() != (n % 2)) stop(); if (e_logic_t() != !(n % 2)) stop(); diff --git a/test_regress/t/t_dpi_string_c.cpp b/test_regress/t/t_dpi_string_c.cpp index 05b001886..9216d9316 100644 --- a/test_regress/t/t_dpi_string_c.cpp +++ b/test_regress/t/t_dpi_string_c.cpp @@ -39,5 +39,5 @@ extern int dpii_string(const char* s); int dpii_string(const char* s) { printf("dpii_string: %s\n", s); - return strlen(s); + return std::strlen(s); } diff --git a/test_regress/t/t_dpi_var.cpp b/test_regress/t/t_dpi_var.cpp index f35647d41..5f9ee79f1 100644 --- a/test_regress/t/t_dpi_var.cpp +++ b/test_regress/t/t_dpi_var.cpp @@ -60,9 +60,9 @@ void mon_scope_name(const char* namep) { #ifdef TEST_VERBOSE VL_PRINTF("- mon_scope_name('%s', \"%s\");\n", modp, namep); #endif - if (strcmp(namep, "t.sub")) + if (std::strcmp(namep, "t.sub")) vl_fatal(__FILE__, __LINE__, "", (std::string{"Unexp scope name "} + namep).c_str()); - if (strcmp(modp, "t.sub")) + if (std::strcmp(modp, "t.sub")) vl_fatal(__FILE__, __LINE__, "", (std::string{"Unexp dpiscope name "} + modp).c_str()); } diff --git a/test_regress/t/t_sc_names.cpp b/test_regress/t/t_sc_names.cpp index 6839252b0..6f73c4c1d 100644 --- a/test_regress/t/t_sc_names.cpp +++ b/test_regress/t/t_sc_names.cpp @@ -15,7 +15,7 @@ int sc_main(int argc, char* argv[]) { /* We expect to find clk in here. */ for (int i = 0; i < ch.size(); ++i) { - if (!strcmp(ch[i]->basename(), "clk")) found = true; + if (!std::strcmp(ch[i]->basename(), "clk")) found = true; } if (found) { diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp index 9136c8ee3..d9f554d8b 100644 --- a/test_regress/t/t_scope_map.cpp +++ b/test_regress/t/t_scope_map.cpp @@ -100,7 +100,7 @@ int main(int argc, char** argv, char** env) { #endif // Clear out the data - memset(varData, 0, (varBits + 7) / 8); + std::memset(varData, 0, (varBits + 7) / 8); } } diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index fdd93ee01..898664841 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -71,7 +71,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 754cc2660..1c2de048c 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -61,7 +61,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ @@ -100,7 +100,7 @@ int mon_check() { CHECK_RESULT_NZ(t_name); // Icarus reports the top most module as "top" - if (strcmp(t_name, "top") == 0) { + if (std::strcmp(t_name, "top") == 0) { it = vpi_iterate(vpiModule, topmod); CHECK_RESULT_NZ(it); CHECK_RESULT(vpi_get(vpiType, it), vpiModule); @@ -129,7 +129,7 @@ int mon_check() { CHECK_RESULT_NZ(mod3); const char* mod_c_name = vpi_get_str(vpiName, mod3); - if (strcmp(mod_c_name, "mod_b") == 0) { + if (std::strcmp(mod_c_name, "mod_b") == 0) { // Full visibility in other simulators, skip mod_b TestVpiHandle mod4 = vpi_scan(it3); CHECK_RESULT_NZ(mod4); diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index 51415a38b..dcc4a7fb9 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -71,7 +71,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index 549d66e1e..e91515a6e 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -66,7 +66,7 @@ unsigned int callback_count = 0; } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index b8186c281..1c5c76f50 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -90,7 +90,7 @@ bool verbose = false; } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ ((got) != NULL) ? (got) : "", ((exp) != NULL) ? (exp) : ""); \ return __LINE__; \ @@ -117,7 +117,7 @@ int _mon_check_mcd() { } status = vpi_mcd_printf(mcd, (PLI_BYTE8*)"hello %s", "vpi_mcd_printf"); - CHECK_RESULT(status, strlen("hello vpi_mcd_printf")); + CHECK_RESULT(status, std::strlen("hello vpi_mcd_printf")); status = vpi_mcd_printf(0, (PLI_BYTE8*)"empty"); CHECK_RESULT(status, 0); @@ -634,7 +634,7 @@ int _mon_check_vlog_info() { CHECK_RESULT_Z(vlog_info.argv[4]); if (TestSimulator::is_verilator()) { CHECK_RESULT_CSTR(vlog_info.product, "Verilator"); - CHECK_RESULT(strlen(vlog_info.version) > 0, 1); + CHECK_RESULT(std::strlen(vlog_info.version) > 0, 1); } return 0; } From e43c089ab833ed4ec62466ee37c63bf613f74603 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 14 Sep 2022 23:26:34 -0400 Subject: [PATCH 25/25] Commentary --- README.rst | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index 8dd636245..d46296d02 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,7 @@ Welcome to Verilator - |Logo| * - |verilator multithreaded performance| - **Fast** - * Outperforms many commercial simulators + * Outperforms many closed-source commercial simulators * Single- and multi-threaded output models * - **Widely Used** * Wide industry and academic deployment @@ -55,20 +55,19 @@ performing lint checks, and optionally inserting assertion checks and coverage-analysis points. It outputs single- or multi-threaded .cpp and .h files, the "Verilated" code. -The user writes a little C++/SystemC wrapper file, which instantiates the -"Verilated" model of the user's top level module. These C++/SystemC files -are then compiled by a C++ compiler (gcc/clang/MSVC++). Executing the -resulting executable performs the design simulation. Verilator also -supports linking Verilated generated libraries, optionally encrypted, into -other simulators. +These Verilated C++/SystemC files are then compiled by a C++ compiler +(gcc/clang/MSVC++), optionally along with a user's own C++/SystemC wrapper +file to instantiate the Verilated model. Executing the resulting executable +performs the design simulation. Verilator also supports linking Verilated +generated libraries, optionally encrypted, into other simulators. Verilator may not be the best choice if you are expecting a full featured -replacement for Incisive, ModelSim/Questa, VCS or another commercial -Verilog simulator, or if you are looking for a behavioral Verilog simulator -e.g. for a quick class project (we recommend `Icarus Verilog`_ for this.) -However, if you are looking for a path to migrate SystemVerilog to C++ or -SystemC, or your team is comfortable writing just a touch of C++ code, -Verilator is the tool for you. +replacement for a closed-source Verilog simulator, need SDF annotation, +mixed-signal simulation, or are doing a quick class project (we recommend +`Icarus Verilog`_ for classwork.) However, if you are looking for a path +to migrate SystemVerilog to C++/SystemC, or want high speed simulation of +synthesizable designs containing limited verification constructs, Verilator +is the tool for you. Performance @@ -85,9 +84,11 @@ multithreading (yielding 200-1000x total over interpreted simulators). Verilator has typically similar or better performance versus the closed-source Verilog simulators (Carbon Design Systems Carbonator, -Modelsim, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic -CVer/CVC). But, Verilator is open-sourced, so you can spend on computes -rather than licenses. Thus Verilator gives you the best cycles/dollar. +Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and +Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on +computes rather than licenses. Thus Verilator gives you the best +cycles/dollar. + Installation & Documentation ============================