From 2022ec43cfa22a01328b7f7ddf08376606dbe2a8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 24 Apr 2021 11:00:35 -0400 Subject: [PATCH 01/80] Update gtkwave from upstream. --- include/gtkwave/fst_win_unistd.h | 52 +++++++++++++++ include/gtkwave/fstapi.c | 106 ++++++++++++++++--------------- include/gtkwave/fstapi.h | 6 +- 3 files changed, 113 insertions(+), 51 deletions(-) create mode 100644 include/gtkwave/fst_win_unistd.h diff --git a/include/gtkwave/fst_win_unistd.h b/include/gtkwave/fst_win_unistd.h new file mode 100644 index 000000000..15ab2c1fc --- /dev/null +++ b/include/gtkwave/fst_win_unistd.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009-2018 Tony Bybell. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ + +#ifndef WIN_UNISTD_H +#define WIN_UNISTD_H + +#include +#ifdef _WIN64 +#include +#else +#include +#endif + +#include + +#define ftruncate _chsize_s +#define unlink _unlink +#define fileno _fileno +#define lseek _lseeki64 + +#ifdef _WIN64 +#define ssize_t __int64 +#define SSIZE_MAX 9223372036854775807i64 +#else +#define ssize_t long +#define SSIZE_MAX 2147483647L +#endif + +#include "stdint.h" + +#endif //WIN_UNISTD_H diff --git a/include/gtkwave/fstapi.c b/include/gtkwave/fstapi.c index 3cb4652c9..b4c9823d2 100644 --- a/include/gtkwave/fstapi.c +++ b/include/gtkwave/fstapi.c @@ -80,6 +80,12 @@ #define PATH_MAX (4096) #endif +#if defined(_MSC_VER) +typedef int64_t fst_off_t; +#else +typedef off_t fst_off_t; +#endif + /* note that Judy versus Jenkins requires more experimentation: they are */ /* functionally equivalent though it appears Jenkins is slightly faster. */ /* in addition, Jenkins is not bound by the LGPL. */ @@ -155,8 +161,8 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 #ifdef __MINGW32__ #include #ifndef HAVE_FSEEKO -#define ftello ftell -#define fseeko fseek +#define ftello _ftelli64 +#define fseeko _fseeki64 #endif #endif @@ -284,7 +290,7 @@ static size_t fstFwrite(const void *buf, size_t siz, size_t cnt, FILE *fp) return(fwrite(buf, siz, cnt, fp)); } -static int fstFtruncate(int fd, off_t length) +static int fstFtruncate(int fd, fst_off_t length) { return(ftruncate(fd, length)); } @@ -329,12 +335,12 @@ return(NULL); #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off)) #define fstMunmap(__addr,__len) free(__addr) -static void *fstMmap2(size_t __len, int __fd, off_t __off) +static void *fstMmap2(size_t __len, int __fd, fst_off_t __off) { (void)__off; unsigned char *pnt = (unsigned char *)malloc(__len); -off_t cur_offs = lseek(__fd, 0, SEEK_CUR); +fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR); size_t i; lseek(__fd, 0, SEEK_SET); @@ -734,7 +740,7 @@ FILE *tchn_handle; unsigned char *vchg_mem; -off_t hier_file_len; +fst_off_t hier_file_len; uint32_t *valpos_mem; unsigned char *curval_mem; @@ -754,7 +760,7 @@ unsigned fourpack : 1; unsigned fastpack : 1; int64_t timezero; -off_t section_header_truncpos; +fst_off_t section_header_truncpos; uint32_t tchn_cnt, tchn_idx; uint64_t curtime; uint64_t firsttime; @@ -762,7 +768,7 @@ uint32_t vchg_siz; uint32_t vchg_alloc_siz; uint32_t secnum; -off_t section_start; +fst_off_t section_start; uint32_t numscopes; double nan; /* nan value for uninitialized doubles */ @@ -820,7 +826,7 @@ fstEnumHandle max_enumhandle; }; -static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, off_t offset, int whence) +static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, fst_off_t offset, int whence) { int rc = fseeko(stream, offset, whence); @@ -987,7 +993,7 @@ if(pnt == MAP_FAILED) static void fstWriterCreateMmaps(struct fstWriterContext *xc) { -off_t curpos = ftello(xc->handle); +fst_off_t curpos = ftello(xc->handle); fflush(xc->hier_handle); @@ -1041,7 +1047,7 @@ if(xc->curval_mem) { unsigned char *pnt = xc->curval_mem; int __fd = fileno(xc->curval_handle); - off_t cur_offs = lseek(__fd, 0, SEEK_CUR); + fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR); size_t i; size_t __len = xc->maxvalpos; @@ -1282,14 +1288,14 @@ int cnt = 0; unsigned int i; unsigned char *vchg_mem; FILE *f; -off_t fpos, indxpos, endpos; +fst_off_t fpos, indxpos, endpos; uint32_t prevpos; int zerocnt; unsigned char *scratchpad; unsigned char *scratchpnt; unsigned char *tmem; -off_t tlen; -off_t unc_memreq = 0; /* for reader */ +fst_off_t tlen; +fst_off_t unc_memreq = 0; /* for reader */ unsigned char *packmem; unsigned int packmemlen; uint32_t *vm4ip; @@ -1733,7 +1739,7 @@ if(tmem) unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen)); int rc = compress2(dmem, &destlen, tmem, tlen, 9); - if((rc == Z_OK) && (((off_t)destlen) < tlen)) + if((rc == Z_OK) && (((fst_off_t)destlen) < tlen)) { fstFwrite(dmem, destlen, 1, xc->handle); } @@ -1781,7 +1787,7 @@ fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET); xc2->section_header_truncpos = endpos; /* cache in case of need to truncate */ if(xc->dump_size_limit) { - if(endpos >= ((off_t)xc->dump_size_limit)) + if(endpos >= ((fst_off_t)xc->dump_size_limit)) { xc2->skip_writing_section_hdr = 1; xc2->size_limit_locked = 1; @@ -1931,7 +1937,7 @@ if(xc) if(xc && !xc->already_in_close && !xc->already_in_flush) { unsigned char *tmem = NULL; - off_t fixup_offs, tlen, hlen; + fst_off_t fixup_offs, tlen, hlen; xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */ @@ -1991,7 +1997,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen)); int rc = compress2(dmem, &destlen, tmem, tlen, 9); - if((rc != Z_OK) || (((off_t)destlen) > tlen)) + if((rc != Z_OK) || (((fst_off_t)destlen) > tlen)) { destlen = tlen; } @@ -2002,7 +2008,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) fstWriterUint64(xc->handle, tlen); /* uncompressed */ /* compressed len is section length - 24 */ fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */ - fstFwrite((((off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle); + fstFwrite((((fst_off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle); fflush(xc->handle); fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); @@ -2018,7 +2024,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) if(xc->num_blackouts) { uint64_t cur_bl = 0; - off_t bpos, eos; + fst_off_t bpos, eos; uint32_t i; fixup_offs = ftello(xc->handle); @@ -2051,7 +2057,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) if(xc->compress_hier) { - off_t hl, eos; + fst_off_t hl, eos; gzFile zhandle; int zfd; int fourpack_duo = 0; @@ -2174,7 +2180,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) if(xc->repack_on_close) { FILE *fp; - off_t offpnt, uclen; + fst_off_t offpnt, uclen; int flen = strlen(xc->filename); char *hf = (char *)calloc(1, flen + 5); @@ -2281,7 +2287,7 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { char s[FST_HDR_DATE_SIZE]; - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); int len = strlen(dat); fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_DATE, SEEK_SET); @@ -2300,7 +2306,7 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc && vers) { char s[FST_HDR_SIM_VERSION_SIZE]; - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); int len = strlen(vers); fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET); @@ -2320,7 +2326,7 @@ if(xc) { if(/*(filetype >= FST_FT_MIN) &&*/ (filetype <= FST_FT_MAX)) { - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); xc->filetype = filetype; @@ -2461,7 +2467,7 @@ void fstWriterSetTimescale(void *ctx, int ts) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET); fputc(ts & 255, xc->handle); fflush(xc->handle); @@ -2519,7 +2525,7 @@ void fstWriterSetTimezero(void *ctx, int64_t tim) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET); fstWriterUint64(xc->handle, (xc->timezero = tim)); fflush(xc->handle); @@ -3361,7 +3367,7 @@ char date[FST_HDR_DATE_SIZE + 1]; int64_t timezero; char *filename, *filename_unpacked; -off_t hier_pos; +fst_off_t hier_pos; uint32_t num_blackouts; uint64_t *blackout_times; @@ -3376,10 +3382,10 @@ uint64_t *rvat_time_table; uint64_t rvat_beg_tim, rvat_end_tim; unsigned char *rvat_frame_data; uint64_t rvat_frame_maxhandle; -off_t *rvat_chain_table; +fst_off_t *rvat_chain_table; uint32_t *rvat_chain_table_lengths; uint64_t rvat_vc_maxhandle; -off_t rvat_vc_start; +fst_off_t rvat_vc_start; uint32_t *rvat_sig_offs; int rvat_packtype; @@ -3418,7 +3424,7 @@ char *fh_nam; }; -int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, off_t offset, int whence) +int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, fst_off_t offset, int whence) { int rc = fseeko(stream, offset, whence); @@ -3911,11 +3917,11 @@ int pass_status = 1; if(!xc->fh) { - off_t offs_cache = ftello(xc->f); + fst_off_t offs_cache = ftello(xc->f); char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN); - off_t hl, uclen; - off_t clen = 0; + fst_off_t hl, uclen; + fst_off_t clen = 0; gzFile zhandle = NULL; int zfd; int htyp = FST_BL_SKIP; @@ -4535,8 +4541,8 @@ return(1); */ int fstReaderInit(struct fstReaderContext *xc) { -off_t blkpos = 0; -off_t endfile; +fst_off_t blkpos = 0; +fst_off_t endfile; uint64_t seclen; int sectype; uint64_t vc_section_count_actual = 0; @@ -4548,7 +4554,7 @@ sectype = fgetc(xc->f); if(sectype == FST_BL_ZWRAPPER) { FILE *fcomp; - off_t offpnt, uclen; + fst_off_t offpnt, uclen; char gz_membuf[FST_GZIO_LEN]; gzFile zhandle; int zfd; @@ -4981,15 +4987,15 @@ uint64_t *time_table = NULL; uint64_t tsec_nitems; unsigned int secnum = 0; int blocks_skipped = 0; -off_t blkpos = 0; +fst_off_t blkpos = 0; uint64_t seclen, beg_tim; #ifdef FST_DEBUG uint64_t end_tim; #endif uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle; -off_t vc_start; -off_t indx_pntr, indx_pos; -off_t *chain_table = NULL; +fst_off_t vc_start; +fst_off_t indx_pntr, indx_pos; +fst_off_t *chain_table = NULL; uint32_t *chain_table_lengths = NULL; unsigned char *chain_cmem; unsigned char *pnt; @@ -5105,7 +5111,7 @@ for(;;) destlen = tsec_uclen; sourcelen = tsec_clen; - fstReaderFseeko(xc, xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); + fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR); if(tsec_uclen != tsec_clen) { @@ -5346,11 +5352,11 @@ for(;;) } free(mu); - fstReaderFseeko(xc, xc->f, -((off_t)frame_clen), SEEK_CUR); + fstReaderFseeko(xc, xc->f, -((fst_off_t)frame_clen), SEEK_CUR); } } - fstReaderFseeko(xc, xc->f, (off_t)frame_clen, SEEK_CUR); /* skip past compressed data */ + fstReaderFseeko(xc, xc->f, (fst_off_t)frame_clen, SEEK_CUR); /* skip past compressed data */ vc_maxhandle = fstReaderVarint64(xc->f); vc_start = ftello(xc->f); /* points to '!' character */ @@ -5380,7 +5386,7 @@ for(;;) free(chain_table_lengths); vc_maxhandle_largest = vc_maxhandle; - chain_table = (off_t *)calloc((vc_maxhandle+1), sizeof(off_t)); + chain_table = (fst_off_t *)calloc((vc_maxhandle+1), sizeof(fst_off_t)); chain_table_lengths = (uint32_t *)calloc((vc_maxhandle+1), sizeof(uint32_t)); } @@ -6001,7 +6007,7 @@ return(buf); char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; -off_t blkpos = 0, prev_blkpos; +fst_off_t blkpos = 0, prev_blkpos; uint64_t beg_tim, end_tim, beg_tim2, end_tim2; int sectype; unsigned int secnum = 0; @@ -6012,7 +6018,7 @@ uint64_t frame_uclen, frame_clen; #ifdef FST_DEBUG uint64_t mem_required_for_traversal; #endif -off_t indx_pntr, indx_pos; +fst_off_t indx_pntr, indx_pos; long chain_clen; unsigned char *chain_cmem; unsigned char *pnt; @@ -6074,7 +6080,7 @@ for(;;) { if((tim == end_tim) && (tim != xc->end_time)) { - off_t cached_pos = ftello(xc->f); + fst_off_t cached_pos = ftello(xc->f); fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); sectype = fgetc(xc->f); @@ -6136,7 +6142,7 @@ ucdata = (unsigned char *)malloc(tsec_uclen); destlen = tsec_uclen; sourcelen = tsec_clen; -fstReaderFseeko(xc, xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); +fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR); if(tsec_uclen != tsec_clen) { cdata = (unsigned char *)malloc(tsec_clen); @@ -6221,7 +6227,7 @@ chain_cmem = (unsigned char *)malloc(chain_clen); fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); fstFread(chain_cmem, chain_clen, 1, xc->f); -xc->rvat_chain_table = (off_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(off_t)); +xc->rvat_chain_table = (fst_off_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(fst_off_t)); xc->rvat_chain_table_lengths = (uint32_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t)); pnt = chain_cmem; diff --git a/include/gtkwave/fstapi.h b/include/gtkwave/fstapi.h index e347449ce..e2ca1783a 100644 --- a/include/gtkwave/fstapi.h +++ b/include/gtkwave/fstapi.h @@ -35,7 +35,11 @@ extern "C" { #include #include #include -#include +#if defined(_MSC_VER) + #include "fst_win_unistd.h" +#else + #include +#endif #include #define FST_RDLOAD "FSTLOAD | " From 4351abfe7107487a524fe51b631119487c2fa6b9 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 25 Apr 2021 11:46:05 +0900 Subject: [PATCH 02/80] Fix assertion failure in bitOpTree opt (#2899) * Tests: Add another testcase that triggers assertion failure in bitOpTree opt. * Fix assertion failure in bitOpTree opt reported in #2891. Consider the follwoing case. CCast -> WordSel -> VarRef(leaf) * Make sure that m_bitPolarity is expanded enough. --- src/V3Const.cpp | 33 ++++++++++++++++++++++++------- test_regress/t/t_const_opt_cov.pl | 2 +- test_regress/t/t_const_opt_cov.v | 25 ++++++++++++----------- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 3d87a2057..a66793857 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -96,11 +96,6 @@ class ConstBitOpTreeVisitor final : public AstNVisitor { ConstBitOpTreeVisitor* m_parentp; // ConstBitOpTreeVisitor that holds this VarInfo AstVarRef* m_refp; // Points the variable that this VarInfo covers V3Number m_bitPolarity; // Coefficient of each bit - static int widthOfRef(AstVarRef* refp) { - if (AstWordSel* selp = VN_CAST(refp->backp(), WordSel)) return selp->width(); - if (AstCCast* castp = VN_CAST(refp->backp(), CCast)) return castp->width(); - return refp->width(); - } public: // METHODS @@ -108,6 +103,30 @@ class ConstBitOpTreeVisitor final : public AstNVisitor { bool sameVarAs(const AstNodeVarRef* otherp) const { return m_refp->sameGateTree(otherp); } void setPolarity(bool compBit, int bit) { UASSERT_OBJ(!hasConstantResult(), m_refp, "Already has result of " << m_constResult); + UASSERT_OBJ(bit < VL_QUADSIZE, m_refp, + "bit:" << bit << " is too big after V3Expand" + << " back:" << m_refp->backp()); + if (bit >= m_bitPolarity.width()) { // Need to expand m_bitPolarity + const V3Number oldPol = std::move(m_bitPolarity); + // oldPol.width() is 8, 16, or 32 because this visitor is called after V3Expand + // newWidth is increased by 2x because + // - CCast will cast to such bitwidth anyway + // - can avoid frequent expansion + int newWidth = oldPol.width(); + while (bit >= newWidth) newWidth *= 2; + m_bitPolarity = V3Number{m_refp, newWidth}; + UASSERT_OBJ(newWidth == 16 || newWidth == 32 || newWidth == 64, m_refp, + "bit:" << bit << " newWidth:" << newWidth); + m_bitPolarity.setAllBitsX(); + for (int i = 0; i < oldPol.width(); ++i) { + if (oldPol.bitIs0(i)) + m_bitPolarity.setBit(i, '0'); + else if (oldPol.bitIs1(i)) + m_bitPolarity.setBit(i, '1'); + } + } + UASSERT_OBJ(bit < m_bitPolarity.width(), m_refp, + "bit:" << bit << " width:" << m_bitPolarity.width() << m_refp); if (m_bitPolarity.bitIsX(bit)) { // The bit is not yet set m_bitPolarity.setBit(bit, compBit); } else { // Priviously set the bit @@ -129,7 +148,7 @@ class ConstBitOpTreeVisitor final : public AstNVisitor { FileLine* fl = m_refp->fileline(); AstNode* srcp = VN_CAST(m_refp->backp(), WordSel); if (!srcp) srcp = m_refp; - const int width = widthOfRef(m_refp); + const int width = m_bitPolarity.width(); if (hasConstantResult()) return new AstConst{fl, @@ -160,7 +179,7 @@ class ConstBitOpTreeVisitor final : public AstNVisitor { VarInfo(ConstBitOpTreeVisitor* parent, AstVarRef* refp) : m_parentp(parent) , m_refp(refp) - , m_bitPolarity(refp, widthOfRef(refp)) { + , m_bitPolarity(refp, refp->isWide() ? VL_EDATASIZE : refp->width()) { m_bitPolarity.setAllBitsX(); } }; diff --git a/test_regress/t/t_const_opt_cov.pl b/test_regress/t/t_const_opt_cov.pl index 1e0a96b74..0a72e4f4f 100755 --- a/test_regress/t/t_const_opt_cov.pl +++ b/test_regress/t/t_const_opt_cov.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2=>["-Wno-UNOPTTHREADS", "--stats", "--coverage"], + verilator_flags2=>["-Wno-UNOPTTHREADS", "--stats", "--coverage", "--trace"], ); execute( diff --git a/test_regress/t/t_const_opt_cov.v b/test_regress/t/t_const_opt_cov.v index 245309007..c939ad806 100644 --- a/test_regress/t/t_const_opt_cov.v +++ b/test_regress/t/t_const_opt_cov.v @@ -20,19 +20,20 @@ module t(/*AUTOARG*/ logic bank_rd_vec_m3; always_ff @(posedge clk) bank_rd_vec_m3 <= crc[33]; - - wire out; - ecc_check_pipe u_bank_data_ecc_check( - .clk (clk), - .bank_rd_m3 (bank_rd_vec_m3), - .data_i (in), - .ecc_err_o (out) - ); - - + logic [3:0][31:0] data_i; + wire [3:0] out; + for (genvar i = 0; i < 4; ++i) begin + always_ff @(posedge clk) data_i[i] <= crc[63:32]; + ecc_check_pipe u_bank_data_ecc_check( + .clk (clk), + .bank_rd_m3 (bank_rd_vec_m3), + .data_i ({1'b0, data_i[i]}), + .ecc_err_o (out[i]) + ); + end // Aggregate outputs into a single result vector - wire [63:0] result = {63'b0, out}; + wire [63:0] result = {60'b0, out}; // Test loop always @ (posedge clk) begin @@ -54,7 +55,7 @@ module t(/*AUTOARG*/ $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); if (crc !== 64'hc77bb9b3784ea091) $stop; // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'h768b162c5835e35b +`define EXPECTED_SUM 64'ha2601675a6ae4972 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; From 12416bc0a390daf9a4efa628804756d8e2b1b407 Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Mon, 26 Apr 2021 09:50:25 -0400 Subject: [PATCH 03/80] Scope module fix (#2893) --- src/V3EmitCSyms.cpp | 19 +++++++++++------ test_regress/t/t_vpi_module.cpp | 7 ++++-- test_regress/t/t_vpi_module.pl | 5 ++--- test_regress/t/t_vpi_module.v | 14 +++++------- test_regress/t/t_vpi_module_dpi.pl | 34 ++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 21 deletions(-) create mode 100755 test_regress/t/t_vpi_module_dpi.pl diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index bf3953e8e..43a521a17 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -170,7 +170,12 @@ class EmitCSyms final : EmitCBaseVisitor { const auto scpit = m_vpiScopeCandidates.find(scp); if ((scpit != m_vpiScopeCandidates.end()) && (m_scopeNames.find(scp) == m_scopeNames.end())) { - m_scopeNames.emplace(scpit->second.m_symName, scpit->second); + auto scopeNameit = m_scopeNames.find(scpit->second.m_symName); + if (scopeNameit == m_scopeNames.end()) { + m_scopeNames.emplace(scpit->second.m_symName, scpit->second); + } else { + scopeNameit->second.m_type = scpit->second.m_type; + } } string::size_type pos = scp.rfind("__DOT__"); if (pos == string::npos) { @@ -233,20 +238,20 @@ class EmitCSyms final : EmitCBaseVisitor { ++it) { if (it->second.m_type != "SCOPE_MODULE") continue; - string name = it->second.m_prettyName; - if (name.substr(0, 4) == "TOP.") name.replace(0, 4, ""); + string symName = it->second.m_symName; + string above = symName; + if (above.substr(0, 4) == "TOP.") above.replace(0, 4, ""); - string above = name; while (!above.empty()) { - string::size_type pos = above.rfind('.'); + string::size_type pos = above.rfind("__"); if (pos == string::npos) break; above.resize(pos); if (m_vpiScopeHierarchy.find(above) != m_vpiScopeHierarchy.end()) { - m_vpiScopeHierarchy[above].push_back(name); + m_vpiScopeHierarchy[above].push_back(symName); break; } } - m_vpiScopeHierarchy[name] = std::vector(); + m_vpiScopeHierarchy[symName] = std::vector(); } } diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 7c00dcbf5..2e9ca88e5 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -90,9 +90,12 @@ int mon_check() { // modDump(it, 0); // return 1; - TestVpiHandle topmod = vpi_scan(it); + TestVpiHandle topmod; + // both somepackage and t exist at the top level + while ((topmod = vpi_scan(it))) { + if (vpi_get(vpiType, topmod) == vpiModule) break; + } CHECK_RESULT_NZ(topmod); - CHECK_RESULT(vpi_get(vpiType, topmod), vpiModule); const char* t_name = vpi_get_str(vpiName, topmod); CHECK_RESULT_NZ(t_name); diff --git a/test_regress/t/t_vpi_module.pl b/test_regress/t/t_vpi_module.pl index bee11c3f0..a1835cb60 100755 --- a/test_regress/t/t_vpi_module.pl +++ b/test_regress/t/t_vpi_module.pl @@ -17,9 +17,8 @@ compile( make_top_shell => 0, make_main => 0, make_pli => 1, - iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"], - v_flags2 => ["+define+USE_VPI_NOT_DPI"], - verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_module.cpp"], + iv_flags2 => ["-g2005-sv"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' +define+USE_DOLLAR_C32 --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_module.cpp"], ); execute( diff --git a/test_regress/t/t_vpi_module.v b/test_regress/t/t_vpi_module.v index ab6ac8201..b997270f1 100644 --- a/test_regress/t/t_vpi_module.v +++ b/test_regress/t/t_vpi_module.v @@ -6,9 +6,7 @@ // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -`ifdef USE_VPI_NOT_DPI -//We call it via $c so we can verify DPI isn't required - see bug572 -`else +`ifndef IVERILOG import "DPI-C" context function int mon_check(); `endif @@ -21,7 +19,7 @@ module t (/*AUTOARG*/ clk ); -`ifdef VERILATOR +`ifdef USE_DOLLAR_C32 `systemc_header extern "C" int mon_check(); `verilog @@ -43,13 +41,11 @@ extern "C" int mon_check(); // Test loop initial begin -`ifdef VERILATOR - status = $c32("mon_check()"); -`endif `ifdef IVERILOG status = $mon_check(); -`endif -`ifndef USE_VPI_NOT_DPI +`elsif USE_DOLLAR_C32 + status = $c32("mon_check()"); +`else status = mon_check(); `endif if (status!=0) begin diff --git a/test_regress/t/t_vpi_module_dpi.pl b/test_regress/t/t_vpi_module_dpi.pl new file mode 100755 index 000000000..1a546432b --- /dev/null +++ b/test_regress/t/t_vpi_module_dpi.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 2010 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); + +skip("Known compiler limitation") + if $Self->cxx_version =~ /\(GCC\) 4.4/; + +VM_PREFIX("Vt_vpi_module"); +top_filename("t/t_vpi_module.v"); +pli_filename("t_vpi_module.cpp"); + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + iv_flags2 => ["-g2005-sv"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_module.cpp"], + ); + +execute( + use_libvpi => 1, + check_finished => 1 + ); + +ok(1); +1; From 422c076fec475a0cdfee613c6d664e97fe565cd5 Mon Sep 17 00:00:00 2001 From: Udi Finkelstein Date: Tue, 27 Apr 2021 01:16:24 +0300 Subject: [PATCH 04/80] Support ignoring "`pragma protect ..." (#2886) This support code merely adds the capability to skip over the encrypted parts. Many models have unencrypted module interfaces with ports, and only encrypt the critical parts. --- docs/guide/warnings.rst | 17 + src/V3Error.h | 10 +- src/V3PreLex.h | 7 + src/V3PreLex.l | 122 ++++- test_regress/t/t_lint_pragma_protected.pl | 19 + test_regress/t/t_lint_pragma_protected.v | 48 ++ .../t/t_lint_pragma_protected_err.out | 17 + test_regress/t/t_lint_pragma_protected_err.pl | 20 + test_regress/t/t_lint_pragma_protected_err.v | 60 +++ test_regress/t/t_pp_pragma_bad.out | 3 +- test_regress/t/t_preproc.out | 454 ++++++++++-------- test_regress/t/t_preproc.v | 49 ++ test_regress/t/t_preproc_comments.out | 312 +++++++----- 13 files changed, 801 insertions(+), 337 deletions(-) create mode 100755 test_regress/t/t_lint_pragma_protected.pl create mode 100644 test_regress/t/t_lint_pragma_protected.v create mode 100644 test_regress/t/t_lint_pragma_protected_err.out create mode 100755 test_regress/t/t_lint_pragma_protected_err.pl create mode 100644 test_regress/t/t_lint_pragma_protected_err.v diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index ac0ca9329..3ef35d307 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -128,6 +128,13 @@ List Of Warnings simulate correctly. +.. option:: BADSTDPRAGMA + + Error that a pragma is badly formed, when that pragma is defined by IEEE1800-2017. + For example, an empty `pragma line, or an incorrect specified '`pragma protect'. + Note that 3rd party pragmas not defined by IEEE1800-2017 are ignored. + + .. option:: BLKANDNBLK .. TODO better example @@ -988,6 +995,16 @@ List Of Warnings a var/reg must be used as the target of procedural assignments. +.. option:: PROTECTED + + Warning that a '`pragma protected' section was encountered. The code + inside the protected region will be partly checked for correctness, but is + otherwise ignored. + + Suppressing the warning may make Verilator differ from a simulator that + accepts the protected code. + + .. option:: RANDC Warns that the :code:`randc` keyword is currently unsupported, and that diff --git a/src/V3Error.h b/src/V3Error.h index eb1cff471..870893c8e 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -64,6 +64,7 @@ public: ALWCOMBORDER, // Always_comb with unordered statements ASSIGNDLY, // Assignment delays ASSIGNIN, // Assigning to input + BADSTDPRAGMA, // Any error related to pragmas BLKANDNBLK, // Blocked and non-blocking assignments to same variable BLKLOOPINIT, // Delayed assignment to array inside for loops BLKSEQ, // Blocking assignments in sequential block @@ -109,6 +110,7 @@ public: PINNOTFOUND, // instance port name not found in it's module PKGNODECL, // Error: Package/class needs to be predeclared PROCASSWIRE, // Procedural assignment on wire + PROTECTED, // detected `pragma protected RANDC, // Unsupported: 'randc' converted to 'rand' REALCVT, // Real conversion REDEFMACRO, // Redefining existing define macro @@ -159,7 +161,7 @@ public: "DETECTARRAY", "ENCAPSULATED", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", // Warnings " EC_FIRST_WARN", - "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", + "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE", "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG", @@ -171,7 +173,7 @@ public: "LATCH", "LITENDIAN", "MODDUP", "MULTIDRIVEN", "MULTITOP","NOLATCH", "NULLPORT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PROCASSWIRE", - "RANDC", "REALCVT", "REDEFMACRO", + "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", @@ -192,8 +194,8 @@ public: // Warnings we'll present to the user as errors // Later -Werror- options may make more of these. bool pretendError() const { - return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG - || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL + return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BLKANDNBLK || m_e == BLKLOOPINIT + || m_e == CONTASSREG || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL || m_e == PROCASSWIRE); // Says IEEE } // Warnings to mention manual diff --git a/src/V3PreLex.h b/src/V3PreLex.h index b5b239a6a..3eeda4fa4 100644 --- a/src/V3PreLex.h +++ b/src/V3PreLex.h @@ -146,6 +146,10 @@ private: void lexStreamDepthAdd(int delta); }; +//====================================================================== +// Enum Class for `pragma protect encoding types +enum class Enctype : uint8_t { UUENCODE, BASE64, QUOTE_PRINTABLE, RAW, ERR }; + //====================================================================== // Class entry for each per-lexer state @@ -170,6 +174,9 @@ public: // Used only by V3PreLex.cpp and V3PreProc.cpp bool m_defQuote = false; // Definition value inside quote string m_defValue; // Definition value being built. int m_enterExit = 0; // For VL_LINE, the enter/exit level + int m_protLength = 0; // unencoded length for BASE64 + int m_protBytes = 0; // decoded length for BASE64 + Enctype m_encType; // encoding type for `pragma protect // CONSTRUCTORS V3PreLex(V3PreProcImp* preimpp, FileLine* filelinep) diff --git a/src/V3PreLex.l b/src/V3PreLex.l index 0ad5c5a61..81dcd763f 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -77,6 +77,11 @@ static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t, l) %x ARGMODE %x INCMODE %x PRTMODE +%x PRAGMA +%x PRAGMAERR +%x PRAGMAPRT +%x PRAGMAPRTERR +%x ENCBASE64 /* drop: Drop Ctrl-Z - can't pass thru or may EOF the output too soon */ @@ -112,12 +117,119 @@ bom [\357\273\277] "`undef" { FL_FWDC; return VP_UNDEF; } "`undefineall" { FL_FWDC; return VP_UNDEFINEALL; } "`error" { FL_FWDC; if (!pedantic()) return VP_ERROR; else return VP_DEFREF; } -"`pragma"{wsn}*[^\n\r]* { FL_FWDC; - const char* pointp = yytext + strlen("`pragma"); - while (isspace(*pointp)) ++pointp; - if (!*pointp && v3Global.opt.pedantic()) { - yyerrorf("`pragma is missing a pragma_expression."); + /* We wanted this to be next to `protect But it must be before `pramga */ + /* we win only because we both match to the end of the line so the length */ + /* is equal and we are first*/ +"encoding"{wsn}*[^\n\r]* { FL_FWDC; + int res; + char enctype[16]; // long enough to hold "quote-printable" + 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); + if (res == 0) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "`pragma protected encoding must have an \"enctype\" field"); + LEXP->m_encType = !VL_STRCASECMP(enctype, "uuencode") ? Enctype::UUENCODE : + !VL_STRCASECMP(enctype, "base64") ? Enctype::BASE64 : + !VL_STRCASECMP(enctype, "quoted-printable") ? Enctype::QUOTE_PRINTABLE : + !VL_STRCASECMP(enctype, "raw") ? Enctype::RAW : Enctype::ERR; + if (LEXP->m_encType == Enctype::ERR) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "Illegal encoding type for `pragma protected encoding"); + if (LEXP->m_encType != Enctype::BASE64) + LEXP->curFilelinep()->v3warn(E_UNSUPPORTED, "Unsupported: only BASE64 is recognized for `pragma protected encoding"); + if (res == 3) { + if ((LEXP->m_encType == Enctype::BASE64) && (LEXP->m_protLength & 3)) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "line_length must be multiple of 4 for BASE64"); + } else { + // default values + LEXP->m_protBytes = 0; + LEXP->m_protLength = 76; // ?? default value not mentioned in IEEE spec + } + BEGIN(INITIAL); + return VP_TEXT; + } +"key_block"{wsn}*[\n\r] { + FL_FWDC; + linenoInc(); + BEGIN(ENCBASE64); + return VP_TEXT; } +"data_block"{wsn}*[\n\r] { + FL_FWDC; + linenoInc(); + LEXP->curFilelinep()->v3warn(PROTECTED, "A '`pragma protected data_block' encrypted section was detected and will be skipped."); + BEGIN(ENCBASE64); + return VP_TEXT; } +("begin_protected"|"end_protected")[\n\r] { FL_FWDC; linenoInc(); BEGIN(INITIAL); return VP_TEXT; } +"version="[^\n\r]*[\n\r] { + FL_FWDC; + linenoInc(); + BEGIN(INITIAL); + return VP_TEXT; } +("encrypt_agent"|"encrypt_agent_info"|"key_keyowner"|"key_keyname"){wsn}*={wsn}*[\"][^\n\r]*[\"][\n\r] { + FL_FWDC; + linenoInc(); + BEGIN(INITIAL); + return VP_TEXT; } +("data_method"|"key_method"){wsn}*={wsn}*[\"][^\n\r]*[\"][\n\r] { + FL_FWDC; + linenoInc(); + BEGIN(INITIAL); + return VP_TEXT; } + /* catch-all for unknown '`pragma protect' rules */ +. { yyless(0); + BEGIN(PRAGMAPRTERR); + return VP_TEXT; } +[A-Za-z0-9+/]+[=]{0,2}[\n\r] { FL_FWDC; linenoInc(); FL_BRK; + if ((yyourleng()-1) <= size_t(LEXP->m_protLength) && ((yyleng & 3) == 1)) { + LEXP->m_protBytes -= (yyleng-1)/4*3; + } else { + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "BASE64 line too long in `pragma protect key_bloock/data_block"); + } + if (yytext[yyleng-3] == '=') + LEXP->m_protBytes++; + if (yytext[yyleng-2] == '=') + LEXP->m_protBytes++; + if (LEXP->m_protBytes == 0) { + BEGIN(INITIAL); + } else if (LEXP->m_protBytes < 0) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "BASE64 encoding (too short) in `pragma protect key_bloock/data_block"); + /*return VP_TEXT;*/ } +{wsn}*[\n\r] { FL_FWDC; + if (LEXP->m_protBytes != 0) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "BASE64 encoding length mismatch in `pragma protect key_bloock/data_block"); + linenoInc(); BEGIN(INITIAL); + return VP_TEXT; } + + /* Catch only empty `pragma lines */ +"`pragma"{wsn}*[\n\r] { + yyless(yyleng-1); FL_FWDC; + if (v3Global.opt.pedantic()) { + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "`pragma is missing a pragma_expression."); + } + return VP_TEXT; } + + /* catch all other nonempty `pragma */ +"`pragma"{wsn}*[^\n\r] { + yyless(yyleng-1); FL_FWDC; + if (!v3Global.opt.preprocOnly()) + BEGIN(PRAGMA); + return VP_TEXT; } +"protect"{wsn}* { FL_FWDC; BEGIN(PRAGMAPRT); return VP_TEXT;} + + /* catch-all for unknown `pragma rules */ +. { yyless(0); + BEGIN(PRAGMAERR); + return VP_TEXT; } + + /* the catch-all rule only got 1 char, lets get all line */ +[^\n\r]* { FL_FWDC; + /* Add a warning here for unknown pragmas if desired, at the moment , we don't */ + /* LEXP->curFilelinep()->v3warn(BADPRAGMA, "Unknown `pragma"); */ + BEGIN(INITIAL); + return VP_TEXT; } +[^\n\r]* { FL_FWDC; + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "Unknown '`pragma protect' error"); + BEGIN(INITIAL); return VP_TEXT; } "`__FILE__" { FL_FWDC; static string rtnfile; diff --git a/test_regress/t/t_lint_pragma_protected.pl b/test_regress/t/t_lint_pragma_protected.pl new file mode 100755 index 000000000..26a2c09ae --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected.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 2021 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(linter => 1); + + +lint( + verilator_flags2 => ['--lint-only -Wno-PROTECTED'], + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_pragma_protected.v b/test_regress/t/t_lint_pragma_protected.v new file mode 100644 index 000000000..dc8eb4cad --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected.v @@ -0,0 +1,48 @@ +// This part should pass OK + +module t_lint_pragma_protected; + +`pragma protect begin_protected +`pragma protect version=1 +`pragma protect encrypt_agent="XXXXX" +`pragma protect encrypt_agent_info="YYYYY" +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 64) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`pragma protect end_protected + +endmodule diff --git a/test_regress/t/t_lint_pragma_protected_err.out b/test_regress/t/t_lint_pragma_protected_err.out new file mode 100644 index 000000000..2e5922f37 --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected_err.out @@ -0,0 +1,17 @@ +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:8:17: Unknown '`pragma protect' error + 8 | `pragma protect encrypt_agent=123 + | ^~~~~~~~~~~~~~~~~ + ... For error description see https://verilator.org/warn/BADSTDPRAGMA?v=latest +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:10:17: Unknown '`pragma protect' error + 10 | `pragma protect encrypt_agent_info + | ^~~~~~~~~~~~~~~~~~ +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:23:1: BASE64 encoding length mismatch in `pragma protect key_bloock/data_block +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:27:17: multiple `pragma protected encoding sections + 27 | `pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +%Warning-PROTECTED: t/t_lint_pragma_protected_err.v:44:17: A '`pragma protected data_block' encrypted section was detected and will be skipped. + ... Use "/* verilator lint_off PROTECTED */" and lint_on around source to disable this message. +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:58:1: `pragma is missing a pragma_expression. + 58 | `pragma + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_pragma_protected_err.pl b/test_regress/t/t_lint_pragma_protected_err.pl new file mode 100755 index 000000000..ad84f1b54 --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected_err.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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(linter => 1); + +lint( + fails => 1, + verilator_flags2 => ['--lint-only -Wpedantic'], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_pragma_protected_err.v b/test_regress/t/t_lint_pragma_protected_err.v new file mode 100644 index 000000000..5e761c364 --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected_err.v @@ -0,0 +1,60 @@ +module t_lint_pragma_protected_err; + +// This part should see some failures + +`pragma protect begin_protected +`pragma protect version="xx" +// should fail because value should be quoted +`pragma protect encrypt_agent=123 +// should fail because no value given at all +`pragma protect encrypt_agent_info +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" + +// expect error in key_block below, 64 bytes but expecting 65 +// also expect "multiple `pragma encoding sections` error because number of +// bytes does not go down to 0 in the end of the section below due to the 64->65 change +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 65) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`pragma protect end_protected + +// Should trigger unknown pragma warning, although in principle unknown pragmas should be safely ignored. +`pragma XXXXX + +// Should trigger missing pragma warning +`pragma + +endmodule diff --git a/test_regress/t/t_pp_pragma_bad.out b/test_regress/t/t_pp_pragma_bad.out index 912313652..713607531 100644 --- a/test_regress/t/t_pp_pragma_bad.out +++ b/test_regress/t/t_pp_pragma_bad.out @@ -1,6 +1,7 @@ -%Error: t/t_pp_pragma_bad.v:7:1: `pragma is missing a pragma_expression. +%Error-BADSTDPRAGMA: t/t_pp_pragma_bad.v:7:1: `pragma is missing a pragma_expression. 7 | `pragma | ^~~~~~~ + ... For error description see https://verilator.org/warn/BADSTDPRAGMA?v=latest `line 1 "t/t_pp_pragma_bad.v" 1 diff --git a/test_regress/t/t_preproc.out b/test_regress/t/t_preproc.out index db7c40637..376c8eb4b 100644 --- a/test_regress/t/t_preproc.out +++ b/test_regress/t/t_preproc.out @@ -274,6 +274,62 @@ endmodule `line 164 "t/t_preproc.v" 0 +module t_lint_pragma_protected; + +`line 168 "t/t_preproc.v" 0 +`pragma protect begin_protected +`pragma protect version=1 +`pragma protect encrypt_agent="XXXXX" +`pragma protect encrypt_agent_info="YYYYY" +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 64) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`line 181 "t/t_preproc.v" 0 +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`line 190 "t/t_preproc.v" 0 +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`line 199 "t/t_preproc.v" 0 +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`line 209 "t/t_preproc.v" 0 +`pragma protect end_protected + +`line 211 "t/t_preproc.v" 0 +endmodule + +`line 213 "t/t_preproc.v" 0 + + @@ -282,17 +338,17 @@ endmodule -`line 174 "t/t_preproc.v" 0 +`line 223 "t/t_preproc.v" 0 begin addr <= (({regs[6], regs[7]} + 1)); rd <= 1; end and begin addr <= (({regs[6], regs[7]})); wdata <= (rdata); wr <= 1; end begin addr <= ({regs[6], regs[7]} + 1); rd <= 1; end begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more -`line 178 "t/t_preproc.v" 0 +`line 227 "t/t_preproc.v" 0 -`line 181 "t/t_preproc.v" 0 +`line 230 "t/t_preproc.v" 0 `line 1 "t/t_preproc_inc4.vh" 1 `line 2 "t/t_preproc_inc4.vh" 0 @@ -304,57 +360,57 @@ begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more `line 8 "t/t_preproc_inc4.vh" 2 -`line 181 "t/t_preproc.v" 0 +`line 230 "t/t_preproc.v" 0 -`line 182 "t/t_preproc.v" 0 +`line 231 "t/t_preproc.v" 0 -`line 185 "t/t_preproc.v" 0 +`line 234 "t/t_preproc.v" 0 -`line 187 "t/t_preproc.v" 0 +`line 236 "t/t_preproc.v" 0 -`line 191 "t/t_preproc.v" 0 +`line 240 "t/t_preproc.v" 0 -`line 194 "t/t_preproc.v" 0 +`line 243 "t/t_preproc.v" 0 $blah("ab,cd","e,f"); $blah(this.logfile,vec); $blah(this.logfile,vec[1,2,3]); $blah(this.logfile,{blah.name(), " is not foo"}); -`line 200 "t/t_preproc.v" 0 +`line 249 "t/t_preproc.v" 0 -`line 203 "t/t_preproc.v" 0 +`line 252 "t/t_preproc.v" 0 `pragma foo = 1 `default_nettype none `default_nettype uwire -`line 207 "t/t_preproc.v" 0 +`line 256 "t/t_preproc.v" 0 -`line 210 "t/t_preproc.v" 0 +`line 259 "t/t_preproc.v" 0 -`line 214 "t/t_preproc.v" 0 -Line_Preproc_Check 214 +`line 263 "t/t_preproc.v" 0 +Line_Preproc_Check 263 -`line 216 "t/t_preproc.v" 0 +`line 265 "t/t_preproc.v" 0 -`line 219 "t/t_preproc.v" 0 +`line 268 "t/t_preproc.v" 0 @@ -362,15 +418,15 @@ Line_Preproc_Check 214 -`line 226 "t/t_preproc.v" 0 +`line 275 "t/t_preproc.v" 0 (x,y) -Line_Preproc_Check 227 +Line_Preproc_Check 276 -`line 229 "t/t_preproc.v" 0 +`line 278 "t/t_preproc.v" 0 -`line 232 "t/t_preproc.v" 0 +`line 281 "t/t_preproc.v" 0 @@ -379,17 +435,17 @@ beginend beginend "beginend" -`line 240 "t/t_preproc.v" 0 +`line 289 "t/t_preproc.v" 0 `\esc`def -`line 246 "t/t_preproc.v" 0 +`line 295 "t/t_preproc.v" 0 Not a \`define -`line 248 "t/t_preproc.v" 0 +`line 297 "t/t_preproc.v" 0 @@ -398,123 +454,26 @@ Not a \`define x,y)--bee submacro has comma paren -`line 256 "t/t_preproc.v" 0 +`line 305 "t/t_preproc.v" 0 $display("10 %d %d", $bits(foo), 10); -`line 261 "t/t_preproc.v" 0 - - - - - -`line 266 "t/t_preproc.v" 0 - - - -`line 269 "t/t_preproc.v" 0 - - - - - - - - - - - - - - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - assign a3 = ~b3 ; -`line 283 "t/t_preproc.v" 0 - - -`line 285 "t/t_preproc.v" 0 - - \ - - - - - - - - -`line 294 "t/t_preproc.v" 0 - -`line 294 "t/t_preproc.v" 0 - -`line 294 "t/t_preproc.v" 0 - def i - - -`line 296 "t/t_preproc.v" 0 - - -`line 298 "t/t_preproc.v" 0 - - - - - -`line 302 "t/t_preproc.v" 0 - - - - - - -`line 308 "t/t_preproc.v" 0 -1 /*verilator NOT IN DEFINE*/ (nodef) -2 /*verilator PART OF DEFINE*/ (hasdef) -3 `line 310 "t/t_preproc.v" 0 -/*verilator NOT PART - OF DEFINE*/ (nodef) -`line 311 "t/t_preproc.v" 0 -4 -`line 311 "t/t_preproc.v" 0 -/*verilator PART - OF DEFINE*/ (nodef) -`line 312 "t/t_preproc.v" 0 -5 also in -`line 312 "t/t_preproc.v" 0 - also3 (nodef) + + + -HAS a NEW `line 315 "t/t_preproc.v" 0 -LINE + + -`line 317 "t/t_preproc.v" 0 +`line 318 "t/t_preproc.v" 0 + - -`line 319 "t/t_preproc.v" 0 - @@ -527,10 +486,107 @@ LINE `line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + assign a3 = ~b3 ; +`line 332 "t/t_preproc.v" 0 + + +`line 334 "t/t_preproc.v" 0 + + \ -`line 335 "t/t_preproc.v" 0 + + + + + +`line 343 "t/t_preproc.v" 0 + +`line 343 "t/t_preproc.v" 0 + +`line 343 "t/t_preproc.v" 0 + def i + + +`line 345 "t/t_preproc.v" 0 + + +`line 347 "t/t_preproc.v" 0 + + + + + +`line 351 "t/t_preproc.v" 0 + + + + + + +`line 357 "t/t_preproc.v" 0 +1 /*verilator NOT IN DEFINE*/ (nodef) +2 /*verilator PART OF DEFINE*/ (hasdef) +3 +`line 359 "t/t_preproc.v" 0 +/*verilator NOT PART + OF DEFINE*/ (nodef) +`line 360 "t/t_preproc.v" 0 +4 +`line 360 "t/t_preproc.v" 0 +/*verilator PART + OF DEFINE*/ (nodef) +`line 361 "t/t_preproc.v" 0 +5 also in +`line 361 "t/t_preproc.v" 0 + also3 (nodef) + + +HAS a NEW +`line 364 "t/t_preproc.v" 0 +LINE + +`line 366 "t/t_preproc.v" 0 + + +`line 368 "t/t_preproc.v" 0 + + + + + + + + + + + + + +`line 381 "t/t_preproc.v" 0 + + + +`line 384 "t/t_preproc.v" 0 EXP: clxx_scen clxx_scen EXP: clxx_scen @@ -538,44 +594,44 @@ EXP: clxx_scen EXP: do if (start("verilog/inc1.v", 25)) begin message({"Blah-", "clx_scen", " end"}); end while(0); -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 do -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 - if (start("t/t_preproc.v", 341)) begin -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 + if (start("t/t_preproc.v", 390)) begin +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 message({"Blah-", "clx_scen", " end"}); -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 end -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 while(0); -`line 343 "t/t_preproc.v" 0 +`line 392 "t/t_preproc.v" 0 -`line 345 "t/t_preproc.v" 0 +`line 394 "t/t_preproc.v" 0 -`line 349 "t/t_preproc.v" 0 +`line 398 "t/t_preproc.v" 0 -`line 349 "t/t_preproc.v" 0 +`line 398 "t/t_preproc.v" 0 -`line 350 "t/t_preproc.v" 0 +`line 399 "t/t_preproc.v" 0 EXP: This is fooed @@ -583,7 +639,7 @@ This is fooed EXP: This is fooed_2 This is fooed_2 -`line 357 "t/t_preproc.v" 0 +`line 406 "t/t_preproc.v" 0 np @@ -595,11 +651,11 @@ np -`line 368 "t/t_preproc.v" 0 +`line 417 "t/t_preproc.v" 0 -`line 371 "t/t_preproc.v" 0 +`line 420 "t/t_preproc.v" 0 @@ -608,12 +664,12 @@ np -`line 379 "t/t_preproc.v" 0 +`line 428 "t/t_preproc.v" 0 -`line 383 "t/t_preproc.v" 0 +`line 432 "t/t_preproc.v" 0 hello3hello3hello3 hello4hello4hello4hello4 @@ -621,7 +677,7 @@ hello4hello4hello4hello4 -`line 389 "t/t_preproc.v" 0 +`line 438 "t/t_preproc.v" 0 `line 1 "t/t_preproc_inc4.vh" 1 `line 2 "t/t_preproc_inc4.vh" 0 @@ -633,9 +689,9 @@ hello4hello4hello4hello4 `line 8 "t/t_preproc_inc4.vh" 2 -`line 389 "t/t_preproc.v" 0 +`line 438 "t/t_preproc.v" 0 -`line 390 "t/t_preproc.v" 0 +`line 439 "t/t_preproc.v" 0 @@ -645,28 +701,28 @@ hello4hello4hello4hello4 -`line 398 "t/t_preproc.v" 0 +`line 447 "t/t_preproc.v" 0 -Line_Preproc_Check 402 +Line_Preproc_Check 451 -Line_Preproc_Check 408 +Line_Preproc_Check 457 "FOO \ BAR " "arg_line1 \ arg_line2" "FOO \ BAR " -`line 411 "t/t_preproc.v" 0 -Line_Preproc_Check 411 +`line 460 "t/t_preproc.v" 0 +Line_Preproc_Check 460 -`line 415 "t/t_preproc.v" 0 +`line 464 "t/t_preproc.v" 0 @@ -677,14 +733,14 @@ abc -`line 425 "t/t_preproc.v" 0 +`line 474 "t/t_preproc.v" 0 EXP: sonet_frame sonet_frame -`line 431 "t/t_preproc.v" 0 +`line 480 "t/t_preproc.v" 0 EXP: sonet_frame @@ -695,7 +751,7 @@ sonet_frame EXP: sonet_frame sonet_frame -`line 441 "t/t_preproc.v" 0 +`line 490 "t/t_preproc.v" 0 @@ -703,13 +759,13 @@ EXP: module zzz ; endmodule module zzz ; endmodule module zzz ; endmodule -`line 448 "t/t_preproc.v" 0 +`line 497 "t/t_preproc.v" 0 EXP: module a_b ; endmodule module a_b ; endmodule module a_b ; endmodule -`line 453 "t/t_preproc.v" 0 +`line 502 "t/t_preproc.v" 0 integer foo; @@ -723,7 +779,7 @@ module t; initial begin : \`LEX_CAT(a[0],_assignment) -`line 465 "t/t_preproc.v" 0 +`line 514 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`LEX_CAT(a[0],_assignment) "); end @@ -732,7 +788,7 @@ module t; initial begin : \a[0]_assignment_a[1] -`line 472 "t/t_preproc.v" 0 +`line 521 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\a[0]_assignment_a[1] "); end @@ -748,7 +804,7 @@ module t; initial begin : \`CAT(ff,bb) -`line 486 "t/t_preproc.v" 0 +`line 535 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`CAT(ff,bb) "); end @@ -756,7 +812,7 @@ module t; initial begin : \`zzz -`line 492 "t/t_preproc.v" 0 +`line 541 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`zzz "); end @@ -765,11 +821,11 @@ module t; initial begin : \`FOO -`line 499 "t/t_preproc.v" 0 +`line 548 "t/t_preproc.v" 0 $write("GOT%%m='%m' OTHER_EXP='%s'\n OUR_EXP='%s'", "t.bar ","t.\\`FOO "); end initial begin : \xx`FOO -`line 501 "t/t_preproc.v" 0 +`line 550 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\xx`FOO "); end @@ -802,27 +858,27 @@ module t; initial -`line 532 "t/t_preproc.v" 0 +`line 581 "t/t_preproc.v" 0 $display("%s%s","a1","b2c3\n"); endmodule -`line 535 "t/t_preproc.v" 0 +`line 584 "t/t_preproc.v" 0 -`line 538 "t/t_preproc.v" 0 +`line 587 "t/t_preproc.v" 0 $display("RAM0"); $display("CPU"); -`line 543 "t/t_preproc.v" 0 +`line 592 "t/t_preproc.v" 0 -`line 548 "t/t_preproc.v" 0 +`line 597 "t/t_preproc.v" 0 XXE_FAMILY = XXE_ @@ -830,7 +886,7 @@ XXE_FAMILY = XXE_ $display("XXE_ is defined"); -`line 555 "t/t_preproc.v" 0 +`line 604 "t/t_preproc.v" 0 XYE_FAMILY = XYE_ @@ -838,7 +894,7 @@ XYE_FAMILY = XYE_ $display("XYE_ is defined"); -`line 562 "t/t_preproc.v" 0 +`line 611 "t/t_preproc.v" 0 XXS_FAMILY = XXS_some @@ -846,7 +902,7 @@ XXS_FAMILY = XXS_some $display("XXS_some is defined"); -`line 569 "t/t_preproc.v" 0 +`line 618 "t/t_preproc.v" 0 XYS_FAMILY = XYS_foo @@ -854,10 +910,10 @@ XYS_FAMILY = XYS_foo $display("XYS_foo is defined"); -`line 576 "t/t_preproc.v" 0 +`line 625 "t/t_preproc.v" 0 -`line 578 "t/t_preproc.v" 0 +`line 627 "t/t_preproc.v" 0 @@ -866,7 +922,7 @@ XYS_FAMILY = XYS_foo -`line 586 "t/t_preproc.v" 0 +`line 635 "t/t_preproc.v" 0 @@ -874,7 +930,7 @@ XYS_FAMILY = XYS_foo -`line 593 "t/t_preproc.v" 0 +`line 642 "t/t_preproc.v" 0 @@ -882,7 +938,7 @@ XYS_FAMILY = XYS_foo -`line 600 "t/t_preproc.v" 0 +`line 649 "t/t_preproc.v" 0 @@ -890,26 +946,26 @@ XYS_FAMILY = XYS_foo -`line 607 "t/t_preproc.v" 0 +`line 656 "t/t_preproc.v" 0 -`line 609 "t/t_preproc.v" 0 +`line 658 "t/t_preproc.v" 0 -`line 611 "t/t_preproc.v" 0 +`line 660 "t/t_preproc.v" 0 (.mySig (myInterface.pa5), -`line 615 "t/t_preproc.v" 0 +`line 664 "t/t_preproc.v" 0 -`line 618 "t/t_preproc.v" 0 +`line 667 "t/t_preproc.v" 0 `dbg_hdl(UVM_LOW, ("Functional coverage enabled: paramgrp")); -`line 621 "t/t_preproc.v" 0 +`line 670 "t/t_preproc.v" 0 @@ -918,28 +974,28 @@ XYS_FAMILY = XYS_foo -`line 629 "t/t_preproc.v" 0 +`line 678 "t/t_preproc.v" 0 module pcc2_cfg; generate -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 covergroup a @(posedge b); -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 c: coverpoint d iff ((c) === 1'b1); endgroup -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 a u_a; -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 initial do begin $display ("DEBUG : %s [%m]", $sformatf ("Functional coverage enabled: u_a")); end while(0); endgenerate endmodule -`line 635 "t/t_preproc.v" 0 +`line 684 "t/t_preproc.v" 0 "`NOT_DEFINED_STR" -`line 640 "t/t_preproc.v" 0 +`line 689 "t/t_preproc.v" 0 @@ -962,4 +1018,4 @@ predef 2 2 -`line 662 "t/t_preproc.v" 2 +`line 711 "t/t_preproc.v" 2 diff --git a/test_regress/t/t_preproc.v b/test_regress/t/t_preproc.v index 31d7ab17f..a52ce02c1 100644 --- a/test_regress/t/t_preproc.v +++ b/test_regress/t/t_preproc.v @@ -161,6 +161,55 @@ module prot(); endmodule //" +//====================================================================== +// Check IEEE1800-2017 `pragma protect encrypted modules +module t_lint_pragma_protected; + +`pragma protect begin_protected +`pragma protect version=1 +`pragma protect encrypt_agent="XXXXX" +`pragma protect encrypt_agent_info="YYYYY" +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 64) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`pragma protect end_protected + +endmodule + //====================================================================== // macro call with define that has comma `define REG_H 6 diff --git a/test_regress/t/t_preproc_comments.out b/test_regress/t/t_preproc_comments.out index 158faa511..1d2795895 100644 --- a/test_regress/t/t_preproc_comments.out +++ b/test_regress/t/t_preproc_comments.out @@ -273,6 +273,62 @@ endmodule `line 164 "t/t_preproc.v" 0 //====================================================================== +// Check IEEE1800-2017 `pragma protect encrypted modules +module t_lint_pragma_protected; + +`line 168 "t/t_preproc.v" 0 +`pragma protect begin_protected +`pragma protect version=1 +`pragma protect encrypt_agent="XXXXX" +`pragma protect encrypt_agent_info="YYYYY" +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 64) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`line 181 "t/t_preproc.v" 0 +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`line 190 "t/t_preproc.v" 0 +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`line 199 "t/t_preproc.v" 0 +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`line 209 "t/t_preproc.v" 0 +`pragma protect end_protected + +`line 211 "t/t_preproc.v" 0 +endmodule + +`line 213 "t/t_preproc.v" 0 +//====================================================================== // macro call with define that has comma @@ -282,17 +338,17 @@ endmodule -`line 174 "t/t_preproc.v" 0 +`line 223 "t/t_preproc.v" 0 begin addr <= (({regs[6], regs[7]} + 1)); rd <= 1; end and begin addr <= (({regs[6], regs[7]})); wdata <= (rdata); wr <= 1; end begin addr <= ({regs[6], regs[7]} + 1); rd <= 1; end begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more -`line 178 "t/t_preproc.v" 0 +`line 227 "t/t_preproc.v" 0 //====================================================================== // include of parameterized file -`line 181 "t/t_preproc.v" 0 +`line 230 "t/t_preproc.v" 0 `line 1 "t/t_preproc_inc4.vh" 1 // DESCRIPTION: Verilog::Preproc: Example source code `line 2 "t/t_preproc_inc4.vh" 0 @@ -304,57 +360,57 @@ begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more `line 8 "t/t_preproc_inc4.vh" 2 -`line 181 "t/t_preproc.v" 0 +`line 230 "t/t_preproc.v" 0 -`line 182 "t/t_preproc.v" 0 +`line 231 "t/t_preproc.v" 0 -`line 185 "t/t_preproc.v" 0 +`line 234 "t/t_preproc.v" 0 -`line 187 "t/t_preproc.v" 0 +`line 236 "t/t_preproc.v" 0 -`line 191 "t/t_preproc.v" 0 +`line 240 "t/t_preproc.v" 0 //====================================================================== // macro call with , in {} -`line 194 "t/t_preproc.v" 0 +`line 243 "t/t_preproc.v" 0 $blah("ab,cd","e,f"); $blah(this.logfile,vec); $blah(this.logfile,vec[1,2,3]); $blah(this.logfile,{blah.name(), " is not foo"}); -`line 200 "t/t_preproc.v" 0 +`line 249 "t/t_preproc.v" 0 //====================================================================== // pragma/default net type -`line 203 "t/t_preproc.v" 0 +`line 252 "t/t_preproc.v" 0 `pragma foo = 1 `default_nettype none `default_nettype uwire -`line 207 "t/t_preproc.v" 0 +`line 256 "t/t_preproc.v" 0 //====================================================================== // Ifdef -`line 210 "t/t_preproc.v" 0 +`line 259 "t/t_preproc.v" 0 -`line 214 "t/t_preproc.v" 0 -Line_Preproc_Check 214 +`line 263 "t/t_preproc.v" 0 +Line_Preproc_Check 263 -`line 216 "t/t_preproc.v" 0 +`line 265 "t/t_preproc.v" 0 //====================================================================== // bug84 -`line 219 "t/t_preproc.v" 0 +`line 268 "t/t_preproc.v" 0 // Hello, comments MIGHT not be legal /*more,,)cmts*/ // But newlines ARE legal... who speced THAT? @@ -362,15 +418,15 @@ Line_Preproc_Check 214 -`line 226 "t/t_preproc.v" 0 +`line 275 "t/t_preproc.v" 0 (//Here x,y //Too) -Line_Preproc_Check 227 +Line_Preproc_Check 276 -`line 229 "t/t_preproc.v" 0 +`line 278 "t/t_preproc.v" 0 //====================================================================== // defines split arguments -`line 232 "t/t_preproc.v" 0 +`line 281 "t/t_preproc.v" 0 @@ -379,17 +435,17 @@ beginend // 2001 spec doesn't require two tokens, so "beginend" ok beginend // 2001 spec doesn't require two tokens, so "beginend" ok "beginend" // No space "beginend" -`line 240 "t/t_preproc.v" 0 +`line 289 "t/t_preproc.v" 0 //====================================================================== // bug106 `\esc`def -`line 246 "t/t_preproc.v" 0 +`line 295 "t/t_preproc.v" 0 Not a \`define -`line 248 "t/t_preproc.v" 0 +`line 297 "t/t_preproc.v" 0 //====================================================================== // misparsed comma in submacro @@ -398,23 +454,23 @@ Not a \`define x,y)--bee submacro has comma paren -`line 256 "t/t_preproc.v" 0 +`line 305 "t/t_preproc.v" 0 //====================================================================== // bug191 $display("10 %d %d", $bits(foo), 10); -`line 261 "t/t_preproc.v" 0 +`line 310 "t/t_preproc.v" 0 //====================================================================== // 1800-2009 -`line 266 "t/t_preproc.v" 0 +`line 315 "t/t_preproc.v" 0 -`line 269 "t/t_preproc.v" 0 +`line 318 "t/t_preproc.v" 0 //====================================================================== // bug202 @@ -429,34 +485,34 @@ $display("10 %d %d", $bits(foo), 10); -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 assign a3 = ~b3 ; -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 285 "t/t_preproc.v" 0 +`line 334 "t/t_preproc.v" 0 /* multi \ line1*/ \ -`line 287 "t/t_preproc.v" 0 +`line 336 "t/t_preproc.v" 0 /*multi \ line2*/ @@ -465,59 +521,59 @@ $display("10 %d %d", $bits(foo), 10); -`line 294 "t/t_preproc.v" 0 +`line 343 "t/t_preproc.v" 0 -`line 294 "t/t_preproc.v" 0 +`line 343 "t/t_preproc.v" 0 -`line 294 "t/t_preproc.v" 0 +`line 343 "t/t_preproc.v" 0 /* multi line 3*/ -`line 294 "t/t_preproc.v" 0 +`line 343 "t/t_preproc.v" 0 def i -`line 296 "t/t_preproc.v" 0 +`line 345 "t/t_preproc.v" 0 //====================================================================== -`line 298 "t/t_preproc.v" 0 +`line 347 "t/t_preproc.v" 0 -`line 302 "t/t_preproc.v" 0 +`line 351 "t/t_preproc.v" 0 -`line 308 "t/t_preproc.v" 0 +`line 357 "t/t_preproc.v" 0 1 // verilator NOT IN DEFINE (nodef) 2 /* verilator PART OF DEFINE */ (hasdef) 3 -`line 310 "t/t_preproc.v" 0 +`line 359 "t/t_preproc.v" 0 /* verilator NOT PART OF DEFINE */ (nodef) -`line 311 "t/t_preproc.v" 0 +`line 360 "t/t_preproc.v" 0 4 -`line 311 "t/t_preproc.v" 0 +`line 360 "t/t_preproc.v" 0 /* verilator PART OF DEFINE */ (nodef) -`line 312 "t/t_preproc.v" 0 +`line 361 "t/t_preproc.v" 0 5 also in -`line 312 "t/t_preproc.v" 0 +`line 361 "t/t_preproc.v" 0 also3 // CMT NOT (nodef) HAS a NEW -`line 315 "t/t_preproc.v" 0 +`line 364 "t/t_preproc.v" 0 LINE -`line 317 "t/t_preproc.v" 0 +`line 366 "t/t_preproc.v" 0 //====================================================================== -`line 319 "t/t_preproc.v" 0 +`line 368 "t/t_preproc.v" 0 @@ -531,11 +587,11 @@ LINE -`line 332 "t/t_preproc.v" 0 +`line 381 "t/t_preproc.v" 0 -`line 335 "t/t_preproc.v" 0 +`line 384 "t/t_preproc.v" 0 EXP: clxx_scen clxx_scen EXP: clxx_scen @@ -543,44 +599,44 @@ EXP: clxx_scen EXP: do if (start("verilog/inc1.v", 25)) begin message({"Blah-", "clx_scen", " end"}); end while(0); -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 do -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 /* synopsys translate_off */ -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 - if (start("t/t_preproc.v", 341)) begin -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 + if (start("t/t_preproc.v", 390)) begin +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 message({"Blah-", "clx_scen", " end"}); -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 end -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 /* synopsys translate_on */ -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 while(0); -`line 343 "t/t_preproc.v" 0 +`line 392 "t/t_preproc.v" 0 //====================================================================== -`line 345 "t/t_preproc.v" 0 +`line 394 "t/t_preproc.v" 0 -`line 349 "t/t_preproc.v" 0 +`line 398 "t/t_preproc.v" 0 -`line 349 "t/t_preproc.v" 0 +`line 398 "t/t_preproc.v" 0 -`line 350 "t/t_preproc.v" 0 +`line 399 "t/t_preproc.v" 0 //`ifndef def_fooed_2 `error "No def_fooed_2" `endif EXP: This is fooed @@ -588,7 +644,7 @@ This is fooed EXP: This is fooed_2 This is fooed_2 -`line 357 "t/t_preproc.v" 0 +`line 406 "t/t_preproc.v" 0 //====================================================================== np @@ -600,11 +656,11 @@ np -`line 368 "t/t_preproc.v" 0 +`line 417 "t/t_preproc.v" 0 -`line 371 "t/t_preproc.v" 0 +`line 420 "t/t_preproc.v" 0 //====================================================================== // Metaprogramming @@ -613,12 +669,12 @@ np -`line 379 "t/t_preproc.v" 0 +`line 428 "t/t_preproc.v" 0 -`line 383 "t/t_preproc.v" 0 +`line 432 "t/t_preproc.v" 0 hello3hello3hello3 hello4hello4hello4hello4 //====================================================================== @@ -626,7 +682,7 @@ hello4hello4hello4hello4 -`line 389 "t/t_preproc.v" 0 +`line 438 "t/t_preproc.v" 0 `line 1 "t/t_preproc_inc4.vh" 1 // DESCRIPTION: Verilog::Preproc: Example source code `line 2 "t/t_preproc_inc4.vh" 0 @@ -638,9 +694,9 @@ hello4hello4hello4hello4 `line 8 "t/t_preproc_inc4.vh" 2 -`line 389 "t/t_preproc.v" 0 +`line 438 "t/t_preproc.v" 0 -`line 390 "t/t_preproc.v" 0 +`line 439 "t/t_preproc.v" 0 //====================================================================== // Defines doing defines @@ -650,28 +706,28 @@ hello4hello4hello4hello4 -`line 398 "t/t_preproc.v" 0 +`line 447 "t/t_preproc.v" 0 -Line_Preproc_Check 402 +Line_Preproc_Check 451 //====================================================================== // Quoted multiline - track line numbers, and ensure \\n gets propagated -Line_Preproc_Check 408 +Line_Preproc_Check 457 "FOO \ BAR " "arg_line1 \ arg_line2" "FOO \ BAR " -`line 411 "t/t_preproc.v" 0 -Line_Preproc_Check 411 +`line 460 "t/t_preproc.v" 0 +Line_Preproc_Check 460 //====================================================================== // bug283 -`line 415 "t/t_preproc.v" 0 +`line 464 "t/t_preproc.v" 0 @@ -682,14 +738,14 @@ abc -`line 425 "t/t_preproc.v" 0 +`line 474 "t/t_preproc.v" 0 EXP: sonet_frame sonet_frame -`line 431 "t/t_preproc.v" 0 +`line 480 "t/t_preproc.v" 0 EXP: sonet_frame @@ -700,7 +756,7 @@ sonet_frame EXP: sonet_frame sonet_frame -`line 441 "t/t_preproc.v" 0 +`line 490 "t/t_preproc.v" 0 // The existance of non-existance of a base define can make a difference @@ -708,13 +764,13 @@ EXP: module zzz ; endmodule module zzz ; endmodule module zzz ; endmodule -`line 448 "t/t_preproc.v" 0 +`line 497 "t/t_preproc.v" 0 EXP: module a_b ; endmodule module a_b ; endmodule module a_b ; endmodule -`line 453 "t/t_preproc.v" 0 +`line 502 "t/t_preproc.v" 0 //====================================================================== // bug311 integer/*NEED_SPACE*/ foo; @@ -728,7 +784,7 @@ module t; initial begin : \`LEX_CAT(a[0],_assignment) -`line 465 "t/t_preproc.v" 0 +`line 514 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`LEX_CAT(a[0],_assignment) "); end //----- // SHOULD(simulator-dependant): Backslash doesn't prevent arguments from @@ -737,7 +793,7 @@ module t; initial begin : \a[0]_assignment_a[1] -`line 472 "t/t_preproc.v" 0 +`line 521 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\a[0]_assignment_a[1] "); end //----- @@ -753,7 +809,7 @@ module t; // Similar to above; \ does not allow expansion after substitution initial begin : \`CAT(ff,bb) -`line 486 "t/t_preproc.v" 0 +`line 535 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`CAT(ff,bb) "); end //----- @@ -761,7 +817,7 @@ module t; // MUST: Unknown macro with backslash escape stays as escaped symbol name initial begin : \`zzz -`line 492 "t/t_preproc.v" 0 +`line 541 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`zzz "); end //----- @@ -770,11 +826,11 @@ module t; // SHOULD(simulator-dependant): Known macro with backslash escape expands initial begin : \`FOO -`line 499 "t/t_preproc.v" 0 +`line 548 "t/t_preproc.v" 0 $write("GOT%%m='%m' OTHER_EXP='%s'\n OUR_EXP='%s'", "t.bar ","t.\\`FOO "); end // SHOULD(simulator-dependant): Prefix breaks the above initial begin : \xx`FOO -`line 501 "t/t_preproc.v" 0 +`line 550 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\xx`FOO "); end //----- @@ -807,27 +863,27 @@ module t; initial -`line 532 "t/t_preproc.v" 0 +`line 581 "t/t_preproc.v" 0 $display("%s%s","a1","b2c3\n"); endmodule -`line 535 "t/t_preproc.v" 0 +`line 584 "t/t_preproc.v" 0 //====================================================================== //bug1225 -`line 538 "t/t_preproc.v" 0 +`line 587 "t/t_preproc.v" 0 $display("RAM0"); $display("CPU"); -`line 543 "t/t_preproc.v" 0 +`line 592 "t/t_preproc.v" 0 -`line 548 "t/t_preproc.v" 0 +`line 597 "t/t_preproc.v" 0 XXE_FAMILY = XXE_ @@ -835,7 +891,7 @@ XXE_FAMILY = XXE_ $display("XXE_ is defined"); -`line 555 "t/t_preproc.v" 0 +`line 604 "t/t_preproc.v" 0 XYE_FAMILY = XYE_ @@ -843,7 +899,7 @@ XYE_FAMILY = XYE_ $display("XYE_ is defined"); -`line 562 "t/t_preproc.v" 0 +`line 611 "t/t_preproc.v" 0 XXS_FAMILY = XXS_some @@ -851,7 +907,7 @@ XXS_FAMILY = XXS_some $display("XXS_some is defined"); -`line 569 "t/t_preproc.v" 0 +`line 618 "t/t_preproc.v" 0 XYS_FAMILY = XYS_foo @@ -859,10 +915,10 @@ XYS_FAMILY = XYS_foo $display("XYS_foo is defined"); -`line 576 "t/t_preproc.v" 0 +`line 625 "t/t_preproc.v" 0 //==== -`line 578 "t/t_preproc.v" 0 +`line 627 "t/t_preproc.v" 0 @@ -871,7 +927,7 @@ XYS_FAMILY = XYS_foo -`line 586 "t/t_preproc.v" 0 +`line 635 "t/t_preproc.v" 0 @@ -879,7 +935,7 @@ XYS_FAMILY = XYS_foo -`line 593 "t/t_preproc.v" 0 +`line 642 "t/t_preproc.v" 0 @@ -887,7 +943,7 @@ XYS_FAMILY = XYS_foo -`line 600 "t/t_preproc.v" 0 +`line 649 "t/t_preproc.v" 0 @@ -895,26 +951,26 @@ XYS_FAMILY = XYS_foo -`line 607 "t/t_preproc.v" 0 +`line 656 "t/t_preproc.v" 0 -`line 609 "t/t_preproc.v" 0 +`line 658 "t/t_preproc.v" 0 // NEVER -`line 611 "t/t_preproc.v" 0 +`line 660 "t/t_preproc.v" 0 //bug1227 (.mySig (myInterface.pa5), -`line 615 "t/t_preproc.v" 0 +`line 664 "t/t_preproc.v" 0 //====================================================================== // Stringify bug -`line 618 "t/t_preproc.v" 0 +`line 667 "t/t_preproc.v" 0 `dbg_hdl(UVM_LOW, ("Functional coverage enabled: paramgrp")); -`line 621 "t/t_preproc.v" 0 +`line 670 "t/t_preproc.v" 0 @@ -923,28 +979,28 @@ XYS_FAMILY = XYS_foo -`line 629 "t/t_preproc.v" 0 +`line 678 "t/t_preproc.v" 0 module pcc2_cfg; generate -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 covergroup a @(posedge b); -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 c: coverpoint d iff ((c) === 1'b1); endgroup -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 a u_a; -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 initial do begin $display ("DEBUG : %s [%m]", $sformatf ("Functional coverage enabled: u_a")); end while(0); endgenerate endmodule -`line 635 "t/t_preproc.v" 0 +`line 684 "t/t_preproc.v" 0 //====================================================================== // Verilog-Perl bug1668 "`NOT_DEFINED_STR" -`line 640 "t/t_preproc.v" 0 +`line 689 "t/t_preproc.v" 0 //====================================================================== // IEEE mandated predefines // undefineall should have no effect on these @@ -967,4 +1023,4 @@ predef 2 2 // After `undefineall above, for testing --dump-defines -`line 662 "t/t_preproc.v" 2 +`line 711 "t/t_preproc.v" 2 From d77c9da9838f2b83850016803cfb5694d3d8db8f Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 2 May 2021 06:12:38 +0900 Subject: [PATCH 05/80] Tests: Add a case to cover the line using m_frozenNodes. (#2915) --- test_regress/t/t_const_opt.v | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index b9881d967..e8f31dfe1 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -57,7 +57,7 @@ module t(/*AUTOARG*/ $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); if (crc !== 64'hc77bb9b3784ea091) $stop; // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'hfab547b426149442 +`define EXPECTED_SUM 64'he78be35df15ae0ab if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; @@ -80,7 +80,7 @@ module Test(/*AUTOARG*/ output logic o; - logic [3:0] tmp; + logic [4:0] tmp; assign o = ^tmp; always_ff @(posedge clk) begin @@ -100,6 +100,7 @@ module Test(/*AUTOARG*/ tmp[1] <= ((32'd2 ** i) & 32'h10) == 32'b0; // replacePowShift tmp[2] <= ((d0 & d1) | (d0 & d2))^ ((d3 & d4) | (d5 & d4)); // replaceAndOr() tmp[3] <= d0 <-> d1; // replaceLogEq() + tmp[4] <= i[0] & (i[1] & (i[2] & (i[3] | d[4]))); // ConstBitOpTreeVisitor::m_frozenNodes end endmodule From 008b8d5b5643729c7ec41683557d1f20bf954bc2 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 2 May 2021 04:51:41 +0100 Subject: [PATCH 06/80] Speed up sparse V3Number multiplication --- src/V3Number.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/V3Number.cpp b/src/V3Number.cpp index b6bd7937b..70be0ac19 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1759,13 +1759,17 @@ V3Number& V3Number::opMul(const V3Number& lhs, const V3Number& rhs) { opCleanThis(); // Mult produces extra bits in result } else { for (int lword = 0; lword < lhs.words(); lword++) { + const vluint64_t lwordval = static_cast(lhs.m_value[lword]); + if (lwordval == 0) continue; for (int rword = 0; rword < rhs.words(); rword++) { - vluint64_t mul = static_cast(lhs.m_value[lword]) - * static_cast(rhs.m_value[rword]); + const vluint64_t rwordval = static_cast(rhs.m_value[rword]); + if (rwordval == 0) continue; + vluint64_t mul = lwordval * rwordval; for (int qword = lword + rword; qword < this->words(); qword++) { mul += static_cast(m_value[qword]); m_value[qword] = (mul & 0xffffffffULL); mul = (mul >> 32ULL) & 0xffffffffULL; + if (mul == 0) break; } } } From 76494891cfc5b3ba71be32de12df6c21f835a39c Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 2 May 2021 11:23:09 +0100 Subject: [PATCH 07/80] Speed up V3Width by pulling skip condition before node iteration. --- src/V3Width.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a36501eb1..dc556aa00 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -6125,6 +6125,7 @@ private: } void userIterateAndNext(AstNode* nodep, WidthVP* vup) { if (!nodep) return; + if (nodep->didWidth()) return; // Avoid iterating list we have already iterated { VL_RESTORER(m_vup); m_vup = vup; From 53d9c30277a5624f919e8888f787e8f98b220bdc Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Tue, 4 May 2021 06:30:18 +0900 Subject: [PATCH 08/80] Internals: Factor out V3OptionParser from V3Options.cpp. No functional change is intended. (#2919) --- src/Makefile_obj.in | 1 + src/V3OptionParser.cpp | 232 +++++++++++++++++++++++++++++++++++++ src/V3OptionParser.h | 156 +++++++++++++++++++++++++ src/V3Options.cpp | 255 +++-------------------------------------- 4 files changed, 405 insertions(+), 239 deletions(-) create mode 100644 src/V3OptionParser.cpp create mode 100644 src/V3OptionParser.h diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 4562bcd7d..f6f02249d 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -221,6 +221,7 @@ RAW_OBJS = \ V3MergeCond.o \ V3Name.o \ V3Number.o \ + V3OptionParser.o \ V3Options.o \ V3Order.o \ V3Os.o \ diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp new file mode 100644 index 000000000..dd26b0846 --- /dev/null +++ b/src/V3OptionParser.cpp @@ -0,0 +1,232 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Command line option parser +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* + +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +#include "V3Global.h" +#include "V3Options.h" +#endif +#include "V3Error.h" +#include "V3OptionParser.h" +#include "V3String.h" + +//###################################################################### +// V3OptionParser::Impl +struct V3OptionParser::Impl { + // TYPES + + // Setting for isOnOffAllowed() and isPartialMatchAllowed() + enum class en : uint8_t { + NONE, // "-opt" + ONOFF, // "-opt" and "-no-opt" + VALUE // "-opt val" + }; + // Base class of actual action classes + template + class ActionBase VL_NOT_FINAL : public ActionIfs { + bool m_undocumented = false; // This option is not documented + public: + virtual bool isValueNeeded() const override final { return MODE == en::VALUE; } + virtual bool isOnOffAllowed() const override final { return MODE == en::ONOFF; } + virtual bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; } + virtual bool isUndocumented() const override { return m_undocumented; } + virtual void undocumented() override { m_undocumented = true; } + }; + + // Actual action classes + template class ActionSet; // "-opt" for bool-ish, "-opt val" for int and string + template class ActionOnOff; // "-opt" and "-no-opt" for bool-ish + class ActionCbCall; // Callback without argument for "-opt" + class ActionCbOnOff; // Callback for "-opt" and "-no-opt" + template class ActionCbVal; // Callback for "-opt val" + class ActionCbPartialMatch; // Callback "-O3" for "-O" + class ActionCbPartialMatchVal; // Callback "-debugi-V3Options 3" for "-debugi-" + + // MEMBERS + std::map> m_options; // All actions for option + bool m_isFinalized{false}; // Becomes after finalize() is called + VSpellCheck m_spellCheck; // Suggests closest option when not found +}; + +//###################################################################### +// Action classes in V3OptionParser::Impl + +#define V3OPTION_PARSER_DEF_ACT_CLASS(className, type, body, enType) \ + template <> class V3OptionParser::Impl::className final : public ActionBase { \ + type* m_valp; /* Pointer to a option variable*/ \ +\ + public: \ + explicit className(type* valp) \ + : m_valp(valp) {} \ + virtual void exec(const char* optp, const char* argp) override { body; } \ + } + +V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, bool, *m_valp = true, en::NONE); +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, VOptionBool, m_valp->setTrueOrFalse(true), en::NONE); +#endif +V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, int, *m_valp = std::atoi(argp), en::VALUE); +V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, string, *m_valp = argp, en::VALUE); + +V3OPTION_PARSER_DEF_ACT_CLASS(ActionOnOff, bool, *m_valp = !hasPrefixNo(optp), en::ONOFF); +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +V3OPTION_PARSER_DEF_ACT_CLASS(ActionOnOff, VOptionBool, m_valp->setTrueOrFalse(!hasPrefixNo(optp)), + en::ONOFF); +#endif +#undef V3OPTION_PARSER_DEF_ACT_CLASS + +#define V3OPTION_PARSER_DEF_ACT_CB_CLASS(className, funcType, body, ...) \ + class V3OptionParser::Impl::className final : public ActionBase<__VA_ARGS__> { \ + std::function m_cb; /* Callback function */ \ +\ + public: \ + using CbType = std::function; \ + explicit className(CbType cb) \ + : m_cb(std::move(cb)) {} \ + virtual void exec(const char* optp, const char* argp) override { body; } \ + } + +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbCall, void(void), m_cb(), en::NONE); +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbOnOff, void(bool), m_cb(!hasPrefixNo(optp)), en::ONOFF); +template <> +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbVal, void(int), m_cb(std::atoi(argp)), en::VALUE); +template <> +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbVal, void(const char*), m_cb(argp), + en::VALUE); +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbPartialMatch, void(const char*), m_cb(optp), en::NONE, + true); +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbPartialMatchVal, void(const char*, const char*), + m_cb(optp, argp), en::VALUE, true); + +#undef V3OPTION_PARSER_DEF_ACT_CB_CLASS + +//###################################################################### +// Member functions of V3OptionParser + +V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { + auto it = m_pimpl->m_options.find(optp); + if (it != m_pimpl->m_options.end()) return it->second.get(); + for (auto&& act : m_pimpl->m_options) { + if (act.second->isOnOffAllowed()) { // Find starts with "-no" + const char* const nop = std::strncmp(optp, "-no", 3) ? nullptr : (optp + 3); + if (nop && (act.first == nop || act.first == (string{"-"} + nop))) { + return act.second.get(); + } + } else if (act.second->isPartialMatchAllowed()) { + if (!std::strncmp(optp, act.first.c_str(), act.first.length())) { + return act.second.get(); + } + } + } + return nullptr; +} + +template +V3OptionParser::ActionIfs& V3OptionParser::add(const std::string& opt, ARG arg) { + UASSERT(!m_pimpl->m_isFinalized, "Cannot add after finalize() is called"); + std::unique_ptr act{new ACT{std::move(arg)}}; + UASSERT(opt.size() >= 2, opt << " is too short"); + UASSERT(opt[0] == '-' || opt[0] == '+', opt << " does not start with either '-' or '+'"); + UASSERT(!(opt[0] == '-' && opt[1] == '-'), "Option must have single '-', but " << opt); + const auto insertedResult = m_pimpl->m_options.emplace(opt, std::move(act)); + UASSERT(insertedResult.second, opt << " is already registered"); + return *insertedResult.first->second; +} + +bool V3OptionParser::hasPrefixNo(const char* strp) { + UASSERT(strp[0] == '-', strp << " does not start with '-'"); + if (strp[1] == '-') ++strp; + return std::strncmp(strp, "-no", 3) == 0; +} + +int V3OptionParser::parse(int idx, int argc, char* argv[]) { + UASSERT(m_pimpl->m_isFinalized, "finalize() must be called before parse()"); + const char* optp = argv[idx]; + if (optp[0] == '-' && optp[1] == '-') ++optp; + ActionIfs* actp = find(optp); + if (!actp) return 0; + if (!actp->isValueNeeded()) { + actp->exec(optp, nullptr); + return 1; + } else if (idx + 1 < argc) { + actp->exec(optp, argv[idx + 1]); + return 2; + } + return 0; +} + +string V3OptionParser::getSuggestion(const char* str) const { + return m_pimpl->m_spellCheck.bestCandidateMsg(str); +} + +void V3OptionParser::addSuggestionCandidate(const string& s) { + m_pimpl->m_spellCheck.pushCandidate(s); +} + +void V3OptionParser::finalize() { + UASSERT(!m_pimpl->m_isFinalized, "finalize() must not be called twice"); + for (auto&& opt : m_pimpl->m_options) { + if (opt.second->isUndocumented()) continue; + m_pimpl->m_spellCheck.pushCandidate(opt.first); + if (opt.second->isOnOffAllowed()) m_pimpl->m_spellCheck.pushCandidate("-no" + opt.first); + } + m_pimpl->m_isFinalized = true; +} + +V3OptionParser::V3OptionParser() + : m_pimpl{new Impl{}} {} + +V3OptionParser::~V3OptionParser() = default; + +//###################################################################### +// Member functions of V3OptionParser::AppendHelper + +#define V3OPTION_PARSER_DEF_OP(actKind, argType, actType) \ + V3OptionParser::ActionIfs& V3OptionParser::AppendHelper::operator()( \ + const char* optp, actKind, argType arg) const { \ + return m_parser.add(optp, arg); \ + } +V3OPTION_PARSER_DEF_OP(Set, bool*, ActionSet) +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +V3OPTION_PARSER_DEF_OP(Set, VOptionBool*, ActionSet) +#endif +V3OPTION_PARSER_DEF_OP(Set, int*, ActionSet) +V3OPTION_PARSER_DEF_OP(Set, string*, ActionSet) +V3OPTION_PARSER_DEF_OP(OnOff, bool*, ActionOnOff) +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +V3OPTION_PARSER_DEF_OP(OnOff, VOptionBool*, ActionOnOff) +#endif +V3OPTION_PARSER_DEF_OP(CbCall, Impl::ActionCbCall::CbType, ActionCbCall) +V3OPTION_PARSER_DEF_OP(CbOnOff, Impl::ActionCbOnOff::CbType, ActionCbOnOff) +V3OPTION_PARSER_DEF_OP(CbVal, Impl::ActionCbVal::CbType, ActionCbVal) +V3OPTION_PARSER_DEF_OP(CbVal, Impl::ActionCbVal::CbType, ActionCbVal) +#undef V3OPTION_PARSER_DEF_OP + +V3OptionParser::ActionIfs& +V3OptionParser::AppendHelper::operator()(const char* optp, CbPartialMatch, + Impl::ActionCbPartialMatch::CbType cb) const { + const size_t prefixLen = std::strlen(optp); + auto wrap = [prefixLen, cb](const char* optp) { cb(optp + prefixLen); }; + return m_parser.add(optp, std::move(wrap)); +} + +V3OptionParser::ActionIfs& +V3OptionParser::AppendHelper::operator()(const char* optp, CbPartialMatchVal, + Impl::ActionCbPartialMatchVal::CbType cb) const { + const size_t prefixLen = std::strlen(optp); + auto wrap + = [prefixLen, cb](const char* optp, const char* argp) { cb(optp + prefixLen, argp); }; + return m_parser.add(optp, std::move(wrap)); +} diff --git a/src/V3OptionParser.h b/src/V3OptionParser.h new file mode 100644 index 000000000..42ad88135 --- /dev/null +++ b/src/V3OptionParser.h @@ -0,0 +1,156 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Command line option parser +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* + +#ifndef VERILATOR_V3OPTION_PARSER_H_ +#define VERILATOR_V3OPTION_PARSER_H_ + +#include "config_build.h" +#include "verilatedos.h" + +#include +#include +#include + +// Not to include V3Option.h here so that VlcMain or other executables can use this file easily. +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +class VOptionBool; +#endif + +// Typycal usage would look as below. +// See also V3Options::parseOptsList() in V3Optoins.cpp for more detailed usage. +// +// V3OptionParser parser; +// V3OptionParser::AppendHelper DECL_OPTION{parser}; +// V3OPTION_PARSER_DECL_TAGS; +// +// DECL_OPPTION("-help", CbCall, []() { showHelp(); }); +// DECL_OPPTION("-some_opt", Set, &m_intMember}); +// parser.finalize(); +// for (int i = 1; i < argc;) { +// if (int consumed = parser.parse(i, argc, argv)) { +// i += consumed; +// } else { // error +// cerr << parser.getSuggestion(argv[i]) << endl; +// } +// } +// + +//###################################################################### +// V3 OptionParser + +class V3OptionParser final { +public: + // TYPES + class ActionIfs; + // Functor to register options to V3OptionParser + class AppendHelper; + struct Impl; + +private: + // MEMBERS + std::unique_ptr m_pimpl; + + // METHODS + ActionIfs* find(const char* optp); + template ActionIfs& add(const string& opt, ARG arg); + static bool hasPrefixNo(const char* strp); // Returns true if strp starts with "-no" + +public: + // METHODS + // Returns how many args are consumed. 0 means not match + int parse(int idx, int argc, char* argv[]); + // Find the most similar option + string getSuggestion(const char* str) const; + void addSuggestionCandidate(const string& s); + // Call this function after all options are registered. + void finalize(); + + // CONSTRUCTORS + V3OptionParser(); + ~V3OptionParser(); +}; + +class V3OptionParser::ActionIfs VL_NOT_FINAL { +public: + virtual ~ActionIfs() = default; + virtual bool isValueNeeded() const = 0; // Need val of "-opt val" + virtual bool isOnOffAllowed() const = 0; // true if "-no-opt" is allowd + virtual bool isPartialMatchAllowed() const = 0; // true if "-Wno-" matches "-Wno-fatal" + virtual bool isUndocumented() const = 0; // Will not be suggested in typo + // Set a value or run callback + virtual void exec(const char* optp, const char* valp) = 0; + // Mark this option undocumented. (Exclude this option from suggestion list). + virtual void undocumented() = 0; +}; + +// A helper class to register options +class V3OptionParser::AppendHelper final { +public: + // TYPES + // Tag to specify which operator() to call + struct Set {}; // For ActionSet + struct OnOff {}; // For ActionOnOff + struct CbCall {}; // For ActionCbCall + struct CbOnOff {}; // For ActionOnOff + struct CbVal {}; // For ActionCbVal + struct CbPartialMatch {}; // For ActionCbPartialMatch + struct CbPartialMatchVal {}; // For ActionCbPartialMatchVal + +private: + // MEMBERS + V3OptionParser& m_parser; // The actual option registory + +public: + // METHODS + ActionIfs& operator()(const char* optp, Set, bool*) const; +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL + ActionIfs& operator()(const char* optp, Set, VOptionBool*) const; +#endif + ActionIfs& operator()(const char* optp, Set, int*) const; + ActionIfs& operator()(const char* optp, Set, string*) const; + + ActionIfs& operator()(const char* optp, OnOff, bool*) const; +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL + ActionIfs& operator()(const char* optp, OnOff, VOptionBool*) const; +#endif + + ActionIfs& operator()(const char* optp, CbCall, std::function) const; + ActionIfs& operator()(const char* optp, CbOnOff, std::function) const; + ActionIfs& operator()(const char* optp, CbVal, std::function) const; + ActionIfs& operator()(const char* optp, CbVal, std::function) const; + + ActionIfs& operator()(const char* optp, CbPartialMatch, + std::function) const; + ActionIfs& operator()(const char* optp, CbPartialMatchVal, + std::function) const; + + // CONSTRUCTORS + explicit AppendHelper(V3OptionParser& parser) + : m_parser{parser} {} +}; + +#define V3OPTION_PARSER_DECL_TAGS \ + const auto Set = V3OptionParser::AppendHelper::Set{}; \ + const auto OnOff = V3OptionParser::AppendHelper::OnOff{}; \ + const auto CbCall = V3OptionParser::AppendHelper::CbCall{}; \ + const auto CbOnOff = V3OptionParser::AppendHelper::CbOnOff{}; \ + const auto CbVal = V3OptionParser::AppendHelper::CbVal{}; \ + const auto CbPartialMatch = V3OptionParser::AppendHelper::CbPartialMatch{}; \ + const auto CbPartialMatchVal = V3OptionParser::AppendHelper::CbPartialMatchVal {} + +//###################################################################### + +#endif // guard diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 244d890d0..7533f01a8 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -19,9 +19,9 @@ #include "V3Global.h" #include "V3Ast.h" -#include "V3String.h" #include "V3Os.h" #include "V3Options.h" +#include "V3OptionParser.h" #include "V3Error.h" #include "V3File.h" #include "V3PreShell.h" @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -106,226 +105,6 @@ public: ~V3OptionsImp() = default; }; -//###################################################################### -// V3 OptionParser - -class V3OptionsParser final { -public: - // TYPES - class ActionIfs VL_NOT_FINAL { - public: - virtual ~ActionIfs() = default; - virtual bool isValueNeeded() const = 0; // Need val of "-opt val" - virtual bool isOnOffAllowed() const = 0; // true if "-no-opt" is allowd - virtual bool isPartialMatchAllowed() const = 0; // true if "-Wno-" matches "-Wno-fatal" - virtual bool isUndocumented() const = 0; // Will not be suggested in typo - // Set a value or run callback - virtual void exec(const char* optp, const char* valp) = 0; - virtual void undocumented() = 0; - }; - enum class en { // Setting for isOnOffAllowed() and isPartialMatchAllowed() - NONE, // "-opt" - ONOFF, // "-opt" and "-no-opt" - VALUE // "-opt val" - }; - // Base class of actual action classes - template - class ActionBase VL_NOT_FINAL : public ActionIfs { - bool m_undocumented = false; // This option is not documented - public: - virtual bool isValueNeeded() const override final { return MODE == en::VALUE; } - virtual bool isOnOffAllowed() const override final { return MODE == en::ONOFF; } - virtual bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; } - virtual bool isUndocumented() const override { return m_undocumented; } - virtual void undocumented() override { m_undocumented = true; } - }; - // Actual action classes - template class ActionSet; // "-opt" for bool-ish, "-opt val" for int and string - template class ActionOnOff; // "-opt" and "-no-opt" for bool-ish - class ActionCbCall; // Callback without argument for "-opt" - class ActionCbOnOff; // Callback for "-opt" and "-no-opt" - template class ActionCbVal; // Callback for "-opt val" - class ActionCbPartialMatch; // Callback "-O3" for "-O" - class ActionCbPartialMatchVal; // Callback "-debugi-V3Options 3" for "-debugi-" - - // Functor to register options to V3OptionsParser - struct AppendHelper; - -private: - // MEMBERS - std::map> m_options; // All actions for option - bool m_isFinalized{false}; // Becomes after finalize() is called - VSpellCheck m_spellCheck; // Suggests closest option when not found - - // METHODS - ActionIfs* find(const char* optp) { - auto it = m_options.find(optp); - if (it != m_options.end()) return it->second.get(); - for (auto&& act : m_options) { - if (act.second->isOnOffAllowed()) { // Find starts with "-no" - const char* const nop = std::strncmp(optp, "-no", 3) ? nullptr : (optp + 3); - if (nop && (act.first == nop || act.first == (string{"-"} + nop))) { - return act.second.get(); - } - } else if (act.second->isPartialMatchAllowed()) { - if (!std::strncmp(optp, act.first.c_str(), act.first.length())) { - return act.second.get(); - } - } - } - return nullptr; - } - template ActionIfs& add(const std::string& opt, ARG arg) { - UASSERT(!m_isFinalized, "Cannot add after finalize() is called"); - std::unique_ptr act{new ACT{std::move(arg)}}; - UASSERT(opt.size() >= 2, opt << " is too short"); - UASSERT(opt[0] == '-' || opt[0] == '+', opt << " does not start with either '-' or '+'"); - UASSERT(!(opt[0] == '-' && opt[1] == '-'), "Option must have single '-', but " << opt); - const auto insertedResult = m_options.emplace(opt, std::move(act)); - UASSERT(insertedResult.second, opt << " is already registered"); - return *insertedResult.first->second; - } - static bool hasPrefixNo(const char* strp) { // Returns true if strp starts with "-no" - UASSERT(strp[0] == '-', strp << " does not start with '-'"); - if (strp[1] == '-') ++strp; - return std::strncmp(strp, "-no", 3) == 0; - } - -public: - // METHODS - // Returns how many args are consumed. 0 means not match - int parse(int idx, int argc, char* argv[]) { - UASSERT(m_isFinalized, "finalize() must be called before parse()"); - const char* optp = argv[idx]; - if (optp[0] == '-' && optp[1] == '-') ++optp; - ActionIfs* actp = find(optp); - if (!actp) return 0; - if (!actp->isValueNeeded()) { - actp->exec(optp, nullptr); - return 1; - } else if (idx + 1 < argc) { - actp->exec(optp, argv[idx + 1]); - return 2; - } - return 0; - } - // Find the most similar option - string getSuggestion(const char* str) const { return m_spellCheck.bestCandidateMsg(str); } - void addSuggestionCandidate(const string& s) { m_spellCheck.pushCandidate(s); } - void finalize() { - UASSERT(!m_isFinalized, "finalize() must not be called twice"); - for (auto&& opt : m_options) { - if (opt.second->isUndocumented()) continue; - m_spellCheck.pushCandidate(opt.first); - if (opt.second->isOnOffAllowed()) m_spellCheck.pushCandidate("-no" + opt.first); - } - m_isFinalized = true; - } -}; - -#define V3OPTIONS_DEF_ACT_CLASS(className, type, body, enType) \ - template <> class V3OptionsParser::className final : public ActionBase { \ - type* m_valp; /* Pointer to a option variable*/ \ -\ - public: \ - explicit className(type* valp) \ - : m_valp(valp) {} \ - virtual void exec(const char* optp, const char* argp) override { body; } \ - } - -V3OPTIONS_DEF_ACT_CLASS(ActionSet, bool, *m_valp = true, en::NONE); -V3OPTIONS_DEF_ACT_CLASS(ActionSet, VOptionBool, m_valp->setTrueOrFalse(true), en::NONE); -V3OPTIONS_DEF_ACT_CLASS(ActionSet, int, *m_valp = std::atoi(argp), en::VALUE); -V3OPTIONS_DEF_ACT_CLASS(ActionSet, string, *m_valp = argp, en::VALUE); - -V3OPTIONS_DEF_ACT_CLASS(ActionOnOff, bool, *m_valp = !hasPrefixNo(optp), en::ONOFF); -V3OPTIONS_DEF_ACT_CLASS(ActionOnOff, VOptionBool, m_valp->setTrueOrFalse(!hasPrefixNo(optp)), - en::ONOFF); - -#undef V3OPTIONS_DEF_ACT_CLASS - -#define V3OPTIONS_DEF_ACT_CB_CLASS(className, funcType, body, ...) \ - class V3OptionsParser::className final : public ActionBase<__VA_ARGS__> { \ - std::function m_cb; /* Callback function */ \ -\ - public: \ - using CbType = std::function; \ - explicit className(CbType cb) \ - : m_cb(std::move(cb)) {} \ - virtual void exec(const char* optp, const char* argp) override { body; } \ - } - -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbCall, void(void), m_cb(), en::NONE); -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbOnOff, void(bool), m_cb(!hasPrefixNo(optp)), en::ONOFF); -template <> -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbVal, void(int), m_cb(std::atoi(argp)), en::VALUE); -template <> -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbVal, void(const char*), m_cb(argp), en::VALUE); -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbPartialMatch, void(const char*), m_cb(optp), en::NONE, true); -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbPartialMatchVal, void(const char*, const char*), - m_cb(optp, argp), en::VALUE, true); - -#undef V3OPTIONS_DEF_ACT_CB_CLASS - -// A helper class to register options -struct V3OptionsParser::AppendHelper final { - V3OptionsParser& m_parser; // The actual option registory - - // TYPES - // Tag to specify which operator() to call - struct Set {}; // For ActionSet - struct OnOff {}; // For ActionOnOff - struct CbCall {}; // For ActionCbCall - struct CbOnOff {}; // For ActionOnOff - struct CbVal {}; // For ActionCbVal - struct CbPartialMatch {}; // For ActionCbPartialMatch - struct CbPartialMatchVal {}; // For ActionCbPartialMatchVal - - // METHODS - -#define V3OPTIONS_DEF_OP(actKind, argType, actType) \ - ActionIfs& operator()(const char* optp, actKind, argType arg) const { \ - return m_parser.add(optp, arg); \ - } - V3OPTIONS_DEF_OP(Set, bool*, ActionSet) - V3OPTIONS_DEF_OP(Set, VOptionBool*, ActionSet) - V3OPTIONS_DEF_OP(Set, int*, ActionSet) - V3OPTIONS_DEF_OP(Set, string*, ActionSet) - V3OPTIONS_DEF_OP(OnOff, bool*, ActionOnOff) - V3OPTIONS_DEF_OP(OnOff, VOptionBool*, ActionOnOff) - V3OPTIONS_DEF_OP(CbCall, ActionCbCall::CbType, ActionCbCall) - V3OPTIONS_DEF_OP(CbOnOff, ActionCbOnOff::CbType, ActionCbOnOff) - V3OPTIONS_DEF_OP(CbVal, ActionCbVal::CbType, ActionCbVal) - V3OPTIONS_DEF_OP(CbVal, ActionCbVal::CbType, ActionCbVal) -#undef V3OPTIONS_DEF_OP - - // Syntax sugar to register a member function of V3Options directry - ActionIfs& operator()(const char* optp, CbVal, - std::pair arg) const { - auto cb = [arg](int v) { (arg.first->*arg.second)(v); }; - return m_parser.add>(optp, cb); - } - ActionIfs& operator()(const char* optp, CbVal, - std::pair arg) const { - auto cb = [arg](const string& v) { (arg.first->*arg.second)(v); }; - return m_parser.add>(optp, cb); - } - // Callback of partial match expects prefix to be removed, so wrap the given callback - ActionIfs& operator()(const char* optp, CbPartialMatch, - ActionCbPartialMatch::CbType cb) const { - const size_t prefixLen = std::strlen(optp); - auto wrap = [prefixLen, cb](const char* optp) { cb(optp + prefixLen); }; - return m_parser.add(optp, std::move(wrap)); - } - ActionIfs& operator()(const char* optp, CbPartialMatchVal, - ActionCbPartialMatchVal::CbType cb) const { - const size_t prefixLen = std::strlen(optp); - auto wrap - = [prefixLen, cb](const char* optp, const char* argp) { cb(optp + prefixLen, argp); }; - return m_parser.add(optp, std::move(wrap)); - } -}; - //###################################################################### // V3LangCode class functions @@ -1112,20 +891,18 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char addArg(argv[i]); // -f's really should be inserted in the middle, but this is for debug } - V3OptionsParser parser; - const auto Set = V3OptionsParser::AppendHelper::Set{}; - const auto OnOff = V3OptionsParser::AppendHelper::OnOff{}; - const auto CbCall = V3OptionsParser::AppendHelper::CbCall{}; - const auto CbOnOff = V3OptionsParser::AppendHelper::CbOnOff{}; - const auto CbVal = V3OptionsParser::AppendHelper::CbVal{}; - const auto CbPartialMatch = V3OptionsParser::AppendHelper::CbPartialMatch{}; - const auto CbPartialMatchVal = V3OptionsParser::AppendHelper::CbPartialMatchVal{}; - V3OptionsParser::AppendHelper DECL_OPTION{parser}; + V3OptionParser parser; + V3OptionParser::AppendHelper DECL_OPTION{parser}; + V3OPTION_PARSER_DECL_TAGS; + + auto callStrSetter = [this](void (V3Options::*cbStr)(const string&)) { + return [this, cbStr](const string& v) { (this->*cbStr)(v); }; + }; // Usage // DECL_OPTION("-option", action, pointer_or_lambda); // action: one of Set, OnOff, CbCall, CbOnOff, CbVal, CbPartialMatch, and CbPartialMatchVal // Set : Set value to a variable, pointer_or_lambda must be a pointer to the - // variable. + // variable. // true is set to bool-ish variable when '-opt' is passed to verilator. // val is set to int and string variable when '-opt val' is passed. // OnOff : Set value to a bool-ish variable, pointer_or_lambda must be a pointer @@ -1138,7 +915,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char // CbVal : Call lambda or function that takes int or const char*. // "-opt val" is passed to verilator, val is passed to the lambda. // If a function to be called is a member of V3Options that only takes - // bool/const string&, {this, &V3Options::memberFunc} can be passed + // const string&, callStrSetter(&V3Options::memberFunc) can be passed // instead of lambda as a syntax sugar. // CbPartialMatch : Call lambda or function that takes remaining string. // e.g. DECL_OPTION("-opt-", CbPartialMatch, [](const char*optp) { cout << @@ -1201,14 +978,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-bin", Set, &m_bin); DECL_OPTION("-build", Set, &m_build); - DECL_OPTION("-CFLAGS", CbVal, {this, &V3Options::addCFlags}); + DECL_OPTION("-CFLAGS", CbVal, callStrSetter(&V3Options::addCFlags)); DECL_OPTION("-cc", CbCall, [this]() { m_outFormatOk = true; m_systemC = false; }); DECL_OPTION("-cdc", OnOff, &m_cdc); - DECL_OPTION("-clk", CbVal, {this, &V3Options::addClocker}); - DECL_OPTION("-no-clk", CbVal, {this, &V3Options::addNoClocker}); + DECL_OPTION("-clk", CbVal, callStrSetter(&V3Options::addClocker)); + DECL_OPTION("-no-clk", CbVal, callStrSetter(&V3Options::addNoClocker)); DECL_OPTION("-comp-limit-blocks", Set, &m_compLimitBlocks).undocumented(); DECL_OPTION("-comp-limit-members", Set, &m_compLimitMembers) @@ -1244,7 +1021,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-D", CbPartialMatch, [this](const char* valp) { addDefine(valp, false); }); DECL_OPTION("-debug", CbCall, [this]() { setDebugMode(3); }); - DECL_OPTION("-debugi", CbVal, {this, &V3Options::setDebugMode}); + DECL_OPTION("-debugi", CbVal, [this](int v) { setDebugMode(v); }); DECL_OPTION("-debugi-", CbPartialMatchVal, [this](const char* optp, const char* valp) { setDebugSrcLevel(optp, std::atoi(valp)); }); @@ -1320,7 +1097,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char }); DECL_OPTION("-inline-mult", Set, &m_inlineMult); - DECL_OPTION("-LDFLAGS", CbVal, {this, &V3Options::addLdLibs}); + DECL_OPTION("-LDFLAGS", CbVal, callStrSetter(&V3Options::addLdLibs)); auto setLang = [this, fl](const char* valp) { V3LangCode optval = V3LangCode(valp); if (optval.legal()) { @@ -1340,7 +1117,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-no-l2name", CbCall, [this]() { m_l2Name = ""; }).undocumented(); // Historical DECL_OPTION("-l2name", CbCall, [this]() { m_l2Name = "v"; }).undocumented(); // Historical - DECL_OPTION("-MAKEFLAGS", CbVal, {this, &V3Options::addMakeFlags}); + DECL_OPTION("-MAKEFLAGS", CbVal, callStrSetter(&V3Options::addMakeFlags)); DECL_OPTION("-MMD", OnOff, &m_makeDepend); DECL_OPTION("-MP", OnOff, &m_makePhony); DECL_OPTION("-Mdir", CbVal, [this](const char* valp) { From 52900625498a41fecc0d3bd5e14e56e46c0cb909 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Mon, 3 May 2021 23:59:41 +0200 Subject: [PATCH 09/80] Fix bounds check in VL_SEL_IWII (#2910) --- include/verilated.h | 2 +- test_regress/t/t_emit_constw.v | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index f9a15307c..7df6e08de 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -2705,7 +2705,7 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) VL_MT_SAFE { int msb = lsb + width - 1; - if (VL_UNLIKELY(msb > lbits)) { + if (VL_UNLIKELY(msb >= lbits)) { return ~0; // Spec says you can go outside the range of a array. Don't coredump if so. } else if (VL_BITWORD_E(msb) == VL_BITWORD_E(static_cast(lsb))) { return VL_BITRSHIFT_W(lwp, lsb); diff --git a/test_regress/t/t_emit_constw.v b/test_regress/t/t_emit_constw.v index e49d532de..ae9774734 100644 --- a/test_regress/t/t_emit_constw.v +++ b/test_regress/t/t_emit_constw.v @@ -62,7 +62,7 @@ module t (/*AUTOARG*/ ^ bytehash(w17)); // verilator lint_on WIDTH -`define EXPECTED_SUM 64'hb6fdb64085fc17f5 +`define EXPECTED_SUM 64'h2bc7c2a98a302891 // Test loop always @ (posedge clk) begin From 490f9f757d530870337404e540f6beb413fdfdcc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 3 May 2021 19:34:02 -0400 Subject: [PATCH 10/80] devel release --- Changes | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 3a0460c94..833de7b7c 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,10 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 4.203 devel +========================== + + Verilator 4.202 2021-04-24 ========================== diff --git a/configure.ac b/configure.ac index fce513b17..6f82920b9 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.202 2021-04-24], +AC_INIT([Verilator],[4.203 devel], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file From e68788d914eebbe8ed97d806699e41b222032ba4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 3 May 2021 19:36:53 -0400 Subject: [PATCH 11/80] Fix initialization of assoc in assoc array (#2914). --- Changes | 4 ++++ src/V3EmitC.cpp | 6 +++--- test_regress/t/t_assoc2.pl | 21 +++++++++++++++++++++ test_regress/t/t_assoc2.v | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_assoc2.pl create mode 100644 test_regress/t/t_assoc2.v diff --git a/Changes b/Changes index 833de7b7c..30937b5d8 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,10 @@ contributors that suggested a given feature are shown in []. Thanks! Verilator 4.203 devel ========================== +**Minor:** + +* Fix initialization of assoc in assoc array (#2914). [myftptoyman] + Verilator 4.202 2021-04-24 ========================== diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index eae2581cd..c6b6ed359 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1778,19 +1778,19 @@ class EmitCImp final : EmitCStmts { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, - ".atDefault()" + cvtarray); + suffix + ".atDefault()" + cvtarray); } else if (VN_IS(dtypep, ClassRefDType)) { return ""; // Constructor does it } else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, - ".atDefault()" + cvtarray); + suffix + ".atDefault()" + cvtarray); } else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, - ".atDefault()" + cvtarray); + suffix + ".atDefault()" + cvtarray); } else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp, "Should have swapped msb & lsb earlier."); diff --git a/test_regress/t/t_assoc2.pl b/test_regress/t/t_assoc2.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_assoc2.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 2019 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_assoc2.v b/test_regress/t/t_assoc2.v new file mode 100644 index 000000000..4c938a35a --- /dev/null +++ b/test_regress/t/t_assoc2.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + + // associative array of an associative array + logic [31:0] a [logic [31:0]][logic [63:0]]; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 1) begin + a[5][8] = 8; + a[5][9] = 9; + end + else if (cyc == 2) begin + `checkh(a[5][8], 8); + `checkh(a[5][9], 9); + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule From 8624ce6a84dcd0908a9d721420e1f790ffaf4ba1 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Tue, 4 May 2021 10:40:16 +0900 Subject: [PATCH 12/80] Stop checking dtype for better optimization chance in BitOpTree (#2909) * Tests: Add more case that does not match native C++ width (8, 16, 32 or 64). * Use AstVarRef::same() instead of AstNode::sameGateTree() because the latter checks dtype in addition to scope. AstVarRef may have different minWidth in some cases, but the difference should be ignored in the context of bitOpTree optimization. --- src/V3Const.cpp | 2 +- test_regress/t/t_const_opt_red.pl | 2 +- test_regress/t/t_const_opt_red.v | 10 ++++++---- test_regress/t/t_func_crc.pl | 2 +- test_regress/t/t_gate_ormux.pl | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index a66793857..f802d5524 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -100,7 +100,7 @@ class ConstBitOpTreeVisitor final : public AstNVisitor { public: // METHODS bool hasConstantResult() const { return m_constResult >= 0; } - bool sameVarAs(const AstNodeVarRef* otherp) const { return m_refp->sameGateTree(otherp); } + bool sameVarAs(const AstNodeVarRef* otherp) const { return m_refp->same(otherp); } void setPolarity(bool compBit, int bit) { UASSERT_OBJ(!hasConstantResult(), m_refp, "Already has result of " << m_constResult); UASSERT_OBJ(bit < VL_QUADSIZE, m_refp, diff --git a/test_regress/t/t_const_opt_red.pl b/test_regress/t/t_const_opt_red.pl index 573f3e618..4cc2b40a0 100755 --- a/test_regress/t/t_const_opt_red.pl +++ b/test_regress/t/t_const_opt_red.pl @@ -19,7 +19,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 135); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 141); } ok(1); diff --git a/test_regress/t/t_const_opt_red.v b/test_regress/t/t_const_opt_red.v index ee5d9fd06..1f5e407d7 100644 --- a/test_regress/t/t_const_opt_red.v +++ b/test_regress/t/t_const_opt_red.v @@ -162,7 +162,7 @@ module t(/*AUTOARG*/ $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); if (crc !== 64'hc77bb9b3784ea091) $stop; // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'he9b854d521ebb8b6 +`define EXPECTED_SUM 64'h727fb78d09c1981e if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; @@ -190,7 +190,9 @@ module Test(/*AUTOARG*/ output logic z1, z2, z3, z4, z5, z6, z7; logic [127:0] d; + logic [17:0] e; always_ff @(posedge clk) d <= {i, ~i, ~i, i}; + always_ff @(posedge clk) e <= i[17:00]; always_ff @(posedge clk) begin a1 <= (i[5] & ~i[3] & i[1]); @@ -203,7 +205,7 @@ module Test(/*AUTOARG*/ a8 <= &(~i[5:3]); a9 <= ~i[5] & !i[4] & !i[3] && ~i[5] && !i[4]; a10 <= ~(i[5] & ~d[3]) & (!i[5] & d[1]); // cannot be optimized - a11 <= d[0] & d[33] & d[66] & d[99] & !d[31] & !d[62] & !d[93] & !d[124]; + a11 <= d[0] & d[33] & d[66] & d[99] & !d[31] & !d[62] & !d[93] & !d[124] & e[0] & !e[1] & e[2]; // o1 <= (~i[5] | i[3] | ~i[1]); o2 <= (i[5]!=1 | i[3]!=0 | i[1]!=1); @@ -215,7 +217,7 @@ module Test(/*AUTOARG*/ o8 <= |(~i[5:3]); o9 <= ~i[5] | !i[4] | ~i[3] || !i[5] || ~i[4]; o10 <= ~(~i[5] | d[3]) | (i[5] | ~d[1]); // cannot be optimized - o11 <= d[0] | d[33] | d[66] | d[99] | !d[31] | !d[62] | !d[93] | !d[124]; + o11 <= d[0] | d[33] | d[66] | d[99] | !d[31] | !d[62] | !d[93] | !d[124] | e[0] | !e[1] | e[2]; // x1 <= (i[5] ^ ~i[3] ^ i[1]); x2 <= (i[5]==1 ^ i[3]==0 ^ i[1]==1); @@ -225,7 +227,7 @@ module Test(/*AUTOARG*/ x6 <= i[5] ^ ~i[3] ^ i[1] ^ i[3] ^ !i[1] ^ i[3] ^ ~i[1]; x7 <= i[5] ^ (^((i & 32'b001010) ^ 32'b001000)); x8 <= ~(~i[5] ^ d[3]) ^ (i[5] ^ ~d[1]); - x9 <= d[0] ^ d[33] ^ d[66] ^ d[99] ^ !d[31] ^ !d[62] ^ !d[93] ^ !d[124]; + x9 <= d[0] ^ d[33] ^ d[66] ^ d[99] ^ !d[31] ^ !d[62] ^ !d[93] ^ !d[124] ^ e[0] ^ !e[1] ^ e[2]; // // All zero/all one cases z1 <= (i[5] & ~i[3] & ~i[5]); diff --git a/test_regress/t/t_func_crc.pl b/test_regress/t/t_func_crc.pl index 179c4c77d..6549284aa 100755 --- a/test_regress/t/t_func_crc.pl +++ b/test_regress/t/t_func_crc.pl @@ -19,7 +19,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 3870); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 3888); } ok(1); diff --git a/test_regress/t/t_gate_ormux.pl b/test_regress/t/t_gate_ormux.pl index b4bc92497..996e05170 100755 --- a/test_regress/t/t_gate_ormux.pl +++ b/test_regress/t/t_gate_ormux.pl @@ -19,7 +19,7 @@ compile( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 898); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 994); } execute( From 44fd205e12790e8c9eddfc9cdae0a63892d9d1c6 Mon Sep 17 00:00:00 2001 From: Philipp Wagner Date: Thu, 6 May 2021 17:07:15 +0100 Subject: [PATCH 13/80] Fix make support for gmake 3.x (#2920) (#2921) The "file" make function is only available in gmake 4.x, which isn't available on RHEL/CentOS 7. Use alternative syntax to support older gmake versions. Fixes #2920 --- include/verilated.mk.in | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/verilated.mk.in b/include/verilated.mk.in index e1c8f91ca..2edde9c11 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -202,16 +202,19 @@ else endif # When archiving just objects (.o), use single $(AR) run -# 1. Make .tmp file with list of objects so don't exceed commend line +# 1. Make .verilator_deplist.tmp file with list of objects so don't exceed +# the command line limits when calling $(AR). +# The approach to write the dependency file is compatible with GNU Make 3, +# and can be simplified using the file function once GNU Make 4.x becomes +# the minimum supported version. # When merging objects (.o) and archives (.a) additionally: # 1. Extract object files from .a # 2. Create a new archive from extracted .o and given .o -%.a: +%.a: | %.verilator_deplist.tmp $(info Archive $(AR) -rcs $@ $^) - $(file >$@.tmp) - $(foreach L, $(filter-out %.a,$^), $(file >>$@.tmp, $L)) + $(foreach L, $(filter-out %.a,$^), $(shell echo $L >>$@.verilator_deplist.tmp)) @if test $(words $(filter %.a,$^)) -eq 0; then \ - $(AR) -rcs $@ @$@.tmp; \ + $(AR) -rcs $@ @$@.verilator_deplist.tmp; \ else \ $(RM) -rf $@.tmpdir; \ for archive in $(filter %.a,$^); do \ @@ -220,9 +223,13 @@ endif $(AR) -x ../../$${archive}; \ cd ../..; \ done; \ - $(AR) -rcs $@ @$@.tmp $@.tmpdir/*/*.o; \ + $(AR) -rcs $@ @$@.verilator_deplist.tmp $@.tmpdir/*/*.o; \ fi \ - ; $(RM) -rf $@.tmp $@.tmpdir + ; $(RM) -rf $@.verilator_deplist.tmp $@.tmpdir + +# Truncate the dependency list file used in the %.a target above. +%.verilator_deplist.tmp: + echo "" > $@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS) From b2139f65d8cff468ca88b2a14df307cbd180d26b Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Fri, 7 May 2021 07:17:54 -0400 Subject: [PATCH 14/80] VPI memory access for packed arrays (#2922) --- src/V3AstNodes.h | 1 + src/V3EmitCSyms.cpp | 13 ++- test_regress/t/TestCheck.h | 9 ++ test_regress/t/t_vpi_get.cpp | 2 +- test_regress/t/t_vpi_memory.cpp | 165 +++++++++++++++++--------------- test_regress/t/t_vpi_memory.v | 29 ++++-- 6 files changed, 128 insertions(+), 91 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 0e621df7f..ba1e6dc9b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -935,6 +935,7 @@ public: const VNumRange& nrange() const { return m.m_nrange; } int hi() const { return (rangep() ? rangep()->hiConst() : m.m_nrange.hi()); } int lo() const { return (rangep() ? rangep()->loConst() : m.m_nrange.lo()); } + int elements() const { return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements()); } int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration int right() const { return littleEndian() ? hi() : lo(); } bool littleEndian() const { diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 43a521a17..a04288b68 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -762,6 +762,7 @@ void EmitCSyms::emitSymImp() { AstScope* scopep = it->second.m_scopep; AstVar* varp = it->second.m_varp; // + int pwidth = 1; int pdim = 0; int udim = 0; string bounds; @@ -773,6 +774,7 @@ void EmitCSyms::emitSymImp() { bounds += ","; bounds += cvtToStr(basicp->lo()); pdim++; + pwidth *= basicp->elements(); } for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) { dtypep @@ -784,6 +786,7 @@ void EmitCSyms::emitSymImp() { bounds += cvtToStr(adtypep->right()); if (VN_IS(dtypep, PackArrayDType)) { pdim++; + pwidth *= adtypep->elementsConst(); } else { udim++; } @@ -793,8 +796,14 @@ void EmitCSyms::emitSymImp() { } } } - // - if (udim > 1 && (pdim && udim)) { + // TODO: actually expose packed arrays as vpiRegArray + if (pdim > 1 && udim == 0) { + bounds = ", "; + bounds += cvtToStr(pwidth - 1); + bounds += ",0"; + pdim = 1; + } + if (pdim > 1 || udim > 1) { puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays } puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,"); diff --git a/test_regress/t/TestCheck.h b/test_regress/t/TestCheck.h index 947afaed9..17236efbf 100644 --- a/test_regress/t/TestCheck.h +++ b/test_regress/t/TestCheck.h @@ -54,6 +54,15 @@ static const bool verbose = false; } \ } while (0) +#define TEST_CHECK_Z(got) \ + do { \ + if ((got)) { \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << std::hex \ + << ": GOT!= NULL EXP=NULL" << std::endl; \ + ++errors; \ + } \ + } while (0) + #define TEST_CHECK_NZ(got) \ do { \ if (!(got)) { \ diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index fa97e5095..592246b3b 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -173,7 +173,7 @@ int mon_check_props() { {"sub.the_intf.bytesig", {8, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, {"sub.the_intf.param", {32, vpiNoDirection, 0, vpiParameter}, {0, 0, 0, 0}}, {"sub.the_intf.lparam", {32, vpiNoDirection, 0, vpiParameter}, {0, 0, 0, 0}}, - {"twobytwo", {2, vpiNoDirection, 0, vpiMemory}, {2, vpiNoDirection, 0, vpiMemoryWord}}, + {"twobytwo", {4, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, {NULL, {0, 0, 0, 0}, {0, 0, 0, 0}}}; struct params* value = values; while (value->signal) { diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index c420baebc..3dc17b55a 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -33,6 +33,7 @@ #include "TestSimulator.h" #include "TestVpi.h" +#include "TestCheck.h" // __FILE__ is too long #define FILENM "t_vpi_memory.cpp" @@ -41,116 +42,103 @@ if (0) printf unsigned int main_time = 0; +int errors = 0; //====================================================================== -#define CHECK_RESULT_VH(got, exp) \ - if ((got) != (exp)) { \ - printf("%%Error: %s:%d: GOT = %p EXP = %p\n", FILENM, __LINE__, (got), (exp)); \ - return __LINE__; \ - } - -#define CHECK_RESULT_NZ(got) \ - if (!(got)) { \ - printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \ - return __LINE__; \ - } - -// Use cout to avoid issues with %d/%lx etc -#define CHECK_RESULT(got, exp) \ - if ((got) != (exp)) { \ - std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ - << " EXP = " << (exp) << std::endl; \ - return __LINE__; \ - } - -#define CHECK_RESULT_HEX(got, exp) \ - if ((got) != (exp)) { \ - std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << std::hex \ - << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ - return __LINE__; \ - } - -#define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ - printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ - (got) ? (got) : "", (exp) ? (exp) : ""); \ - return __LINE__; \ - } - -#define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) - -int _mon_check_range(const TestVpiHandle& handle, int size, int left, int right) { +void _mon_check_range(const TestVpiHandle& handle, int size, int left, int right) { s_vpi_value value; value.format = vpiIntVal; value.value.integer = 0; // check size of object { int vpisize = vpi_get(vpiSize, handle); - CHECK_RESULT(vpisize, size); + TEST_CHECK_EQ(vpisize, size); } int coherency; { // check left hand side of range TestVpiHandle left_h = vpi_handle(vpiLeftRange, handle); - CHECK_RESULT_NZ(left_h); + TEST_CHECK_NZ(left_h); vpi_get_value(left_h, &value); - CHECK_RESULT(value.value.integer, left); + TEST_CHECK_EQ(value.value.integer, left); coherency = value.value.integer; } { // check right hand side of range TestVpiHandle right_h = vpi_handle(vpiRightRange, handle); - CHECK_RESULT_NZ(right_h); + TEST_CHECK_NZ(right_h); vpi_get_value(right_h, &value); - CHECK_RESULT(value.value.integer, right); + TEST_CHECK_EQ(value.value.integer, right); coherency -= value.value.integer; } // calculate size & check coherency = abs(coherency) + 1; - CHECK_RESULT(coherency, size); - return 0; // Ok + TEST_CHECK_EQ(coherency, size); } -int _mon_check_memory() { +void _mem_check(const char* name, int size, int left, int right, int words) { s_vpi_value value; - value.format = vpiIntVal; - value.value.integer = 0; s_vpi_error_info e; - vpi_printf((PLI_BYTE8*)"Check memory vpi ...\n"); - TestVpiHandle mem_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted("mem0"), NULL); - CHECK_RESULT_NZ(mem_h); - { - // check type - int vpitype = vpi_get(vpiType, mem_h); - CHECK_RESULT(vpitype, vpiMemory); + vpi_printf((PLI_BYTE8*)"Check memory vpi (%s) ...\n", name); + TestVpiHandle mem_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted(name), NULL); + TEST_CHECK_NZ(mem_h); + // check type + int vpitype = vpi_get(vpiType, mem_h); + if (vpitype != vpiMemory && vpitype != vpiReg) { + printf("%%Error: %s:%d vpiType neither vpiMemory or vpiReg: %d\n", FILENM, __LINE__, + vpitype); + errors++; + } + std::string binStr; + for (int i = words; i >= 1; i--) { + for (int pos = size - 1; pos >= 0; pos--) { + int posValue = (i >> pos) & 0x1; + binStr += posValue ? "1" : "0"; + } } - if (int status = _mon_check_range(mem_h, 16, 16, 1)) return status; // iterate and store - { + if (vpitype == vpiMemory) { + _mon_check_range(mem_h, words, words, 1); TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); int cnt = 0; while (TestVpiHandle lcl_h = vpi_scan(iter_h)) { + value.format = vpiIntVal; value.value.integer = ++cnt; vpi_put_value(lcl_h, &value, NULL, vpiNoDelay); + TEST_CHECK_Z(vpi_chk_error(&e)); // check size and range - if (int status = _mon_check_range(lcl_h, 32, 31, 0)) return status; + _mon_check_range(lcl_h, size, left, right); } iter_h.freed(); // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle - CHECK_RESULT(cnt, 16); // should be 16 addresses + TEST_CHECK_EQ(cnt, words); // should be words addresses + } else { + int expSize = size * words; + _mon_check_range(mem_h, expSize, expSize - 1, 0); + value.format = vpiBinStrVal; + value.value.str = const_cast(binStr.c_str()); + vpi_put_value(mem_h, &value, NULL, vpiNoDelay); + TEST_CHECK_Z(vpi_chk_error(&e)); } - { + if (vpitype == vpiMemory) { // iterate and accumulate TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); int cnt = 0; while (TestVpiHandle lcl_h = vpi_scan(iter_h)) { ++cnt; + value.format = vpiIntVal; vpi_get_value(lcl_h, &value); - CHECK_RESULT(value.value.integer, cnt); + TEST_CHECK_Z(vpi_chk_error(&e)); + TEST_CHECK_EQ(value.value.integer, cnt); } iter_h.freed(); // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle - CHECK_RESULT(cnt, 16); // should be 16 addresses + TEST_CHECK_EQ(cnt, words); // should be words addresses + } else { + value.format = vpiBinStrVal; + vpi_get_value(mem_h, &value); + TEST_CHECK_Z(vpi_chk_error(&e)); + TEST_CHECK_EQ(std::string(value.value.str), binStr); } // don't care for non verilator @@ -158,58 +146,77 @@ int _mon_check_memory() { if (TestSimulator::is_icarus()) { vpi_printf((PLI_BYTE8*)"Skipping property checks for simulator %s\n", TestSimulator::get_info().product); - return 0; // Ok + return; // Ok } { // make sure trying to get properties that don't exist // doesn't crash TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); int should_be_0 = vpi_get(vpiSize, iter_h); - CHECK_RESULT(should_be_0, 0); + TEST_CHECK_EQ(should_be_0, 0); should_be_0 = vpi_get(vpiIndex, iter_h); - CHECK_RESULT(should_be_0, 0); + TEST_CHECK_EQ(should_be_0, 0); vpiHandle should_be_NULL = vpi_handle(vpiLeftRange, iter_h); - CHECK_RESULT(should_be_NULL, 0); + TEST_CHECK_EQ(should_be_NULL, 0); should_be_NULL = vpi_handle(vpiRightRange, iter_h); - CHECK_RESULT(should_be_NULL, 0); + TEST_CHECK_EQ(should_be_NULL, 0); should_be_NULL = vpi_handle(vpiScope, iter_h); - CHECK_RESULT(should_be_NULL, 0); + TEST_CHECK_EQ(should_be_NULL, 0); } - { + if (vpitype == vpiMemory) { // check vpiRange TestVpiHandle iter_h = vpi_iterate(vpiRange, mem_h); - CHECK_RESULT_NZ(iter_h); + TEST_CHECK_NZ(iter_h); TestVpiHandle lcl_h = vpi_scan(iter_h); - CHECK_RESULT_NZ(lcl_h); + TEST_CHECK_NZ(lcl_h); { TestVpiHandle side_h = vpi_handle(vpiLeftRange, lcl_h); - CHECK_RESULT_NZ(side_h); + TEST_CHECK_NZ(side_h); vpi_get_value(side_h, &value); - CHECK_RESULT(value.value.integer, 16); + TEST_CHECK_EQ(value.value.integer, 16); } { TestVpiHandle side_h = vpi_handle(vpiRightRange, lcl_h); - CHECK_RESULT_NZ(side_h); + TEST_CHECK_NZ(side_h); vpi_get_value(side_h, &value); - CHECK_RESULT(value.value.integer, 1); + TEST_CHECK_EQ(value.value.integer, 1); // check writing to vpiConstant vpi_put_value(side_h, &value, NULL, vpiNoDelay); - CHECK_RESULT_NZ(vpi_chk_error(&e)); + TEST_CHECK_NZ(vpi_chk_error(&e)); } { // iterator should exhaust after 1 dimension TestVpiHandle zero_h = vpi_scan(iter_h); iter_h.freed(); // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle - CHECK_RESULT(zero_h, 0); + TEST_CHECK_EQ(zero_h, 0); } } - return 0; // Ok +} + +struct params { + const char* name; + int size; + int left; + int right; + int words; +}; + +void _mon_check_memory() { + // See note in t_vpi_get.cpp about static + static struct params values[] + = {{"mem0", 32, 31, 0, 16}, {"memp32", 32, 31, 0, 16}, {"memp31", 31, 30, 0, 16}, + {"memp33", 33, 32, 0, 15}, {"memw", 32, 31, 0, 16}, {NULL, 0, 0, 0, 0}}; + struct params* value = values; + while (value->name) { + _mem_check(value->name, value->size, value->left, value->right, value->words); + value++; + } } int mon_check() { // Callback from initial block in monitor - if (int status = _mon_check_memory()) return status; - return 0; // Ok + _mon_check_memory(); + return errors; } //====================================================================== diff --git a/test_regress/t/t_vpi_memory.v b/test_regress/t/t_vpi_memory.v index c16a59cb5..ee99b1319 100644 --- a/test_regress/t/t_vpi_memory.v +++ b/test_regress/t/t_vpi_memory.v @@ -25,31 +25,42 @@ extern "C" int mon_check(); input clk; + typedef logic [31:0] word_t; reg [31:0] mem0 [16:1] /*verilator public_flat_rw @(posedge clk) */; + reg [16:1] [31:0] memp32 /*verilator public_flat_rw @(posedge clk) */; + reg [16:1] [30:0] memp31 /*verilator public_flat_rw @(posedge clk) */; + reg [15:1] [32:0] memp33 /*verilator public_flat_rw @(posedge clk) */; + word_t [16:1] memw /*verilator public_flat_rw @(posedge clk) */; integer i, status; +`define CHECK_MEM(mem, words) \ + for (i = words; i > 0; i--) \ + if (integer'(mem[i]) !== i) begin \ + $write("%%Error: %s[%d] : GOT = %d EXP = %d\n", `"mem`", i, mem[i], i); \ + status = -1; \ + end + // Test loop initial begin `ifdef VERILATOR status = $c32("mon_check()"); -`endif -`ifdef IVERILOG +`else status = $mon_check(); `endif `ifndef USE_VPI_NOT_DPI status = mon_check(); `endif if (status!=0) begin - $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $write("%%Error: t_vpi_memory.cpp: C Test failed (rc=%0d)\n", status); $stop; end - for (i = 16; i > 0; i--) - if (mem0[i] !== i) begin - $write("%%Error: %d : GOT = %d EXP = %d\n", i, mem0[i], i); - status = 1; - end + `CHECK_MEM(mem0, 16) + `CHECK_MEM(memp32, 16) + `CHECK_MEM(memp31, 16) + `CHECK_MEM(memp33, 15) + `CHECK_MEM(memw, 16) if (status!=0) begin - $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $write("%%Error: Verilog memory checks failed\n"); $stop; end $write("*-* All Finished *-*\n"); From 1e4839e5d1865ce9e92c2936b3d2110d7ec0267a Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sat, 8 May 2021 01:00:36 +0900 Subject: [PATCH 15/80] Fix casting to integer not to cause integer overflow. (#2930) --- include/verilated.cpp | 13 ++++++------- test_regress/t/t_time_vpi_100s10ms.out | 6 +++--- test_regress/t/t_time_vpi_10ms10ns.out | 2 +- test_regress/t/t_time_vpi_1ms10ns.out | 2 +- test_regress/t/t_time_vpi_1ns1ns.out | 2 +- test_regress/t/t_time_vpi_1ps1fs.out | 2 +- test_regress/t/t_time_vpi_1s10ns.out | 2 +- test_regress/t/t_time_vpi_1us1ns.out | 4 ++-- 8 files changed, 16 insertions(+), 17 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 14949b740..a1c070cad 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -646,17 +646,16 @@ std::string _vl_vsformat_time(char* tmp, double ld, bool left, size_t width) { int shift = prec - userUnits + fracDigits; // 0..-15 double shiftd = vl_time_multiplier(shift); double scaled = ld * shiftd; - QData fracDiv = static_cast(vl_time_multiplier(fracDigits)); - QData whole = static_cast(scaled) / fracDiv; - QData fraction = static_cast(scaled) % fracDiv; + const double fracDiv = vl_time_multiplier(fracDigits); + const double whole = scaled / fracDiv; int digits = 0; if (!fracDigits) { - digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%" VL_PRI64 "u%s", whole, - suffix.c_str()); + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.0f%s", whole, suffix.c_str()); } else { - digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%" VL_PRI64 "u.%0*" VL_PRI64 "u%s", - whole, fracDigits, fraction, suffix.c_str()); + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.*f%s", fracDigits, whole, + suffix.c_str()); } + int needmore = width - digits; std::string padding; if (needmore > 0) padding.append(needmore, ' '); // Pad with spaces diff --git a/test_regress/t/t_time_vpi_100s10ms.out b/test_regress/t/t_time_vpi_100s10ms.out index 73db352ca..7cb4c886d 100644 --- a/test_regress/t/t_time_vpi_100s10ms.out +++ b/test_regress/t/t_time_vpi_100s10ms.out @@ -3,11 +3,11 @@ Time scale of t is 100s / 10ms [100000000] time%0d=10000 123%0t=1230000 dig%0t=0 dig%0d=0 rdig%0t=543 rdig%0f=0.054321 -[0.000000ns] time%0d=10000 123%0t=12300000000000.000000ns +[1000000000000000.000000ns] time%0d=10000 123%0t=12300000000000.000000ns dig%0t=0.000000ns dig%0d=0 rdig%0t=5432109876.543210ns rdig%0f=0.054321 -[0.000000ns] stime%0t=0.000000ns stime%0d=10000 stime%0f=10000.000000 -[0.000000ns] rtime%0t=0.000000ns rtime%0d=10000 rtime%0f=10000.000000 +[1000000000000000.000000ns] stime%0t=1000000000000000.000000ns stime%0d=10000 stime%0f=10000.000000 +[1000000000000000.000000ns] rtime%0t=1000000000000000.000000ns rtime%0d=10000 rtime%0f=10000.000000 global vpiSimTime = 0,100000000 vpiScaledRealTime = 1e+08 global vpiTimeUnit = -2 vpiTimePrecision = -2 top.t vpiSimTime = 0,100000000 vpiScaledRealTime = 10000 diff --git a/test_regress/t/t_time_vpi_10ms10ns.out b/test_regress/t/t_time_vpi_10ms10ns.out index a561b40c3..faa888180 100644 --- a/test_regress/t/t_time_vpi_10ms10ns.out +++ b/test_regress/t/t_time_vpi_10ms10ns.out @@ -2,7 +2,7 @@ Time scale of t is 10ms / 10ns [60000000] time%0d=60 123%0t=123000000 dig%0t=543000000 dig%0d=543 - rdig%0t=543210987 rdig%0f=543.210988 + rdig%0t=543210988 rdig%0f=543.210988 [600000000.000000ns] time%0d=60 123%0t=1230000000.000000ns dig%0t=5430000000.000000ns dig%0d=543 rdig%0t=5432109876.543210ns rdig%0f=543.210988 diff --git a/test_regress/t/t_time_vpi_1ms10ns.out b/test_regress/t/t_time_vpi_1ms10ns.out index 90ce5a0ed..5c279c04b 100644 --- a/test_regress/t/t_time_vpi_1ms10ns.out +++ b/test_regress/t/t_time_vpi_1ms10ns.out @@ -2,7 +2,7 @@ Time scale of t is 1ms / 10ns [6000000] time%0d=60 123%0t=12300000 dig%0t=543200000 dig%0d=5432 - rdig%0t=543210987 rdig%0f=5432.109877 + rdig%0t=543210988 rdig%0f=5432.109877 [60000000.000000ns] time%0d=60 123%0t=123000000.000000ns dig%0t=5432000000.000000ns dig%0d=5432 rdig%0t=5432109876.543210ns rdig%0f=5432.109877 diff --git a/test_regress/t/t_time_vpi_1ns1ns.out b/test_regress/t/t_time_vpi_1ns1ns.out index b6dad7274..83c8cd9f6 100644 --- a/test_regress/t/t_time_vpi_1ns1ns.out +++ b/test_regress/t/t_time_vpi_1ns1ns.out @@ -2,7 +2,7 @@ Time scale of t is 1ns / 1ns [60] time%0d=60 123%0t=123 dig%0t=5432109877 dig%0d=5432109877 - rdig%0t=5432109876 rdig%0f=5432109876.543210 + rdig%0t=5432109877 rdig%0f=5432109876.543210 [60.000000ns] time%0d=60 123%0t=123.000000ns dig%0t=5432109877.000000ns dig%0d=5432109877 rdig%0t=5432109876.543210ns rdig%0f=5432109876.543210 diff --git a/test_regress/t/t_time_vpi_1ps1fs.out b/test_regress/t/t_time_vpi_1ps1fs.out index c4935bc16..bd62df6af 100644 --- a/test_regress/t/t_time_vpi_1ps1fs.out +++ b/test_regress/t/t_time_vpi_1ps1fs.out @@ -7,7 +7,7 @@ Time scale of t is 1ps / 1fs dig%0t=5432109876.543000ns dig%0d=5432109876543 rdig%0t=5432109876.543209ns rdig%0f=5432109876543.209961 [0.060000ns] stime%0t=0.060000ns stime%0d=60 stime%0f=60.000000 -[0.060000ns] rtime%0t=0.059999ns rtime%0d=60 rtime%0f=60.000000 +[0.060000ns] rtime%0t=0.060000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 global vpiTimeUnit = -12 vpiTimePrecision = -15 top.t vpiSimTime = 0,60000 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1s10ns.out b/test_regress/t/t_time_vpi_1s10ns.out index ba22c32bb..15d1750a9 100644 --- a/test_regress/t/t_time_vpi_1s10ns.out +++ b/test_regress/t/t_time_vpi_1s10ns.out @@ -2,7 +2,7 @@ Time scale of t is 1s / 10ns [6000000000] time%0d=60 123%0t=12300000000 dig%0t=500000000 dig%0d=5 - rdig%0t=543210987 rdig%0f=5.432110 + rdig%0t=543210988 rdig%0f=5.432110 [60000000000.000000ns] time%0d=60 123%0t=123000000000.000000ns dig%0t=5000000000.000000ns dig%0d=5 rdig%0t=5432109876.543210ns rdig%0f=5.432110 diff --git a/test_regress/t/t_time_vpi_1us1ns.out b/test_regress/t/t_time_vpi_1us1ns.out index 182c19aa7..e6b5dd50b 100644 --- a/test_regress/t/t_time_vpi_1us1ns.out +++ b/test_regress/t/t_time_vpi_1us1ns.out @@ -2,12 +2,12 @@ Time scale of t is 1us / 1ns [60000] time%0d=60 123%0t=123000 dig%0t=5432110000 dig%0d=5432110 - rdig%0t=5432109876 rdig%0f=5432109.876543 + rdig%0t=5432109877 rdig%0f=5432109.876543 [60000.000000ns] time%0d=60 123%0t=123000.000000ns dig%0t=5432110000.000000ns dig%0d=5432110 rdig%0t=5432109876.543209ns rdig%0f=5432109.876543 [60000.000000ns] stime%0t=60000.000000ns stime%0d=60 stime%0f=60.000000 -[60000.000000ns] rtime%0t=59999.999999ns rtime%0d=60 rtime%0f=60.000000 +[60000.000000ns] rtime%0t=60000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 global vpiTimeUnit = -6 vpiTimePrecision = -9 top.t vpiSimTime = 0,60000 vpiScaledRealTime = 60 From 9797af0ad4ee1cfecbd6aa339fc43f30472aaa19 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sat, 8 May 2021 07:16:40 +0900 Subject: [PATCH 16/80] Introduce a macro VL_ATTR_NO_SANITIZE_ALIGN to suppress unaligned access check in ubsan (#2929) * Add VL_ATTR_NO_SANITIZE_ALIGN macro to disable alignment check of ubsan * Mark a function VL_ATTR_NO_SANITIZE_ALIGN because the function is intentionally using unaligned access for the sake of performance. Co-authored-by: Wilson Snyder --- include/verilated_vcd_c.cpp | 12 ++++++++++-- include/verilatedos.h | 9 +++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index e11ed947d..bfc185c34 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -586,8 +586,10 @@ void VerilatedVcd::declTriArray(vluint32_t code, const char* name, bool array, i //============================================================================= // Trace rendering prinitives -void VerilatedVcd::finishLine(vluint32_t code, char* writep) { - const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE; +static inline void +VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) VL_ATTR_NO_SANITIZE_ALIGN; + +static inline void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) { // Copy the whole suffix (this avoid having hard to predict branches which // helps a lot). Note: The maximum length of the suffix is // VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed. @@ -605,6 +607,12 @@ void VerilatedVcd::finishLine(vluint32_t code, char* writep) { writep[5] = suffixp[5]; writep[6] = '\n'; // The 6th index is always '\n' if it's relevant, no need to fetch it. #endif +} + +void VerilatedVcd::finishLine(vluint32_t code, char* writep) { + const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE; + VerilatedVcdCCopyAndAppendNewLine(writep, suffixp); + // Now write back the write pointer incremented by the actual size of the // suffix, which was stored in the last byte of the suffix buffer entry. m_writep = writep + suffixp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1]; diff --git a/include/verilatedos.h b/include/verilatedos.h index 21cc1447f..4b1b0874d 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -43,6 +43,12 @@ # define VL_ATTR_COLD __attribute__((cold)) # define VL_ATTR_HOT __attribute__((hot)) # define VL_ATTR_NORETURN __attribute__((noreturn)) +// clang and gcc-8.0+ support no_sanitize("string") style attribute +# if defined(__clang__) || (__GNUC__ >= 8) +# define VL_ATTR_NO_SANITIZE_ALIGN __attribute__((no_sanitize("alignment"))) +#else // The entire undefined sanitizer has to be disabled for older gcc +# define VL_ATTR_NO_SANITIZE_ALIGN __attribute__((no_sanitize_undefined)) +#endif # define VL_ATTR_PRINTF(fmtArgNum) __attribute__((format(printf, (fmtArgNum), (fmtArgNum) + 1))) # define VL_ATTR_PURE __attribute__((pure)) # define VL_ATTR_UNUSED __attribute__((unused)) @@ -85,6 +91,9 @@ #ifndef VL_ATTR_NORETURN # define VL_ATTR_NORETURN ///< Attribute that function does not ever return #endif +#ifndef VL_ATTR_NO_SANITIZE_ALIGN +# define VL_ATTR_NO_SANITIZE_ALIGN ///< Attribute that the function contains intended unaligned access +#endif #ifndef VL_ATTR_PRINTF # define VL_ATTR_PRINTF(fmtArgNum) ///< Attribute for function with printf format checking #endif From 39ce2f77f4cc64042ca67fc2b4869616000027da Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sat, 8 May 2021 09:45:58 +0900 Subject: [PATCH 17/80] Internals: Remove VerilatedVcd::m_suffixesp. No functional change is intended. (#2933) Reasons are: - it's error prone to keep updating whennever m_suffixes is resized - invalid pointer may be set when there is not signal to trace as in t_trace_dumporder_bad --- include/verilated_vcd_c.cpp | 6 +----- include/verilated_vcd_c.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index bfc185c34..ccbccde8e 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -99,7 +99,6 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) { m_wrBufp = new char[m_wrChunkSize * 8]; m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; m_writep = m_wrBufp; - m_suffixesp = nullptr; } void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) { @@ -114,9 +113,6 @@ void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) { dumpHeader(); - // Get the direct access pointer to the code strings - m_suffixesp = &m_suffixes[0]; // Note: C++11 m_suffixes.data(); - // When using rollover, the first chunk contains the header only. if (m_rolloverMB) openNextImp(true); } @@ -610,7 +606,7 @@ static inline void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* s } void VerilatedVcd::finishLine(vluint32_t code, char* writep) { - const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE; + const char* const suffixp = m_suffixes.data() + code * VL_TRACE_SUFFIX_ENTRY_SIZE; VerilatedVcdCCopyAndAppendNewLine(writep, suffixp); // Now write back the write pointer incremented by the actual size of the diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index f9d07a731..f6fdd1494 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -80,7 +80,6 @@ private: vluint64_t m_wroteBytes = 0; // Number of bytes written to this file std::vector m_suffixes; // VCD line end string codes + metadata - const char* m_suffixesp; // Pointer to first element of above using NameMap = std::map; NameMap* m_namemapp = nullptr; // List of names for the header From 2bf248bf609e1bf4cf1f4fd44e20e891504305ee Mon Sep 17 00:00:00 2001 From: Jonathan Drolet Date: Sat, 8 May 2021 08:18:08 -0400 Subject: [PATCH 18/80] Add TRACE_THREADS to CMake (#2934) --- docs/CONTRIBUTORS | 1 + docs/guide/verilating.rst | 12 +- src/V3EmitCMake.cpp | 2 + test_regress/CMakeLists.txt | 6 +- test_regress/t/t_trace_fst_cmake.out | 1028 ++++++++++++++++++++++++++ test_regress/t/t_trace_fst_cmake.pl | 27 + test_regress/t/t_trace_fst_cmake.v | 99 +++ verilator-config.cmake.in | 18 +- 8 files changed, 1190 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_trace_fst_cmake.out create mode 100755 test_regress/t/t_trace_fst_cmake.pl create mode 100644 test_regress/t/t_trace_fst_cmake.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index f8c20a846..2196c9c2e 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -38,6 +38,7 @@ Jean Berniolles Jeremy Bennett John Coiner John Demme +Jonathan Drolet Josh Redford Julien Margetts Kaleb Barrett diff --git a/docs/guide/verilating.rst b/docs/guide/verilating.rst index 53810b67e..d1231a314 100644 --- a/docs/guide/verilating.rst +++ b/docs/guide/verilating.rst @@ -360,7 +360,8 @@ Verilate in CMake verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name] [TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE] [INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...] - [OPT_GLOBAL ..] [DIRECTORY dir] [VERILATOR_ARGS ...]) + [OPT_GLOBAL ..] [DIRECTORY dir] [THREADS num] + [TRACE_THREADS num] [VERILATOR_ARGS ...]) Lowercase and ... should be replaced with arguments, the uppercase parts delimit the arguments and can be passed in any order, or left out entirely @@ -429,6 +430,15 @@ SystemC include directories and link to the SystemC libraries. the SystemC library. This can be specified using the SYSTEMC_CXX_FLAGS environment variable. +.. describe:: THREADS + + Optional. Generated a multi-threaded model, same as "--threads". + +.. describe:: TRACE_THREADS + + Optional. Generated multi-threaded trace dumping, same as + "--trace-threads". + .. describe:: TOP_MODULE Optional. Sets the name of the top module. Defaults to the name of the diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index e9097abde..288a576ec 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -113,6 +113,8 @@ class CMakeEmitter final { cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage() ? "1" : "0"); *of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); + *of << "# Threaded tracing output mode? 0/1/N threads (from --trace-threads)\n"; + cmake_set_raw(*of, name + "_TRACE_THREADS", cvtToStr(v3Global.opt.traceThreads())); *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; cmake_set_raw(*of, name + "_TRACE_VCD", (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD)) diff --git a/test_regress/CMakeLists.txt b/test_regress/CMakeLists.txt index 28a045961..413578a64 100644 --- a/test_regress/CMakeLists.txt +++ b/test_regress/CMakeLists.txt @@ -52,9 +52,10 @@ string(REGEX REPLACE "(^|;)--" "\\1-" getarg(TEST_VERILATOR_ARGS_NORM "-prefix" TEST_PREFIX) getarg(TEST_VERILATOR_ARGS_NORM "-threads" TEST_THREADS) +getarg(TEST_VERILATOR_ARGS_NORM "-trace-threads" TEST_TRACE_THREADS) # Strip unwanted args with 1 parameter -string(REGEX REPLACE "(^|;)--?(Mdir|make|prefix|threads);[^;]*" "" +string(REGEX REPLACE "(^|;)--?(Mdir|make|prefix|threads|trace-threads);[^;]*" "" TEST_VERILATOR_ARGS "${TEST_VERILATOR_ARGS}") # Strip unwanted args @@ -81,6 +82,9 @@ endif() if(TEST_THREADS) list(APPEND verilate_ARGS THREADS ${TEST_THREADS}) endif() +if(TEST_TRACE_THREADS) + list(APPEND verilate_ARGS TRACE_THREADS ${TEST_TRACE_THREADS}) +endif() if(TEST_SYSTEMC) list(APPEND verilate_ARGS SYSTEMC) endif() diff --git a/test_regress/t/t_trace_fst_cmake.out b/test_regress/t/t_trace_fst_cmake.out new file mode 100644 index 000000000..dde4f07e0 --- /dev/null +++ b/test_regress/t/t_trace_fst_cmake.out @@ -0,0 +1,1028 @@ +$date + Sun Apr 19 04:15:36 2020 + +$end +$version + fstWriter +$end +$timescale + 1ps +$end +$scope module top $end +$var wire 1 ! clk $end +$var wire 5 " state $end +$scope module t $end +$var wire 1 ! clk $end +$var int 32 # cyc $end +$var logic 1 $ rstn $end +$var wire 5 " state $end +$var real_parameter 64 % fst_gparam_real $end +$var real_parameter 64 & fst_lparam_real $end +$var real 64 % fst_real $end +$var integer 32 ' fst_integer $end +$var bit 1 ( fst_bit $end +$var logic 1 ) fst_logic $end +$var int 32 * fst_int $end +$var shortint 16 + fst_shortint $end +$var longint 64 , fst_longint $end +$var byte 8 - fst_byte $end +$var parameter 32 . fst_parameter $end +$var parameter 32 / fst_lparam $end +$var supply0 1 0 fst_supply0 $end +$var supply1 1 1 fst_supply1 $end +$var tri0 1 2 fst_tri0 $end +$var tri1 1 3 fst_tri1 $end +$var tri 1 4 fst_tri $end +$var wire 1 5 fst_wire $end +$scope module test $end +$var wire 1 ! clk $end +$var wire 1 $ rstn $end +$var wire 5 " state $end +$var logic 5 6 state_w $end +$var logic 5 7 state_array(0) $end +$var logic 5 8 state_array(1) $end +$var logic 5 9 state_array(2) $end +$scope module unnamedblk2 $end +$var int 32 : i $end +$upscope $end +$scope module unnamedblk1 $end +$var int 32 ; i $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +b00000 " +b00000000000000000000000000000000 # +0$ +r1.23 % +r4.56 & +b00000000000000000000000000000000 ' +0( +0) +b00000000000000000000000000000000 * +b0000000000000000 + +b0000000000000000000000000000000000000000000000000000000000000000 , +b00000000 - +b00000000000000000000000001111011 . +b00000000000000000000000111001000 / +00 +11 +02 +13 +04 +05 +b00000 6 +b00000 7 +b00000 8 +b00000 9 +b00000000000000000000000000000000 : +b00000000000000000000000000000000 ; +#10 +b00000000000000000000000000000011 ; +b00001 9 +b00001 8 +b00001 7 +b10100 6 +b00000000000000000000000000000001 # +b00001 " +1! +#15 +0! +#20 +1! +b00000000000000000000000000000010 # +#25 +0! +#30 +1! +b00000000000000000000000000000011 # +#35 +0! +#40 +1! +b00000000000000000000000000000100 # +#45 +0! +#50 +1! +b00000000000000000000000000000101 # +#55 +0! +#60 +1! +b00000000000000000000000000000110 # +#65 +0! +#70 +1! +b00000000000000000000000000000111 # +#75 +0! +#80 +1! +b00000000000000000000000000001000 # +#85 +0! +#90 +1! +b00000000000000000000000000001001 # +#95 +0! +#100 +1! +b00000000000000000000000000001010 # +#105 +0! +#110 +1! +b00000000000000000000000000001011 # +1$ +#115 +0! +#120 +1! +b00000000000000000000000000001100 # +b01010 6 +b10100 9 +b00000000000000000000000000000010 : +#125 +0! +#130 +1! +b01010 9 +b00101 6 +b00000000000000000000000000001101 # +b10100 8 +#135 +0! +#140 +1! +b01010 8 +b00000000000000000000000000001110 # +b10110 6 +b00101 9 +b10100 " +b10100 7 +#145 +0! +#150 +1! +b01010 7 +b01010 " +b10110 9 +b01011 6 +b00000000000000000000000000001111 # +b00101 8 +#155 +0! +#160 +1! +b10110 8 +b00000000000000000000000000010000 # +b10001 6 +b01011 9 +b00101 " +b00101 7 +#165 +0! +#170 +1! +b10110 7 +b10110 " +b10001 9 +b11100 6 +b00000000000000000000000000010001 # +b01011 8 +#175 +0! +#180 +1! +b10001 8 +b00000000000000000000000000010010 # +b01110 6 +b11100 9 +b01011 " +b01011 7 +#185 +0! +#190 +1! +b10001 7 +b10001 " +b01110 9 +b00111 6 +b00000000000000000000000000010011 # +b11100 8 +#195 +0! +#200 +1! +b01110 8 +b00000000000000000000000000010100 # +b10111 6 +b00111 9 +b11100 " +b11100 7 +#205 +0! +#210 +1! +b01110 7 +b01110 " +b10111 9 +b11111 6 +b00000000000000000000000000010101 # +b00111 8 +#215 +0! +#220 +1! +b10111 8 +b00000000000000000000000000010110 # +b11011 6 +b11111 9 +b00111 " +b00111 7 +#225 +0! +#230 +1! +b10111 7 +b10111 " +b11011 9 +b11001 6 +b00000000000000000000000000010111 # +b11111 8 +#235 +0! +#240 +1! +b11011 8 +b00000000000000000000000000011000 # +b11000 6 +b11001 9 +b11111 " +b11111 7 +#245 +0! +#250 +1! +b11011 7 +b11011 " +b11000 9 +b01100 6 +b00000000000000000000000000011001 # +b11001 8 +#255 +0! +#260 +1! +b11000 8 +b00000000000000000000000000011010 # +b00110 6 +b01100 9 +b11001 " +b11001 7 +#265 +0! +#270 +1! +b11000 7 +b11000 " +b00110 9 +b00011 6 +b00000000000000000000000000011011 # +b01100 8 +#275 +0! +#280 +1! +b00110 8 +b00000000000000000000000000011100 # +b10101 6 +b00011 9 +b01100 " +b01100 7 +#285 +0! +#290 +1! +b00110 7 +b00110 " +b10101 9 +b11110 6 +b00000000000000000000000000011101 # +b00011 8 +#295 +0! +#300 +1! +b10101 8 +b00000000000000000000000000011110 # +b01111 6 +b11110 9 +b00011 " +b00011 7 +#305 +0! +#310 +1! +b10101 7 +b10101 " +b01111 9 +b10011 6 +b00000000000000000000000000011111 # +b11110 8 +#315 +0! +#320 +1! +b01111 8 +b00000000000000000000000000100000 # +b11101 6 +b10011 9 +b11110 " +b11110 7 +#325 +0! +#330 +1! +b01111 7 +b01111 " +b11101 9 +b11010 6 +b00000000000000000000000000100001 # +b10011 8 +#335 +0! +#340 +1! +b11101 8 +b00000000000000000000000000100010 # +b01101 6 +b11010 9 +b10011 " +b10011 7 +#345 +0! +#350 +1! +b11101 7 +b11101 " +b01101 9 +b10010 6 +b00000000000000000000000000100011 # +b11010 8 +#355 +0! +#360 +1! +b01101 8 +b00000000000000000000000000100100 # +b01001 6 +b10010 9 +b11010 " +b11010 7 +#365 +0! +#370 +1! +b01101 7 +b01101 " +b01001 9 +b10000 6 +b00000000000000000000000000100101 # +b10010 8 +#375 +0! +#380 +1! +b01001 8 +b00000000000000000000000000100110 # +b01000 6 +b10000 9 +b10010 " +b10010 7 +#385 +0! +#390 +1! +b01001 7 +b01001 " +b01000 9 +b00100 6 +b00000000000000000000000000100111 # +b10000 8 +#395 +0! +#400 +1! +b01000 8 +b00000000000000000000000000101000 # +b00010 6 +b00100 9 +b10000 " +b10000 7 +#405 +0! +#410 +1! +b01000 7 +b01000 " +b00010 9 +b00001 6 +b00000000000000000000000000101001 # +b00100 8 +#415 +0! +#420 +1! +b00010 8 +b00000000000000000000000000101010 # +b10100 6 +b00001 9 +b00100 " +b00100 7 +#425 +0! +#430 +1! +b00010 7 +b00010 " +b10100 9 +b01010 6 +b00000000000000000000000000101011 # +b00001 8 +#435 +0! +#440 +1! +b10100 8 +b00000000000000000000000000101100 # +b00101 6 +b01010 9 +b00001 " +b00001 7 +#445 +0! +#450 +1! +b10100 7 +b10100 " +b00101 9 +b10110 6 +b00000000000000000000000000101101 # +b01010 8 +#455 +0! +#460 +1! +b00101 8 +b00000000000000000000000000101110 # +b01011 6 +b10110 9 +b01010 " +b01010 7 +#465 +0! +#470 +1! +b00101 7 +b00101 " +b01011 9 +b10001 6 +b00000000000000000000000000101111 # +b10110 8 +#475 +0! +#480 +1! +b01011 8 +b00000000000000000000000000110000 # +b11100 6 +b10001 9 +b10110 " +b10110 7 +#485 +0! +#490 +1! +b01011 7 +b01011 " +b11100 9 +b01110 6 +b00000000000000000000000000110001 # +b10001 8 +#495 +0! +#500 +1! +b11100 8 +b00000000000000000000000000110010 # +b00111 6 +b01110 9 +b10001 " +b10001 7 +#505 +0! +#510 +1! +b11100 7 +b11100 " +b00111 9 +b10111 6 +b00000000000000000000000000110011 # +b01110 8 +#515 +0! +#520 +1! +b00111 8 +b00000000000000000000000000110100 # +b11111 6 +b10111 9 +b01110 " +b01110 7 +#525 +0! +#530 +1! +b00111 7 +b00111 " +b11111 9 +b11011 6 +b00000000000000000000000000110101 # +b10111 8 +#535 +0! +#540 +1! +b11111 8 +b00000000000000000000000000110110 # +b11001 6 +b11011 9 +b10111 " +b10111 7 +#545 +0! +#550 +1! +b11111 7 +b11111 " +b11001 9 +b11000 6 +b00000000000000000000000000110111 # +b11011 8 +#555 +0! +#560 +1! +b11001 8 +b00000000000000000000000000111000 # +b01100 6 +b11000 9 +b11011 " +b11011 7 +#565 +0! +#570 +1! +b11001 7 +b11001 " +b01100 9 +b00110 6 +b00000000000000000000000000111001 # +b11000 8 +#575 +0! +#580 +1! +b01100 8 +b00000000000000000000000000111010 # +b00011 6 +b00110 9 +b11000 " +b11000 7 +#585 +0! +#590 +1! +b01100 7 +b01100 " +b00011 9 +b10101 6 +b00000000000000000000000000111011 # +b00110 8 +#595 +0! +#600 +1! +b00011 8 +b00000000000000000000000000111100 # +b11110 6 +b10101 9 +b00110 " +b00110 7 +#605 +0! +#610 +1! +b00011 7 +b00011 " +b11110 9 +b01111 6 +b00000000000000000000000000111101 # +b10101 8 +#615 +0! +#620 +1! +b11110 8 +b00000000000000000000000000111110 # +b10011 6 +b01111 9 +b10101 " +b10101 7 +#625 +0! +#630 +1! +b11110 7 +b11110 " +b10011 9 +b11101 6 +b00000000000000000000000000111111 # +b01111 8 +#635 +0! +#640 +1! +b10011 8 +b00000000000000000000000001000000 # +b11010 6 +b11101 9 +b01111 " +b01111 7 +#645 +0! +#650 +1! +b10011 7 +b10011 " +b11010 9 +b01101 6 +b00000000000000000000000001000001 # +b11101 8 +#655 +0! +#660 +1! +b11010 8 +b00000000000000000000000001000010 # +b10010 6 +b01101 9 +b11101 " +b11101 7 +#665 +0! +#670 +1! +b11010 7 +b11010 " +b10010 9 +b01001 6 +b00000000000000000000000001000011 # +b01101 8 +#675 +0! +#680 +1! +b10010 8 +b00000000000000000000000001000100 # +b10000 6 +b01001 9 +b01101 " +b01101 7 +#685 +0! +#690 +1! +b10010 7 +b10010 " +b10000 9 +b01000 6 +b00000000000000000000000001000101 # +b01001 8 +#695 +0! +#700 +1! +b10000 8 +b00000000000000000000000001000110 # +b00100 6 +b01000 9 +b01001 " +b01001 7 +#705 +0! +#710 +1! +b10000 7 +b10000 " +b00100 9 +b00010 6 +b00000000000000000000000001000111 # +b01000 8 +#715 +0! +#720 +1! +b00100 8 +b00000000000000000000000001001000 # +b00001 6 +b00010 9 +b01000 " +b01000 7 +#725 +0! +#730 +1! +b00100 7 +b00100 " +b00001 9 +b10100 6 +b00000000000000000000000001001001 # +b00010 8 +#735 +0! +#740 +1! +b00001 8 +b00000000000000000000000001001010 # +b01010 6 +b10100 9 +b00010 " +b00010 7 +#745 +0! +#750 +1! +b00001 7 +b00001 " +b01010 9 +b00101 6 +b00000000000000000000000001001011 # +b10100 8 +#755 +0! +#760 +1! +b01010 8 +b00000000000000000000000001001100 # +b10110 6 +b00101 9 +b10100 " +b10100 7 +#765 +0! +#770 +1! +b01010 7 +b01010 " +b10110 9 +b01011 6 +b00000000000000000000000001001101 # +b00101 8 +#775 +0! +#780 +1! +b10110 8 +b00000000000000000000000001001110 # +b10001 6 +b01011 9 +b00101 " +b00101 7 +#785 +0! +#790 +1! +b10110 7 +b10110 " +b10001 9 +b11100 6 +b00000000000000000000000001001111 # +b01011 8 +#795 +0! +#800 +1! +b10001 8 +b00000000000000000000000001010000 # +b01110 6 +b11100 9 +b01011 " +b01011 7 +#805 +0! +#810 +1! +b10001 7 +b10001 " +b01110 9 +b00111 6 +b00000000000000000000000001010001 # +b11100 8 +#815 +0! +#820 +1! +b01110 8 +b00000000000000000000000001010010 # +b10111 6 +b00111 9 +b11100 " +b11100 7 +#825 +0! +#830 +1! +b01110 7 +b01110 " +b10111 9 +b11111 6 +b00000000000000000000000001010011 # +b00111 8 +#835 +0! +#840 +1! +b10111 8 +b00000000000000000000000001010100 # +b11011 6 +b11111 9 +b00111 " +b00111 7 +#845 +0! +#850 +1! +b10111 7 +b10111 " +b11011 9 +b11001 6 +b00000000000000000000000001010101 # +b11111 8 +#855 +0! +#860 +1! +b11011 8 +b00000000000000000000000001010110 # +b11000 6 +b11001 9 +b11111 " +b11111 7 +#865 +0! +#870 +1! +b11011 7 +b11011 " +b11000 9 +b01100 6 +b00000000000000000000000001010111 # +b11001 8 +#875 +0! +#880 +1! +b11000 8 +b00000000000000000000000001011000 # +b00110 6 +b01100 9 +b11001 " +b11001 7 +#885 +0! +#890 +1! +b11000 7 +b11000 " +b00110 9 +b00011 6 +b00000000000000000000000001011001 # +b01100 8 +#895 +0! +#900 +1! +b00110 8 +b00000000000000000000000001011010 # +b10101 6 +b00011 9 +b01100 " +b01100 7 +#905 +0! +#910 +1! +b00110 7 +b00110 " +b10101 9 +b11110 6 +b00000000000000000000000001011011 # +b00011 8 +#915 +0! +#920 +1! +b10101 8 +b00000000000000000000000001011100 # +b01111 6 +b11110 9 +b00011 " +b00011 7 +#925 +0! +#930 +1! +b10101 7 +b10101 " +b01111 9 +b10011 6 +b00000000000000000000000001011101 # +b11110 8 +#935 +0! +#940 +1! +b01111 8 +b00000000000000000000000001011110 # +b11101 6 +b10011 9 +b11110 " +b11110 7 +#945 +0! +#950 +1! +b01111 7 +b01111 " +b11101 9 +b11010 6 +b00000000000000000000000001011111 # +b10011 8 +#955 +0! +#960 +1! +b11101 8 +b00000000000000000000000001100000 # +b01101 6 +b11010 9 +b10011 " +b10011 7 +#965 +0! +#970 +1! +b11101 7 +b11101 " +b01101 9 +b10010 6 +b00000000000000000000000001100001 # +b11010 8 +#975 +0! +#980 +1! +b01101 8 +b00000000000000000000000001100010 # +b01001 6 +b10010 9 +b11010 " +b11010 7 +#985 +0! +#990 +1! +b01101 7 +b01101 " +b01001 9 +b10000 6 +b00000000000000000000000001100011 # +b10010 8 +#995 +0! +#1000 +1! +b01001 8 +b00000000000000000000000001100100 # +b01000 6 +b10000 9 +b10010 " +b10010 7 diff --git a/test_regress/t/t_trace_fst_cmake.pl b/test_regress/t/t_trace_fst_cmake.pl new file mode 100755 index 000000000..4a00d2fb6 --- /dev/null +++ b/test_regress/t/t_trace_fst_cmake.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } + +scenarios(vlt_all => 1); + +compile( + v_flags2 => ["--trace-fst"], + verilator_make_gmake => 0, + verilator_make_cmake => 1, +); + +execute( + check_finished => 1, +); + +fst_identical($Self->trace_filename, $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_fst_cmake.v b/test_regress/t/t_trace_fst_cmake.v new file mode 100644 index 000000000..288ddadfc --- /dev/null +++ b/test_regress/t/t_trace_fst_cmake.v @@ -0,0 +1,99 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// Author: Yu-Sheng Lin johnjohnlys@media.ee.ntu.edu.tw +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Outputs + state, + // Inputs + clk + ); + + input clk; + + int cyc; + reg rstn; + output [4:0] state; + + parameter real fst_gparam_real = 1.23; + localparam real fst_lparam_real = 4.56; + real fst_real = 1.23; + integer fst_integer; + bit fst_bit; + logic fst_logic; + int fst_int; + shortint fst_shortint; + longint fst_longint; + byte fst_byte; + + parameter fst_parameter = 123; + localparam fst_lparam = 456; + supply0 fst_supply0; + supply1 fst_supply1; + tri0 fst_tri0; + tri1 fst_tri1; + tri fst_tri; + wire fst_wire; + + Test test (/*AUTOINST*/ + // Outputs + .state (state[4:0]), + // Inputs + .clk (clk), + .rstn (rstn)); + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc==0) begin + // Setup + rstn <= ~'1; + end + else if (cyc<10) begin + rstn <= ~'1; + end + else if (cyc<90) begin + rstn <= ~'0; + end + else if (cyc==99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + + +module Test ( + input clk, + input rstn, + output logic [4:0] state + ); + + logic [4:0] state_w; + logic [4:0] state_array [3]; + assign state = state_array[0]; + + always_comb begin + state_w[4] = state_array[2][0]; + state_w[3] = state_array[2][4]; + state_w[2] = state_array[2][3] ^ state_array[2][0]; + state_w[1] = state_array[2][2]; + state_w[0] = state_array[2][1]; + end + + always_ff @(posedge clk or negedge rstn) begin + if (!rstn) begin + for (int i = 0; i < 3; i++) + state_array[i] <= 'b1; + end + else begin + for (int i = 0; i < 2; i++) + state_array[i] <= state_array[i+1]; + state_array[2] <= state_w; + end + end + +endmodule diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index cfd6ed2b2..f91fab2d1 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -83,6 +83,12 @@ define_property(TARGET FULL_DOCS "Verilator multithreading enabled" ) +define_property(TARGET + PROPERTY VERILATOR_TRACE_THREADED + BRIEF_DOCS "Verilator multithread tracing enabled" + FULL_DOCS "Verilator multithread tracing enabled" +) + define_property(TARGET PROPERTY VERILATOR_COVERAGE BRIEF_DOCS "Verilator coverage enabled" @@ -115,7 +121,7 @@ define_property(TARGET function(verilate TARGET) cmake_parse_arguments(VERILATE "COVERAGE;TRACE;TRACE_FST;SYSTEMC" - "PREFIX;TOP_MODULE;THREADS;DIRECTORY" + "PREFIX;TOP_MODULE;THREADS;TRACE_THREADS;DIRECTORY" "SOURCES;VERILATOR_ARGS;INCLUDE_DIRS;OPT_SLOW;OPT_FAST;OPT_GLOBAL" ${ARGN}) if (NOT VERILATE_SOURCES) @@ -136,6 +142,10 @@ function(verilate TARGET) list(APPEND VERILATOR_ARGS --threads ${VERILATE_THREADS}) endif() + if (VERILATE_TRACE_THREADS) + list(APPEND VERILATOR_ARGS --trace-threads ${VERILATE_TRACE_THREADS}) + endif() + if (VERILATE_COVERAGE) list(APPEND VERILATOR_ARGS --coverage) endif() @@ -240,6 +250,11 @@ function(verilate TARGET) set_property(TARGET ${TARGET} PROPERTY VERILATOR_THREADED ON) endif() + if (${VERILATE_PREFIX}_TRACE_THREADS) + # If any verilate() call specifies TRACE_THREADS, define VL_TRACE_THREADED in the final build + set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_THREADED ON) + endif() + if (${VERILATE_PREFIX}_COVERAGE) # If any verilate() call specifies COVERAGE, define VM_COVERAGE in the final build set_property(TARGET ${TARGET} PROPERTY VERILATOR_COVERAGE ON) @@ -296,6 +311,7 @@ function(verilate TARGET) VM_COVERAGE=$> VM_SC=$> $<$>:VL_THREADED> + $<$>:VL_TRACE_THREADED> VM_TRACE=$> VM_TRACE_VCD=$> VM_TRACE_FST=$> From 5e56f4d11bddacf097c825a2d3f12a35fb27cd5e Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sat, 8 May 2021 21:20:26 +0900 Subject: [PATCH 19/80] Tests: Enable undefined behavior sanitizor when --sanitize is set. (#2923) --- test_regress/driver.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 4bd0ccc70..c2efa85ee 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -908,7 +908,7 @@ sub compile_vlt_flags { unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /; unshift @verilator_flags, "--debug-partition" if $param{vltmt}; unshift @verilator_flags, "-CFLAGS -ggdb -LDFLAGS -ggdb" if $opt_gdbsim; - unshift @verilator_flags, "-CFLAGS -fsanitize=address -LDFLAGS -fsanitize=address" if $param{sanitize}; + unshift @verilator_flags, "-CFLAGS -fsanitize=address,undefined -LDFLAGS -fsanitize=address,undefined" if $param{sanitize}; unshift @verilator_flags, "--make gmake" if $param{verilator_make_gmake}; unshift @verilator_flags, "--make cmake" if $param{verilator_make_cmake}; unshift @verilator_flags, "--exe" if From 37d68d39c89788d93e9d19ec11b5e258044b84b7 Mon Sep 17 00:00:00 2001 From: Jonathan Drolet Date: Sat, 8 May 2021 08:42:00 -0400 Subject: [PATCH 20/80] Support --trace-fst for SystemC with CMake (#2927) --- src/V3EmitCMake.cpp | 5 - test_regress/t/t_trace_fst_sc_cmake.out | 1824 +++++++++++++++++++++++ test_regress/t/t_trace_fst_sc_cmake.pl | 31 + test_regress/t/t_trace_fst_sc_cmake.v | 98 ++ 4 files changed, 1953 insertions(+), 5 deletions(-) create mode 100644 test_regress/t/t_trace_fst_sc_cmake.out create mode 100755 test_regress/t/t_trace_fst_sc_cmake.pl create mode 100644 test_regress/t/t_trace_fst_sc_cmake.v diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 288a576ec..e8ff6e06d 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -169,11 +169,6 @@ class CMakeEmitter final { global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase() + "_c.cpp"); if (v3Global.opt.systemC()) { - if (v3Global.opt.traceFormat() != TraceFormat::VCD) { - v3warn(E_UNSUPPORTED, - "Unsupported: This trace format is not supported in SystemC, " - "use VCD format."); - } global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang() + ".cpp"); } diff --git a/test_regress/t/t_trace_fst_sc_cmake.out b/test_regress/t/t_trace_fst_sc_cmake.out new file mode 100644 index 000000000..3fe026e70 --- /dev/null +++ b/test_regress/t/t_trace_fst_sc_cmake.out @@ -0,0 +1,1824 @@ +$date + Thu Apr 1 14:28:55 2021 + +$end +$version + fstWriter +$end +$timescale + 1ps +$end +$scope module top $end +$scope module t $end +$var wire 1 ! clk $end +$var int 32 " cyc $end +$var logic 1 # rstn $end +$var real_parameter 64 $ fst_gparam_real $end +$var real_parameter 64 % fst_lparam_real $end +$var real 64 $ fst_real $end +$var integer 32 & fst_integer $end +$var bit 1 ' fst_bit $end +$var logic 1 ( fst_logic $end +$var int 32 ) fst_int $end +$var shortint 16 * fst_shortint $end +$var longint 64 + fst_longint $end +$var byte 8 , fst_byte $end +$var parameter 32 - fst_parameter $end +$var parameter 32 . fst_lparam $end +$var supply0 1 / fst_supply0 $end +$var supply1 1 0 fst_supply1 $end +$var tri0 1 1 fst_tri0 $end +$var tri1 1 2 fst_tri1 $end +$var tri 1 3 fst_tri $end +$var wire 1 4 fst_wire $end +$var logic 5 5 state $end +$scope module test $end +$var wire 1 ! clk $end +$var wire 1 # rstn $end +$var wire 5 5 state $end +$var logic 5 6 state_w $end +$var logic 5 7 state_array(0) $end +$var logic 5 8 state_array(1) $end +$var logic 5 9 state_array(2) $end +$scope module unnamedblk2 $end +$var int 32 : i $end +$upscope $end +$scope module unnamedblk1 $end +$var int 32 ; i $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$enddefinitions $end +#0 +$dumpvars +b00000000000000000000000000000000 ; +b00000000000000000000000000000000 : +b00000 9 +b00000 8 +b00000 7 +b00000 6 +b00000 5 +04 +03 +12 +01 +10 +0/ +b00000000000000000000000111001000 . +b00000000000000000000000001111011 - +b00000000 , +b0000000000000000000000000000000000000000000000000000000000000000 + +b0000000000000000 * +b00000000000000000000000000000000 ) +0( +0' +b00000000000000000000000000000000 & +r4.56 % +r1.23 $ +0# +b00000000000000000000000000000000 " +0! +$end +#10 +1! +b00000000000000000000000000000001 " +b00001 5 +b10100 6 +b00001 7 +b00001 8 +b00001 9 +b00000000000000000000000000000011 ; +#11 +#12 +#13 +#14 +#15 +0! +#16 +#17 +#18 +#19 +#20 +1! +b00000000000000000000000000000010 " +#21 +#22 +#23 +#24 +#25 +0! +#26 +#27 +#28 +#29 +#30 +1! +b00000000000000000000000000000011 " +#31 +#32 +#33 +#34 +#35 +0! +#36 +#37 +#38 +#39 +#40 +1! +b00000000000000000000000000000100 " +#41 +#42 +#43 +#44 +#45 +0! +#46 +#47 +#48 +#49 +#50 +1! +b00000000000000000000000000000101 " +#51 +#52 +#53 +#54 +#55 +0! +#56 +#57 +#58 +#59 +#60 +1! +b00000000000000000000000000000110 " +#61 +#62 +#63 +#64 +#65 +0! +#66 +#67 +#68 +#69 +#70 +1! +b00000000000000000000000000000111 " +#71 +#72 +#73 +#74 +#75 +0! +#76 +#77 +#78 +#79 +#80 +1! +b00000000000000000000000000001000 " +#81 +#82 +#83 +#84 +#85 +0! +#86 +#87 +#88 +#89 +#90 +1! +b00000000000000000000000000001001 " +#91 +#92 +#93 +#94 +#95 +0! +#96 +#97 +#98 +#99 +#100 +1! +b00000000000000000000000000001010 " +#101 +#102 +#103 +#104 +#105 +0! +#106 +#107 +#108 +#109 +#110 +1! +b00000000000000000000000000001011 " +1# +#111 +#112 +#113 +#114 +#115 +0! +#116 +#117 +#118 +#119 +#120 +1! +b00000000000000000000000000001100 " +b10100 9 +b01010 6 +b00000000000000000000000000000010 : +#121 +#122 +#123 +#124 +#125 +0! +#126 +#127 +#128 +#129 +#130 +1! +b00101 6 +b01010 9 +b00000000000000000000000000001101 " +b10100 8 +#131 +#132 +#133 +#134 +#135 +0! +#136 +#137 +#138 +#139 +#140 +1! +b01010 8 +b00000000000000000000000000001110 " +b00101 9 +b10110 6 +b10100 7 +b10100 5 +#141 +#142 +#143 +#144 +#145 +0! +#146 +#147 +#148 +#149 +#150 +1! +b01010 5 +b01010 7 +b01011 6 +b10110 9 +b00000000000000000000000000001111 " +b00101 8 +#151 +#152 +#153 +#154 +#155 +0! +#156 +#157 +#158 +#159 +#160 +1! +b10110 8 +b00000000000000000000000000010000 " +b01011 9 +b10001 6 +b00101 7 +b00101 5 +#161 +#162 +#163 +#164 +#165 +0! +#166 +#167 +#168 +#169 +#170 +1! +b10110 5 +b10110 7 +b11100 6 +b10001 9 +b00000000000000000000000000010001 " +b01011 8 +#171 +#172 +#173 +#174 +#175 +0! +#176 +#177 +#178 +#179 +#180 +1! +b10001 8 +b00000000000000000000000000010010 " +b11100 9 +b01110 6 +b01011 7 +b01011 5 +#181 +#182 +#183 +#184 +#185 +0! +#186 +#187 +#188 +#189 +#190 +1! +b10001 5 +b10001 7 +b00111 6 +b01110 9 +b00000000000000000000000000010011 " +b11100 8 +#191 +#192 +#193 +#194 +#195 +0! +#196 +#197 +#198 +#199 +#200 +1! +b01110 8 +b00000000000000000000000000010100 " +b00111 9 +b10111 6 +b11100 7 +b11100 5 +#201 +#202 +#203 +#204 +#205 +0! +#206 +#207 +#208 +#209 +#210 +1! +b01110 5 +b01110 7 +b11111 6 +b10111 9 +b00000000000000000000000000010101 " +b00111 8 +#211 +#212 +#213 +#214 +#215 +0! +#216 +#217 +#218 +#219 +#220 +1! +b10111 8 +b00000000000000000000000000010110 " +b11111 9 +b11011 6 +b00111 7 +b00111 5 +#221 +#222 +#223 +#224 +#225 +0! +#226 +#227 +#228 +#229 +#230 +1! +b10111 5 +b10111 7 +b11001 6 +b11011 9 +b00000000000000000000000000010111 " +b11111 8 +#231 +#232 +#233 +#234 +#235 +0! +#236 +#237 +#238 +#239 +#240 +1! +b11011 8 +b00000000000000000000000000011000 " +b11001 9 +b11000 6 +b11111 7 +b11111 5 +#241 +#242 +#243 +#244 +#245 +0! +#246 +#247 +#248 +#249 +#250 +1! +b11011 5 +b11011 7 +b01100 6 +b11000 9 +b00000000000000000000000000011001 " +b11001 8 +#251 +#252 +#253 +#254 +#255 +0! +#256 +#257 +#258 +#259 +#260 +1! +b11000 8 +b00000000000000000000000000011010 " +b01100 9 +b00110 6 +b11001 7 +b11001 5 +#261 +#262 +#263 +#264 +#265 +0! +#266 +#267 +#268 +#269 +#270 +1! +b11000 5 +b11000 7 +b00011 6 +b00110 9 +b00000000000000000000000000011011 " +b01100 8 +#271 +#272 +#273 +#274 +#275 +0! +#276 +#277 +#278 +#279 +#280 +1! +b00110 8 +b00000000000000000000000000011100 " +b00011 9 +b10101 6 +b01100 7 +b01100 5 +#281 +#282 +#283 +#284 +#285 +0! +#286 +#287 +#288 +#289 +#290 +1! +b00110 5 +b00110 7 +b11110 6 +b10101 9 +b00000000000000000000000000011101 " +b00011 8 +#291 +#292 +#293 +#294 +#295 +0! +#296 +#297 +#298 +#299 +#300 +1! +b10101 8 +b00000000000000000000000000011110 " +b11110 9 +b01111 6 +b00011 7 +b00011 5 +#301 +#302 +#303 +#304 +#305 +0! +#306 +#307 +#308 +#309 +#310 +1! +b10101 5 +b10101 7 +b10011 6 +b01111 9 +b00000000000000000000000000011111 " +b11110 8 +#311 +#312 +#313 +#314 +#315 +0! +#316 +#317 +#318 +#319 +#320 +1! +b01111 8 +b00000000000000000000000000100000 " +b10011 9 +b11101 6 +b11110 7 +b11110 5 +#321 +#322 +#323 +#324 +#325 +0! +#326 +#327 +#328 +#329 +#330 +1! +b01111 5 +b01111 7 +b11010 6 +b11101 9 +b00000000000000000000000000100001 " +b10011 8 +#331 +#332 +#333 +#334 +#335 +0! +#336 +#337 +#338 +#339 +#340 +1! +b11101 8 +b00000000000000000000000000100010 " +b11010 9 +b01101 6 +b10011 7 +b10011 5 +#341 +#342 +#343 +#344 +#345 +0! +#346 +#347 +#348 +#349 +#350 +1! +b11101 5 +b11101 7 +b10010 6 +b01101 9 +b00000000000000000000000000100011 " +b11010 8 +#351 +#352 +#353 +#354 +#355 +0! +#356 +#357 +#358 +#359 +#360 +1! +b01101 8 +b00000000000000000000000000100100 " +b10010 9 +b01001 6 +b11010 7 +b11010 5 +#361 +#362 +#363 +#364 +#365 +0! +#366 +#367 +#368 +#369 +#370 +1! +b01101 5 +b01101 7 +b10000 6 +b01001 9 +b00000000000000000000000000100101 " +b10010 8 +#371 +#372 +#373 +#374 +#375 +0! +#376 +#377 +#378 +#379 +#380 +1! +b01001 8 +b00000000000000000000000000100110 " +b10000 9 +b01000 6 +b10010 7 +b10010 5 +#381 +#382 +#383 +#384 +#385 +0! +#386 +#387 +#388 +#389 +#390 +1! +b01001 5 +b01001 7 +b00100 6 +b01000 9 +b00000000000000000000000000100111 " +b10000 8 +#391 +#392 +#393 +#394 +#395 +0! +#396 +#397 +#398 +#399 +#400 +1! +b01000 8 +b00000000000000000000000000101000 " +b00100 9 +b00010 6 +b10000 7 +b10000 5 +#401 +#402 +#403 +#404 +#405 +0! +#406 +#407 +#408 +#409 +#410 +1! +b01000 5 +b01000 7 +b00001 6 +b00010 9 +b00000000000000000000000000101001 " +b00100 8 +#411 +#412 +#413 +#414 +#415 +0! +#416 +#417 +#418 +#419 +#420 +1! +b00010 8 +b00000000000000000000000000101010 " +b00001 9 +b10100 6 +b00100 7 +b00100 5 +#421 +#422 +#423 +#424 +#425 +0! +#426 +#427 +#428 +#429 +#430 +1! +b00010 5 +b00010 7 +b01010 6 +b10100 9 +b00000000000000000000000000101011 " +b00001 8 +#431 +#432 +#433 +#434 +#435 +0! +#436 +#437 +#438 +#439 +#440 +1! +b10100 8 +b00000000000000000000000000101100 " +b01010 9 +b00101 6 +b00001 7 +b00001 5 +#441 +#442 +#443 +#444 +#445 +0! +#446 +#447 +#448 +#449 +#450 +1! +b10100 5 +b10100 7 +b10110 6 +b00101 9 +b00000000000000000000000000101101 " +b01010 8 +#451 +#452 +#453 +#454 +#455 +0! +#456 +#457 +#458 +#459 +#460 +1! +b00101 8 +b00000000000000000000000000101110 " +b10110 9 +b01011 6 +b01010 7 +b01010 5 +#461 +#462 +#463 +#464 +#465 +0! +#466 +#467 +#468 +#469 +#470 +1! +b00101 5 +b00101 7 +b10001 6 +b01011 9 +b00000000000000000000000000101111 " +b10110 8 +#471 +#472 +#473 +#474 +#475 +0! +#476 +#477 +#478 +#479 +#480 +1! +b01011 8 +b00000000000000000000000000110000 " +b10001 9 +b11100 6 +b10110 7 +b10110 5 +#481 +#482 +#483 +#484 +#485 +0! +#486 +#487 +#488 +#489 +#490 +1! +b01011 5 +b01011 7 +b01110 6 +b11100 9 +b00000000000000000000000000110001 " +b10001 8 +#491 +#492 +#493 +#494 +#495 +0! +#496 +#497 +#498 +#499 +#500 +1! +b11100 8 +b00000000000000000000000000110010 " +b01110 9 +b00111 6 +b10001 7 +b10001 5 +#501 +#502 +#503 +#504 +#505 +0! +#506 +#507 +#508 +#509 +#510 +1! +b11100 5 +b11100 7 +b10111 6 +b00111 9 +b00000000000000000000000000110011 " +b01110 8 +#511 +#512 +#513 +#514 +#515 +0! +#516 +#517 +#518 +#519 +#520 +1! +b00111 8 +b00000000000000000000000000110100 " +b10111 9 +b11111 6 +b01110 7 +b01110 5 +#521 +#522 +#523 +#524 +#525 +0! +#526 +#527 +#528 +#529 +#530 +1! +b00111 5 +b00111 7 +b11011 6 +b11111 9 +b00000000000000000000000000110101 " +b10111 8 +#531 +#532 +#533 +#534 +#535 +0! +#536 +#537 +#538 +#539 +#540 +1! +b11111 8 +b00000000000000000000000000110110 " +b11011 9 +b11001 6 +b10111 7 +b10111 5 +#541 +#542 +#543 +#544 +#545 +0! +#546 +#547 +#548 +#549 +#550 +1! +b11111 5 +b11111 7 +b11000 6 +b11001 9 +b00000000000000000000000000110111 " +b11011 8 +#551 +#552 +#553 +#554 +#555 +0! +#556 +#557 +#558 +#559 +#560 +1! +b11001 8 +b00000000000000000000000000111000 " +b11000 9 +b01100 6 +b11011 7 +b11011 5 +#561 +#562 +#563 +#564 +#565 +0! +#566 +#567 +#568 +#569 +#570 +1! +b11001 5 +b11001 7 +b00110 6 +b01100 9 +b00000000000000000000000000111001 " +b11000 8 +#571 +#572 +#573 +#574 +#575 +0! +#576 +#577 +#578 +#579 +#580 +1! +b01100 8 +b00000000000000000000000000111010 " +b00110 9 +b00011 6 +b11000 7 +b11000 5 +#581 +#582 +#583 +#584 +#585 +0! +#586 +#587 +#588 +#589 +#590 +1! +b01100 5 +b01100 7 +b10101 6 +b00011 9 +b00000000000000000000000000111011 " +b00110 8 +#591 +#592 +#593 +#594 +#595 +0! +#596 +#597 +#598 +#599 +#600 +1! +b00011 8 +b00000000000000000000000000111100 " +b10101 9 +b11110 6 +b00110 7 +b00110 5 +#601 +#602 +#603 +#604 +#605 +0! +#606 +#607 +#608 +#609 +#610 +1! +b00011 5 +b00011 7 +b01111 6 +b11110 9 +b00000000000000000000000000111101 " +b10101 8 +#611 +#612 +#613 +#614 +#615 +0! +#616 +#617 +#618 +#619 +#620 +1! +b11110 8 +b00000000000000000000000000111110 " +b01111 9 +b10011 6 +b10101 7 +b10101 5 +#621 +#622 +#623 +#624 +#625 +0! +#626 +#627 +#628 +#629 +#630 +1! +b11110 5 +b11110 7 +b11101 6 +b10011 9 +b00000000000000000000000000111111 " +b01111 8 +#631 +#632 +#633 +#634 +#635 +0! +#636 +#637 +#638 +#639 +#640 +1! +b10011 8 +b00000000000000000000000001000000 " +b11101 9 +b11010 6 +b01111 7 +b01111 5 +#641 +#642 +#643 +#644 +#645 +0! +#646 +#647 +#648 +#649 +#650 +1! +b10011 5 +b10011 7 +b01101 6 +b11010 9 +b00000000000000000000000001000001 " +b11101 8 +#651 +#652 +#653 +#654 +#655 +0! +#656 +#657 +#658 +#659 +#660 +1! +b11010 8 +b00000000000000000000000001000010 " +b01101 9 +b10010 6 +b11101 7 +b11101 5 +#661 +#662 +#663 +#664 +#665 +0! +#666 +#667 +#668 +#669 +#670 +1! +b11010 5 +b11010 7 +b01001 6 +b10010 9 +b00000000000000000000000001000011 " +b01101 8 +#671 +#672 +#673 +#674 +#675 +0! +#676 +#677 +#678 +#679 +#680 +1! +b10010 8 +b00000000000000000000000001000100 " +b01001 9 +b10000 6 +b01101 7 +b01101 5 +#681 +#682 +#683 +#684 +#685 +0! +#686 +#687 +#688 +#689 +#690 +1! +b10010 5 +b10010 7 +b01000 6 +b10000 9 +b00000000000000000000000001000101 " +b01001 8 +#691 +#692 +#693 +#694 +#695 +0! +#696 +#697 +#698 +#699 +#700 +1! +b10000 8 +b00000000000000000000000001000110 " +b01000 9 +b00100 6 +b01001 7 +b01001 5 +#701 +#702 +#703 +#704 +#705 +0! +#706 +#707 +#708 +#709 +#710 +1! +b10000 5 +b10000 7 +b00010 6 +b00100 9 +b00000000000000000000000001000111 " +b01000 8 +#711 +#712 +#713 +#714 +#715 +0! +#716 +#717 +#718 +#719 +#720 +1! +b00100 8 +b00000000000000000000000001001000 " +b00010 9 +b00001 6 +b01000 7 +b01000 5 +#721 +#722 +#723 +#724 +#725 +0! +#726 +#727 +#728 +#729 +#730 +1! +b00100 5 +b00100 7 +b10100 6 +b00001 9 +b00000000000000000000000001001001 " +b00010 8 +#731 +#732 +#733 +#734 +#735 +0! +#736 +#737 +#738 +#739 +#740 +1! +b00001 8 +b00000000000000000000000001001010 " +b10100 9 +b01010 6 +b00010 7 +b00010 5 +#741 +#742 +#743 +#744 +#745 +0! +#746 +#747 +#748 +#749 +#750 +1! +b00001 5 +b00001 7 +b00101 6 +b01010 9 +b00000000000000000000000001001011 " +b10100 8 +#751 +#752 +#753 +#754 +#755 +0! +#756 +#757 +#758 +#759 +#760 +1! +b01010 8 +b00000000000000000000000001001100 " +b00101 9 +b10110 6 +b10100 7 +b10100 5 +#761 +#762 +#763 +#764 +#765 +0! +#766 +#767 +#768 +#769 +#770 +1! +b01010 5 +b01010 7 +b01011 6 +b10110 9 +b00000000000000000000000001001101 " +b00101 8 +#771 +#772 +#773 +#774 +#775 +0! +#776 +#777 +#778 +#779 +#780 +1! +b10110 8 +b00000000000000000000000001001110 " +b01011 9 +b10001 6 +b00101 7 +b00101 5 +#781 +#782 +#783 +#784 +#785 +0! +#786 +#787 +#788 +#789 +#790 +1! +b10110 5 +b10110 7 +b11100 6 +b10001 9 +b00000000000000000000000001001111 " +b01011 8 +#791 +#792 +#793 +#794 +#795 +0! +#796 +#797 +#798 +#799 +#800 +1! +b10001 8 +b00000000000000000000000001010000 " +b11100 9 +b01110 6 +b01011 7 +b01011 5 +#801 +#802 +#803 +#804 +#805 +0! +#806 +#807 +#808 +#809 +#810 +1! +b10001 5 +b10001 7 +b00111 6 +b01110 9 +b00000000000000000000000001010001 " +b11100 8 +#811 +#812 +#813 +#814 +#815 +0! +#816 +#817 +#818 +#819 +#820 +1! +b01110 8 +b00000000000000000000000001010010 " +b00111 9 +b10111 6 +b11100 7 +b11100 5 +#821 +#822 +#823 +#824 +#825 +0! +#826 +#827 +#828 +#829 +#830 +1! +b01110 5 +b01110 7 +b11111 6 +b10111 9 +b00000000000000000000000001010011 " +b00111 8 +#831 +#832 +#833 +#834 +#835 +0! +#836 +#837 +#838 +#839 +#840 +1! +b10111 8 +b00000000000000000000000001010100 " +b11111 9 +b11011 6 +b00111 7 +b00111 5 +#841 +#842 +#843 +#844 +#845 +0! +#846 +#847 +#848 +#849 +#850 +1! +b10111 5 +b10111 7 +b11001 6 +b11011 9 +b00000000000000000000000001010101 " +b11111 8 +#851 +#852 +#853 +#854 +#855 +0! +#856 +#857 +#858 +#859 +#860 +1! +b11011 8 +b00000000000000000000000001010110 " +b11001 9 +b11000 6 +b11111 7 +b11111 5 +#861 +#862 +#863 +#864 +#865 +0! +#866 +#867 +#868 +#869 +#870 +1! +b11011 5 +b11011 7 +b01100 6 +b11000 9 +b00000000000000000000000001010111 " +b11001 8 +#871 +#872 +#873 +#874 +#875 +0! +#876 +#877 +#878 +#879 +#880 +1! +b11000 8 +b00000000000000000000000001011000 " +b01100 9 +b00110 6 +b11001 7 +b11001 5 +#881 +#882 +#883 +#884 +#885 +0! +#886 +#887 +#888 +#889 +#890 +1! +b11000 5 +b11000 7 +b00011 6 +b00110 9 +b00000000000000000000000001011001 " +b01100 8 +#891 +#892 +#893 +#894 +#895 +0! +#896 +#897 +#898 +#899 +#900 +1! +b00110 8 +b00000000000000000000000001011010 " +b00011 9 +b10101 6 +b01100 7 +b01100 5 +#901 +#902 +#903 +#904 +#905 +0! +#906 +#907 +#908 +#909 +#910 +1! +b00110 5 +b00110 7 +b11110 6 +b10101 9 +b00000000000000000000000001011011 " +b00011 8 +#911 +#912 +#913 +#914 +#915 +0! +#916 +#917 +#918 +#919 +#920 +1! +b10101 8 +b00000000000000000000000001011100 " +b11110 9 +b01111 6 +b00011 7 +b00011 5 +#921 +#922 +#923 +#924 +#925 +0! +#926 +#927 +#928 +#929 +#930 +1! +b10101 5 +b10101 7 +b10011 6 +b01111 9 +b00000000000000000000000001011101 " +b11110 8 +#931 +#932 +#933 +#934 +#935 +0! +#936 +#937 +#938 +#939 +#940 +1! +b01111 8 +b00000000000000000000000001011110 " +b10011 9 +b11101 6 +b11110 7 +b11110 5 +#941 +#942 +#943 +#944 +#945 +0! +#946 +#947 +#948 +#949 +#950 +1! +b01111 5 +b01111 7 +b11010 6 +b11101 9 +b00000000000000000000000001011111 " +b10011 8 +#951 +#952 +#953 +#954 +#955 +0! +#956 +#957 +#958 +#959 +#960 +1! +b11101 8 +b00000000000000000000000001100000 " +b11010 9 +b01101 6 +b10011 7 +b10011 5 +#961 +#962 +#963 +#964 +#965 +0! +#966 +#967 +#968 +#969 +#970 +1! +b11101 5 +b11101 7 +b10010 6 +b01101 9 +b00000000000000000000000001100001 " +b11010 8 +#971 +#972 +#973 +#974 +#975 +0! +#976 +#977 +#978 +#979 +#980 +1! +b01101 8 +b00000000000000000000000001100010 " +b10010 9 +b01001 6 +b11010 7 +b11010 5 +#981 +#982 +#983 +#984 +#985 +0! +#986 +#987 +#988 +#989 +#990 +1! +b01101 5 +b01101 7 +b10000 6 +b01001 9 +b00000000000000000000000001100011 " +b10010 8 +#991 +#992 +#993 +#994 +#995 +0! +#996 +#997 +#998 +#999 +#1000 +1! +b01001 8 +b00000000000000000000000001100100 " +b10000 9 +b01000 6 +b10010 7 +b10010 5 +#1001 +#1002 +#1003 +#1004 diff --git a/test_regress/t/t_trace_fst_sc_cmake.pl b/test_regress/t/t_trace_fst_sc_cmake.pl new file mode 100755 index 000000000..9764d6bf0 --- /dev/null +++ b/test_regress/t/t_trace_fst_sc_cmake.pl @@ -0,0 +1,31 @@ +#!/usr/bin/env perl +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } + +scenarios(vlt_all => 1); + +if (!$Self->have_sc) { + skip("No SystemC installed"); +} +else { + compile( + verilator_flags2 => ["--trace-fst --sc"], + verilator_make_gmake => 0, + verilator_make_cmake => 1, + ); + + execute( + check_finished => 1, + ); + + fst_identical($Self->trace_filename, $Self->{golden_filename}); +} +ok(1); +1; diff --git a/test_regress/t/t_trace_fst_sc_cmake.v b/test_regress/t/t_trace_fst_sc_cmake.v new file mode 100644 index 000000000..52c148bd5 --- /dev/null +++ b/test_regress/t/t_trace_fst_sc_cmake.v @@ -0,0 +1,98 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// Author: Yu-Sheng Lin johnjohnlys@media.ee.ntu.edu.tw +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc; + reg rstn; + + parameter real fst_gparam_real = 1.23; + localparam real fst_lparam_real = 4.56; + real fst_real = 1.23; + integer fst_integer; + bit fst_bit; + logic fst_logic; + int fst_int; + shortint fst_shortint; + longint fst_longint; + byte fst_byte; + + parameter fst_parameter = 123; + localparam fst_lparam = 456; + supply0 fst_supply0; + supply1 fst_supply1; + tri0 fst_tri0; + tri1 fst_tri1; + tri fst_tri; + wire fst_wire; + + logic [4:0] state; + + Test test (/*AUTOINST*/ + // Outputs + .state (state[4:0]), + // Inputs + .clk (clk), + .rstn (rstn)); + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc==0) begin + // Setup + rstn <= ~'1; + end + else if (cyc<10) begin + rstn <= ~'1; + end + else if (cyc<90) begin + rstn <= ~'0; + end + else if (cyc==99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + + +module Test ( + input clk, + input rstn, + output logic [4:0] state + ); + + logic [4:0] state_w; + logic [4:0] state_array [3]; + assign state = state_array[0]; + + always_comb begin + state_w[4] = state_array[2][0]; + state_w[3] = state_array[2][4]; + state_w[2] = state_array[2][3] ^ state_array[2][0]; + state_w[1] = state_array[2][2]; + state_w[0] = state_array[2][1]; + end + + always_ff @(posedge clk or negedge rstn) begin + if (!rstn) begin + for (int i = 0; i < 3; i++) + state_array[i] <= 'b1; + end + else begin + for (int i = 0; i < 2; i++) + state_array[i] <= state_array[i+1]; + state_array[2] <= state_w; + end + end + +endmodule From f6c0108c86bf2a784a5a15e76b17c56ba5a1d077 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 8 May 2021 20:04:56 +0100 Subject: [PATCH 21/80] Optimize large lookup tables to static data (#2926) Implements #2925 --- Changes | 1 + src/V3EmitC.cpp | 15 ++- src/V3Number.cpp | 7 +- src/V3Premit.cpp | 97 ++++++++++++----- test_regress/t/t_extract_static_const.out | 9 ++ test_regress/t/t_extract_static_const.pl | 31 ++++++ test_regress/t/t_extract_static_const.v | 32 ++++++ .../t/t_extract_static_const_multimodule.out | 11 ++ .../t/t_extract_static_const_multimodule.pl | 31 ++++++ .../t/t_extract_static_const_multimodule.v | 102 ++++++++++++++++++ 10 files changed, 300 insertions(+), 36 deletions(-) create mode 100644 test_regress/t/t_extract_static_const.out create mode 100755 test_regress/t/t_extract_static_const.pl create mode 100755 test_regress/t/t_extract_static_const.v create mode 100644 test_regress/t/t_extract_static_const_multimodule.out create mode 100755 test_regress/t/t_extract_static_const_multimodule.pl create mode 100755 test_regress/t/t_extract_static_const_multimodule.v diff --git a/Changes b/Changes index 30937b5d8..9891e89cb 100644 --- a/Changes +++ b/Changes @@ -36,6 +36,7 @@ Verilator 4.202 2021-04-24 * Add PINNOTFOUND warning in place of error (#2868). [Udi Finkelstein] * Support overlaps in priority case statements (#2864). [Rupert Swarbrick] * Support for null ports (#2875). [Udi Finkelstein] +* Optimize large lookup tables to static data (#2925). [Geza Lore] * Fix class unpacked-array compile error (#2774). [Iru Cai] * Fix scope types in FST and VCD traces (#2805). [Alex Torregrosa] * Fix exceeding command-line ar limit (#2834). [Yinan Xu] diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index c6b6ed359..a8f4de8ea 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1814,13 +1814,18 @@ class EmitCImp final : EmitCStmts { splitSizeInc(1); if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide string out; - if (zeroit) { - out += "VL_ZERO_RESET_W("; + if (varp->valuep()) { + AstConst* const constp = VN_CAST(varp->valuep(), Const); + if (!constp) varp->v3fatalSrc("non-const initializer for variable"); + for (int w = 0; w < varp->widthWords(); ++w) { + out += varp->nameProtect() + suffix + "[" + cvtToStr(w) + "] = "; + out += cvtToStr(constp->num().edataWord(w)) + "U;\n"; + } } else { - out += "VL_RAND_RESET_W("; + out += zeroit ? "VL_ZERO_RESET_W(" : "VL_RAND_RESET_W("; + out += cvtToStr(dtypep->widthMin()); + out += ", " + varp->nameProtect() + suffix + ");\n"; } - out += cvtToStr(dtypep->widthMin()); - out += ", " + varp->nameProtect() + suffix + ");\n"; return out; } else { string out = varp->nameProtect() + suffix; diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 70be0ac19..a5f7491d9 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1526,11 +1526,8 @@ bool V3Number::isCaseEq(const V3Number& rhs) const { if (isString()) return toString() == rhs.toString(); if (isDouble()) return toDouble() == rhs.toDouble(); if (this->width() != rhs.width()) return false; - - for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) { - if (this->bitIs(bit) != rhs.bitIs(bit)) return false; - } - return true; + if (m_value != rhs.m_value) return false; + return m_valueX == rhs.m_valueX; } V3Number& V3Number::opCaseEq(const V3Number& lhs, const V3Number& rhs) { diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 97bb3357f..ebd47c626 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -30,17 +30,21 @@ #include "V3Global.h" #include "V3Premit.h" #include "V3Ast.h" +#include "V3Hashed.h" +#include "V3Stats.h" #include +constexpr int STATIC_CONST_MIN_WIDTH = 256; // Minimum size to extract to static constant + //###################################################################### // Structure for global state class PremitAssignVisitor final : public AstNVisitor { private: // NODE STATE - // AstVar::user4() // bool; occurs on LHS of current assignment - AstUser4InUse m_inuser4; + // AstVar::user3() // bool; occurs on LHS of current assignment + AstUser3InUse m_inuser3; // STATE bool m_noopt = false; // Disable optimization of variables in this block @@ -50,7 +54,7 @@ private: // VISITORS virtual void visit(AstNodeAssign* nodep) override { - // AstNode::user4ClearTree(); // Implied by AstUser4InUse + // AstNode::user3ClearTree(); // Implied by AstUser3InUse // LHS first as fewer varrefs iterateAndNextNull(nodep->lhsp()); // Now find vars marked as lhs @@ -59,9 +63,9 @@ private: virtual void visit(AstVarRef* nodep) override { // it's LHS var is used so need a deep temporary if (nodep->access().isWriteOrRW()) { - nodep->varp()->user4(true); + nodep->varp()->user3(true); } else { - if (nodep->varp()->user4()) { + if (nodep->varp()->user3()) { if (!m_noopt) UINFO(4, "Block has LHS+RHS var: " << nodep << endl); m_noopt = true; } @@ -88,9 +92,11 @@ private: // AstNodeMath::user() -> bool. True if iterated already // AstShiftL::user2() -> bool. True if converted to conditional // AstShiftR::user2() -> bool. True if converted to conditional + // AstConst::user2p() -> Replacement static variable pointer // *::user4() -> See PremitAssignVisitor AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; + // AstUser4InUse part of V3Hashed // STATE AstNodeModule* m_modp = nullptr; // Current module @@ -100,6 +106,11 @@ private: AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts + V3Hashed m_hashed; // Hash set for static constants that can be reused + + VDouble0 m_staticConstantsExtracted; // Statistic tracking + VDouble0 m_staticConstantsReused; // Statistic tracking + // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -139,14 +150,6 @@ private: } } - AstVar* getBlockTemp(AstNode* nodep) { - string newvarname = (string("__Vtemp") + cvtToStr(m_modp->varNumGetInc())); - AstVar* varp - = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()); - m_cfuncp->addInitsp(varp); - return varp; - } - void insertBeforeStmt(AstNode* newp) { // Insert newp before m_stmtp if (m_inWhilep) { @@ -173,28 +176,66 @@ private: AstNRelinker linker; nodep->unlinkFrBack(&linker); - AstVar* varp = getBlockTemp(nodep); + AstVar* varp = nullptr; + + AstConst* const constp = VN_CAST(nodep, Const); + + const bool useStatic = constp && (constp->width() >= STATIC_CONST_MIN_WIDTH) + && !constp->num().isFourState(); + if (useStatic) { + // Extract as static constant + m_hashed.hash(constp); + const auto& it = m_hashed.findDuplicate(constp); + if (it == m_hashed.end()) { + const string newvarname = string("__Vconst") + cvtToStr(m_modp->varNumGetInc()); + varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, newvarname, + nodep->dtypep()); + varp->isConst(true); + varp->isStatic(true); + varp->valuep(constp); + m_modp->addStmtp(varp); + m_hashed.hashAndInsert(constp); + nodep->user2p(varp); + ++m_staticConstantsExtracted; + } else { + varp = VN_CAST(it->second->user2p(), Var); + ++m_staticConstantsReused; + } + } else { + // Keep as local temporary + const string newvarname = string("__Vtemp") + cvtToStr(m_modp->varNumGetInc()); + varp + = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()); + m_cfuncp->addInitsp(varp); + } + if (noSubst) varp->noSubst(true); // Do not remove varrefs to this in V3Const + // Replace node tree with reference to var AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); linker.relink(newp); - // Put assignment before the referencing statement - AstAssign* assp = new AstAssign( - nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep); - insertBeforeStmt(assp); - if (debug() > 8) assp->dumpTree(cout, "deepou:"); + + if (!useStatic) { + // Put assignment before the referencing statement + AstAssign* assp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep); + insertBeforeStmt(assp); + if (debug() > 8) assp->dumpTree(cout, "deepou:"); + } + nodep->user1(true); // Don't add another assignment } // VISITORS virtual void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); - VL_RESTORER(m_modp); - { - m_modp = nodep; - m_cfuncp = nullptr; - iterateChildren(nodep); - } + UASSERT_OBJ(m_modp == nullptr, nodep, "Nested modules ?"); + UASSERT_OBJ(m_hashed.mmap().empty(), nodep, "Statements outside module ?"); + m_modp = nodep; + m_cfuncp = nullptr; + iterateChildren(nodep); + m_modp = nullptr; + m_hashed.clear(); } virtual void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); @@ -401,7 +442,11 @@ private: public: // CONSTRUCTORS explicit PremitVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~PremitVisitor() override = default; + virtual ~PremitVisitor() { + V3Stats::addStat("Optimizations, Prelim static constants extracted", + m_staticConstantsExtracted); + V3Stats::addStat("Optimizations, Prelim static constants reused", m_staticConstantsReused); + } }; //---------------------------------------------------------------------- diff --git a/test_regress/t/t_extract_static_const.out b/test_regress/t/t_extract_static_const.out new file mode 100644 index 000000000..6b9780e61 --- /dev/null +++ b/test_regress/t/t_extract_static_const.out @@ -0,0 +1,9 @@ +0x88888888 +0x77777777 +0x66666666 +0x55555555 +0x44444444 +0x33333333 +0x22222222 +0x11111111 +*-* All Finished *-* diff --git a/test_regress/t/t_extract_static_const.pl b/test_regress/t/t_extract_static_const.pl new file mode 100755 index 000000000..63299d45f --- /dev/null +++ b/test_regress/t/t_extract_static_const.pl @@ -0,0 +1,31 @@ +#!/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_all => 1); + +compile( + verilator_flags2 => ["--stats"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, Prelim static constants extracted\s+(\d+)/i, + 1); + file_grep($Self->{stats}, qr/Optimizations, Prelim static constants reused\s+(\d+)/i, + 7); +} + +ok(1); +1; diff --git a/test_regress/t/t_extract_static_const.v b/test_regress/t/t_extract_static_const.v new file mode 100755 index 000000000..9cda8a26c --- /dev/null +++ b/test_regress/t/t_extract_static_const.v @@ -0,0 +1,32 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + wire [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 optimizatoin by Verilator + $display("0x%32x", C[$c(0*32)+:32]); + $display("0x%32x", C[$c(1*32)+:32]); + $display("0x%32x", C[$c(2*32)+:32]); + $display("0x%32x", C[$c(3*32)+:32]); + $display("0x%32x", C[$c(4*32)+:32]); + $display("0x%32x", C[$c(5*32)+:32]); + $display("0x%32x", C[$c(6*32)+:32]); + $display("0x%32x", C[$c(7*32)+:32]); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_extract_static_const_multimodule.out b/test_regress/t/t_extract_static_const_multimodule.out new file mode 100644 index 000000000..f739c8e51 --- /dev/null +++ b/test_regress/t/t_extract_static_const_multimodule.out @@ -0,0 +1,11 @@ +0x88888888 +0x66666666 +0x44444444 +0x22222222 +0x1111111122222222333333334444444455555555666666667777777788888888 +0x77777777 +0x55555555 +0x33333333 +0x11111111 +0x1111111122222222333333334444444455555555666666667777777788888888 +*-* All Finished *-* diff --git a/test_regress/t/t_extract_static_const_multimodule.pl b/test_regress/t/t_extract_static_const_multimodule.pl new file mode 100755 index 000000000..6767e6bcc --- /dev/null +++ b/test_regress/t/t_extract_static_const_multimodule.pl @@ -0,0 +1,31 @@ +#!/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_all => 1); + +compile( + verilator_flags2 => ["--stats"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, Prelim static constants extracted\s+(\d+)/i, + 2); + file_grep($Self->{stats}, qr/Optimizations, Prelim static constants reused\s+(\d+)/i, + 6); +} + +ok(1); +1; diff --git a/test_regress/t/t_extract_static_const_multimodule.v b/test_regress/t/t_extract_static_const_multimodule.v new file mode 100755 index 000000000..0f959991a --- /dev/null +++ b/test_regress/t/t_extract_static_const_multimodule.v @@ -0,0 +1,102 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +// +// Constants should not be shared by different non-inlined modules +// + +module a( + input wire clk, + input wire trig_i, + output reg trig_o + ); + /* verilator no_inline_module */ + + // Same constant as in module b + wire [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}; + + always @(posedge clk) begin + trig_o <= 1'd0; + if (trig_i) begin + // Note: Base index via $c to prevent optimizatoin by Verilator + $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]); + $display("0x%256x", C); + trig_o <= 1'd1; + end + end + +endmodule + +module b( + input wire clk, + input wire trig_i, + output reg trig_o + ); + /* verilator no_inline_module */ + + // Same constant as in module a + wire [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}; + + always @(posedge clk) begin + trig_o <= 1'd0; + if (trig_i) begin + // Note: Base index via $c to prevent optimizatoin by Verilator + $display("0x%32x", C[$c(1*32)+:32]); + $display("0x%32x", C[$c(3*32)+:32]); + $display("0x%32x", C[$c(5*32)+:32]); + $display("0x%32x", C[$c(7*32)+:32]); + $display("0x%256x", C); + trig_o <= 1'd1; + end + end + +endmodule + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + integer cyc = 0; + + reg trig_i; + wire trig_ab; + wire trig_o; + + a a_inst(.clk(clk), .trig_i(trig_i), .trig_o(trig_ab)); + b b_inst(.clk(clk), .trig_i(trig_ab), .trig_o(trig_o)); + + always @(posedge clk) begin + trig_i <= cyc == 1; + + if (trig_o) begin + $write("*-* All Finished *-*\n"); + $finish; + end + + cyc++; + end + +endmodule From 45fbd98ff1d404f5f71d74326fce54a651204328 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 9 May 2021 07:04:22 +0900 Subject: [PATCH 22/80] Use V3OptionParser in verilator_coverage (#2935) * Internals: Mark unused to avoid compilation failure. No functional change is intended. * Use V3OptionParser in VlcMain.cpp --- src/V3OptionParser.h | 15 ++++---- src/VlcMain.cpp | 89 +++++++++++++++----------------------------- src/VlcOptions.h | 1 - 3 files changed, 38 insertions(+), 67 deletions(-) diff --git a/src/V3OptionParser.h b/src/V3OptionParser.h index 42ad88135..fe3d0b703 100644 --- a/src/V3OptionParser.h +++ b/src/V3OptionParser.h @@ -143,13 +143,14 @@ public: }; #define V3OPTION_PARSER_DECL_TAGS \ - const auto Set = V3OptionParser::AppendHelper::Set{}; \ - const auto OnOff = V3OptionParser::AppendHelper::OnOff{}; \ - const auto CbCall = V3OptionParser::AppendHelper::CbCall{}; \ - const auto CbOnOff = V3OptionParser::AppendHelper::CbOnOff{}; \ - const auto CbVal = V3OptionParser::AppendHelper::CbVal{}; \ - const auto CbPartialMatch = V3OptionParser::AppendHelper::CbPartialMatch{}; \ - const auto CbPartialMatchVal = V3OptionParser::AppendHelper::CbPartialMatchVal {} + const auto Set VL_ATTR_UNUSED = V3OptionParser::AppendHelper::Set{}; \ + const auto OnOff VL_ATTR_UNUSED = V3OptionParser::AppendHelper::OnOff{}; \ + const auto CbCall VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbCall{}; \ + const auto CbOnOff VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbOnOff{}; \ + const auto CbVal VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbVal{}; \ + const auto CbPartialMatch VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbPartialMatch{}; \ + const auto CbPartialMatchVal VL_ATTR_UNUSED \ + = V3OptionParser::AppendHelper::CbPartialMatchVal {} //###################################################################### diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp index 68e22cc70..970aab9c3 100644 --- a/src/VlcMain.cpp +++ b/src/VlcMain.cpp @@ -27,6 +27,8 @@ #define V3ERROR_NO_GLOBAL_ #include "V3Error.cpp" #include "V3String.cpp" +#define V3OPTION_PARSER_NO_VOPTION_BOOL +#include "V3OptionParser.cpp" #include "V3Os.cpp" #include "VlcTop.cpp" @@ -47,74 +49,43 @@ string VlcOptions::version() { return ver; } -bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) { - // if sw==arg, then return true (found it), and flag=true - // if sw=="-no-arg", then return true (found it), and flag=false - // if sw=="-noarg", then return true (found it), and flag=false - // else return false - if (arg[0] != '-') v3fatalSrc("OnOff switches must have leading dash."); - if (0 == strcmp(sw, arg)) { - flag = true; - return true; - } else if (0 == strncmp(sw, "-no", 3) && (0 == strcmp(sw + 3, arg + 1))) { - flag = false; - return true; - } else if (0 == strncmp(sw, "-no-", 4) && (0 == strcmp(sw + 4, arg + 1))) { - flag = false; - return true; - } - return false; -} - void VlcOptions::parseOptsList(int argc, char** argv) { + V3OptionParser parser; + V3OptionParser::AppendHelper DECL_OPTION{parser}; + V3OPTION_PARSER_DECL_TAGS; + + DECL_OPTION("-annotate-all", OnOff, &m_annotateAll); + DECL_OPTION("-rank", OnOff, &m_rank); + DECL_OPTION("-unlink", OnOff, &m_unlink); + DECL_OPTION("-annotate-min", Set, &m_annotateMin); + DECL_OPTION("-annotate", Set, &m_annotateOut); + DECL_OPTION("-debug", CbCall, []() { V3Error::debugDefault(3); }); + DECL_OPTION("-debugi", CbVal, [](int v) { V3Error::debugDefault(v); }); + DECL_OPTION("-V", CbCall, []() { + showVersion(true); + std::exit(0); + }); + DECL_OPTION("-version", CbCall, []() { + showVersion(false); + std::exit(0); + }); + DECL_OPTION("-write", Set, &m_writeFile); + DECL_OPTION("-write-info", Set, &m_writeInfoFile); + parser.finalize(); + // Parse parameters // Note argc and argv DO NOT INCLUDE the filename in [0]!!! // May be called recursively when there are -f files. for (int i = 0; i < argc;) { UINFO(9, " Option: " << argv[i] << endl); if (argv[i][0] == '-') { - const char* sw = argv[i]; - bool flag = true; - // Allow gnu -- switches - if (sw[0] == '-' && sw[1] == '-') ++sw; - // Single switches - if (onoff(sw, "-annotate-all", flag /*ref*/)) { - m_annotateAll = flag; - } else if (onoff(sw, "-rank", flag /*ref*/)) { - m_rank = flag; - } else if (onoff(sw, "-unlink", flag /*ref*/)) { - m_unlink = flag; - } - // Parameterized switches - else if (!strcmp(sw, "-annotate-min") && (i + 1) < argc) { - ++i; - m_annotateMin = atoi(argv[i]); - } else if (!strcmp(sw, "-annotate") && (i + 1) < argc) { - ++i; - m_annotateOut = argv[i]; - } else if (!strcmp(sw, "-debug")) { - V3Error::debugDefault(3); - } else if (!strcmp(sw, "-debugi") && (i + 1) < argc) { - ++i; - V3Error::debugDefault(atoi(argv[i])); - } else if (!strcmp(sw, "-V")) { - showVersion(true); - std::exit(0); - } else if (!strcmp(sw, "-version")) { - showVersion(false); - std::exit(0); - } else if (!strcmp(sw, "-write") && (i + 1) < argc) { - ++i; - m_writeFile = argv[i]; - } else if (!strcmp(sw, "-write-info") && (i + 1) < argc) { - ++i; - m_writeInfoFile = argv[i]; + if (int consumed = parser.parse(i, argc, argv)) { + i += consumed; } else { - v3fatal("Invalid option: " << argv[i]); + v3fatal("Invalid option: " << argv[i] << parser.getSuggestion(argv[i])); + ++i; } - ++i; - } // - options - else { + } else { addReadFile(argv[i]); ++i; } diff --git a/src/VlcOptions.h b/src/VlcOptions.h index fc76f4b76..22d98dd4a 100644 --- a/src/VlcOptions.h +++ b/src/VlcOptions.h @@ -47,7 +47,6 @@ class VlcOptions final { private: // METHODS static void showVersion(bool verbose); - static bool onoff(const char* sw, const char* arg, bool& flag); public: // CONSTRUCTORS From 267c6f6dce96937595baeed873e5adc636511006 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 10 May 2021 18:01:11 +0100 Subject: [PATCH 23/80] Improve Reloop to accept constant index offsets. (#2939) V3Reloop now can roll up indexed assignments between arrays if there is a constant offset between indices on the left and right hand sides, e.g.: a[0] = b[2]; a[1] = b[3]; ... a[x] = b[x + 2]; --- src/V3Reloop.cpp | 113 +++++++++++++++++------------ test_regress/t/t_reloop_offset.out | 17 +++++ test_regress/t/t_reloop_offset.pl | 33 +++++++++ test_regress/t/t_reloop_offset.v | 50 +++++++++++++ 4 files changed, 167 insertions(+), 46 deletions(-) create mode 100644 test_regress/t/t_reloop_offset.out create mode 100755 test_regress/t/t_reloop_offset.pl create mode 100755 test_regress/t/t_reloop_offset.v diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index d9b6aeabc..facf7497e 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -18,12 +18,12 @@ // Each CFunc: // Look for a series of assignments that would look better in a loop: // -// ASSIGN(ARRAYREF(var, #), ARRAYREF(var, #)) -// ASSIGN(ARRAYREF(var, #+1), ARRAYREF(var, #+1)) +// ASSIGN(ARRAYREF(var, #), ARRAYREF(var, #+C)) +// ASSIGN(ARRAYREF(var, #+1), ARRAYREF(var, #+1+C)) // -> // Create __Vilp local variable // FOR(__Vilp = low; __Vilp <= high; ++__Vlip) -// ASSIGN(ARRAYREF(var, __Vilp), ARRAYREF(var, __Vilp)) +// ASSIGN(ARRAYREF(var, __Vilp), ARRAYREF(var, __Vilp + C)) // // Likewise vector assign to the same constant converted to a loop. // @@ -61,6 +61,7 @@ private: AstNodeSel* m_mgSelRp = nullptr; // Parent select, nullptr = constant AstNodeVarRef* m_mgVarrefLp = nullptr; // Parent varref AstNodeVarRef* m_mgVarrefRp = nullptr; // Parent varref, nullptr = constant + int64_t m_mgOffset = 0; // Index offset AstConst* m_mgConstRp = nullptr; // Parent RHS constant, nullptr = sel uint32_t m_mgIndexLo = 0; // Merge range uint32_t m_mgIndexHi = 0; // Merge range @@ -83,38 +84,50 @@ private: if (!m_mgAssignps.empty()) { uint32_t items = m_mgIndexHi - m_mgIndexLo + 1; UINFO(9, "End merge iter=" << items << " " << m_mgIndexHi << ":" << m_mgIndexLo << " " - << m_mgAssignps[0] << endl); + << m_mgOffset << " " << m_mgAssignps[0] << endl); if (items >= RELOOP_MIN_ITERS) { UINFO(6, "Reloop merging items=" << items << " " << m_mgIndexHi << ":" - << m_mgIndexLo << " " << m_mgAssignps[0] << endl); + << m_mgIndexLo << " " << m_mgOffset << " " + << m_mgAssignps[0] << endl); ++m_statReloops; m_statReItems += items; // Transform first assign into for loop body - AstNodeAssign* bodyp = m_mgAssignps.front(); + AstNodeAssign* const bodyp = m_mgAssignps.front(); UASSERT_OBJ(bodyp->lhsp() == m_mgSelLp, bodyp, "Corrupt queue/state"); - FileLine* fl = bodyp->fileline(); - AstVar* itp = findCreateVarTemp(fl, m_mgCfuncp); + FileLine* const fl = bodyp->fileline(); + AstVar* const itp = findCreateVarTemp(fl, m_mgCfuncp); - AstNode* initp = new AstAssign(fl, new AstVarRef(fl, itp, VAccess::WRITE), - new AstConst(fl, m_mgIndexLo)); - AstNode* condp = new AstLte(fl, new AstVarRef(fl, itp, VAccess::READ), - new AstConst(fl, m_mgIndexHi)); - AstNode* incp = new AstAssign( + if (m_mgOffset > 0) { + UASSERT_OBJ(m_mgIndexLo >= m_mgOffset, bodyp, + "Reloop iteration starts at negative index"); + m_mgIndexLo -= m_mgOffset; + m_mgIndexHi -= m_mgOffset; + } + + AstNode* const initp = new AstAssign(fl, new AstVarRef(fl, itp, VAccess::WRITE), + new AstConst(fl, m_mgIndexLo)); + AstNode* const condp = new AstLte(fl, new AstVarRef(fl, itp, VAccess::READ), + new AstConst(fl, m_mgIndexHi)); + AstNode* const incp = new AstAssign( fl, new AstVarRef(fl, itp, VAccess::WRITE), new AstAdd(fl, new AstConst(fl, 1), new AstVarRef(fl, itp, VAccess::READ))); - AstWhile* whilep = new AstWhile(fl, condp, nullptr, incp); + AstWhile* const whilep = new AstWhile(fl, condp, nullptr, incp); initp->addNext(whilep); bodyp->replaceWith(initp); whilep->addBodysp(bodyp); // Replace constant index with new loop index - AstNode* lbitp = m_mgSelLp->bitp(); - lbitp->replaceWith(new AstVarRef(fl, itp, VAccess::READ)); + AstNode* const offsetp + = m_mgOffset == 0 ? nullptr : new AstConst(fl, std::abs(m_mgOffset)); + AstNode* const lbitp = m_mgSelLp->bitp(); + AstNode* const lvrefp = new AstVarRef(fl, itp, VAccess::READ); + lbitp->replaceWith(m_mgOffset > 0 ? new AstAdd(fl, lvrefp, offsetp) : lvrefp); VL_DO_DANGLING(lbitp->deleteTree(), lbitp); if (m_mgSelRp) { // else constant and no replace - AstNode* rbitp = m_mgSelRp->bitp(); - rbitp->replaceWith(new AstVarRef(fl, itp, VAccess::READ)); + AstNode* const rbitp = m_mgSelRp->bitp(); + AstNode* const rvrefp = new AstVarRef(fl, itp, VAccess::READ); + rbitp->replaceWith(m_mgOffset < 0 ? new AstAdd(fl, rvrefp, offsetp) : rvrefp); VL_DO_DANGLING(rbitp->deleteTree(), lbitp); } if (debug() >= 9) initp->dumpTree(cout, "-new: "); @@ -133,6 +146,7 @@ private: m_mgSelRp = nullptr; m_mgVarrefLp = nullptr; m_mgVarrefRp = nullptr; + m_mgOffset = 0; m_mgConstRp = nullptr; } } @@ -143,6 +157,7 @@ private: { m_cfuncp = nodep; iterateChildren(nodep); + mergeEnd(); // Finish last pending merge, if any } } virtual void visit(AstNodeAssign* nodep) override { @@ -155,7 +170,7 @@ private: return; } // Of a constant index - AstConst* lbitp = VN_CAST(lselp->bitp(), Const); + AstConst* const lbitp = VN_CAST(lselp->bitp(), Const); if (!lbitp) { mergeEnd(); return; @@ -164,53 +179,58 @@ private: mergeEnd(); return; } - uint32_t index = lbitp->toUInt(); + const uint32_t lindex = lbitp->toUInt(); // Of variable - AstNodeVarRef* lvarrefp = VN_CAST(lselp->fromp(), NodeVarRef); + AstNodeVarRef* const lvarrefp = VN_CAST(lselp->fromp(), NodeVarRef); if (!lvarrefp) { mergeEnd(); return; } // RHS is a constant or a select - AstConst* rconstp = VN_CAST(nodep->rhsp(), Const); - AstNodeSel* rselp = VN_CAST(nodep->rhsp(), NodeSel); + AstConst* const rconstp = VN_CAST(nodep->rhsp(), Const); + AstNodeSel* const rselp = VN_CAST(nodep->rhsp(), NodeSel); AstNodeVarRef* rvarrefp = nullptr; + uint32_t rindex = lindex; if (rconstp) { // Ok - } else { - if (!rselp) { - mergeEnd(); - return; - } - AstConst* rbitp = VN_CAST(rselp->bitp(), Const); + } else if (rselp) { + AstConst* const rbitp = VN_CAST(rselp->bitp(), Const); rvarrefp = VN_CAST(rselp->fromp(), NodeVarRef); - if (!rbitp || rbitp->toUInt() != index || !rvarrefp - || lvarrefp->varp() == rvarrefp->varp()) { + if (!rbitp || !rvarrefp || lvarrefp->varp() == rvarrefp->varp()) { mergeEnd(); return; } + rindex = rbitp->toUInt(); + } else { + mergeEnd(); + return; } if (m_mgSelLp) { // Old merge - if (m_mgCfuncp == m_cfuncp && m_mgNextp == nodep && m_mgSelLp->same(lselp) - && m_mgVarrefLp->same(lvarrefp) - && (m_mgConstRp - ? (rconstp && m_mgConstRp->same(rconstp)) - : (rselp && m_mgSelRp->same(rselp) && m_mgVarrefRp->same(rvarrefp))) - && (index == m_mgIndexLo - 1 || index == m_mgIndexHi + 1)) { + if (m_mgCfuncp == m_cfuncp // In same function + && m_mgNextp == nodep // Consecutive node + && m_mgVarrefLp->same(lvarrefp) // Same array on left hand side + && (m_mgConstRp // On the right hand side either ... + ? (rconstp && m_mgConstRp->same(rconstp)) // ... same constant + : (rselp && m_mgVarrefRp->same(rvarrefp))) // ... or same array + && (lindex == m_mgIndexLo - 1 || lindex == m_mgIndexHi + 1) // Left index +/- 1 + && (m_mgConstRp || lindex == rindex + m_mgOffset) // Same right index offset + ) { // Sequentially next to last assign; continue merge - if (index == m_mgIndexLo - 1) { - m_mgIndexLo = index; - } else if (index == m_mgIndexHi + 1) { - m_mgIndexHi = index; + if (lindex == m_mgIndexLo - 1) { + m_mgIndexLo = lindex; + } else if (lindex == m_mgIndexHi + 1) { + m_mgIndexHi = lindex; } - UINFO(9, "Continue merge i=" << index << " " << m_mgIndexHi << ":" << m_mgIndexLo + UINFO(9, "Continue merge i=" << lindex << " " << m_mgIndexHi << ":" << m_mgIndexLo << " " << nodep << endl); m_mgAssignps.push_back(nodep); m_mgNextp = nodep->nextp(); return; } else { - // This assign doesn't merge with previous assign, + UINFO(9, "End merge i=" + << lindex << " " << m_mgIndexHi << ":" << m_mgIndexLo << " " << nodep + << endl); // This assign doesn't merge with previous assign, // but should start a new merge mergeEnd(); } @@ -224,10 +244,11 @@ private: m_mgSelRp = rselp; m_mgVarrefLp = lvarrefp; m_mgVarrefRp = rvarrefp; + m_mgOffset = static_cast(lindex) - static_cast(rindex); m_mgConstRp = rconstp; - m_mgIndexLo = index; - m_mgIndexHi = index; - UINFO(9, "Start merge i=" << index << " " << nodep << endl); + m_mgIndexLo = lindex; + m_mgIndexHi = lindex; + UINFO(9, "Start merge i=" << lindex << " o=" << m_mgOffset << nodep << endl); } //-------------------- virtual void visit(AstVar*) override {} // Accelerate diff --git a/test_regress/t/t_reloop_offset.out b/test_regress/t/t_reloop_offset.out new file mode 100644 index 000000000..bc7054287 --- /dev/null +++ b/test_regress/t/t_reloop_offset.out @@ -0,0 +1,17 @@ +shift down 1 +oarray[63] is 0 +oarray[62] is 63 +oarray[61] is 62 +oarray[32] is 33 +oarray[ 2] is 3 +oarray[ 1] is 2 +oarray[ 0] is 1 +shift up 2 +oarray[63] is 61 +oarray[62] is 60 +oarray[61] is 59 +oarray[32] is 30 +oarray[ 2] is 0 +oarray[ 1] is 2 +oarray[ 0] is 1 +*-* All Finished *-* diff --git a/test_regress/t/t_reloop_offset.pl b/test_regress/t/t_reloop_offset.pl new file mode 100755 index 000000000..02f1f01fc --- /dev/null +++ b/test_regress/t/t_reloop_offset.pl @@ -0,0 +1,33 @@ +#!/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( + verilator_flags2 => ["-unroll-count 1024", + $Self->wno_unopthreads_for_few_cores(), + "--stats"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, Reloop iterations\s+(\d+)/i, + 125); + file_grep($Self->{stats}, qr/Optimizations, Reloops\s+(\d+)/i, + 2); +} + +ok(1); +1; diff --git a/test_regress/t/t_reloop_offset.v b/test_regress/t/t_reloop_offset.v new file mode 100755 index 000000000..b4bfc4198 --- /dev/null +++ b/test_regress/t/t_reloop_offset.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +`define show(x) $display("oarray[%2d] is %2d", x, oarray[x]) + +module t (/*AUTOARG*/); + + int iarray [63:0]; + int oarray [63:0]; + + initial begin + for (int i = 0; i < 64 ; i = i + 1) begin + iarray[i] = i; + oarray[i] = 0; + end + + for (int i = 0; i < 63; i = i + 1) begin + oarray[i] = iarray[i + 1]; + end + + $display("shift down 1"); + `show(63); + `show(62); + `show(61); + `show(32); + `show(2); + `show(1); + `show(0); + + for (int i = 63; i >= 2 ; i = i - 1) begin + oarray[i] = iarray[i - 2]; + end + + $display("shift up 2"); + `show(63); + `show(62); + `show(61); + `show(32); + `show(2); + `show(1); + `show(0); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 1a6378291ac16484addec833f55a536bc85dbe6c Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 10 May 2021 22:15:12 +0100 Subject: [PATCH 24/80] Emit 'else if' without nesting. No functional change intended. (#2944) Instead of: if (a) { x; } else { if (b) { y; } else { if (c) { z; } else { w; } } } Emit: if (a) { x; } else if (b) { y; } else if (c) { z; } else { w; } --- src/V3EmitC.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index a8f4de8ea..3a8b4b89b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -812,11 +812,19 @@ public: if (!nodep->branchPred().unknown()) puts(")"); puts(") {\n"); iterateAndNextNull(nodep->ifsp()); - if (nodep->elsesp()) { - puts("} else {\n"); - iterateAndNextNull(nodep->elsesp()); + puts("}"); + if (!nodep->elsesp()) { + puts("\n"); + } else { + if (VN_IS(nodep->elsesp(), NodeIf) && !nodep->elsesp()->nextp()) { + puts(" else "); + iterateAndNextNull(nodep->elsesp()); + } else { + puts(" else {\n"); + iterateAndNextNull(nodep->elsesp()); + puts("}\n"); + } } - puts("}\n"); } virtual void visit(AstExprStmt* nodep) override { // GCC allows compound statements in expressions, but this is not standard. From 1422c2343454f972957bfe3b2b047a250c057316 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 11 May 2021 12:44:07 +0100 Subject: [PATCH 25/80] Split procedures to better respect --output-split-cfuncs (#2942) CFuncs only used to be split at procedure (always/initial/final block), which on occasion can still yield huge output files if they have large procedures. This patch make CFuncs split at statement boundaries within procedures. This has the potential to help a lot, but still does not help if there are huge statements within procedures. --- Changes | 1 + src/V3Order.cpp | 95 ++++++++++++++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/Changes b/Changes index 9891e89cb..b01f73847 100644 --- a/Changes +++ b/Changes @@ -37,6 +37,7 @@ Verilator 4.202 2021-04-24 * Support overlaps in priority case statements (#2864). [Rupert Swarbrick] * Support for null ports (#2875). [Udi Finkelstein] * Optimize large lookup tables to static data (#2925). [Geza Lore] +* Split always blocks to better respect --output-split-cfuncs. [Geza Lore] * Fix class unpacked-array compile error (#2774). [Iru Cai] * Fix scope types in FST and VCD traces (#2805). [Alex Torregrosa] * Fix exceeding command-line ar limit (#2834). [Yinan Xu] diff --git a/src/V3Order.cpp b/src/V3Order.cpp index b354a157d..9baa69c7a 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1723,50 +1723,73 @@ void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp, AstCFunc*& newFuncpr, int& newStmtsr) { AstActive* activep = nullptr; - AstScope* scopep = lvertexp->scopep(); - AstSenTree* domainp = lvertexp->domainp(); + AstScope* const scopep = lvertexp->scopep(); + AstSenTree* const domainp = lvertexp->domainp(); AstNode* nodep = lvertexp->nodep(); - AstNodeModule* modp = VN_CAST(scopep->user1p(), NodeModule); // Stashed by visitor func + AstNodeModule* const modp = VN_CAST(scopep->user1p(), NodeModule); // Stashed by visitor func UASSERT(modp, "nullptr"); if (VN_IS(nodep, SenTree)) { // Just ignore sensitivities, we'll deal with them when we move statements that need them } else { // Normal logic - // Make or borrow a CFunc to contain the new statements - if (v3Global.opt.profCFuncs() - || (v3Global.opt.outputSplitCFuncs() - && v3Global.opt.outputSplitCFuncs() < newStmtsr)) { - // Put every statement into a unique function to ease profiling or reduce function size - newFuncpr = nullptr; - } - if (!newFuncpr && domainp != m_deleteDomainp) { - string name = cfuncName(modp, domainp, scopep, nodep); - newFuncpr = new AstCFunc(nodep->fileline(), name, scopep); - newFuncpr->argTypes(EmitCBaseVisitor::symClassVar()); - newFuncpr->symProlog(true); - newStmtsr = 0; - if (domainp->hasInitial() || domainp->hasSettle()) newFuncpr->slow(true); - scopep->addActivep(newFuncpr); - // Where will we be adding the call? - activep = new AstActive(nodep->fileline(), name, domainp); - // Add a top call to it - AstCCall* callp = new AstCCall(nodep->fileline(), newFuncpr); - callp->argTypes("vlSymsp"); - activep->addStmtsp(callp); - UINFO(6, " New " << newFuncpr << endl); + // Move the logic into a CFunc + nodep->unlinkFrBack(); + + // Process procedures per statement (unless profCFuncs), so we can split CFuncs within + // procedures. Everything else is handled in one go + AstNodeProcedure* const procp = VN_CAST(nodep, NodeProcedure); + if (procp && !v3Global.opt.profCFuncs()) { + nodep = procp->bodysp(); + pushDeletep(procp); } - // Move the logic to the function we're creating - nodep->unlinkFrBack(); - if (domainp == m_deleteDomainp) { - UINFO(4, " Ordering deleting pre-settled " << nodep << endl); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - } else { - newFuncpr->addStmtsp(nodep); - if (v3Global.opt.outputSplitCFuncs()) { - // Add in the number of nodes we're adding - EmitCBaseCounterVisitor visitor(nodep); - newStmtsr += visitor.count(); + while (nodep) { + // Make or borrow a CFunc to contain the new statements + if (v3Global.opt.profCFuncs() + || (v3Global.opt.outputSplitCFuncs() + && v3Global.opt.outputSplitCFuncs() < newStmtsr)) { + // Put every statement into a unique function to ease profiling or reduce function + // size + newFuncpr = nullptr; } + if (!newFuncpr && domainp != m_deleteDomainp) { + const string name = cfuncName(modp, domainp, scopep, nodep); + newFuncpr = new AstCFunc(nodep->fileline(), name, scopep); + newFuncpr->argTypes(EmitCBaseVisitor::symClassVar()); + newFuncpr->symProlog(true); + newStmtsr = 0; + if (domainp->hasInitial() || domainp->hasSettle()) newFuncpr->slow(true); + scopep->addActivep(newFuncpr); + // Create top call to it + AstCCall* const callp = new AstCCall(nodep->fileline(), newFuncpr); + callp->argTypes("vlSymsp"); + // Where will we be adding the call? + AstActive* const newActivep = new AstActive(nodep->fileline(), name, domainp); + newActivep->addStmtsp(callp); + if (!activep) { + activep = newActivep; + } else { + activep->addNext(newActivep); + } + UINFO(6, " New " << newFuncpr << endl); + } + + AstNode* const nextp = nodep->nextp(); + // When processing statements in a procedure, unlink the current statement + if (nodep->backp()) nodep->unlinkFrBack(); + + if (domainp == m_deleteDomainp) { + UINFO(4, " Ordering deleting pre-settled " << nodep << endl); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { + newFuncpr->addStmtsp(nodep); + if (v3Global.opt.outputSplitCFuncs()) { + // Add in the number of nodes we're adding + EmitCBaseCounterVisitor visitor(nodep); + newStmtsr += visitor.count(); + } + } + + nodep = nextp; } } return activep; From 00cedf3797d3e6bd0ed215785f58e33a7dd299bb Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Tue, 11 May 2021 22:27:31 +0900 Subject: [PATCH 26/80] Tests: Add a test to check if there is overflow or rounding (#2945) --- test_regress/t/t_time_vpi.v | 3 +++ test_regress/t/t_time_vpi_100s10ms.out | 2 ++ test_regress/t/t_time_vpi_10ms10ns.out | 2 ++ test_regress/t/t_time_vpi_1fs1fs.out | 2 ++ test_regress/t/t_time_vpi_1ms10ns.out | 2 ++ test_regress/t/t_time_vpi_1ns1ns.out | 2 ++ test_regress/t/t_time_vpi_1ps1fs.out | 2 ++ test_regress/t/t_time_vpi_1s10ns.out | 2 ++ test_regress/t/t_time_vpi_1us1ns.out | 2 ++ 9 files changed, 19 insertions(+) diff --git a/test_regress/t/t_time_vpi.v b/test_regress/t/t_time_vpi.v index 84496b256..f1178d444 100644 --- a/test_regress/t/t_time_vpi.v +++ b/test_regress/t/t_time_vpi.v @@ -18,6 +18,7 @@ module t (/*AUTOARG*/ // verilator lint_off REALCVT time digits = 5432109876.543210ns; // Will round to time units realtime rdigits = 5432109876.543210ns; // Will round to time precision + time high_acc = 64'd12345678901234567890; // Would lose accuracy if calculated in double // verilator lint_on REALCVT always @ (posedge clk) begin @@ -31,10 +32,12 @@ module t (/*AUTOARG*/ $write("[%0t] time%%0d=%0d 123%%0t=%0t\n", $time, $time, 123); $write(" dig%%0t=%0t dig%%0d=%0d\n", digits, digits); $write(" rdig%%0t=%0t rdig%%0f=%0f\n", rdigits, rdigits); + $write(" acc%%0t=%0t acc%%0d=%0d\n", high_acc, high_acc); $timeformat(-9, 6, "ns", 16); $write("[%0t] time%%0d=%0d 123%%0t=%0t\n", $time, $time, 123); $write(" dig%%0t=%0t dig%%0d=%0d\n", digits, digits); $write(" rdig%%0t=%0t rdig%%0f=%0f\n", rdigits, rdigits); + $write(" acc%%0t=%0t acc%%0d=%0d\n", high_acc, high_acc); $write("[%0t] stime%%0t=%0t stime%%0d=%0d stime%%0f=%0f\n", $time, $stime, $stime, $stime); // verilator lint_off REALCVT diff --git a/test_regress/t/t_time_vpi_100s10ms.out b/test_regress/t/t_time_vpi_100s10ms.out index 7cb4c886d..c581dbf6c 100644 --- a/test_regress/t/t_time_vpi_100s10ms.out +++ b/test_regress/t/t_time_vpi_100s10ms.out @@ -3,9 +3,11 @@ Time scale of t is 100s / 10ms [100000000] time%0d=10000 123%0t=1230000 dig%0t=0 dig%0d=0 rdig%0t=543 rdig%0f=0.054321 + acc%0t=11177671081359484928 acc%0d=12345678901234567890 [1000000000000000.000000ns] time%0d=10000 123%0t=12300000000000.000000ns dig%0t=0.000000ns dig%0d=0 rdig%0t=5432109876.543210ns rdig%0f=0.054321 + acc%0t=111776710813594856498135040.000000ns acc%0d=12345678901234567890 [1000000000000000.000000ns] stime%0t=1000000000000000.000000ns stime%0d=10000 stime%0f=10000.000000 [1000000000000000.000000ns] rtime%0t=1000000000000000.000000ns rtime%0d=10000 rtime%0f=10000.000000 global vpiSimTime = 0,100000000 vpiScaledRealTime = 1e+08 diff --git a/test_regress/t/t_time_vpi_10ms10ns.out b/test_regress/t/t_time_vpi_10ms10ns.out index faa888180..4b7180883 100644 --- a/test_regress/t/t_time_vpi_10ms10ns.out +++ b/test_regress/t/t_time_vpi_10ms10ns.out @@ -3,9 +3,11 @@ Time scale of t is 10ms / 10ns [60000000] time%0d=60 123%0t=123000000 dig%0t=543000000 dig%0d=543 rdig%0t=543210988 rdig%0f=543.210988 + acc%0t=10962463713375475712 acc%0d=12345678901234567890 [600000000.000000ns] time%0d=60 123%0t=1230000000.000000ns dig%0t=5430000000.000000ns dig%0d=543 rdig%0t=5432109876.543210ns rdig%0f=543.210988 + acc%0t=109624637133754744832.000000ns acc%0d=12345678901234567890 [600000000.000000ns] stime%0t=600000000.000000ns stime%0d=60 stime%0f=60.000000 [600000000.000000ns] rtime%0t=600000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000000 vpiScaledRealTime = 6e+07 diff --git a/test_regress/t/t_time_vpi_1fs1fs.out b/test_regress/t/t_time_vpi_1fs1fs.out index 680d87168..612a7023b 100644 --- a/test_regress/t/t_time_vpi_1fs1fs.out +++ b/test_regress/t/t_time_vpi_1fs1fs.out @@ -3,9 +3,11 @@ Time scale of t is 1fs / 1fs [60] time%0d=60 123%0t=123 dig%0t=5432109876543210 dig%0d=5432109876543210 rdig%0t=5432109876543210 rdig%0f=5432109876543210.000000 + acc%0t=12345678901234567168 acc%0d=12345678901234567890 [0.000060ns] time%0d=60 123%0t=0.000123ns dig%0t=5432109876.543210ns dig%0d=5432109876543210 rdig%0t=5432109876.543210ns rdig%0f=5432109876543210.000000 + acc%0t=12345678901234.566406ns acc%0d=12345678901234567890 [0.000060ns] stime%0t=0.000060ns stime%0d=60 stime%0f=60.000000 [0.000060ns] rtime%0t=0.000060ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1ms10ns.out b/test_regress/t/t_time_vpi_1ms10ns.out index 5c279c04b..a6e35ad26 100644 --- a/test_regress/t/t_time_vpi_1ms10ns.out +++ b/test_regress/t/t_time_vpi_1ms10ns.out @@ -3,9 +3,11 @@ Time scale of t is 1ms / 10ns [6000000] time%0d=60 123%0t=12300000 dig%0t=543200000 dig%0d=5432 rdig%0t=543210988 rdig%0f=5432.109877 + acc%0t=1096246371337547520 acc%0d=12345678901234567890 [60000000.000000ns] time%0d=60 123%0t=123000000.000000ns dig%0t=5432000000.000000ns dig%0d=5432 rdig%0t=5432109876.543210ns rdig%0f=5432.109877 + acc%0t=10962463713375473664.000000ns acc%0d=12345678901234567890 [60000000.000000ns] stime%0t=60000000.000000ns stime%0d=60 stime%0f=60.000000 [60000000.000000ns] rtime%0t=60000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,6000000 vpiScaledRealTime = 6e+06 diff --git a/test_regress/t/t_time_vpi_1ns1ns.out b/test_regress/t/t_time_vpi_1ns1ns.out index 83c8cd9f6..05e68341c 100644 --- a/test_regress/t/t_time_vpi_1ns1ns.out +++ b/test_regress/t/t_time_vpi_1ns1ns.out @@ -3,9 +3,11 @@ Time scale of t is 1ns / 1ns [60] time%0d=60 123%0t=123 dig%0t=5432109877 dig%0d=5432109877 rdig%0t=5432109877 rdig%0f=5432109876.543210 + acc%0t=12345678901234567168 acc%0d=12345678901234567890 [60.000000ns] time%0d=60 123%0t=123.000000ns dig%0t=5432109877.000000ns dig%0d=5432109877 rdig%0t=5432109876.543210ns rdig%0f=5432109876.543210 + acc%0t=12345678901234565120.000000ns acc%0d=12345678901234567890 [60.000000ns] stime%0t=60.000000ns stime%0d=60 stime%0f=60.000000 [60.000000ns] rtime%0t=60.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1ps1fs.out b/test_regress/t/t_time_vpi_1ps1fs.out index bd62df6af..35ab855e0 100644 --- a/test_regress/t/t_time_vpi_1ps1fs.out +++ b/test_regress/t/t_time_vpi_1ps1fs.out @@ -3,9 +3,11 @@ Time scale of t is 1ps / 1fs [60000] time%0d=60 123%0t=123000 dig%0t=5432109876543000 dig%0d=5432109876543 rdig%0t=5432109876543209 rdig%0f=5432109876543.209961 + acc%0t=4807115922877858816 acc%0d=12345678901234567890 [0.060000ns] time%0d=60 123%0t=0.123000ns dig%0t=5432109876.543000ns dig%0d=5432109876543 rdig%0t=5432109876.543209ns rdig%0f=5432109876543.209961 + acc%0t=4807115922877.858398ns acc%0d=12345678901234567890 [0.060000ns] stime%0t=0.060000ns stime%0d=60 stime%0f=60.000000 [0.060000ns] rtime%0t=0.060000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 diff --git a/test_regress/t/t_time_vpi_1s10ns.out b/test_regress/t/t_time_vpi_1s10ns.out index 15d1750a9..f9a17a8f8 100644 --- a/test_regress/t/t_time_vpi_1s10ns.out +++ b/test_regress/t/t_time_vpi_1s10ns.out @@ -3,9 +3,11 @@ Time scale of t is 1s / 10ns [6000000000] time%0d=60 123%0t=12300000000 dig%0t=500000000 dig%0d=5 rdig%0t=543210988 rdig%0f=5.432110 + acc%0t=7888470988684038144 acc%0d=12345678901234567890 [60000000000.000000ns] time%0d=60 123%0t=123000000000.000000ns dig%0t=5000000000.000000ns dig%0d=5 rdig%0t=5432109876.543210ns rdig%0f=5.432110 + acc%0t=78884709886840389632.000000ns acc%0d=12345678901234567890 [60000000000.000000ns] stime%0t=60000000000.000000ns stime%0d=60 stime%0f=60.000000 [60000000000.000000ns] rtime%0t=60000000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 1,1705032704 vpiScaledRealTime = 6e+09 diff --git a/test_regress/t/t_time_vpi_1us1ns.out b/test_regress/t/t_time_vpi_1us1ns.out index e6b5dd50b..4c2c152d0 100644 --- a/test_regress/t/t_time_vpi_1us1ns.out +++ b/test_regress/t/t_time_vpi_1us1ns.out @@ -3,9 +3,11 @@ Time scale of t is 1us / 1ns [60000] time%0d=60 123%0t=123000 dig%0t=5432110000 dig%0d=5432110 rdig%0t=5432109877 rdig%0f=5432109.876543 + acc%0t=4807115922877858816 acc%0d=12345678901234567890 [60000.000000ns] time%0d=60 123%0t=123000.000000ns dig%0t=5432110000.000000ns dig%0d=5432110 rdig%0t=5432109876.543209ns rdig%0f=5432109.876543 + acc%0t=4807115922877858816.000000ns acc%0d=12345678901234567890 [60000.000000ns] stime%0t=60000.000000ns stime%0d=60 stime%0f=60.000000 [60000.000000ns] rtime%0t=60000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 From f7c23c4adeb8f2d628599d591b1c7d03c8373c7f Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Tue, 11 May 2021 22:38:13 +0900 Subject: [PATCH 27/80] Internals: Set missing timescale though it is not referred yet. (#2946) --- src/V3Assert.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 5ee211b09..8b53adf95 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -108,6 +108,7 @@ private: // Like newFireAssert() but omits the asserts-on check AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message, nullptr, nullptr); + dispp->fmtp()->timeunit(m_modp->timeunit()); AstNode* bodysp = dispp; replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format bodysp->addNext(new AstStop(nodep->fileline(), true)); From e3b20a3ea228f46d9178cb71dfc1ffd7880cd7db Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Wed, 12 May 2021 00:45:43 +0900 Subject: [PATCH 28/80] Internals: Mark VerilatedContextImp::timeFormatSuffix() const (#2947) --- include/verilated_imp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/verilated_imp.h b/include/verilated_imp.h index e1b3d30da..584213b38 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -245,7 +245,7 @@ public: // But only for verilated*.cpp static vluint32_t randSeedEpoch() VL_MT_SAFE { return s().s_randSeedEpoch; } // METHODS - timeformat - int timeFormatUnits() VL_MT_SAFE { + int timeFormatUnits() const VL_MT_SAFE { if (m_s.m_timeFormatUnits == VerilatedContext::Serialized::UNITS_NONE) return timeprecision(); return m_s.m_timeFormatUnits; @@ -255,7 +255,7 @@ public: // But only for verilated*.cpp void timeFormatPrecision(int value) VL_MT_SAFE { m_s.m_timeFormatPrecision = value; } int timeFormatWidth() const VL_MT_SAFE { return m_s.m_timeFormatWidth; } void timeFormatWidth(int value) VL_MT_SAFE { m_s.m_timeFormatWidth = value; } - std::string timeFormatSuffix() VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) { + std::string timeFormatSuffix() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) { const VerilatedLockGuard lock(m_timeDumpMutex); return m_timeFormatSuffix; } From 9c85426e7768d8b79abc12504e44a2f2bb96e2d1 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Thu, 13 May 2021 06:45:56 +0900 Subject: [PATCH 29/80] Internals: Fix build failure on older gcc such as 4.8.5 on CentOS7. No functional change is intended. (#2954) --- src/V3OptionParser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3OptionParser.h b/src/V3OptionParser.h index fe3d0b703..a42c5fca2 100644 --- a/src/V3OptionParser.h +++ b/src/V3OptionParser.h @@ -139,7 +139,7 @@ public: // CONSTRUCTORS explicit AppendHelper(V3OptionParser& parser) - : m_parser{parser} {} + : m_parser(parser) {} }; #define V3OPTION_PARSER_DECL_TAGS \ From a4ab3e12f64e50008c02263471b877d973e99f58 Mon Sep 17 00:00:00 2001 From: Ameya Vikram Singh Date: Thu, 13 May 2021 23:56:53 +0530 Subject: [PATCH 30/80] Update latest C++ Standard Compilation flag (#2951) For SystemC Project sets the CXX_STANDARD flag from SystemC CMake build config. --- configure.ac | 10 +++++++--- docs/CONTRIBUTORS | 1 + examples/cmake_hello_sc/CMakeLists.txt | 7 ++++++- examples/cmake_tracing_sc/CMakeLists.txt | 7 ++++++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 6f82920b9..5dd1ed07c 100644 --- a/configure.ac +++ b/configure.ac @@ -272,13 +272,15 @@ AC_DEFUN([_MY_LDLIBS_CHECK_OPT], # Flag to select newest language standard supported # Macros work such that first option that passes is the one we take -# gnu++17 code is clean, but SystemC in 2018 doesn't link with it (bug1339) -# gnu++14 is the newest that Verilator supports +# Currently enabled gnu++14/c++14 due to packaged SystemC dependency +# gnu++17 is the newest that Verilator supports enable flags according to one's environment. # std++03 is the oldest that Verilator supports +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++20) #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++17) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++14) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++11) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++03) +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++20) #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++17) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++14) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++11) @@ -289,11 +291,13 @@ AC_SUBST(CFG_CXXFLAGS_STD_NEWEST) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++03) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++11) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++14) -#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=std++17) +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++17) +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++20) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++03) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++11) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++14) #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++17) +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++20) AC_SUBST(CFG_CXXFLAGS_STD_OLDEST) # Flags for compiling Verilator internals including parser, and Verilated files diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 2196c9c2e..3293cb65f 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -6,6 +6,7 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all. Ahmed El-Mahmoudy Alex Chadwick Àlex Torregrosa +Ameya Vikram Singh Andreas Kuster Chris Randall Conor McCullough diff --git a/examples/cmake_hello_sc/CMakeLists.txt b/examples/cmake_hello_sc/CMakeLists.txt index 211b73170..490391c12 100644 --- a/examples/cmake_hello_sc/CMakeLists.txt +++ b/examples/cmake_hello_sc/CMakeLists.txt @@ -20,7 +20,7 @@ # cmake --build . cmake_minimum_required(VERSION 3.8) -project(cmake_hello_sc) +project(cmake_hello_sc CXX) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) if (NOT verilator_FOUND) @@ -37,6 +37,11 @@ find_package(SystemCLanguage QUIET) # Create a new executable target that will contain all your sources add_executable(example ../make_hello_sc/sc_main.cpp) +set_property( + TARGET example + PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD} + ) + # Add the Verilated circuit to the target verilate(example SYSTEMC INCLUDE_DIRS "../make_hello_sc" diff --git a/examples/cmake_tracing_sc/CMakeLists.txt b/examples/cmake_tracing_sc/CMakeLists.txt index eb785d76a..a06af17f8 100644 --- a/examples/cmake_tracing_sc/CMakeLists.txt +++ b/examples/cmake_tracing_sc/CMakeLists.txt @@ -20,7 +20,7 @@ # cmake --build . cmake_minimum_required(VERSION 3.8) -project(cmake_tracing_sc_example) +project(cmake_tracing_sc_example CXX) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) if (NOT verilator_FOUND) @@ -37,6 +37,11 @@ find_package(SystemCLanguage QUIET) # Create a new executable target that will contain all your sources add_executable(example ../make_tracing_sc/sc_main.cpp) +set_property( + TARGET example + PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD} + ) + # Add the Verilated circuit to the target verilate(example SYSTEMC COVERAGE TRACE INCLUDE_DIRS "../make_tracing_sc" From 3718fe1ca14735a510ef642c1c6f873d47229a00 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 13 May 2021 18:34:20 -0400 Subject: [PATCH 31/80] Commentary (trigger rebuild) --- configure.ac | 2 +- include/verilatedos.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5dd1ed07c..00fc24e25 100644 --- a/configure.ac +++ b/configure.ac @@ -273,7 +273,7 @@ AC_DEFUN([_MY_LDLIBS_CHECK_OPT], # Flag to select newest language standard supported # Macros work such that first option that passes is the one we take # Currently enabled gnu++14/c++14 due to packaged SystemC dependency -# gnu++17 is the newest that Verilator supports enable flags according to one's environment. +# gnu++17 is the newest that Verilator supports # std++03 is the oldest that Verilator supports #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++20) #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++17) diff --git a/include/verilatedos.h b/include/verilatedos.h index 4b1b0874d..06d07d3a6 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -437,6 +437,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type (((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL) /// Return mask for EData with 1's where relevant bits are (0=all bits) #define VL_MASK_E(nbits) VL_MASK_I(nbits) + #define VL_EUL(n) VL_UL(n) // Make constant number EData sized #define VL_BITWORD_I(bit) ((bit) / VL_IDATASIZE) ///< Word number for sv DPI vectors From 88fed4bc2fd408926e2518c8cf9f489ffb7baa30 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 13 May 2021 18:56:07 -0400 Subject: [PATCH 32/80] Commentary on traces (#2925) --- docs/guide/faq.rst | 14 ++++++++------ include/verilated_fst_c.h | 2 ++ include/verilated_vcd_c.h | 2 ++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/guide/faq.rst b/docs/guide/faq.rst index ca99d5e7e..5628828ec 100644 --- a/docs/guide/faq.rst +++ b/docs/guide/faq.rst @@ -118,9 +118,9 @@ A. Pass the :vlopt:`--trace` option to Verilator, and in your top level C B. Or, for finer-grained control, or C++ files with multiple Verilated modules you may also create the trace purely from C++. Create a - VerilatedVcdC object, and in your main loop call - ``trace_object->dump(time)`` every time step, and finally call - ``trace_object->close()``. + VerilatedVcdC object, and in your main loop right after ``eval()`` call + ``trace_object->dump(contextp->time())`` every time step, and finally + call ``trace_object->close()``. .. code-block:: C++ :emphasize-lines: 1,5-8,12 @@ -128,15 +128,17 @@ B. Or, for finer-grained control, or C++ files with multiple Verilated #include "verilated_vcd_c.h" ... int main(int argc, char** argv, char** env) { + const std::unique_ptr contextp{new VerilatedContext}; ... Verilated::traceEverOn(true); VerilatedVcdC* tfp = new VerilatedVcdC; topp->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("obj_dir/t_trace_ena_cc/simx.vcd"); ... - while (Verilated::time() < sim_time && !Verilated::gotFinish()) { - Verilated::timeInc(1); - tfp->dump(main_time); + while (contextp->time() < sim_time && !contextp->gotFinish()) { + contextp->timeInc(1); + topp->eval(); + tfp->dump(contextp->time()); } tfp->close(); } diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 3a8e404c5..2426a3e5a 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -152,6 +152,8 @@ public: /// Flush dump void flush() VL_MT_SAFE { m_sptrace.flush(); } /// Write one cycle of dump data + /// Call with the current context's time just after eval'ed, + /// e.g. ->dump(contextp->time()) void dump(vluint64_t timeui) { m_sptrace.dump(timeui); } /// Write one cycle of dump data - backward compatible and to reduce /// conversion warnings. It's better to use a vluint64_t time instead. diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index f6fdd1494..d167d3977 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -368,6 +368,8 @@ public: /// Flush dump void flush() VL_MT_SAFE { m_sptrace.flush(); } /// Write one cycle of dump data + /// Call with the current context's time just after eval'ed, + /// e.g. ->dump(contextp->time()) void dump(vluint64_t timeui) VL_MT_SAFE { m_sptrace.dump(timeui); } /// Write one cycle of dump data - backward compatible and to reduce /// conversion warnings. It's better to use a vluint64_t time instead. From 5e95cc92806400db6b80a994f18e7929f9ba86cd Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 15 May 2021 15:56:28 +0100 Subject: [PATCH 33/80] Internals: Make AstAlwaysPost an AstNodeProcedure. (#2959) This seems to belong there, eliminates some code duplication in V3Clock, and also enables splitting AstAlwaysPost statements into different functions in V3Order, but should otherwise have little effect. --- src/V3AstNodes.h | 25 +++++++++++-------------- src/V3Clock.cpp | 14 -------------- src/V3Delayed.cpp | 2 +- 3 files changed, 12 insertions(+), 29 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index ba1e6dc9b..b9e067989 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3349,6 +3349,7 @@ public: void sensesp(AstSenTree* nodep) { setOp1p(nodep); } VAlwaysKwd keyword() const { return m_keyword; } }; + class AstAlwaysPostponed final : public AstNodeProcedure { // Like always but postponement scheduling region @@ -3358,6 +3359,16 @@ public: ASTNODE_NODE_FUNCS(AlwaysPostponed) }; +class AstAlwaysPost final : public AstNodeProcedure { + // Like always but post assignments for memory assignment IFs +public: + AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) + : ASTGEN_SUPER(fl, bodysp) { + addNOp1p(sensesp); + } + ASTNODE_NODE_FUNCS(AlwaysPost) +}; + class AstAlwaysPublic final : public AstNodeStmt { // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ // Body statements are just AstVarRefs to the public signals @@ -3378,20 +3389,6 @@ public: bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } }; -class AstAlwaysPost final : public AstNode { - // Like always but post assignments for memory assignment IFs -public: - AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { - addNOp1p(sensesp); - addNOp2p(bodysp); - } - ASTNODE_NODE_FUNCS(AlwaysPost) - // - AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate - void addBodysp(AstNode* newp) { addOp2p(newp); } -}; - class AstAssign final : public AstNodeAssign { public: AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp) diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index eb5cd526c..05620b081 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -301,20 +301,6 @@ private: } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstAlwaysPost* nodep) override { - if (AstNode* stmtsp = nodep->bodysp()) { - stmtsp->unlinkFrBackWithNext(); - nodep->addNextHere(stmtsp); - } - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - virtual void visit(AstAlwaysPostponed* nodep) override { - if (AstNode* stmtsp = nodep->bodysp()) { - stmtsp->unlinkFrBackWithNext(); - nodep->addNextHere(stmtsp); - } - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } virtual void visit(AstCoverToggle* nodep) override { // nodep->dumpTree(cout, "ct:"); // COVERTOGGLE(INC, ORIG, CHANGE) -> diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index eaf5fb60d..66d1ff33e 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -351,7 +351,7 @@ private: new AstVarRef(nodep->fileline(), setvscp, VAccess::READ), nullptr, nullptr); UINFO(9, " Created " << postLogicp << endl); - finalp->addBodysp(postLogicp); + finalp->addStmtp(postLogicp); finalp->user3p(setvscp); // Remember IF's vset variable finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it } From 828f78ece4df43aa36fe86689baee67385f2a915 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 15 May 2021 16:05:24 +0100 Subject: [PATCH 34/80] Don't emit empty files with low split limits (#2961) Attempt to split output files when we know a function will actually be emitted, otherwise we might end up with empty files. --- src/V3EmitC.cpp | 97 +++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 3a8b4b89b..0ad110a5d 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1343,6 +1343,7 @@ unsigned EmitVarTspSorter::s_serialNext = 0; class EmitCImp final : EmitCStmts { // MEMBERS AstNodeModule* m_modp = nullptr; + AstNodeModule* m_fileModp = nullptr; // Files (names, headers) constructed using this module std::vector m_blkChangeDetVec; // All encountered changes in block bool m_slow = false; // Creating __Slow file bool m_fast = false; // Creating non __Slow file (or both) @@ -1391,8 +1392,8 @@ class EmitCImp final : EmitCStmts { } } - V3OutCFile* newOutCFile(AstNodeModule* modp, bool slow, bool source, int filenum = 0) { - string filenameNoExt = v3Global.opt.makeDir() + "/" + prefixNameProtect(modp); + V3OutCFile* newOutCFile(bool slow, bool source, int filenum = 0) { + string filenameNoExt = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp); if (filenum) filenameNoExt += "__" + cvtToStr(filenum); filenameNoExt += (slow ? "__Slow" : ""); V3OutCFile* ofp = nullptr; @@ -1413,7 +1414,7 @@ class EmitCImp final : EmitCStmts { } ofp->putsHeader(); - if (modp->isTop() && !source) { + if (m_fileModp->isTop() && !source) { ofp->puts("// DESCR" "IPTION: Verilator output: Primary design header\n"); ofp->puts("//\n"); @@ -1501,7 +1502,10 @@ class EmitCImp final : EmitCStmts { } virtual void visit(AstMTaskBody* nodep) override { - ExecMTask* mtp = nodep->execMTaskp(); + maybeSplit(); + splitSizeInc(10); + + const ExecMTask* const mtp = nodep->execMTaskp(); puts("\n"); puts("void "); puts(prefixNameProtect(m_modp) + "::" + protect(mtp->cFuncName())); @@ -1525,6 +1529,8 @@ class EmitCImp final : EmitCStmts { if (nodep->dpiImport()) return; if (!(nodep->slow() ? m_slow : m_fast)) return; + maybeSplit(); + m_blkChangeDetVec.clear(); splitSizeInc(nodep); @@ -1868,8 +1874,8 @@ class EmitCImp final : EmitCStmts { void emitSavableImp(AstNodeModule* modp); void emitTextSection(AstType type); // High level - void emitImpTop(AstNodeModule* modp); - void emitImp(AstNodeModule* fileModp, AstNodeModule* modp); + void emitImpTop(); + void emitImp(AstNodeModule* modp); void emitSettleLoop(const std::string& eval_call, bool initial); void emitWrapEval(AstNodeModule* modp); void emitWrapFast(AstNodeModule* modp); @@ -1877,7 +1883,7 @@ class EmitCImp final : EmitCStmts { void emitMTaskVertexCtors(bool* firstp); void emitIntTop(AstNodeModule* modp); void emitInt(AstNodeModule* modp); - void maybeSplit(AstNodeModule* modp); + void maybeSplit(); public: EmitCImp() = default; @@ -3351,9 +3357,9 @@ void EmitCImp::emitInt(AstNodeModule* modp) { //---------------------------------------------------------------------- -void EmitCImp::emitImpTop(AstNodeModule* fileModp) { +void EmitCImp::emitImpTop() { puts("\n"); - puts("#include \"" + prefixNameProtect(fileModp) + ".h\"\n"); + puts("#include \"" + prefixNameProtect(m_fileModp) + ".h\"\n"); puts("#include \"" + symClassName() + ".h\"\n"); if (v3Global.dpi()) { @@ -3361,13 +3367,13 @@ void EmitCImp::emitImpTop(AstNodeModule* fileModp) { puts("#include \"verilated_dpi.h\"\n"); } - emitModCUse(fileModp, VUseType::IMP_INCLUDE); - emitModCUse(fileModp, VUseType::IMP_FWD_CLASS); + emitModCUse(m_fileModp, VUseType::IMP_INCLUDE); + emitModCUse(m_fileModp, VUseType::IMP_FWD_CLASS); emitTextSection(AstType::atScImpHdr); } -void EmitCImp::emitImp(AstNodeModule* fileModp, AstNodeModule* modp) { +void EmitCImp::emitImp(AstNodeModule* modp) { puts("\n//==========\n"); if (m_slow) { string section; @@ -3389,37 +3395,33 @@ void EmitCImp::emitImp(AstNodeModule* fileModp, AstNodeModule* modp) { // Blocks for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { - if (AstCFunc* funcp = VN_CAST(nodep, CFunc)) { - maybeSplit(fileModp); - mainDoFunc(funcp); - } + if (AstCFunc* funcp = VN_CAST(nodep, CFunc)) { mainDoFunc(funcp); } } } //###################################################################### -void EmitCImp::maybeSplit(AstNodeModule* fileModp) { - if (splitNeeded()) { - // Splitting file, so using parallel build. - v3Global.useParallelBuild(true); - // Close old file - VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); - // Open a new file - m_ofp = newOutCFile(fileModp, !m_fast, true /*source*/, splitFilenumInc()); - emitImpTop(fileModp); - } - splitSizeInc(10); // Even blank functions get a file with a low csplit +void EmitCImp::maybeSplit() { + if (!splitNeeded()) return; + + // Splitting file, so using parallel build. + v3Global.useParallelBuild(true); + // Close old file + VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); + // Open a new file + m_ofp = newOutCFile(!m_fast, true /*source*/, splitFilenumInc()); + emitImpTop(); } void EmitCImp::mainInt(AstNodeModule* modp) { - AstNodeModule* fileModp = modp; // Filename constructed using this module m_modp = modp; + m_fileModp = modp; m_slow = true; m_fast = true; UINFO(5, " Emitting " << prefixNameProtect(modp) << endl); - m_ofp = newOutCFile(fileModp, false /*slow*/, false /*source*/); + m_ofp = newOutCFile(false /*slow*/, false /*source*/); emitIntTop(modp); emitInt(modp); if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) { @@ -3434,23 +3436,23 @@ void EmitCImp::mainInt(AstNodeModule* modp) { void EmitCImp::mainImp(AstNodeModule* modp, bool slow) { // Output a module - AstNodeModule* fileModp = modp; // Filename constructed using this module m_modp = modp; + m_fileModp = modp; m_slow = slow; m_fast = !slow; UINFO(5, " Emitting " << prefixNameProtect(modp) << endl); - m_ofp = newOutCFile(fileModp, !m_fast, true /*source*/); - emitImpTop(fileModp); - emitImp(fileModp, modp); + m_ofp = newOutCFile(!m_fast, true /*source*/); + emitImpTop(); + emitImp(modp); if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) { // Put the non-static class implementation in same C++ files as // often optimizations are possible when both are seen by the // compiler together m_modp = packagep->classp(); - emitImp(fileModp, packagep->classp()); + emitImp(packagep->classp()); m_modp = modp; } @@ -3463,7 +3465,6 @@ void EmitCImp::mainImp(AstNodeModule* modp, bool slow) { vxp = vxp->verticesNextp()) { const ExecMTask* mtaskp = dynamic_cast(vxp); if (mtaskp->threadRoot()) { - maybeSplit(fileModp); // Only define one function for all the mtasks packed on // a given thread. We'll name this function after the // root mtask though it contains multiple mtasks' worth @@ -3938,21 +3939,29 @@ void V3EmitC::emitc() { for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage - // clang-format off - EmitCImp cint; cint.mainInt(nodep); - cint.mainImp(nodep, true); - { EmitCImp fast; fast.mainImp(nodep, false); } - // clang-format on + { + EmitCImp cint; + cint.mainInt(nodep); + cint.mainImp(nodep, true); + } + { + EmitCImp fast; + fast.mainImp(nodep, false); + } } } void V3EmitC::emitcTrace() { UINFO(2, __FUNCTION__ << ": " << endl); if (v3Global.opt.trace()) { - // clang-format off - { EmitCTrace slow(true); slow.main(); } - { EmitCTrace fast(false); fast.main(); } - // clang-format on + { + EmitCTrace slow(true); + slow.main(); + } + { + EmitCTrace fast(false); + fast.main(); + } } } From 38cab569ed2c58218c2b09acfdb89816f91d531b Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 15 May 2021 18:04:40 +0100 Subject: [PATCH 35/80] Add --reloop-limit argument (#2960) Add --reloop-limit argument --- Changes | 1 + bin/verilator | 1 + docs/guide/exe_verilator.rst | 9 ++++++ src/V3Options.cpp | 4 +++ src/V3Options.h | 2 ++ src/V3Reloop.cpp | 4 +-- test_regress/t/t_reloop_offset_lim_63.pl | 37 ++++++++++++++++++++++++ 7 files changed, 55 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_reloop_offset_lim_63.pl diff --git a/Changes b/Changes index b01f73847..c5888960a 100644 --- a/Changes +++ b/Changes @@ -34,6 +34,7 @@ Verilator 4.202 2021-04-24 * Add VerilatedCovContext::forcePerInstance (#2793). [Kevin Laeufer] * Add FST SystemC tracing (#2806). [Alex Torregrosa] * Add PINNOTFOUND warning in place of error (#2868). [Udi Finkelstein] +* Add --reloop-limit argument (#2943). [Geza Lore] * Support overlaps in priority case statements (#2864). [Rupert Swarbrick] * Support for null ports (#2875). [Udi Finkelstein] * Optimize large lookup tables to static data (#2925). [Geza Lore] diff --git a/bin/verilator b/bin/verilator index 9e1ce7094..706de8e28 100755 --- a/bin/verilator +++ b/bin/verilator @@ -378,6 +378,7 @@ detailed descriptions of these arguments. --quiet-exit Don't print the command on failure --relative-includes Resolve includes relative to current file --no-relative-cfuncs Disallow 'this->' in generated functions + --reloop-limit Minimum iterations for forming loops --report-unoptflat Extra diagnostics for UNOPTFLAT --rr Run Verilator and record with rr --savable Enable model save-restore diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index f7cf6dbd4..eedfd9683 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -915,6 +915,15 @@ Summary: the path of the referencing file, instead of relative to the current directory. +.. option:: --reloop-limit + + Rarely needed. Verilator attempts to turn some common sequences of + statements into loops in the output. This argument specifies the minimum + number of iterations the resulting loop needs to have in order to perform + this transformation. Default limit is 40. A smaller number may slightly + improve C++ compilation time on designs where these sequences are common, + however effect on model performance requires benchmarking. + .. option:: --report-unoptflat Extra diagnostics for UNOPTFLAT warnings. This includes for each loop, diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 7533f01a8..f816b7d41 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1242,6 +1242,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char fl->v3warn(DEPRECATED, "Deprecated --no-relative-cfuncs, unnecessary with C++11."); }); DECL_OPTION("-relative-includes", OnOff, &m_relativeIncludes); + DECL_OPTION("-reloop-limit", CbVal, [this, fl](const char* valp) { + m_reloopLimit = std::atoi(valp); + if (m_reloopLimit < 2) { fl->v3error("--reloop-limit must be >= 2: " << valp); } + }); DECL_OPTION("-report-unoptflat", OnOff, &m_reportUnoptflat); DECL_OPTION("-rr", CbCall, []() {}); // Processed only in bin/verilator shell diff --git a/src/V3Options.h b/src/V3Options.h index 7cb64f2ea..4d3bd8612 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -295,6 +295,7 @@ private: int m_outputSplitCFuncs = -1; // main switch: --output-split-cfuncs int m_outputSplitCTrace = -1; // main switch: --output-split-ctrace int m_pinsBv = 65; // main switch: --pins-bv + int m_reloopLimit = 40; // main switch: --reloop-limit VOptionBool m_skipIdentical; // main switch: --skip-identical int m_threads = 0; // main switch: --threads (0 == --no-threads) int m_threadsMaxMTasks = 0; // main switch: --threads-max-mtasks @@ -491,6 +492,7 @@ public: int outputSplitCFuncs() const { return m_outputSplitCFuncs; } int outputSplitCTrace() const { return m_outputSplitCTrace; } int pinsBv() const { return m_pinsBv; } + int reloopLimit() const { return m_reloopLimit; } VOptionBool skipIdentical() const { return m_skipIdentical; } int threads() const { return m_threads; } int threadsMaxMTasks() const { return m_threadsMaxMTasks; } diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index facf7497e..96e6a4dc8 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -39,8 +39,6 @@ #include -constexpr unsigned RELOOP_MIN_ITERS = 40; // Need at least this many loops to do this optimization - //###################################################################### class ReloopVisitor final : public AstNVisitor { @@ -85,7 +83,7 @@ private: uint32_t items = m_mgIndexHi - m_mgIndexLo + 1; UINFO(9, "End merge iter=" << items << " " << m_mgIndexHi << ":" << m_mgIndexLo << " " << m_mgOffset << " " << m_mgAssignps[0] << endl); - if (items >= RELOOP_MIN_ITERS) { + if (items >= static_cast(v3Global.opt.reloopLimit())) { UINFO(6, "Reloop merging items=" << items << " " << m_mgIndexHi << ":" << m_mgIndexLo << " " << m_mgOffset << " " << m_mgAssignps[0] << endl); diff --git a/test_regress/t/t_reloop_offset_lim_63.pl b/test_regress/t/t_reloop_offset_lim_63.pl new file mode 100755 index 000000000..06d25c7b3 --- /dev/null +++ b/test_regress/t/t_reloop_offset_lim_63.pl @@ -0,0 +1,37 @@ +#!/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); + +top_filename("t/t_reloop_offset.v"); +golden_filename("t/t_reloop_offset.out"); + +compile( + verilator_flags2 => ["-unroll-count 1024", + $Self->wno_unopthreads_for_few_cores(), + "--reloop-limit 63", + "--stats"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, Reloop iterations\s+(\d+)/i, + 63); + file_grep($Self->{stats}, qr/Optimizations, Reloops\s+(\d+)/i, + 1); +} + +ok(1); +1; From 80d62adec73ae7785aed91c240c26c39df0ef644 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 15 May 2021 21:10:16 +0100 Subject: [PATCH 36/80] Make all AstNode* base class constructors protected. (#2962) No functional changes intended. Boring patch in the hope of being helpful to new contributors. Although AstNode* base classes needing to be abstract is described in the internals manual, this might provide a bit of extra safety. --- src/V3Ast.h | 117 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 29 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index d1a4709b5..1483abb7c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1912,9 +1912,11 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); } class AstNodeMath VL_NOT_FINAL : public AstNode { // Math -- anything that's part of an expression tree -public: +protected: AstNodeMath(AstType t, FileLine* fl) : AstNode{t, fl} {} + +public: ASTNODE_BASE_FUNCS(NodeMath) // METHODS virtual void dump(std::ostream& str) const override; @@ -1932,9 +1934,11 @@ public: class AstNodeTermop VL_NOT_FINAL : public AstNodeMath { // Terminal operator -- a operator with no "inputs" -public: +protected: AstNodeTermop(AstType t, FileLine* fl) : AstNodeMath{t, fl} {} + +public: ASTNODE_BASE_FUNCS(NodeTermop) // Know no children, and hot function, so skip iterator for speed // See checkTreeIter also that asserts no children @@ -1945,12 +1949,14 @@ public: class AstNodeUniop VL_NOT_FINAL : public AstNodeMath { // Unary math -public: +protected: AstNodeUniop(AstType t, FileLine* fl, AstNode* lhsp) : AstNodeMath{t, fl} { dtypeFrom(lhsp); setOp1p(lhsp); } + +public: ASTNODE_BASE_FUNCS(NodeUniop) AstNode* lhsp() const { return op1p(); } void lhsp(AstNode* nodep) { return setOp1p(nodep); } @@ -1971,12 +1977,14 @@ public: class AstNodeBiop VL_NOT_FINAL : public AstNodeMath { // Binary math -public: +protected: AstNodeBiop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeMath{t, fl} { setOp1p(lhs); setOp2p(rhs); } + +public: ASTNODE_BASE_FUNCS(NodeBiop) // Clone single node, just get same type back. virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; @@ -2003,13 +2011,15 @@ public: class AstNodeTriop VL_NOT_FINAL : public AstNodeMath { // Trinary math -public: +protected: AstNodeTriop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) : AstNodeMath{t, fl} { setOp1p(lhs); setOp2p(rhs); setOp3p(ths); } + +public: ASTNODE_BASE_FUNCS(NodeTriop) AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } @@ -2036,7 +2046,7 @@ public: class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { // Quaternary math -public: +protected: AstNodeQuadop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs) : AstNodeMath{t, fl} { setOp1p(lhs); @@ -2044,6 +2054,8 @@ public: setOp3p(ths); setOp4p(fhs); } + +public: ASTNODE_BASE_FUNCS(NodeQuadop) AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } @@ -2073,21 +2085,26 @@ public: class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { // Binary math with commutative properties -public: +protected: AstNodeBiCom(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeBiop{t, fl, lhs, rhs} {} + +public: ASTNODE_BASE_FUNCS(NodeBiCom) }; class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom { // Binary math with commutative & associative properties -public: +protected: AstNodeBiComAsv(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeBiCom{t, fl, lhs, rhs} {} + +public: ASTNODE_BASE_FUNCS(NodeBiComAsv) }; + class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { -public: +protected: AstNodeCond(AstType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) : AstNodeTriop{t, fl, condp, expr1p, expr2p} { if (expr1p) { @@ -2096,6 +2113,8 @@ public: dtypeFrom(expr2p); } } + +public: ASTNODE_BASE_FUNCS(NodeCond) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override; @@ -2124,13 +2143,15 @@ class AstNodeBlock VL_NOT_FINAL : public AstNode { private: string m_name; // Name of block bool m_unnamed; // Originally unnamed (name change does not affect this) -public: +protected: AstNodeBlock(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode{t, fl} , m_name{name} { addNOp1p(stmtsp); m_unnamed = (name == ""); } + +public: ASTNODE_BASE_FUNCS(NodeBlock) virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } // * = Block name @@ -2143,13 +2164,15 @@ public: class AstNodePreSel VL_NOT_FINAL : public AstNode { // Something that becomes an AstSel -public: +protected: AstNodePreSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* rhs, AstNode* ths) : AstNode{t, fl} { setOp1p(fromp); setOp2p(rhs); setNOp3p(ths); } + +public: ASTNODE_BASE_FUNCS(NodePreSel) AstNode* fromp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } @@ -2166,11 +2189,13 @@ public: class AstNodeProcedure VL_NOT_FINAL : public AstNode { // IEEE procedure: initial, final, always -public: +protected: AstNodeProcedure(AstType t, FileLine* fl, AstNode* bodysp) : AstNode{t, fl} { addNOp2p(bodysp); } + +public: ASTNODE_BASE_FUNCS(NodeProcedure) // METHODS virtual void dump(std::ostream& str) const override; @@ -2182,10 +2207,12 @@ public: class AstNodeStmt VL_NOT_FINAL : public AstNode { // Statement -- anything that's directly under a function bool m_statement; // Really a statement (e.g. not a function with return) -public: +protected: AstNodeStmt(AstType t, FileLine* fl, bool statement = true) : AstNode{t, fl} , m_statement{statement} {} + +public: ASTNODE_BASE_FUNCS(NodeStmt) // METHODS bool isStatement() const { return m_statement; } // Really a statement @@ -2198,13 +2225,15 @@ public: }; class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { -public: +protected: AstNodeAssign(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeStmt{t, fl} { setOp1p(rhsp); setOp2p(lhsp); dtypeFrom(lhsp); } + +public: ASTNODE_BASE_FUNCS(NodeAssign) // Clone single node, just get same type back. virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; @@ -2223,7 +2252,7 @@ public: }; class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { -public: +protected: AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) : AstNodeStmt{t, fl} { @@ -2232,6 +2261,8 @@ public: addNOp3p(incsp); addNOp4p(bodysp); } + +public: ASTNODE_BASE_FUNCS(NodeFor) AstNode* initsp() const { return op1p(); } // op1 = initial statements AstNode* condp() const { return op2p(); } // op2 = condition to continue @@ -2246,13 +2277,15 @@ public: class AstNodeIf VL_NOT_FINAL : public AstNodeStmt { private: VBranchPred m_branchPred; // Branch prediction as taken/untaken? -public: +protected: AstNodeIf(AstType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) : AstNodeStmt{t, fl} { setOp1p(condp); addNOp2p(ifsp); addNOp3p(elsesp); } + +public: ASTNODE_BASE_FUNCS(NodeIf) AstNode* condp() const { return op1p(); } // op1 = condition AstNode* ifsp() const { return op2p(); } // op2 = list of true statements @@ -2270,12 +2303,14 @@ public: }; class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { -public: +protected: AstNodeCase(AstType t, FileLine* fl, AstNode* exprp, AstNode* casesp) : AstNodeStmt{t, fl} { setOp1p(exprp); addNOp2p(casesp); } + +public: ASTNODE_BASE_FUNCS(NodeCase) virtual int instrCount() const override { return instrCountBranch(); } AstNode* exprp() const { return op1p(); } // op1 = case condition @@ -2299,7 +2334,7 @@ private: string m_hiernameToUnprot; // Scope converted into name-> for emitting bool m_hierThis = false; // Hiername points to "this" function -public: +protected: AstNodeVarRef(AstType t, FileLine* fl, const string& name, const VAccess& access) : AstNodeMath{t, fl} , m_access{access} @@ -2313,6 +2348,8 @@ public: // May have varp==nullptr this->varp(varp); } + +public: ASTNODE_BASE_FUNCS(NodeVarRef) virtual void dump(std::ostream& str) const override; virtual bool hasDType() const override { return true; } @@ -2346,12 +2383,14 @@ class AstNodeText VL_NOT_FINAL : public AstNode { private: string m_text; -public: +protected: // Node that simply puts text into the output stream AstNodeText(AstType t, FileLine* fl, const string& textp) : AstNode{t, fl} { m_text = textp; // Copy it } + +public: ASTNODE_BASE_FUNCS(NodeText) virtual void dump(std::ostream& str = std::cout) const override; virtual V3Hash sameHash() const override { return V3Hash(text()); } @@ -2375,7 +2414,7 @@ private: // Unique number assigned to each dtype during creation for IEEE matching static int s_uniqueNum; -public: +protected: // CONSTRUCTORS AstNodeDType(AstType t, FileLine* fl) : AstNode{t, fl} { @@ -2383,6 +2422,8 @@ public: m_widthMin = 0; m_generic = false; } + +public: ASTNODE_BASE_FUNCS(NodeDType) // ACCESSORS virtual void dump(std::ostream& str) const override; @@ -2474,7 +2515,7 @@ private: bool m_isFourstate; MemberNameMap m_members; -public: +protected: AstNodeUOrStructDType(AstType t, FileLine* fl, VSigning numericUnpack) : AstNodeDType{t, fl} { // VSigning::NOSIGN overloaded to indicate not packed @@ -2482,6 +2523,8 @@ public: m_isFourstate = false; // V3Width computes numeric(VSigning::fromBool(numericUnpack.isSigned())); } + +public: ASTNODE_BASE_FUNCS(NodeUOrStructDType) virtual const char* broken() const override; virtual void dump(std::ostream& str) const override; @@ -2534,9 +2577,11 @@ class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { private: AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) AstNode* rangenp() const { return op2p(); } // op2 = Array(s) of variable -public: +protected: AstNodeArrayDType(AstType t, FileLine* fl) : AstNodeDType{t, fl} {} + +public: ASTNODE_BASE_FUNCS(NodeArrayDType) virtual void dump(std::ostream& str) const override; virtual void dumpSmall(std::ostream& str) const override; @@ -2594,9 +2639,11 @@ public: class AstNodeSel VL_NOT_FINAL : public AstNodeBiop { // Single bit range extraction, perhaps with non-constant selection or array selection -public: +protected: AstNodeSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* bitp) : AstNodeBiop{t, fl, fromp, bitp} {} + +public: ASTNODE_BASE_FUNCS(NodeSel) AstNode* fromp() const { return op1p(); @@ -2610,11 +2657,13 @@ public: class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() -public: +protected: AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop{t, fl, lhsp, rhsp} { if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); } + +public: ASTNODE_BASE_FUNCS(NodeStream) }; @@ -2629,7 +2678,7 @@ class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt { string m_hiernameToUnprot; string m_argTypes; -public: +protected: AstNodeCCall(AstType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) : AstNodeStmt{t, fl, true} , m_funcp{funcp} { @@ -2645,6 +2694,8 @@ public: m_argTypes = oldp->argTypes(); if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext()); } + +public: ASTNODE_BASE_FUNCS(NodeCCall) virtual void dump(std::ostream& str = std::cout) const override; virtual void cloneRelink() override; @@ -2696,7 +2747,7 @@ private: bool m_pureVirtual : 1; // Pure virtual bool m_virtual : 1; // Virtual method in class VLifetime m_lifetime; // Lifetime -public: +protected: AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode{t, fl} , m_name{name} @@ -2720,6 +2771,8 @@ public: addNOp3p(stmtsp); cname(name); // Might be overridden by dpi import/export } + +public: ASTNODE_BASE_FUNCS(NodeFTask) virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } // * = Var name @@ -2796,7 +2849,7 @@ private: string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out bool m_pli = false; // Pli system call ($name) -public: +protected: AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) : AstNodeStmt{t, fl, statement} { setOp1p(namep); @@ -2807,6 +2860,8 @@ public: , m_name{name} { addNOp3p(pinsp); } + +public: ASTNODE_BASE_FUNCS(NodeFTaskRef) virtual const char* broken() const override; virtual void cloneRelink() override { @@ -2862,7 +2917,7 @@ private: VLifetime m_lifetime; // Lifetime VTimescale m_timeunit; // Global time unit VOptionBool m_unconnectedDrive; // State of `unconnected_drive -public: +protected: AstNodeModule(AstType t, FileLine* fl, const string& name) : AstNode{t, fl} , m_name{name} @@ -2875,6 +2930,8 @@ public: , m_internal{false} , m_recursive{false} , m_recursiveClone{false} {} + +public: ASTNODE_BASE_FUNCS(NodeModule) virtual void dump(std::ostream& str) const override; virtual bool maybePointedTo() const override { return true; } @@ -2922,9 +2979,11 @@ public: class AstNodeRange VL_NOT_FINAL : public AstNode { // A range, sized or unsized -public: +protected: AstNodeRange(AstType t, FileLine* fl) : AstNode{t, fl} {} + +public: ASTNODE_BASE_FUNCS(NodeRange) virtual void dump(std::ostream& str) const override; }; From 31779b8b8bb5764247d6fd892b91228a10294395 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 16 May 2021 19:01:03 +0900 Subject: [PATCH 37/80] Format time string using integer (#2940) Co-authored-by: Wilson Snyder --- include/verilated.cpp | 116 +++++++++++++++++++++---- include/verilated.h | 2 + src/V3EmitC.cpp | 13 +++ src/V3Width.cpp | 21 ----- test_regress/t/t_time_vpi_100s10ms.out | 4 +- test_regress/t/t_time_vpi_10ms10ns.out | 4 +- test_regress/t/t_time_vpi_1fs1fs.out | 4 +- test_regress/t/t_time_vpi_1ms10ns.out | 4 +- test_regress/t/t_time_vpi_1ns1ns.out | 4 +- test_regress/t/t_time_vpi_1ps1fs.out | 8 +- test_regress/t/t_time_vpi_1s10ns.out | 4 +- test_regress/t/t_time_vpi_1us1ns.out | 6 +- 12 files changed, 132 insertions(+), 58 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index a1c070cad..f8b460439 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -637,26 +637,80 @@ std::string VL_DECIMAL_NW(int width, WDataInP lwp) VL_MT_SAFE { return output; } -std::string _vl_vsformat_time(char* tmp, double ld, bool left, size_t width) { - // Double may lose precision, but sc_time_stamp has similar limit - std::string suffix = Verilated::threadContextp()->impp()->timeFormatSuffix(); - int userUnits = Verilated::threadContextp()->impp()->timeFormatUnits(); // 0..-15 - int fracDigits = Verilated::threadContextp()->impp()->timeFormatPrecision(); // 0..N - int prec = Verilated::threadContextp()->timeprecision(); // 0..-15 - int shift = prec - userUnits + fracDigits; // 0..-15 - double shiftd = vl_time_multiplier(shift); - double scaled = ld * shiftd; - const double fracDiv = vl_time_multiplier(fracDigits); - const double whole = scaled / fracDiv; +template +std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) { + const VerilatedContextImp* const ctxImpp = Verilated::threadContextp()->impp(); + const std::string suffix = ctxImpp->timeFormatSuffix(); + const int userUnits = ctxImpp->timeFormatUnits(); // 0..-15 + const int fracDigits = ctxImpp->timeFormatPrecision(); // 0..N + const int shift = -userUnits + fracDigits + timeunit; // 0..-15 int digits = 0; - if (!fracDigits) { - digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.0f%s", whole, suffix.c_str()); + if (std::numeric_limits::is_integer) { + constexpr int b = 128; + constexpr int w = VL_WORDS_I(b); + WData tmp0[w], tmp1[w], tmp2[w], tmp3[w]; + + WDataInP shifted = VL_EXTEND_WQ(b, 0, tmp0, ld); + if (shift < 0) { + WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(-shift)); + shifted = VL_DIV_WWW(b, tmp2, shifted, pow10); + } else { + WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(shift)); + shifted = VL_MUL_W(w, tmp2, shifted, pow10); + } + + WDataInP fracDigitsPow10 = VL_EXTEND_WQ(b, 0, tmp3, vl_time_pow10(fracDigits)); + WDataInP integer = VL_DIV_WWW(b, tmp0, shifted, fracDigitsPow10); + WDataInP frac = VL_MODDIV_WWW(b, tmp1, shifted, fracDigitsPow10); + WDataInP max64Bit + = VL_EXTEND_WQ(b, 0, tmp2, std::numeric_limits::max()); // breaks shifted + if (VL_GT_W(w, integer, max64Bit)) { + WDataOutP v = VL_ASSIGN_W(b, tmp3, integer); // breaks fracDigitsPow10 + WData zero[w], ten[w]; + VL_ZERO_W(b, zero); + VL_EXTEND_WI(b, 0, ten, 10); + char buf[128]; // 128B is obviously long enough to represent 128bit integer in decimal + char* ptr = buf + sizeof(buf) - 1; + *ptr = '\0'; + while (VL_GT_W(w, v, zero)) { + --ptr; + WDataInP mod = VL_MODDIV_WWW(b, tmp2, v, ten); // breaks max64Bit + *ptr = "0123456789"[VL_SET_QW(mod)]; + WData divided[w]; + VL_DIV_WWW(b, divided, v, ten); + VL_ASSIGN_W(b, v, divided); + } + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%s%s", ptr, suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%s.%0*" VL_PRI64 "u%s", ptr, + fracDigits, VL_SET_QW(frac), suffix.c_str()); + } + } else { + const vluint64_t integer64 = VL_SET_QW(integer); + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%" VL_PRI64 "u%s", integer64, + suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, + "%" VL_PRI64 "u.%0*" VL_PRI64 "u%s", integer64, fracDigits, + VL_SET_QW(frac), suffix.c_str()); + } + } } else { - digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.*f%s", fracDigits, whole, - suffix.c_str()); + double shiftd = vl_time_multiplier(shift); + double scaled = ld * shiftd; + const double fracDiv = vl_time_multiplier(fracDigits); + const double whole = scaled / fracDiv; + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.0f%s", whole, suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.*f%s", fracDigits, whole, + suffix.c_str()); + } } - int needmore = width - digits; + const int needmore = width - digits; std::string padding; if (needmore > 0) padding.append(needmore, ' '); // Pad with spaces return left ? (tmp + padding) : (padding + tmp); @@ -751,7 +805,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA if (lbits) {} // UNUSED - always 64 if (fmt == '^') { // Realtime if (!widthSet) width = Verilated::threadContextp()->impp()->timeFormatWidth(); - output += _vl_vsformat_time(t_tmp, d, left, width); + const int timeunit = va_arg(ap, int); + output += _vl_vsformat_time(t_tmp, d, timeunit, left, width); } else { std::string fmts(pctp, pos - pctp + 1); VL_SNPRINTF(t_tmp, VL_VALUE_STRING_MAX_WIDTH, fmts.c_str(), d); @@ -850,7 +905,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } case 't': { // Time if (!widthSet) width = Verilated::threadContextp()->impp()->timeFormatWidth(); - output += _vl_vsformat_time(t_tmp, static_cast(ld), left, width); + const int timeunit = va_arg(ap, int); + output += _vl_vsformat_time(t_tmp, ld, timeunit, left, width); break; } case 'b': @@ -2153,6 +2209,30 @@ double vl_time_multiplier(int scale) VL_PURE { return pow10[scale]; } } +vluint64_t vl_time_pow10(int n) { + static const vluint64_t pow10[20] = { + 1ULL, + 10ULL, + 100ULL, + 1000ULL, + 10000ULL, + 100000ULL, + 1000000ULL, + 10000000ULL, + 100000000ULL, + 1000000000ULL, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + }; + return pow10[n]; +} void VL_PRINTTIMESCALE(const char* namep, const char* timeunitp, const VerilatedContext* contextp) VL_MT_SAFE { diff --git a/include/verilated.h b/include/verilated.h index 7df6e08de..123ea92c5 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -1187,6 +1187,8 @@ inline vluint64_t VerilatedContext::time() const VL_MT_SAFE { // Return time precision as multiplier of time units double vl_time_multiplier(int scale) VL_PURE; +// Return power of 10. e.g. returns 100 if n==2 +vluint64_t vl_time_pow10(int n) VL_PURE; #ifdef VL_DEBUG /// Evaluate statement if Verilated::debug() enabled diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 0ad110a5d..08f186b3e 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2282,6 +2282,19 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin())); } emitDispState.pushArg(fmtLetter, argp, ""); + if (fmtLetter == 't' || fmtLetter == '^') { + AstSFormatF* fmtp = nullptr; + if (AstDisplay* nodep = VN_CAST(dispp, Display)) + fmtp = nodep->fmtp(); + else if (AstSFormat* nodep = VN_CAST(dispp, SFormat)) + fmtp = nodep->fmtp(); + else + fmtp = VN_CAST(dispp, SFormatF); + UASSERT_OBJ(fmtp, dispp, + "Use of %t must be under AstDisplay, AstSFormat, or AstSFormatF"); + UASSERT_OBJ(!fmtp->timeunit().isNone(), fmtp, "timenunit must be set"); + emitDispState.pushArg(' ', nullptr, cvtToStr((int)fmtp->timeunit().powerOfTen())); + } } else { emitDispState.pushArg(fmtLetter, nullptr, ""); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index dc556aa00..22e15d1c7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3864,27 +3864,6 @@ private: if (nodep->timeunit().isNone()) { nodep->v3fatalSrc("display %t has no time units"); } - double scale = nodep->timeunit().multiplier() - / v3Global.rootp()->timeprecision().multiplier(); - if (scale != 1.0) { - AstNode* newp; - AstNRelinker relinkHandle; - argp->unlinkFrBack(&relinkHandle); - if (argp->isDouble()) { // Convert it - ch = '^'; - newp = new AstMulD( - argp->fileline(), - new AstConst(argp->fileline(), AstConst::RealDouble(), scale), - argp); - } else { - newp = new AstMul(argp->fileline(), - new AstConst(argp->fileline(), - AstConst::Unsized64(), - std::llround(scale)), - argp); - } - relinkHandle.relink(newp); - } argp = nextp; } break; diff --git a/test_regress/t/t_time_vpi_100s10ms.out b/test_regress/t/t_time_vpi_100s10ms.out index c581dbf6c..8a0428fea 100644 --- a/test_regress/t/t_time_vpi_100s10ms.out +++ b/test_regress/t/t_time_vpi_100s10ms.out @@ -3,11 +3,11 @@ Time scale of t is 100s / 10ms [100000000] time%0d=10000 123%0t=1230000 dig%0t=0 dig%0d=0 rdig%0t=543 rdig%0f=0.054321 - acc%0t=11177671081359484928 acc%0d=12345678901234567890 + acc%0t=123456789012345678900000 acc%0d=12345678901234567890 [1000000000000000.000000ns] time%0d=10000 123%0t=12300000000000.000000ns dig%0t=0.000000ns dig%0d=0 rdig%0t=5432109876.543210ns rdig%0f=0.054321 - acc%0t=111776710813594856498135040.000000ns acc%0d=12345678901234567890 + acc%0t=1234567890123456789000000000000.000000ns acc%0d=12345678901234567890 [1000000000000000.000000ns] stime%0t=1000000000000000.000000ns stime%0d=10000 stime%0f=10000.000000 [1000000000000000.000000ns] rtime%0t=1000000000000000.000000ns rtime%0d=10000 rtime%0f=10000.000000 global vpiSimTime = 0,100000000 vpiScaledRealTime = 1e+08 diff --git a/test_regress/t/t_time_vpi_10ms10ns.out b/test_regress/t/t_time_vpi_10ms10ns.out index 4b7180883..b09a31d11 100644 --- a/test_regress/t/t_time_vpi_10ms10ns.out +++ b/test_regress/t/t_time_vpi_10ms10ns.out @@ -3,11 +3,11 @@ Time scale of t is 10ms / 10ns [60000000] time%0d=60 123%0t=123000000 dig%0t=543000000 dig%0d=543 rdig%0t=543210988 rdig%0f=543.210988 - acc%0t=10962463713375475712 acc%0d=12345678901234567890 + acc%0t=12345678901234567890000000 acc%0d=12345678901234567890 [600000000.000000ns] time%0d=60 123%0t=1230000000.000000ns dig%0t=5430000000.000000ns dig%0d=543 rdig%0t=5432109876.543210ns rdig%0f=543.210988 - acc%0t=109624637133754744832.000000ns acc%0d=12345678901234567890 + acc%0t=123456789012345678900000000.000000ns acc%0d=12345678901234567890 [600000000.000000ns] stime%0t=600000000.000000ns stime%0d=60 stime%0f=60.000000 [600000000.000000ns] rtime%0t=600000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000000 vpiScaledRealTime = 6e+07 diff --git a/test_regress/t/t_time_vpi_1fs1fs.out b/test_regress/t/t_time_vpi_1fs1fs.out index 612a7023b..a353d9cea 100644 --- a/test_regress/t/t_time_vpi_1fs1fs.out +++ b/test_regress/t/t_time_vpi_1fs1fs.out @@ -3,11 +3,11 @@ Time scale of t is 1fs / 1fs [60] time%0d=60 123%0t=123 dig%0t=5432109876543210 dig%0d=5432109876543210 rdig%0t=5432109876543210 rdig%0f=5432109876543210.000000 - acc%0t=12345678901234567168 acc%0d=12345678901234567890 + acc%0t=12345678901234567890 acc%0d=12345678901234567890 [0.000060ns] time%0d=60 123%0t=0.000123ns dig%0t=5432109876.543210ns dig%0d=5432109876543210 rdig%0t=5432109876.543210ns rdig%0f=5432109876543210.000000 - acc%0t=12345678901234.566406ns acc%0d=12345678901234567890 + acc%0t=12345678901234.567890ns acc%0d=12345678901234567890 [0.000060ns] stime%0t=0.000060ns stime%0d=60 stime%0f=60.000000 [0.000060ns] rtime%0t=0.000060ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1ms10ns.out b/test_regress/t/t_time_vpi_1ms10ns.out index a6e35ad26..1276f8d4c 100644 --- a/test_regress/t/t_time_vpi_1ms10ns.out +++ b/test_regress/t/t_time_vpi_1ms10ns.out @@ -3,11 +3,11 @@ Time scale of t is 1ms / 10ns [6000000] time%0d=60 123%0t=12300000 dig%0t=543200000 dig%0d=5432 rdig%0t=543210988 rdig%0f=5432.109877 - acc%0t=1096246371337547520 acc%0d=12345678901234567890 + acc%0t=1234567890123456789000000 acc%0d=12345678901234567890 [60000000.000000ns] time%0d=60 123%0t=123000000.000000ns dig%0t=5432000000.000000ns dig%0d=5432 rdig%0t=5432109876.543210ns rdig%0f=5432.109877 - acc%0t=10962463713375473664.000000ns acc%0d=12345678901234567890 + acc%0t=12345678901234567890000000.000000ns acc%0d=12345678901234567890 [60000000.000000ns] stime%0t=60000000.000000ns stime%0d=60 stime%0f=60.000000 [60000000.000000ns] rtime%0t=60000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,6000000 vpiScaledRealTime = 6e+06 diff --git a/test_regress/t/t_time_vpi_1ns1ns.out b/test_regress/t/t_time_vpi_1ns1ns.out index 05e68341c..b9e6d3ed1 100644 --- a/test_regress/t/t_time_vpi_1ns1ns.out +++ b/test_regress/t/t_time_vpi_1ns1ns.out @@ -3,11 +3,11 @@ Time scale of t is 1ns / 1ns [60] time%0d=60 123%0t=123 dig%0t=5432109877 dig%0d=5432109877 rdig%0t=5432109877 rdig%0f=5432109876.543210 - acc%0t=12345678901234567168 acc%0d=12345678901234567890 + acc%0t=12345678901234567890 acc%0d=12345678901234567890 [60.000000ns] time%0d=60 123%0t=123.000000ns dig%0t=5432109877.000000ns dig%0d=5432109877 rdig%0t=5432109876.543210ns rdig%0f=5432109876.543210 - acc%0t=12345678901234565120.000000ns acc%0d=12345678901234567890 + acc%0t=12345678901234567890.000000ns acc%0d=12345678901234567890 [60.000000ns] stime%0t=60.000000ns stime%0d=60 stime%0f=60.000000 [60.000000ns] rtime%0t=60.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1ps1fs.out b/test_regress/t/t_time_vpi_1ps1fs.out index 35ab855e0..3a391485d 100644 --- a/test_regress/t/t_time_vpi_1ps1fs.out +++ b/test_regress/t/t_time_vpi_1ps1fs.out @@ -2,12 +2,12 @@ Time scale of t is 1ps / 1fs [60000] time%0d=60 123%0t=123000 dig%0t=5432109876543000 dig%0d=5432109876543 - rdig%0t=5432109876543209 rdig%0f=5432109876543.209961 - acc%0t=4807115922877858816 acc%0d=12345678901234567890 + rdig%0t=5432109876543210 rdig%0f=5432109876543.209961 + acc%0t=12345678901234567890000 acc%0d=12345678901234567890 [0.060000ns] time%0d=60 123%0t=0.123000ns dig%0t=5432109876.543000ns dig%0d=5432109876543 - rdig%0t=5432109876.543209ns rdig%0f=5432109876543.209961 - acc%0t=4807115922877.858398ns acc%0d=12345678901234567890 + rdig%0t=5432109876.543210ns rdig%0f=5432109876543.209961 + acc%0t=12345678901234567.890000ns acc%0d=12345678901234567890 [0.060000ns] stime%0t=0.060000ns stime%0d=60 stime%0f=60.000000 [0.060000ns] rtime%0t=0.060000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 diff --git a/test_regress/t/t_time_vpi_1s10ns.out b/test_regress/t/t_time_vpi_1s10ns.out index f9a17a8f8..b950e9176 100644 --- a/test_regress/t/t_time_vpi_1s10ns.out +++ b/test_regress/t/t_time_vpi_1s10ns.out @@ -3,11 +3,11 @@ Time scale of t is 1s / 10ns [6000000000] time%0d=60 123%0t=12300000000 dig%0t=500000000 dig%0d=5 rdig%0t=543210988 rdig%0f=5.432110 - acc%0t=7888470988684038144 acc%0d=12345678901234567890 + acc%0t=1234567890123456789000000000 acc%0d=12345678901234567890 [60000000000.000000ns] time%0d=60 123%0t=123000000000.000000ns dig%0t=5000000000.000000ns dig%0d=5 rdig%0t=5432109876.543210ns rdig%0f=5.432110 - acc%0t=78884709886840389632.000000ns acc%0d=12345678901234567890 + acc%0t=12345678901234567890000000000.000000ns acc%0d=12345678901234567890 [60000000000.000000ns] stime%0t=60000000000.000000ns stime%0d=60 stime%0f=60.000000 [60000000000.000000ns] rtime%0t=60000000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 1,1705032704 vpiScaledRealTime = 6e+09 diff --git a/test_regress/t/t_time_vpi_1us1ns.out b/test_regress/t/t_time_vpi_1us1ns.out index 4c2c152d0..59d7e4ea8 100644 --- a/test_regress/t/t_time_vpi_1us1ns.out +++ b/test_regress/t/t_time_vpi_1us1ns.out @@ -3,11 +3,11 @@ Time scale of t is 1us / 1ns [60000] time%0d=60 123%0t=123000 dig%0t=5432110000 dig%0d=5432110 rdig%0t=5432109877 rdig%0f=5432109.876543 - acc%0t=4807115922877858816 acc%0d=12345678901234567890 + acc%0t=12345678901234567890000 acc%0d=12345678901234567890 [60000.000000ns] time%0d=60 123%0t=123000.000000ns dig%0t=5432110000.000000ns dig%0d=5432110 - rdig%0t=5432109876.543209ns rdig%0f=5432109.876543 - acc%0t=4807115922877858816.000000ns acc%0d=12345678901234567890 + rdig%0t=5432109876.543210ns rdig%0f=5432109.876543 + acc%0t=12345678901234567890000.000000ns acc%0d=12345678901234567890 [60000.000000ns] stime%0t=60000.000000ns stime%0d=60 stime%0f=60.000000 [60000.000000ns] rtime%0t=60000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 From 706842d093b4e64938bd1e223c11510858f1282b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 16 May 2021 15:11:25 -0400 Subject: [PATCH 38/80] CI: Disable Ubuntu-18.04 clang (#2963) --- ci/ci-script.bash | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ci/ci-script.bash b/ci/ci-script.bash index 498531eed..54eeb1756 100755 --- a/ci/ci-script.bash +++ b/ci/ci-script.bash @@ -85,16 +85,24 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then # Run the specified test case $TESTS in dist-vlt-0) + if [[ "$CI_RUNS_ON" != "ubuntu-18.04" || "$CXX" != "clang++" ]]; then # issue #2963 "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=0/2 + fi ;; dist-vlt-1) + if [[ "$CI_RUNS_ON" != "ubuntu-18.04" || "$CXX" != "clang++" ]]; then # issue #2963 "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=1/2 + fi ;; vltmt-0) + if [[ "$CI_RUNS_ON" != "ubuntu-18.04" || "$CXX" != "clang++" ]]; then # issue #2963 "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2 + fi ;; vltmt-1) + if [[ "$CI_RUNS_ON" != "ubuntu-18.04" || "$CXX" != "clang++" ]]; then # issue #2963 "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2 + fi ;; coverage-all) nodist/code_coverage --stages 1- From bdc162db87dc10dbde1c35ee13c9d7ba79785f2a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 16 May 2021 18:38:43 -0400 Subject: [PATCH 39/80] Fix 16.04 gcc warning --- include/verilated.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index f8b460439..aa4bb49c3 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -650,7 +650,7 @@ std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t w constexpr int w = VL_WORDS_I(b); WData tmp0[w], tmp1[w], tmp2[w], tmp3[w]; - WDataInP shifted = VL_EXTEND_WQ(b, 0, tmp0, ld); + WDataInP shifted = VL_EXTEND_WQ(b, 0, tmp0, static_cast(ld)); if (shift < 0) { WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(-shift)); shifted = VL_DIV_WWW(b, tmp2, shifted, pow10); From 471f14d26a6e9ff4ac401d730441649d20e50deb Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 17 May 2021 13:26:24 +0100 Subject: [PATCH 40/80] Clean up V3Combine (#2965) - Remove dead code - Simplify what is left - Minor improvements using C++11 - Remove special case AstNode constructors used only in one place in V3Combine (inlined instead). --- src/V3Ast.h | 10 -- src/V3AstNodes.h | 8 - src/V3Combine.cpp | 425 +++++++++------------------------------------- 3 files changed, 83 insertions(+), 360 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 1483abb7c..a758bf700 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2684,16 +2684,6 @@ protected: , m_funcp{funcp} { addNOp2p(argsp); } - // Replacement form for V3Combine - // Note this removes old attachments from the oldp - AstNodeCCall(AstType t, AstNodeCCall* oldp, AstCFunc* funcp) - : AstNodeStmt{t, oldp->fileline(), true} - , m_funcp{funcp} { - m_hiernameToProt = oldp->hiernameToProt(); - m_hiernameToUnprot = oldp->hiernameToUnprot(); - m_argTypes = oldp->argTypes(); - if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext()); - } public: ASTNODE_BASE_FUNCS(NodeCCall) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b9e067989..b8a2621a5 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -8975,10 +8975,6 @@ class AstCCall final : public AstNodeCCall { public: AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) : ASTGEN_SUPER(fl, funcp, argsp) {} - // Replacement form for V3Combine - // Note this removes old attachments from the oldp - AstCCall(AstCCall* oldp, AstCFunc* funcp) - : ASTGEN_SUPER(oldp, funcp) {} ASTNODE_NODE_FUNCS(CCall) }; @@ -9012,10 +9008,6 @@ public: : ASTGEN_SUPER(fl, funcp, argsp) { statement(false); } - // Replacement form for V3Combine - // Note this removes old attachments from the oldp - AstCNew(AstCCall* oldp, AstCFunc* funcp) - : ASTGEN_SUPER(oldp, funcp) {} virtual bool hasDType() const override { return true; } ASTNODE_NODE_FUNCS(CNew) }; diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index bb9c081aa..1ae206e7a 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -15,19 +15,8 @@ //************************************************************************* // V3Combine's Transformations: // -// For every function that we spit out -// Examine code to find largest common blocks -// Hash each node depth first -// Hash includes varp name and operator type, and constants -// Form lookup table based on hash of each statement w/ nodep and next nodep -// GO through table -// Lookup in hash, while next of each statement match, grow that common block -// Foreach common block -// If common block large enough (> 20 statements) & used 2x or more -// Make new function -// Move common block to function -// Replace each common block ref with funccall -// +// Combine identical CFuncs by retaining only a single copy +// Also drop empty CFuncs //************************************************************************* #include "config_build.h" @@ -45,12 +34,6 @@ //###################################################################### -#ifdef VL_COMBINE_STATEMENTS -constexpr int COMBINE_MIN_STATEMENTS = 50; // Min # of statements to be worth making a function -#endif - -//###################################################################### - class CombBaseVisitor VL_NOT_FINAL : public AstNVisitor { protected: // STATE @@ -67,8 +50,7 @@ class CombCallVisitor final : CombBaseVisitor { // Find all CCALLS of each CFUNC, so that we can later rename them private: // NODE STATE - using CallMmap = std::multimap; - CallMmap m_callMmap; // Associative array of {function}{call} + std::multimap m_callMmap; // Associative array of {function}{call} // METHODS public: void replaceFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) { @@ -81,44 +63,32 @@ public: // Note: m_callMmap modified in loop, so not using equal_range. for (auto it = m_callMmap.find(oldfuncp); it != m_callMmap.end(); it = m_callMmap.find(oldfuncp)) { - AstCCall* callp = it->second; - if (!callp->user3()) { // !already done - UINFO(4, " Called " << callp << endl); - UASSERT_OBJ(callp->funcp() == oldfuncp, callp, - "Call list broken, points to call w/different func"); - if (newfuncp) { - AstCCall* newp = new AstCCall(callp, newfuncp); - // Special new AstCCall form above transfers children of callp to newfuncp - callp->replaceWith(newp); - addCall(newp); // Fix the table - } else { // Just deleting empty function - callp->unlinkFrBack(); - } - callp->user3(true); // Dead now - VL_DO_DANGLING(pushDeletep(callp), callp); + AstCCall* const oldp = it->second; + UINFO(4, " Called " << oldp << endl); + UASSERT_OBJ(oldp->funcp() == oldfuncp, oldp, + "Call list broken, points to call w/different func"); + if (newfuncp) { + // Replace call to oldfuncp with call to newfuncp + AstNode* const argsp + = oldp->argsp() ? oldp->argsp()->unlinkFrBackWithNext() : nullptr; + AstCCall* const newp = new AstCCall(oldp->fileline(), newfuncp, argsp); + newp->hiernameToProt(oldp->hiernameToProt()); + newp->hiernameToUnprot(oldp->hiernameToUnprot()); + newp->argTypes(oldp->argTypes()); + addCall(newp); // Fix the table, in case the newfuncp itself gets replaced + oldp->replaceWith(newp); + } else { + // Just deleting empty function + oldp->unlinkFrBack(); } - // It is safe to unconditionally remove this entry here as the above - // 'if' would never be entered again for this entry (we set user3). - // The only other place where m_callMmap is looked up is deleteCall - // below, but that is only ever called straight after an addCall - // of the node being deleted, so it won't miss this entry. - m_callMmap.erase(it); // Fix the table + VL_DO_DANGLING(pushDeletep(oldp), oldp); + m_callMmap.erase(it); // Fix the table, This call has been replaced } } // METHODS - void addCall(AstCCall* nodep) { m_callMmap.emplace(nodep->funcp(), nodep); } - void deleteCall(AstCCall* nodep) { - std::pair eqrange - = m_callMmap.equal_range(nodep->funcp()); - for (auto nextit = eqrange.first; nextit != eqrange.second;) { - const auto eqit = nextit++; - AstCCall* callp = eqit->second; - if (callp == nodep) { - m_callMmap.erase(eqit); - return; - } - } - nodep->v3fatalSrc("deleteCall node not found in table"); + void addCall(AstCCall* nodep) { + if (nodep->funcp()->dontCombine()) return; + m_callMmap.emplace(nodep->funcp(), nodep); } private: @@ -136,26 +106,6 @@ public: void main(AstNetlist* nodep) { iterate(nodep); } }; -//###################################################################### -// Combine marking function - -class CombMarkVisitor final : CombBaseVisitor { - // Mark all nodes under specified one. -private: - // OUTPUT: - // AstNode::user3() -> bool. True to indicate duplicated - // VISITORS - virtual void visit(AstNode* nodep) override { - nodep->user3(true); - iterateChildren(nodep); - } - -public: - // CONSTRUCTORS - explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~CombMarkVisitor() override = default; -}; - //###################################################################### // Combine state, as a visitor of each AstNode @@ -163,312 +113,103 @@ class CombineVisitor final : CombBaseVisitor { private: // NODE STATE // Entire netlist: - // AstNodeStmt::user() -> bool. True if iterated already - // AstCFunc::user3p() -> AstCFunc*, If set, replace ccalls to this func with new func - // AstNodeStmt::user3() -> AstNode*. True if to ignore this cell - // AstNodeStmt::user4() -> V3Hashed::V3Hash. Hash value of this node (hash of 0 is - // illegal) - AstUser1InUse m_inuser1; - AstUser3InUse m_inuser3; - // AstUser4InUse part of V3Hashed + AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs + // AstUser4InUse part of V3Hashed // STATE - enum CombineState : uint8_t { STATE_IDLE, STATE_HASH, STATE_DUP }; - VDouble0 m_statCombs; // Statistic tracking - CombineState m_state = STATE_IDLE; // Major state - AstNodeModule* m_modp = nullptr; // Current module - AstCFunc* m_cfuncp = nullptr; // Current function + VDouble0 m_cfuncsCombined; // Statistic tracking CombCallVisitor m_call; // Tracking of function call users - int m_modNFuncs = 0; // Number of functions made -#ifdef VL_COMBINE_STATEMENTS - AstNode* m_walkLast1p = nullptr; // Final node that is the same in duplicate list -#endif - AstNode* m_walkLast2p = nullptr; // Final node that is the same in duplicate list - V3Hashed m_hashed; // Hash for every node in module + V3Hashed m_hashed; // Hash for every CFunc in module // METHODS - void hashStatement(AstNode* nodep) { - // Compute hash on entire tree of this statement - m_hashed.hashAndInsert(nodep); - // UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl); - } -#ifdef VL_COMBINE_STATEMENTS - void hashFunctions(AstCFunc* nodep) { - // Compute hash of all statement trees in the function - VL_RESTORER(m_state); - { - m_state = STATE_HASH; - iterate(nodep); - } - } -#endif void walkEmptyFuncs() { for (const auto& itr : m_hashed) { - AstNode* node1p = itr.second; - AstCFunc* oldfuncp = VN_CAST(node1p, CFunc); - if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) { - UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " " - << oldfuncp << endl); - // Mark user3p on entire old tree, so we don't process it more - CombMarkVisitor visitor(oldfuncp); - m_call.replaceFunc(oldfuncp, nullptr); - oldfuncp->unlinkFrBack(); - VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); - } + AstCFunc* const oldfuncp = VN_CAST(itr.second, CFunc); + UASSERT_OBJ(oldfuncp, itr.second, "Not a CFunc in hash"); + if (!oldfuncp->emptyBody()) continue; + UASSERT_OBJ(!oldfuncp->dontCombine(), oldfuncp, + "dontCombine function should not be in hash"); + + // Remove calls to empty function + UASSERT_OBJ(!oldfuncp->user3(), oldfuncp, "Should not be processed yet"); + UINFO(5, " Drop empty CFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " " + << oldfuncp << endl); + oldfuncp->user3SetOnce(); // Mark replaced + m_call.replaceFunc(oldfuncp, nullptr); + oldfuncp->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); } } + void walkDupFuncs() { // Do non-slow first as then favors naming functions based on fast name - for (int slow = 0; slow < 2; ++slow) { - for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) { - AstNode* node1p = it->second; - AstCFunc* cfunc1p = VN_CAST(node1p, CFunc); - if (!cfunc1p) continue; - // cppcheck-suppress compareBoolExpressionWithInt - if (cfunc1p->slow() != slow) continue; - V3Hash hashval = it->first; - UASSERT_OBJ(!hashval.isIllegal(), node1p, "Illegal (unhashed) nodes"); - for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) { - AstNode* node2p = eqit->second; - if (!(eqit->first == hashval)) break; - if (node1p == node2p) continue; // Identical iterator - if (node1p->user3p() || node2p->user3p()) continue; // Already merged - if (node1p->sameTree(node2p)) { // walk of tree has same comparison - // Replace AstCCall's that point here - replaceFuncWFunc(VN_CAST(node2p, CFunc), cfunc1p); - // Replacement may promote a slow routine to fast path - if (!VN_CAST(node2p, CFunc)->slow()) cfunc1p->slow(false); - } + for (const bool slow : {false, true}) { + for (auto newIt = m_hashed.begin(); newIt != m_hashed.end(); ++newIt) { + AstCFunc* const newfuncp = VN_CAST(newIt->second, CFunc); + UASSERT_OBJ(newfuncp, newIt->second, "Not a CFunc in hash"); + if (newfuncp->user3()) continue; // Already replaced + if (newfuncp->slow() != slow) continue; + auto oldIt = newIt; + ++oldIt; // Skip over current position + for (; oldIt != m_hashed.end(); ++oldIt) { + AstCFunc* const oldfuncp = VN_CAST(oldIt->second, CFunc); + UASSERT_OBJ(oldfuncp, oldIt->second, "Not a CFunc in hash"); + UASSERT_OBJ(newfuncp != oldfuncp, newfuncp, + "Same function hashed multiple times"); + if (newIt->first != oldIt->first) break; // Iterate over same hashes only + if (oldfuncp->user3()) continue; // Already replaced + if (!newfuncp->sameTree(oldfuncp)) continue; // Different functions + + // Replace calls to oldfuncp with calls to newfuncp + UINFO(5, " Replace CFunc " << std::hex << V3Hash(newfuncp->user4p()) << " " + << newfuncp << endl); + UINFO(5, " with " << std::hex << V3Hash(oldfuncp->user4p()) << " " + << oldfuncp << endl); + ++m_cfuncsCombined; + oldfuncp->user3SetOnce(); // Mark replaced + m_call.replaceFunc(oldfuncp, newfuncp); + oldfuncp->unlinkFrBack(); + // Replacement may promote a slow routine to fast path + if (!oldfuncp->slow()) newfuncp->slow(false); + VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); } } } } - void replaceFuncWFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) { - UINFO(5, " DupFunc " << std::hex << V3Hash(newfuncp->user4p()) << " " << newfuncp - << endl); - UINFO(5, " and " << std::hex << V3Hash(oldfuncp->user4p()) << " " << oldfuncp - << endl); - // Mark user3p on entire old tree, so we don't process it more - ++m_statCombs; - CombMarkVisitor visitor(oldfuncp); - m_call.replaceFunc(oldfuncp, newfuncp); - oldfuncp->unlinkFrBack(); - VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); - } - -#ifdef VL_COMBINE_STATEMENTS - void replaceOnlyCallFunc(AstCCall* nodep) { - if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) { - // oldfuncp->dumpTree(cout, "MAYDEL: "); - if (nodep->nextp() == nullptr && oldfuncp->initsp() == nullptr - && oldfuncp->stmtsp() == nodep && oldfuncp->finalsp() == nullptr) { - UINFO(9, " Function only has call " << oldfuncp << endl); - m_call.deleteCall(nodep); - CombMarkVisitor visitor(oldfuncp); - VL_DO_DANGLING(replaceFuncWFunc(oldfuncp, nodep->funcp()), nodep); - } - } - } - - void walkDupCodeStart(AstNode* node1p) { - V3Hash hashval(node1p->user4p()); - // UINFO(4," STMT " << hashval << " " << node1p << endl); - // - int bestDepth = 0; // Best substitution found in the search - AstNode* bestNode2p = nullptr; - AstNode* bestLast1p = nullptr; - AstNode* bestLast2p = nullptr; - // - std::pair eqrange - = m_hashed.mmap().equal_range(hashval); - for (V3Hashed::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) { - AstNode* node2p = eqit->second; - if (node1p == node2p) continue; - // - // We need to mark iteration to prevent matching code inside - // code (abab matching in ababab) - AstNode::user1ClearTree(); // user1p() used on entire tree - m_walkLast1p = nullptr; - m_walkLast2p = nullptr; - int depth = walkDupCodeNext(node1p, node2p, 1); - if (depth > COMBINE_MIN_STATEMENTS && depth > bestDepth) { - bestDepth = depth; - bestNode2p = node2p; - bestLast1p = m_walkLast1p; - bestLast2p = m_walkLast2p; - } - } - if (bestDepth) { - // Found a replacement - UINFO(5, " Duplicate of depth " << bestDepth << endl); - UINFO(5, " DupFunc " - << " " << node1p << endl); - UINFO(5, " and " - << " " << bestNode2p << endl); - UINFO(5, " Through " - << " " << bestLast1p << endl); - UINFO(5, " and " - << " " << bestLast2p << endl); - // - walkReplace(node1p, bestNode2p, bestLast1p, bestLast2p); - } - } - - int walkDupCodeNext(AstNode* node1p, AstNode* node2p, int level) { - // Find number of common statements between the two node1p_nextp's... - if (node1p->user1p() || node2p->user1p()) return 0; // Already iterated - if (node1p->user3p() || node2p->user3p()) return 0; // Already merged - if (!m_hashed.sameNodes(node1p, node2p)) return 0; // walk of tree has same comparison - V3Hash hashval(node1p->user4p()); - // UINFO(9, " wdup1 "<user4p())<<" "<user4p())<<" "<user1(true); - node2p->user1(true); - if (node1p->nextp() && node2p->nextp()) { - return hashval.depth() + walkDupCodeNext(node1p->nextp(), node2p->nextp(), level + 1); - } - return hashval.depth(); - } - - void walkReplace(AstNode* node1p, AstNode* node2p, AstNode* last1p, - AstNode* last2p) { // Final node in linked list, maybe null if all statements - // to be grabbed - // Make new function - string oldname = m_cfuncp->name(); - string::size_type pos; - if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos); - if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos); - AstCFunc* newfuncp = new AstCFunc(node1p->fileline(), - oldname + "_common" + cvtToStr(++m_modNFuncs), nullptr); - m_modp->addStmtp(newfuncp); - // Create calls - AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp); - AstCCall* call2p = new AstCCall(node2p->fileline(), newfuncp); - // Grab statement bodies - AstNRelinker relink1Handle; - AstNRelinker relink2Handle; - for (AstNode *nextp, *walkp = node1p; true; walkp = nextp) { - nextp = walkp->nextp(); - if (walkp == node1p) { - walkp->unlinkFrBack(&relink1Handle); - } else { - walkp->unlinkFrBack(); - node1p->addNext(walkp); - } - if (walkp == last1p) break; - } - for (AstNode *nextp, *walkp = node2p; true; walkp = nextp) { - nextp = walkp->nextp(); - if (walkp == node2p) { - walkp->unlinkFrBack(&relink2Handle); - } else { - walkp->unlinkFrBack(); - node2p->addNext(walkp); - } - if (walkp == last2p) break; - } - // Move node1 statements to new function - newfuncp->addStmtsp(node1p); - // newfuncp->dumpTree(cout, " newfunctree: "); - // Mark node2 statements as dead - CombMarkVisitor visitor(node2p); - pushDeletep(node2p); // Delete later - // Link in new function - relink1Handle.relink(call1p); - relink2Handle.relink(call2p); - // Hash the new function - hashFunctions(newfuncp); - m_call.addCall(call1p); - m_call.addCall(call2p); - // If either new statement makes a func with only a single call, replace - // the above callers to call it directly - VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p); - VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p); - } -#endif // VISITORS virtual void visit(AstNetlist* nodep) override { - // Track all callers of each function - m_call.main(nodep); - // - // In V3Hashed AstNode::user4ClearTree(); // user4p() used on entire tree - // Iterate modules backwards, in bottom-up order. - // Required so that a module instantiating another can benefit from collapsing. - iterateChildrenBackwards(nodep); + m_call.main(nodep); // Track all call sites of each function + iterateChildren(nodep); } virtual void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); - m_modp = nodep; - m_modNFuncs = 0; - m_walkLast2p = nullptr; m_hashed.clear(); - // Compute hash of all statement trees in the function - m_state = STATE_HASH; + // Compute hash of all CFuncs in the module iterateChildren(nodep); - m_state = STATE_IDLE; if (debug() >= 9) m_hashed.dumpFilePrefixed("combine"); // Walk the hashes removing empty functions walkEmptyFuncs(); // Walk the hashes looking for duplicate functions walkDupFuncs(); - // Walk the statements looking for large replicated code sections - // Note this is disabled, it still needed work - // Also repair it for DPI functions; when make __common need to ensure proper - // flags get inherited from the old to new AstCFunc, and that AstText doesn't - // get split between functions causing the text to have a dangling reference. -#ifdef VL_COMBINE_STATEMENTS - { - m_state = STATE_DUP; - iterateChildren(nodep); - m_state = STATE_IDLE; - } -#endif - m_modp = nullptr; } virtual void visit(AstCFunc* nodep) override { - VL_RESTORER(m_cfuncp); - m_cfuncp = nodep; - if (!nodep->dontCombine()) { - if (m_state == STATE_HASH) { - hashStatement(nodep); // Hash the entire function - it might be identical - } -#ifdef VL_COMBINE_STATEMENTS - else if (m_state == STATE_DUP) { - iterateChildren(nodep); - } -#endif - } - } - virtual void visit(AstNodeStmt* nodep) override { - if (!nodep->isStatement()) { - iterateChildren(nodep); - return; - } - if (m_state == STATE_HASH && m_cfuncp) { - hashStatement(nodep); - } -#ifdef VL_COMBINE_STATEMENTS - else if (m_state == STATE_DUP && m_cfuncp) { - walkDupCodeStart(nodep); - } -#endif + if (nodep->dontCombine()) return; + // Hash the entire function + m_hashed.hashAndInsert(nodep); } //-------------------- // Default: Just iterate - virtual void visit(AstVar*) override {} - virtual void visit(AstTraceDecl*) override {} - virtual void visit(AstTraceInc*) override {} + virtual void visit(AstVar*) override {} // Accelerate + virtual void visit(AstNodeStmt* nodep) override {} // Accelerate virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit CombineVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~CombineVisitor() override { // - V3Stats::addStat("Optimizations, Combined CFuncs", m_statCombs); + virtual ~CombineVisitor() override { + V3Stats::addStat("Optimizations, Combined CFuncs", m_cfuncsCombined); } }; From 0f7ec6c9ba52160573df8a7ee90bcc38c837eee7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 17 May 2021 18:24:18 -0400 Subject: [PATCH 41/80] Fix missing array include (#2966) --- include/verilated_heavy.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index e89335434..95622b4ad 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -27,6 +27,7 @@ #include "verilated.h" #include +#include #include #include #include From 9699192de8f3c4a77d686c53c85963e8eb6c72b7 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 18 May 2021 19:28:48 +0100 Subject: [PATCH 42/80] Don't merge bit select assignments in C code (#2971) --- Changes | 1 + src/V3Const.cpp | 2 +- test_regress/t/t_no_sel_assign_merge_in_cpp.pl | 16 ++++++++++++++++ test_regress/t/t_no_sel_assign_merge_in_cpp.v | 14 ++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_no_sel_assign_merge_in_cpp.pl create mode 100644 test_regress/t/t_no_sel_assign_merge_in_cpp.v diff --git a/Changes b/Changes index c5888960a..4951e63e9 100644 --- a/Changes +++ b/Changes @@ -14,6 +14,7 @@ Verilator 4.203 devel **Minor:** * Fix initialization of assoc in assoc array (#2914). [myftptoyman] +* Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] Verilator 4.202 2021-04-24 diff --git a/src/V3Const.cpp b/src/V3Const.cpp index f802d5524..7c78cb314 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1719,7 +1719,7 @@ private: VL_DO_DANGLING(streamp->deleteTree(), streamp); // Further reduce, any of the nodes may have more reductions. return true; - } else if (replaceAssignMultiSel(nodep)) { + } else if (m_doV && replaceAssignMultiSel(nodep)) { return true; } return false; diff --git a/test_regress/t/t_no_sel_assign_merge_in_cpp.pl b/test_regress/t/t_no_sel_assign_merge_in_cpp.pl new file mode 100755 index 000000000..72441b2f8 --- /dev/null +++ b/test_regress/t/t_no_sel_assign_merge_in_cpp.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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(); + +ok(1); +1; diff --git a/test_regress/t/t_no_sel_assign_merge_in_cpp.v b/test_regress/t/t_no_sel_assign_merge_in_cpp.v new file mode 100644 index 000000000..6c7f1a62b --- /dev/null +++ b/test_regress/t/t_no_sel_assign_merge_in_cpp.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t_no_sel_assign_merge_in_cpp ( + input wire [(8*39)-1:0] d_i, + output wire [(8*32)-1:0] d_o +); + for (genvar i = 0; i < 8; i = i + 1) begin + assign d_o[i*32 +: 32] = d_i[i*39 +: 32]; + end +endmodule From aba38830920a74d6d54b40466000912a6ef5b0e8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 19 May 2021 08:14:14 -0400 Subject: [PATCH 43/80] Commentary on MULTIDRIVEN (#2972). --- docs/gen/ex_MULTIDRIVEN_faulty.rst | 11 +++++++++++ docs/gen/ex_MULTIDRIVEN_msg.rst | 6 ++++++ docs/guide/warnings.rst | 22 ++++++++++++++++------ test_regress/driver.pl | 10 ++++++---- test_regress/t/t_lint_multidriven_bad.out | 8 ++++---- test_regress/t/t_lint_multidriven_bad.pl | 10 ++++++++++ test_regress/t/t_lint_multidriven_bad.v | 8 ++++---- 7 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 docs/gen/ex_MULTIDRIVEN_faulty.rst create mode 100644 docs/gen/ex_MULTIDRIVEN_msg.rst diff --git a/docs/gen/ex_MULTIDRIVEN_faulty.rst b/docs/gen/ex_MULTIDRIVEN_faulty.rst new file mode 100644 index 000000000..0be24327d --- /dev/null +++ b/docs/gen/ex_MULTIDRIVEN_faulty.rst @@ -0,0 +1,11 @@ +.. comment: generated by t_lint_multidriven_bad +.. code-block:: sv + :linenos: + :emphasize-lines: 2,5 + + always @(posedge clk) begin + out2[7:0] <= d0; // <--- Warning + end + always @(negedge clk) begin + out2[15:8] <= d0; // <--- Warning + end diff --git a/docs/gen/ex_MULTIDRIVEN_msg.rst b/docs/gen/ex_MULTIDRIVEN_msg.rst new file mode 100644 index 000000000..a2b090f34 --- /dev/null +++ b/docs/gen/ex_MULTIDRIVEN_msg.rst @@ -0,0 +1,6 @@ +.. comment: generated by t_lint_multidriven_bad +.. code-block:: + + %Warning-MULTIDRIVEN: example.v:1:22 Signal has multiple driving blocks with different clocking: 'out2' + example.v:1:7 ... Location of first driving block + example.v:1:7 ... Location of other driving block diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 3ef35d307..3e0840c89 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -803,15 +803,25 @@ List Of Warnings .. option:: MULTIDRIVEN - .. TODO better example + Warns that the specified signal comes from multiple always blocks each + with different clocking. This warning does not look at individual bits + (see example below). - Warns that the specified signal comes from multiple always blocks. This - is often unsupported by synthesis tools, and is considered bad style. - It will also cause longer simulation runtimes due to reduced - optimizations. + This is considered bad style, as the consumer of a given signal may be + unaware of the inconsistent clocking, causing clock domain crossing + bugs. + + Faulty example: + + .. include:: ../../docs/gen/ex_MULTIDRIVEN_faulty.rst + + Results in: + + .. include:: ../../docs/gen/ex_MULTIDRIVEN_msg.rst Ignoring this warning will only slow simulations, it will simulate - correctly. + correctly. It may however cause longer simulation runtimes due to + reduced optimizations. .. option:: MULTITOP diff --git a/test_regress/driver.pl b/test_regress/driver.pl index c2efa85ee..37d0f3a3c 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2449,10 +2449,12 @@ sub _lineno_match { my $lineno = shift; my $lines = shift; return 1 if !defined $lines; - if ($lines =~ /^(\d+)$/) { - return $1 == $lineno; - } elsif ($lines =~ /^(\d+)-(\d+)$/) { - return $1 <= $lineno && $2 >= $lineno; + foreach my $lc (split /,/, $lines) { + if ($lc =~ /^(\d+)$/) { + return 1 if $1 == $lineno; + } elsif ($lc =~ /^(\d+)-(\d+)$/) { + return 1 if $1 <= $lineno && $2 >= $lineno; + } } return 0; } diff --git a/test_regress/t/t_lint_multidriven_bad.out b/test_regress/t/t_lint_multidriven_bad.out index ad7fb6500..231a2368c 100644 --- a/test_regress/t/t_lint_multidriven_bad.out +++ b/test_regress/t/t_lint_multidriven_bad.out @@ -1,17 +1,17 @@ %Warning-MULTIDRIVEN: t/t_lint_multidriven_bad.v:21:22: Signal has multiple driving blocks with different clocking: 't.mem' t/t_lint_multidriven_bad.v:27:7: ... Location of first driving block - 27 | mem[a0] <= d1; + 27 | mem[a0] <= d1; | ^~~ t/t_lint_multidriven_bad.v:24:7: ... Location of other driving block - 24 | mem[a0] <= d0; + 24 | mem[a0] <= d0; | ^~~ ... For warning description see https://verilator.org/warn/MULTIDRIVEN?v=latest ... Use "/* verilator lint_off MULTIDRIVEN */" and lint_on around source to disable this message. %Warning-MULTIDRIVEN: t/t_lint_multidriven_bad.v:19:22: Signal has multiple driving blocks with different clocking: 'out2' t/t_lint_multidriven_bad.v:35:7: ... Location of first driving block - 35 | out2[15:8] <= d0; + 35 | out2[15:8] <= d0; | ^~~~ t/t_lint_multidriven_bad.v:32:7: ... Location of other driving block - 32 | out2[7:0] <= d0; + 32 | out2[7:0] <= d0; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_multidriven_bad.pl b/test_regress/t/t_lint_multidriven_bad.pl index a82cf66cb..32299029f 100755 --- a/test_regress/t/t_lint_multidriven_bad.pl +++ b/test_regress/t/t_lint_multidriven_bad.pl @@ -15,5 +15,15 @@ lint( expect_filename => $Self->{golden_filename}, ); +extract( + in => $Self->{top_filename}, + out => "../docs/gen/ex_MULTIDRIVEN_faulty.rst", + lines => "31-36"); + +extract( + in => $Self->{golden_filename}, + out => "../docs/gen/ex_MULTIDRIVEN_msg.rst", + lines => "10,11,14"); + ok(1); 1; diff --git a/test_regress/t/t_lint_multidriven_bad.v b/test_regress/t/t_lint_multidriven_bad.v index 19d4e86e1..d9f68bdf1 100644 --- a/test_regress/t/t_lint_multidriven_bad.v +++ b/test_regress/t/t_lint_multidriven_bad.v @@ -21,18 +21,18 @@ module t (/*AUTOARG*/ reg [7:0] mem [4]; always @(posedge clk) begin - mem[a0] <= d0; + mem[a0] <= d0; // <--- Warning end always @(negedge clk) begin - mem[a0] <= d1; + mem[a0] <= d1; // <--- Warning end assign out = {mem[3],mem[2],mem[1],mem[0]}; always @(posedge clk) begin - out2[7:0] <= d0; + out2[7:0] <= d0; // <--- Warning end always @(negedge clk) begin - out2[15:8] <= d0; + out2[15:8] <= d0; // <--- Warning end endmodule From a44d2b25704522a66f8123eb6b2f5cdbe8c5b83d Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 20 May 2021 11:30:36 +0100 Subject: [PATCH 44/80] Move unreleased changes in right place in Changelog --- Changes | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 4951e63e9..e3de48608 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,9 @@ Verilator 4.203 devel **Minor:** +* Add --reloop-limit argument (#2943). [Geza Lore] +* Optimize large lookup tables to static data (#2925). [Geza Lore] +* Split always blocks to better respect --output-split-cfuncs. [Geza Lore] * Fix initialization of assoc in assoc array (#2914). [myftptoyman] * Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] @@ -35,11 +38,8 @@ Verilator 4.202 2021-04-24 * Add VerilatedCovContext::forcePerInstance (#2793). [Kevin Laeufer] * Add FST SystemC tracing (#2806). [Alex Torregrosa] * Add PINNOTFOUND warning in place of error (#2868). [Udi Finkelstein] -* Add --reloop-limit argument (#2943). [Geza Lore] * Support overlaps in priority case statements (#2864). [Rupert Swarbrick] * Support for null ports (#2875). [Udi Finkelstein] -* Optimize large lookup tables to static data (#2925). [Geza Lore] -* Split always blocks to better respect --output-split-cfuncs. [Geza Lore] * Fix class unpacked-array compile error (#2774). [Iru Cai] * Fix scope types in FST and VCD traces (#2805). [Alex Torregrosa] * Fix exceeding command-line ar limit (#2834). [Yinan Xu] From fd354922262d7b988035557c204789a9908bca49 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 21 May 2021 01:41:46 +0100 Subject: [PATCH 45/80] Split V3Hashed to V3Hasher and V3DupFinder (#2967) V3Hasher is responsible for computing AstNode hashes, while V3DupFinder can be used to find duplicate trees based on hashes. Interface of V3DupFinder simplified somewhat. No functional change intended at this point, but hash computation might differ in minor details, this however should have no perceivable effect on output/runtime. Implements (#2964) --- src/Makefile_obj.in | 3 +- src/V3Ast.h | 9 +- src/V3Combine.cpp | 18 ++-- src/V3CoverageJoin.cpp | 19 ++-- src/V3DupFinder.cpp | 97 +++++++++++++++++++ src/V3DupFinder.h | 82 ++++++++++++++++ src/V3Gate.cpp | 46 +++++---- src/V3Hashed.cpp | 207 ----------------------------------------- src/V3Hashed.h | 92 ------------------ src/V3Hasher.cpp | 91 ++++++++++++++++++ src/V3Hasher.h | 51 ++++++++++ src/V3Param.cpp | 4 +- src/V3Premit.cpp | 17 ++-- src/V3ProtectLib.cpp | 4 +- src/V3SenTree.h | 4 +- src/V3Table.cpp | 2 +- src/V3Trace.cpp | 25 ++--- 17 files changed, 389 insertions(+), 382 deletions(-) create mode 100644 src/V3DupFinder.cpp create mode 100644 src/V3DupFinder.h delete mode 100644 src/V3Hashed.cpp delete mode 100644 src/V3Hashed.h create mode 100644 src/V3Hasher.cpp create mode 100644 src/V3Hasher.h diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index f6f02249d..861383a57 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -181,6 +181,7 @@ RAW_OBJS = \ V3Depth.o \ V3DepthBlock.o \ V3Descope.o \ + V3DupFinder.o \ V3EmitC.o \ V3EmitCInlines.o \ V3EmitCSyms.o \ @@ -202,7 +203,7 @@ RAW_OBJS = \ V3GraphDfa.o \ V3GraphPathChecker.o \ V3GraphTest.o \ - V3Hashed.o \ + V3Hasher.o \ V3HierBlock.o \ V3Inline.o \ V3Inst.o \ diff --git a/src/V3Ast.h b/src/V3Ast.h index a758bf700..306f75b95 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1358,12 +1358,9 @@ public: } // Creating from raw data (sameHash functions) V3Hash() { setBoth(1, 0); } - // cppcheck-suppress noExplicitConstructor - V3Hash(uint32_t val) { setBoth(1, val); } - // cppcheck-suppress noExplicitConstructor - V3Hash(const void* vp) { setBoth(1, cvtToHash(vp)); } - // cppcheck-suppress noExplicitConstructor - V3Hash(const string& name); + explicit V3Hash(uint32_t val) { setBoth(1, val); } + explicit V3Hash(const void* vp) { setBoth(1, cvtToHash(vp)); } + explicit V3Hash(const string& name); V3Hash(V3Hash h1, V3Hash h2) { setBoth(1, h1.hshval() * 31 + h2.hshval()); } V3Hash(V3Hash h1, V3Hash h2, V3Hash h3) { setBoth(1, (h1.hshval() * 31 + h2.hshval()) * 31 + h3.hshval()); diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 1ae206e7a..4fc8f5e6c 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -24,7 +24,7 @@ #include "V3Global.h" #include "V3Combine.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include "V3Stats.h" #include "V3Ast.h" @@ -114,16 +114,16 @@ private: // NODE STATE // Entire netlist: AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs - // AstUser4InUse part of V3Hashed + // AstUser4InUse part of V3Hasher in V3DupFinder // STATE VDouble0 m_cfuncsCombined; // Statistic tracking CombCallVisitor m_call; // Tracking of function call users - V3Hashed m_hashed; // Hash for every CFunc in module + V3DupFinder m_dupFinder; // Duplicate finder for CFuncs in module // METHODS void walkEmptyFuncs() { - for (const auto& itr : m_hashed) { + for (const auto& itr : m_dupFinder) { AstCFunc* const oldfuncp = VN_CAST(itr.second, CFunc); UASSERT_OBJ(oldfuncp, itr.second, "Not a CFunc in hash"); if (!oldfuncp->emptyBody()) continue; @@ -144,14 +144,14 @@ private: void walkDupFuncs() { // Do non-slow first as then favors naming functions based on fast name for (const bool slow : {false, true}) { - for (auto newIt = m_hashed.begin(); newIt != m_hashed.end(); ++newIt) { + for (auto newIt = m_dupFinder.begin(); newIt != m_dupFinder.end(); ++newIt) { AstCFunc* const newfuncp = VN_CAST(newIt->second, CFunc); UASSERT_OBJ(newfuncp, newIt->second, "Not a CFunc in hash"); if (newfuncp->user3()) continue; // Already replaced if (newfuncp->slow() != slow) continue; auto oldIt = newIt; ++oldIt; // Skip over current position - for (; oldIt != m_hashed.end(); ++oldIt) { + for (; oldIt != m_dupFinder.end(); ++oldIt) { AstCFunc* const oldfuncp = VN_CAST(oldIt->second, CFunc); UASSERT_OBJ(oldfuncp, oldIt->second, "Not a CFunc in hash"); UASSERT_OBJ(newfuncp != oldfuncp, newfuncp, @@ -184,10 +184,10 @@ private: } virtual void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); - m_hashed.clear(); + m_dupFinder.clear(); // Compute hash of all CFuncs in the module iterateChildren(nodep); - if (debug() >= 9) m_hashed.dumpFilePrefixed("combine"); + if (debug() >= 9) m_dupFinder.dumpFilePrefixed("combine"); // Walk the hashes removing empty functions walkEmptyFuncs(); // Walk the hashes looking for duplicate functions @@ -196,7 +196,7 @@ private: virtual void visit(AstCFunc* nodep) override { if (nodep->dontCombine()) return; // Hash the entire function - m_hashed.hashAndInsert(nodep); + m_dupFinder.insert(nodep); } //-------------------- diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index 48cf67fad..f0f30c098 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -22,7 +22,7 @@ #include "V3Global.h" #include "V3CoverageJoin.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include "V3Stats.h" #include @@ -33,10 +33,7 @@ class CoverageJoinVisitor final : public AstNVisitor { private: // NODE STATE - // V3Hashed - // AstCoverToggle->VarRef::user4() // V3Hashed calculation - - // AstUser4InUse In V3Hashed + // AstUser4InUse In V3Hasher via V3DupFinder // STATE std::vector m_toggleps; // List of of all AstCoverToggle's @@ -49,9 +46,9 @@ private: void detectDuplicates() { UINFO(9, "Finding duplicates\n"); // Note uses user4 - V3Hashed hashed; // Duplicate code detection + V3DupFinder dupFinder; // Duplicate code detection // Hash all of the original signals we toggle cover - for (AstCoverToggle* nodep : m_toggleps) hashed.hashAndInsert(nodep->origp()); + for (AstCoverToggle* nodep : m_toggleps) dupFinder.insert(nodep->origp()); // Find if there are any duplicates for (AstCoverToggle* nodep : m_toggleps) { // nodep->backp() is null if we already detected it's a duplicate and unlinked it. @@ -60,10 +57,10 @@ private: // This prevents making chains where a->b, then c->d, then b->c, as we'll // find a->b, a->c, a->d directly. while (true) { - const auto dupit = hashed.findDuplicate(nodep->origp()); - if (dupit == hashed.end()) break; + const auto dupit = dupFinder.findDuplicate(nodep->origp()); + if (dupit == dupFinder.end()) break; // - AstNode* duporigp = hashed.iteratorNodep(dupit); + AstNode* duporigp = dupit->second; // Note hashed will point to the original variable (what's // duplicated), not the covertoggle, but we need to get back to the // covertoggle which is immediately above, so: @@ -82,7 +79,7 @@ private: removep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(removep), removep); // Remove node from comparison so don't hit it again - hashed.erase(dupit); + dupFinder.erase(dupit); ++m_statToggleJoins; } } diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp new file mode 100644 index 000000000..e6aa43d36 --- /dev/null +++ b/src/V3DupFinder.cpp @@ -0,0 +1,97 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hashed common code into functions +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Global.h" +#include "V3DupFinder.h" +#include "V3Ast.h" +#include "V3File.h" + +#include +#include +#include +#include + +//###################################################################### +// V3DupFinder class functions + +bool V3DupFinder::sameNodes(AstNode* node1p, AstNode* node2p) { + return m_hasher(node1p) == m_hasher(node2p) // Same hash + && node1p->sameTree(node2p); // Same tree +} + +V3DupFinder::iterator V3DupFinder::findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp) { + const auto& er = equal_range(m_hasher(nodep)); + for (iterator it = er.first; it != er.second; ++it) { + AstNode* const node2p = it->second; + if (nodep == node2p) continue; // Same node is not a duplicate + if (checkp && !checkp->isSame(nodep, node2p)) continue; // User says it is not a duplicate + if (!nodep->sameTree(node2p)) continue; // Not the same trees + // Found duplicate! + return it; + } + return end(); +} + +void V3DupFinder::dumpFile(const string& filename, bool tree) { + const std::unique_ptr logp(V3File::new_ofstream(filename)); + if (logp->fail()) v3fatal("Can't write " << filename); + + std::unordered_map dist; + + V3Hash lasthash; + int num_in_bucket = 0; + for (auto it = cbegin(); true; ++it) { + if (it == cend() || lasthash != it->first) { + if (it != cend()) lasthash = it->first; + if (num_in_bucket) { + if (dist.find(num_in_bucket) == dist.end()) { + dist.emplace(num_in_bucket, 1); + } else { + ++dist[num_in_bucket]; + } + } + num_in_bucket = 0; + } + if (it == cend()) break; + num_in_bucket++; + } + *logp << "\n*** STATS:\n\n"; + *logp << " #InBucket Occurrences\n"; + for (const auto& i : dist) { + *logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << '\n'; + } + + *logp << "\n*** Dump:\n\n"; + for (const auto& it : *this) { + if (lasthash != it.first) { + lasthash = it.first; + *logp << " " << it.first << '\n'; + } + *logp << "\t" << it.second << '\n'; + // Dumping the entire tree may make nearly N^2 sized dumps, + // because the nodes under this one may also be in the hash table! + if (tree) it.second->dumpTree(*logp, " "); + } +} + +void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) { + if (v3Global.opt.dumpTree()) { // + dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); + } +} diff --git a/src/V3DupFinder.h b/src/V3DupFinder.h new file mode 100644 index 000000000..43a63be0d --- /dev/null +++ b/src/V3DupFinder.h @@ -0,0 +1,82 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hash AST trees to find duplicates +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2005-2021 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 +// +//************************************************************************* +// +// Datastructure for finding duplicate AstNode trees via hashing +// +//************************************************************************* + +#ifndef VERILATOR_V3DUPFINDER_H_ +#define VERILATOR_V3DUPFINDER_H_ +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Error.h" +#include "V3Ast.h" +#include "V3Hasher.h" + +#include + +//============================================================================ + +struct V3DupFinderUserSame { + // Functor for V3DupFinder::findDuplicate + virtual bool isSame(AstNode*, AstNode*) = 0; + V3DupFinderUserSame() = default; + virtual ~V3DupFinderUserSame() = default; +}; + +// This really is just a multimap from 'node hash' to 'node pointer', with some minor extensions. +class V3DupFinder final : private std::multimap { + using Super = std::multimap; + + // MEMBERS + const V3Hasher m_hasher; + +public: + // CONSTRUCTORS + V3DupFinder(){}; + ~V3DupFinder() = default; + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + // Expose minimal set of superclass interface + using Super::begin; + using Super::cbegin; + using Super::cend; + using Super::clear; + using Super::const_iterator; + using Super::empty; + using Super::end; + using Super::erase; + using Super::iterator; + + // Insert node into data structure + iterator insert(AstNode* nodep) { return emplace(m_hasher(nodep), nodep); } + + // Check if nodes are the same (same as node1p->sameTree(node2p), + // but first checks the hashes are equal for speed) + bool sameNodes(AstNode* node1p, AstNode* node2p); + + // Return duplicate, if one was inserted, with optional user check for sameness + iterator findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp = nullptr); + + // Dump for debug + void dumpFile(const string& filename, bool tree); + void dumpFilePrefixed(const string& nameComment, bool tree = false); +}; + +#endif // Guard diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 913c6c645..a23c89485 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -30,7 +30,7 @@ #include "V3Graph.h" #include "V3Const.h" #include "V3Stats.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include #include @@ -900,7 +900,7 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* //###################################################################### // Auxiliary hash class for GateDedupeVarVisitor -class GateDedupeHash final : public V3HashedUserSame { +class GateDedupeHash final : public V3DupFinderUserSame { private: // NODE STATE // Ast*::user2p -> parent AstNodeAssign* for this rhsp @@ -911,22 +911,22 @@ private: // AstUser1InUse m_inuser1; (Allocated for use in GateVisitor) // AstUser2InUse m_inuser2; (Allocated for use in GateVisitor) AstUser3InUse m_inuser3; - // AstUser4InUse m_inuser4; (Allocated for use in V3Hashed) + // AstUser4InUse m_inuser4; (Allocated for use in V3Hasher via V3DupFinder) AstUser5InUse m_inuser5; - V3Hashed m_hashed; // Hash, contains rhs of assigns + V3DupFinder m_dupFinder; // Duplicate finder for rhs of assigns std::unordered_set m_nodeDeleteds; // Any node in this hash was deleted VL_DEBUG_FUNC; // Declare debug() - void hash(AstNode* nodep) { - // !nullptr && the object is hashable - if (nodep && !nodep->sameHash().isIllegal()) m_hashed.hash(nodep); - } bool sameHash(AstNode* node1p, AstNode* node2p) { - return (node1p && node2p && !node1p->sameHash().isIllegal() - && !node2p->sameHash().isIllegal() && m_hashed.sameNodes(node1p, node2p)); + return node1p // + && node2p // + && !node1p->sameHash().isIllegal() // + && !node2p->sameHash().isIllegal() // + && m_dupFinder.sameNodes(node1p, node2p); } + bool same(AstNode* node1p, AstNode* node2p) { return node1p == node2p || sameHash(node1p, node2p); } @@ -958,7 +958,7 @@ public: || (extra2p && m_nodeDeleteds.find(extra2p) != m_nodeDeleteds.end())); } - // Callback from V3Hashed::findDuplicate + // Callback from V3DupFinder::findDuplicate virtual bool isSame(AstNode* node1p, AstNode* node2p) override { // Assignment may have been hashReplaced, if so consider non-match (effectively removed) if (isReplaced(node1p) || isReplaced(node2p)) { @@ -977,25 +977,21 @@ public: rhsp->user3p(extra1p); rhsp->user5p(extra2p); - hash(extra1p); - hash(extra2p); - - const auto inserted = m_hashed.hashAndInsert(rhsp); - const auto dupit = m_hashed.findDuplicate(rhsp, this); - // Even though rhsp was just inserted, V3Hashed::findDuplicate doesn't - // return anything in the hash that has the same pointer (V3Hashed.cpp::findDuplicate) + const auto inserted = m_dupFinder.insert(rhsp); + const auto dupit = m_dupFinder.findDuplicate(rhsp, this); + // Even though rhsp was just inserted, V3DupFinder::findDuplicate doesn't + // return anything in the hash that has the same pointer (V3DupFinder::findDuplicate) // So dupit is either a different, duplicate rhsp, or the end of the hash. - if (dupit != m_hashed.end()) { - m_hashed.erase(inserted); - return VN_CAST(m_hashed.iteratorNodep(dupit)->user2p(), NodeAssign); + if (dupit != m_dupFinder.end()) { + m_dupFinder.erase(inserted); + return VN_CAST(dupit->second->user2p(), NodeAssign); } // Retain new inserted information return nullptr; } void check() { - m_hashed.check(); - for (const auto& itr : m_hashed) { + for (const auto& itr : m_dupFinder) { AstNode* nodep = itr.second; AstNode* activep = nodep->user3p(); AstNode* condVarp = nodep->user5p(); @@ -1003,9 +999,9 @@ public: // This class won't break if activep isn't an active, or // ifVar isn't a var, but this is checking the caller's construction. UASSERT_OBJ(!activep || (!VN_DELETED(activep) && VN_IS(activep, Active)), nodep, - "V3Hashed check failed, lost active pointer"); + "V3DupFinder check failed, lost active pointer"); UASSERT_OBJ(!condVarp || !VN_DELETED(condVarp), nodep, - "V3Hashed check failed, lost if pointer"); + "V3DupFinder check failed, lost if pointer"); } } } diff --git a/src/V3Hashed.cpp b/src/V3Hashed.cpp deleted file mode 100644 index acfe9ba94..000000000 --- a/src/V3Hashed.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Hashed common code into functions -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// Copyright 2003-2021 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 -// -//************************************************************************* -// V3Hashed's Transformations: -// -// Hash each node depth first -// Hash includes varp name and operator type, and constants -// Form lookup table based on hash of each statement w/ nodep and next nodep -// -//************************************************************************* - -#include "config_build.h" -#include "verilatedos.h" - -#include "V3Global.h" -#include "V3Hashed.h" -#include "V3Ast.h" -#include "V3File.h" - -#include -#include -#include -#include - -//###################################################################### -// Hashed state, as a visitor of each AstNode - -class HashedVisitor final : public AstNVisitor { -private: - // NODE STATE - // Entire netlist: - // AstNodeStmt::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) - // AstUser4InUse in V3Hashed.h - - // STATE - V3Hash m_lowerHash; // Hash of the statement we're building - bool m_cacheInUser4; // Use user4 to cache each V3Hash? - - // METHODS - VL_DEBUG_FUNC; // Declare debug() - - void nodeHashIterate(AstNode* nodep) { - V3Hash thisHash; - if (!m_cacheInUser4 || !nodep->user4()) { - UASSERT_OBJ( - !(VN_IS(nodep->backp(), CFunc) - && !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))), - nodep, - "Node " << nodep->prettyTypeName() - << " in statement position but not marked stmt (node under function)"); - VL_RESTORER(m_lowerHash); - { - m_lowerHash = nodep->sameHash(); - UASSERT_OBJ(!m_lowerHash.isIllegal(), nodep, - "sameHash function undefined (returns 0) for node under CFunc."); - // For identical nodes, the type should be the same thus - // dtypep should be the same too - m_lowerHash - = V3Hash(m_lowerHash, V3Hash(nodep->type() << 6, V3Hash(nodep->dtypep()))); - // Now update m_lowerHash for our children's (and next children) contributions - iterateChildren(nodep); - // Store the hash value - nodep->user4(m_lowerHash.fullValue()); - // UINFO(9, " hashnode "<(nodep)); - } - V3Hash finalHash() const { return m_lowerHash; } - virtual ~HashedVisitor() override = default; -}; - -//###################################################################### -// Hashed class functions - -V3Hash V3Hashed::uncachedHash(const AstNode* nodep) { - HashedVisitor visitor(nodep); - return visitor.finalHash(); -} - -V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) { - hash(nodep); - return m_hashMmap.emplace(nodeHash(nodep), nodep); -} - -void V3Hashed::hash(AstNode* nodep) { - UINFO(8, " hashI " << nodep << endl); - if (!nodep->user4p()) { HashedVisitor visitor(nodep); } -} - -bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) { - UASSERT_OBJ(node1p->user4p(), node1p, "Called isIdentical on non-hashed nodes"); - UASSERT_OBJ(node2p->user4p(), node2p, "Called isIdentical on non-hashed nodes"); - return (node1p->user4p() == node2p->user4p() // Same hash - && node1p->sameTree(node2p)); -} - -void V3Hashed::erase(iterator it) { - AstNode* nodep = iteratorNodep(it); - UINFO(8, " erase " << nodep << endl); - UASSERT_OBJ(nodep->user4p(), nodep, "Called removeNode on non-hashed node"); - m_hashMmap.erase(it); - nodep->user4p(nullptr); // So we don't allow removeNode again -} - -void V3Hashed::check() { - for (const auto& itr : *this) { - AstNode* nodep = itr.second; - UASSERT_OBJ(nodep->user4p(), nodep, "V3Hashed check failed, non-hashed node"); - } -} - -void V3Hashed::dumpFilePrefixed(const string& nameComment, bool tree) { - if (v3Global.opt.dumpTree()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); -} - -void V3Hashed::dumpFile(const string& filename, bool tree) { - const std::unique_ptr logp(V3File::new_ofstream(filename)); - if (logp->fail()) v3fatal("Can't write " << filename); - - std::unordered_map dist; - - V3Hash lasthash; - int num_in_bucket = 0; - for (HashMmap::iterator it = begin(); true; ++it) { - if (it == end() || lasthash != it->first) { - if (it != end()) lasthash = it->first; - if (num_in_bucket) { - if (dist.find(num_in_bucket) == dist.end()) { - dist.emplace(num_in_bucket, 1); - } else { - ++dist[num_in_bucket]; - } - } - num_in_bucket = 0; - } - if (it == end()) break; - num_in_bucket++; - } - *logp << "\n*** STATS:\n\n"; - *logp << " #InBucket Occurrences\n"; - for (const auto& i : dist) { - *logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << '\n'; - } - - *logp << "\n*** Dump:\n\n"; - for (const auto& itr : *this) { - if (lasthash != itr.first) { - lasthash = itr.first; - *logp << " " << itr.first << '\n'; - } - *logp << "\t" << itr.second << '\n'; - // Dumping the entire tree may make nearly N^2 sized dumps, - // because the nodes under this one may also be in the hash table! - if (tree) itr.second->dumpTree(*logp, " "); - } -} - -V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep, V3HashedUserSame* checkp) { - UINFO(8, " findD " << nodep << endl); - UASSERT_OBJ(nodep->user4p(), nodep, "Called findDuplicate on non-hashed node"); - std::pair eqrange - = mmap().equal_range(nodeHash(nodep)); - for (HashMmap::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) { - AstNode* node2p = eqit->second; - if (nodep != node2p && (!checkp || checkp->isSame(nodep, node2p)) - && sameNodes(nodep, node2p)) { - return eqit; - } - } - return end(); -} diff --git a/src/V3Hashed.h b/src/V3Hashed.h deleted file mode 100644 index 07bdcb7d4..000000000 --- a/src/V3Hashed.h +++ /dev/null @@ -1,92 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Hash AST trees to find duplicates -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// Copyright 2005-2021 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 -// -//************************************************************************* - -#ifndef VERILATOR_V3HASHED_H_ -#define VERILATOR_V3HASHED_H_ -#include "config_build.h" -#include "verilatedos.h" - -#include "V3Error.h" -#include "V3Ast.h" - -//============================================================================ - -class VHashedBase VL_NOT_FINAL { -public: - // CONSTRUCTORS - VHashedBase() = default; - ~VHashedBase() = default; - - // METHODS - VL_DEBUG_FUNC; // Declare debug() -}; - -//============================================================================ - -struct V3HashedUserSame { - // Functor for V3Hashed::findDuplicate - virtual bool isSame(AstNode*, AstNode*) = 0; - V3HashedUserSame() = default; - virtual ~V3HashedUserSame() = default; -}; - -class V3Hashed final : public VHashedBase { - // NODE STATE - // AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) - AstUser4InUse m_inuser4; - - // TYPES -public: - using HashMmap = std::multimap; - using iterator = HashMmap::iterator; - -private: - // MEMBERS - HashMmap m_hashMmap; // hashvalue -> nodes with that hash - -public: - // CONSTRUCTORS - V3Hashed() { clear(); } - ~V3Hashed() = default; - - // ACCESSORS - HashMmap& mmap() { return m_hashMmap; } // Return map for iteration - iterator begin() { return m_hashMmap.begin(); } - iterator end() { return m_hashMmap.end(); } - - // METHODS - void clear() { - m_hashMmap.clear(); - AstNode::user4ClearTree(); - } - void check(); // Check assertions on structure - // Hash the node, and insert into map. Return iterator to inserted - iterator hashAndInsert(AstNode* nodep); - static void hash(AstNode* nodep); // Only hash the node - // After hashing, and tell if identical - static bool sameNodes(AstNode* node1p, AstNode* node2p); - void erase(iterator it); // Remove node from structures - // Return duplicate in hash, if any, with optional user check for sameness - iterator findDuplicate(AstNode* nodep, V3HashedUserSame* checkp = nullptr); - AstNode* iteratorNodep(iterator it) { return it->second; } - void dumpFile(const string& filename, bool tree); - void dumpFilePrefixed(const string& nameComment, bool tree = false); - static V3Hash nodeHash(AstNode* nodep) { return V3Hash(nodep->user4p()); } - // Hash of the nodep tree, without caching in user4. - static V3Hash uncachedHash(const AstNode* nodep); -}; - -#endif // Guard diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp new file mode 100644 index 000000000..4a8f51742 --- /dev/null +++ b/src/V3Hasher.cpp @@ -0,0 +1,91 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hashed common code into functions +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Hasher.h" + +//###################################################################### +// Visitor that computes node hashes + +class HasherVisitor final : public AstNVisitor { +private: + // NODE STATE + // AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) + // AstUser4InUse in V3Hasher.h + + // STATE + V3Hash m_lowerHash; // Hash of the statement we're building + const bool m_cacheInUser4; // Use user4 to cache each V3Hash? + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + //-------------------- + virtual void visit(AstVar*) override {} + virtual void visit(AstTypedef*) override {} + virtual void visit(AstParamTypeDType*) override {} + + virtual void visit(AstNode* nodep) override { + V3Hash thisHash; + if (!m_cacheInUser4 || !nodep->user4()) { + VL_RESTORER(m_lowerHash); + { + m_lowerHash = nodep->sameHash(); + UASSERT_OBJ(!m_lowerHash.isIllegal(), nodep, + "sameHash function undefined (returns 0) for node under CFunc."); + // For identical nodes, the type should be the same thus + // dtypep should be the same too + m_lowerHash = V3Hash(m_lowerHash, + V3Hash(V3Hash(nodep->type() << 6), V3Hash(nodep->dtypep()))); + // Now update m_lowerHash for our children's (and next children) contributions + iterateChildrenConst(nodep); + // Store the hash value + if (m_cacheInUser4) { nodep->user4(m_lowerHash.fullValue()); } + thisHash = m_lowerHash; + } + } + // Update what will become the above node's hash + m_lowerHash += m_cacheInUser4 ? V3Hash(nodep->user4()) : thisHash; + } + +public: + // CONSTRUCTORS + explicit HasherVisitor(AstNode* nodep) + : m_cacheInUser4{true} { + iterate(nodep); + } + explicit HasherVisitor(const AstNode* nodep) + : m_cacheInUser4{false} { + iterate(const_cast(nodep)); + } + V3Hash finalHash() const { return m_lowerHash; } + virtual ~HasherVisitor() override = default; +}; + +//###################################################################### +// V3Hasher methods + +V3Hash V3Hasher::operator()(AstNode* nodep) const { + if (!nodep->user4()) { HasherVisitor visitor(nodep); } + return V3Hash(nodep->user4()); +} + +V3Hash V3Hasher::uncachedHash(const AstNode* nodep) { + HasherVisitor visitor(nodep); + return visitor.finalHash(); +} diff --git a/src/V3Hasher.h b/src/V3Hasher.h new file mode 100644 index 000000000..fc90de27f --- /dev/null +++ b/src/V3Hasher.h @@ -0,0 +1,51 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hash AST trees to find duplicates +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2005-2021 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 +// +//************************************************************************* +// +// V3Hasher handles computation of AstNode hashes +// +//************************************************************************* + +#ifndef VERILATOR_V3HASHER_H_ +#define VERILATOR_V3HASHER_H_ +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Error.h" +#include "V3Ast.h" + +//============================================================================ + +class V3Hasher final { + // NODE STATE + // AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) + AstUser4InUse m_inuser4; + +public: + // CONSTRUCTORS + V3Hasher() = default; + ~V3Hasher() = default; + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + // Compute hash of node. This method caches the hash in the node's user4(). + V3Hash operator()(AstNode* nodep) const; + + // Compute hash of node, without caching in user4. + static V3Hash uncachedHash(const AstNode* nodep); +}; + +#endif // Guard diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 8b7ba30d6..a681572c0 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -56,7 +56,7 @@ #include "V3Parse.h" #include "V3Width.h" #include "V3Unroll.h" -#include "V3Hashed.h" +#include "V3Hasher.h" #include #include @@ -314,7 +314,7 @@ class ParamProcessor final { key += "[" + cvtToStr(bdtp->left()) + ":" + cvtToStr(bdtp->right()) + "]"; } } - V3Hash hash = V3Hashed::uncachedHash(nodep); + V3Hash hash = V3Hasher::uncachedHash(nodep); // Force hash collisions -- for testing only if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash(); int num; diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index ebd47c626..82c2404ae 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -30,7 +30,7 @@ #include "V3Global.h" #include "V3Premit.h" #include "V3Ast.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include "V3Stats.h" #include @@ -96,7 +96,7 @@ private: // *::user4() -> See PremitAssignVisitor AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; - // AstUser4InUse part of V3Hashed + // AstUser4InUse part of V3Hasher via V3DupFinder // STATE AstNodeModule* m_modp = nullptr; // Current module @@ -106,7 +106,7 @@ private: AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts - V3Hashed m_hashed; // Hash set for static constants that can be reused + V3DupFinder m_dupFinder; // Duplicate finder for static constants that can be reused VDouble0 m_staticConstantsExtracted; // Statistic tracking VDouble0 m_staticConstantsReused; // Statistic tracking @@ -184,9 +184,8 @@ private: && !constp->num().isFourState(); if (useStatic) { // Extract as static constant - m_hashed.hash(constp); - const auto& it = m_hashed.findDuplicate(constp); - if (it == m_hashed.end()) { + const auto& it = m_dupFinder.findDuplicate(constp); + if (it == m_dupFinder.end()) { const string newvarname = string("__Vconst") + cvtToStr(m_modp->varNumGetInc()); varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep->dtypep()); @@ -194,7 +193,7 @@ private: varp->isStatic(true); varp->valuep(constp); m_modp->addStmtp(varp); - m_hashed.hashAndInsert(constp); + m_dupFinder.insert(constp); nodep->user2p(varp); ++m_staticConstantsExtracted; } else { @@ -230,12 +229,12 @@ private: virtual void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); UASSERT_OBJ(m_modp == nullptr, nodep, "Nested modules ?"); - UASSERT_OBJ(m_hashed.mmap().empty(), nodep, "Statements outside module ?"); + UASSERT_OBJ(m_dupFinder.empty(), nodep, "Statements outside module ?"); m_modp = nodep; m_cfuncp = nullptr; iterateChildren(nodep); m_modp = nullptr; - m_hashed.clear(); + m_dupFinder.clear(); } virtual void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index ec267187c..7c42f868c 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -20,7 +20,7 @@ #include "V3Global.h" #include "V3String.h" #include "V3ProtectLib.h" -#include "V3Hashed.h" +#include "V3Hasher.h" #include "V3Task.h" #include @@ -87,7 +87,7 @@ private: iterateChildren(nodep); - V3Hash hash = V3Hashed::uncachedHash(m_cfilep); + V3Hash hash = V3Hasher::uncachedHash(m_cfilep); m_hashValuep->addText(fl, cvtToStr(hash.fullValue()) + ";\n"); m_cHashValuep->addText(fl, cvtToStr(hash.fullValue()) + "U;\n"); m_foundTop = true; diff --git a/src/V3SenTree.h b/src/V3SenTree.h index 501157652..78d5f3a34 100644 --- a/src/V3SenTree.h +++ b/src/V3SenTree.h @@ -23,7 +23,7 @@ #include "verilatedos.h" #include "V3Ast.h" -#include "V3Hashed.h" +#include "V3Hasher.h" #include @@ -37,7 +37,7 @@ private: // TYPES struct HashSenTree { size_t operator()(const AstSenTree* kp) const { - return V3Hashed::uncachedHash(kp).fullValue(); + return V3Hasher::uncachedHash(kp).fullValue(); } }; diff --git a/src/V3Table.cpp b/src/V3Table.cpp index c31adb692..eb29e3639 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -342,7 +342,7 @@ private: AstVarScope* findDuplicateTable(AstVarScope* vsc1p) { // See if another table we've created is identical, if so use it for both. - // (A more 'modern' way would be to instead use V3Hashed::findDuplicate) + // (A more 'modern' way would be to instead use V3DupFinder::findDuplicate) AstVar* var1p = vsc1p->varp(); for (AstVarScope* vsc2p : m_modTableVscs) { AstVar* var2p = vsc2p->varp(); diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 49ee14933..601c285e0 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -42,7 +42,7 @@ #include "V3Trace.h" #include "V3EmitCBase.h" #include "V3Graph.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include "V3Stats.h" #include @@ -154,8 +154,8 @@ public: class TraceVisitor final : public EmitCBaseVisitor { private: // NODE STATE - // V3Hashed - // Ast*::user4() // V3Hashed calculation + // V3Hasher in V3DupFinder + // Ast*::user4() // V3Hasher calculation // Cleared entire netlist // AstCFunc::user1() // V3GraphVertex* for this node // AstTraceDecl::user1() // V3GraphVertex* for this node @@ -165,7 +165,7 @@ private: AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; AstUser3InUse m_inuser3; - // AstUser4InUse In V3Hashed + // AstUser4InUse In V3Hasher via V3DupFinder // STATE AstNodeModule* m_topModp = nullptr; // Module to add variables to @@ -194,7 +194,7 @@ private: void detectDuplicates() { UINFO(9, "Finding duplicates\n"); // Note uses user4 - V3Hashed hashed; // Duplicate code detection + V3DupFinder dupFinder; // Duplicate code detection // Hash all of the values the traceIncs need for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { @@ -205,13 +205,9 @@ private: UASSERT_OBJ(nodep->valuep()->backp() == nodep, nodep, "Trace duplicate back needs consistency," " so we can map duplicates back to TRACEINCs"); - hashed.hash(nodep->valuep()); - UINFO(8, " Hashed " << std::hex << hashed.nodeHash(nodep->valuep()) << " " - << nodep << endl); - // Just keep one node in the map and point all duplicates to this node - if (hashed.findDuplicate(nodep->valuep()) == hashed.end()) { - hashed.hashAndInsert(nodep->valuep()); + if (dupFinder.findDuplicate(nodep->valuep()) == dupFinder.end()) { + dupFinder.insert(nodep->valuep()); } } } @@ -221,10 +217,10 @@ private: if (TraceTraceVertex* const vvertexp = dynamic_cast(itp)) { AstTraceDecl* const nodep = vvertexp->nodep(); if (nodep->valuep() && !vvertexp->duplicatep()) { - const auto dupit = hashed.findDuplicate(nodep->valuep()); - if (dupit != hashed.end()) { + const auto dupit = dupFinder.findDuplicate(nodep->valuep()); + if (dupit != dupFinder.end()) { const AstTraceDecl* const dupDeclp - = VN_CAST_CONST(hashed.iteratorNodep(dupit)->backp(), TraceDecl); + = VN_CAST_CONST(dupit->second->backp(), TraceDecl); UASSERT_OBJ(dupDeclp, nodep, "Trace duplicate of wrong type"); TraceTraceVertex* const dupvertexp = dynamic_cast(dupDeclp->user1u().toGraphVertex()); @@ -237,7 +233,6 @@ private: } } } - hashed.clear(); } void graphSimplify(bool initial) { From 8814111724dfe597c0255d4837e18a88df44c03c Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 21 May 2021 14:34:27 +0100 Subject: [PATCH 46/80] Rework Ast hashing to be stable (#2974) Rework Ast hashing to be stable Eliminated reliance on pointer values in AstNode hashes in order to make them stable. This requires moving the sameHash functions into a visitor, as nodes pointed to via members (and not child nodes) need to be hashed themselves. The hashes are now stable (as far as I could test them), and the impact on verilation time is small enough not to be reliably measurable. --- src/Makefile_obj.in | 1 + src/V3Ast.cpp | 14 -- src/V3Ast.h | 76 +------- src/V3AstNodes.h | 142 +------------- src/V3Combine.cpp | 9 +- src/V3DupFinder.cpp | 5 - src/V3DupFinder.h | 4 - src/V3Gate.cpp | 30 ++- src/V3Hash.cpp | 27 +++ src/V3Hash.h | 65 +++++++ src/V3Hasher.cpp | 442 ++++++++++++++++++++++++++++++++++++++++--- src/V3Hasher.h | 1 + src/V3Number.cpp | 2 +- src/V3Number.h | 3 +- src/V3ProtectLib.cpp | 4 +- src/V3SenTree.h | 2 +- 16 files changed, 559 insertions(+), 268 deletions(-) create mode 100644 src/V3Hash.cpp create mode 100644 src/V3Hash.h diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 861383a57..e431515ba 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -203,6 +203,7 @@ RAW_OBJS = \ V3GraphDfa.o \ V3GraphPathChecker.o \ V3GraphTest.o \ + V3Hash.o \ V3Hasher.o \ V3HierBlock.o \ V3Inline.o \ diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 7be1e7a4d..4329c7633 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -970,20 +970,6 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig && (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly))); } -//====================================================================== -// Static utilities - -std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) { - return os << std::hex << std::setw(2) << std::setfill('0') << rhs.depth() << "_" - << std::setw(6) << std::setfill('0') << rhs.hshval(); -} - -V3Hash::V3Hash(const string& name) { - uint32_t val = 0; - for (const auto& c : name) val = val * 31 + c; - setBoth(1, val); -} - //====================================================================== // Debugging diff --git a/src/V3Ast.h b/src/V3Ast.h index 306f75b95..827b9649a 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1271,6 +1271,8 @@ public: virtual ~AstNVisitor() { doDeletes(); } /// Call visit()s on nodep void iterate(AstNode* nodep); + /// Call visit()s on nodep + void iterateNull(AstNode* nodep); /// Call visit()s on nodep's children void iterateChildren(AstNode* nodep); /// Call visit()s on nodep's children in backp() order @@ -1321,56 +1323,6 @@ inline std::ostream& operator<<(std::ostream& os, const AstNRelinker& rhs) { return os; } -//###################################################################### -// V3Hash -- Node hashing for V3Combine - -class V3Hash final { - // A hash of a tree of nodes, consisting of 8 bits with the number of nodes in the hash - // and 24 bit value hash of relevant information about the node. - // A value of 0 is illegal - uint32_t m_both; - static const uint32_t M24 = ((1 << 24) - 1); - void setBoth(uint32_t depth, uint32_t hshval) { - if (depth == 0) depth = 1; - if (depth > 255) depth = 255; - m_both = (depth << 24) | (hshval & M24); - } - -public: - // METHODS - bool isIllegal() const { return m_both == 0; } - uint32_t fullValue() const { return m_both; } - uint32_t depth() const { return (m_both >> 24) & 255; } - uint32_t hshval() const { return m_both & M24; } - // OPERATORS - bool operator==(const V3Hash& rh) const { return m_both == rh.m_both; } - bool operator!=(const V3Hash& rh) const { return m_both != rh.m_both; } - bool operator<(const V3Hash& rh) const { return m_both < rh.m_both; } - // CONSTRUCTORS - class Illegal {}; // for creator type-overload selection - class FullValue {}; // for creator type-overload selection - explicit V3Hash(Illegal) { m_both = 0; } - // Saving and restoring inside a userp - explicit V3Hash(const VNUser& u) { m_both = u.toInt(); } - V3Hash operator+=(const V3Hash& rh) { - setBoth(depth() + rh.depth(), (hshval() * 31 + rh.hshval())); - return *this; - } - // Creating from raw data (sameHash functions) - V3Hash() { setBoth(1, 0); } - explicit V3Hash(uint32_t val) { setBoth(1, val); } - explicit V3Hash(const void* vp) { setBoth(1, cvtToHash(vp)); } - explicit V3Hash(const string& name); - V3Hash(V3Hash h1, V3Hash h2) { setBoth(1, h1.hshval() * 31 + h2.hshval()); } - V3Hash(V3Hash h1, V3Hash h2, V3Hash h3) { - setBoth(1, (h1.hshval() * 31 + h2.hshval()) * 31 + h3.hshval()); - } - V3Hash(V3Hash h1, V3Hash h2, V3Hash h3, V3Hash h4) { - setBoth(1, ((h1.hshval() * 31 + h2.hshval()) * 31 + h3.hshval()) * 31 + h4.hshval()); - } -}; -std::ostream& operator<<(std::ostream& os, const V3Hash& rhs); - //###################################################################### // Callback base class to determine if node matches some formula @@ -1832,9 +1784,6 @@ public: // statement is unlikely to be taken virtual bool isUnlikely() const { return false; } virtual int instrCount() const { return 0; } - virtual V3Hash sameHash() const { - return V3Hash(V3Hash::Illegal()); // Not a node that supports it - } virtual bool same(const AstNode*) const { return true; } // Iff has a data type; dtype() must be non null virtual bool hasDType() const { return false; } @@ -1968,7 +1917,6 @@ public: virtual bool signedFlavor() const { return false; } virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; @@ -2002,7 +1950,6 @@ public: virtual bool signedFlavor() const { return false; } virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; @@ -2037,7 +1984,6 @@ public: virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; @@ -2076,7 +2022,6 @@ public: virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; @@ -2180,7 +2125,6 @@ public: void thsp(AstNode* nodep) { return setOp3p(nodep); } void attrp(AstAttrOf* nodep) { return setOp4p((AstNode*)nodep); } // METHODS - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; @@ -2242,7 +2186,6 @@ public: virtual bool hasDType() const override { return true; } virtual bool cleanRhs() const { return true; } virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } virtual string verilogKwd() const override { return "="; } virtual bool brokeLhsMustBeLvalue() const = 0; @@ -2267,7 +2210,6 @@ public: AstNode* bodysp() const { return op4p(); } // op4 = body of loop virtual bool isGateOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -2293,7 +2235,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isGateDedupable() const override { return true; } virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void branchPred(VBranchPred flag) { m_branchPred = flag; } VBranchPred branchPred() const { return m_branchPred; } @@ -2390,7 +2331,6 @@ protected: public: ASTNODE_BASE_FUNCS(NodeText) virtual void dump(std::ostream& str = std::cout) const override; - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool same(const AstNode* samep) const override { const AstNodeText* asamep = static_cast(samep); return text() == asamep->text(); @@ -2511,10 +2451,12 @@ private: bool m_packed; bool m_isFourstate; MemberNameMap m_members; + const int m_uniqueNum; protected: AstNodeUOrStructDType(AstType t, FileLine* fl, VSigning numericUnpack) - : AstNodeDType{t, fl} { + : AstNodeDType{t, fl} + , m_uniqueNum{uniqueNumInc()} { // VSigning::NOSIGN overloaded to indicate not packed m_packed = (numericUnpack != VSigning::NOSIGN); m_isFourstate = false; // V3Width computes @@ -2523,6 +2465,7 @@ protected: public: ASTNODE_BASE_FUNCS(NodeUOrStructDType) + int uniqueNum() const { return m_uniqueNum; } virtual const char* broken() const override; virtual void dump(std::ostream& str) const override; virtual bool isCompound() const override { return false; } // Because don't support unpacked @@ -2601,9 +2544,6 @@ public: && rangenp()->sameTree(asamep->rangenp()) && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m_refDTypep), V3Hash(hi()), V3Hash(lo())); - } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } @@ -2688,7 +2628,6 @@ public: virtual void cloneRelink() override; virtual const char* broken() const override; virtual int instrCount() const override { return instrCountCall(); } - virtual V3Hash sameHash() const override { return V3Hash(funcp()); } virtual bool same(const AstNode* samep) const override { const AstNodeCCall* asamep = static_cast(samep); return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); @@ -2983,6 +2922,9 @@ public: // Inline AstNVisitor METHODS inline void AstNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); } +inline void AstNVisitor::iterateNull(AstNode* nodep) { + if (VL_LIKELY(nodep)) nodep->accept(*this); +} inline void AstNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); } inline void AstNVisitor::iterateChildrenBackwards(AstNode* nodep) { nodep->iterateChildrenBackwards(*this); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b8a2621a5..d88e700fe 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -170,7 +170,6 @@ public: virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(num().toHash()); } virtual bool same(const AstNode* samep) const override { const AstConst* sp = static_cast(samep); return num().isCaseEq(sp->num()); @@ -226,7 +225,6 @@ public: bool littleEndian() const { return leftConst() < rightConst(); } virtual void dump(std::ostream& str) const override; virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -241,7 +239,6 @@ public: ASTNODE_NODE_FUNCS(BracketRange) virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // Will be removed in V3Width, which relies on this // being a child not a dtype pointed node @@ -257,7 +254,6 @@ public: ASTNODE_NODE_FUNCS(UnsizedRange) virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitVerilog() { return "[]"; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -473,27 +469,27 @@ private: string m_name; void* m_containerp; // In what scope is the name unique, so we can know what are duplicate // definitions (arbitrary value) - int m_uniqueNum; + const int m_uniqueNum; public: AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, VFlagChildDType, AstNodeDType* dtp) : ASTGEN_SUPER(fl) , m_name{name} - , m_containerp{containerp} { + , m_containerp{containerp} + , m_uniqueNum{uniqueNumInc()} { childDTypep(dtp); // Only for parser dtypep(nullptr); // V3Width will resolve - m_uniqueNum = uniqueNumInc(); } ASTNODE_NODE_FUNCS(DefImplicitDType) + int uniqueNum() const { return m_uniqueNum; } virtual bool same(const AstNode* samep) const override { const AstDefImplicitDType* sp = static_cast(samep); - return m_uniqueNum == sp->m_uniqueNum; + return uniqueNum() == sp->uniqueNum(); } virtual bool similarDType(AstNodeDType* samep) const override { return type() == samep->type() && same(samep); } - virtual V3Hash sameHash() const override { return V3Hash(m_uniqueNum); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } @@ -557,7 +553,6 @@ public: } virtual string prettyDTypeName() const override; virtual void dumpSmall(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } virtual AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); } virtual bool isHeavy() const override { return true; } @@ -657,7 +652,6 @@ public: } virtual string prettyDTypeName() const override; virtual void dumpSmall(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } virtual bool isHeavy() const override { return true; } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable @@ -775,7 +769,6 @@ public: && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } virtual void dumpSmall(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } @@ -873,9 +866,6 @@ private: public: ASTNODE_NODE_FUNCS(BasicDType) virtual void dump(std::ostream& str) const override; - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.hi())); - } // width/widthMin/numeric compared elsewhere virtual bool same(const AstNode* samep) const override { const AstBasicDType* sp = static_cast(samep); @@ -983,9 +973,6 @@ public: virtual bool similarDType(AstNodeDType* samep) const override { return skipRefp()->similarDType(samep->skipRefp()); } - virtual V3Hash sameHash() const override { - return V3Hash(m_refDTypep); - } // node's type() included elsewhere virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } @@ -1038,9 +1025,6 @@ public: virtual bool similarDType(AstNodeDType* samep) const override { return this == samep || (type() == samep->type() && same(samep)); } - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m_classp), V3Hash(m_classOrPackagep)); - } virtual void dump(std::ostream& str = std::cout) const override; virtual void dumpSmall(std::ostream& str) const override; virtual string name() const override { return classp() ? classp()->name() : ""; } @@ -1096,7 +1080,6 @@ public: virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual V3Hash sameHash() const override { return V3Hash(m_cellp); } virtual int widthAlignBytes() const override { return 1; } virtual int widthTotalBytes() const override { return 1; } FileLine* modportFileline() const { return m_modportFileline; } @@ -1156,7 +1139,6 @@ public: && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } virtual void dumpSmall(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } virtual string prettyDTypeName() const override; virtual bool isHeavy() const override { return true; } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } @@ -1231,9 +1213,6 @@ public: virtual bool similarDType(AstNodeDType* samep) const override { return skipRefp()->similarDType(samep->skipRefp()); } - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m_typedefp), V3Hash(m_classOrPackagep)); - } virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } virtual string prettyDTypeName() const override { @@ -1403,7 +1382,6 @@ public: virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } virtual int widthAlignBytes() const override { return 1; } virtual int widthTotalBytes() const override { return 1; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool isCompound() const override { return false; } }; @@ -1470,17 +1448,17 @@ class AstEnumDType final : public AstNodeDType { private: string m_name; // Name from upper typedef, if any AstNodeDType* m_refDTypep; // Elements are of this type after V3Width - int m_uniqueNum; + const int m_uniqueNum; public: AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* itemsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER(fl) + , m_uniqueNum{uniqueNumInc()} { childDTypep(dtp); // Only for parser refDTypep(nullptr); addNOp2p(itemsp); dtypep(nullptr); // V3Width will resolve widthFromSub(subDTypep()); - m_uniqueNum = uniqueNumInc(); } ASTNODE_NODE_FUNCS(EnumDType) virtual const char* broken() const override { @@ -1491,12 +1469,12 @@ public: virtual void cloneRelink() override { if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } + int uniqueNum() const { return m_uniqueNum; } virtual bool same(const AstNode* samep) const override { const AstEnumDType* sp = static_cast(samep); - return m_uniqueNum == sp->m_uniqueNum; + return uniqueNum() == sp->uniqueNum(); } virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual V3Hash sameHash() const override { return V3Hash(m_uniqueNum); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Data type void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } @@ -1594,7 +1572,6 @@ public: return true; } // esp for V3Const::ifSameAssign virtual bool isPredictOptimizable() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual int instrCount() const override { return widthInstrs(); } // Special operators @@ -1636,7 +1613,6 @@ public: return true; } // esp for V3Const::ifSameAssign virtual bool isPredictOptimizable() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual int instrCount() const override { return widthInstrs(); } }; @@ -1664,7 +1640,6 @@ public: virtual bool cleanRhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -1678,7 +1653,6 @@ public: addNOp2p(elementsp); } ASTNODE_NODE_FUNCS(SelLoopVars) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool maybePointedTo() const override { return false; } AstNode* fromp() const { return op1p(); } @@ -1770,7 +1744,6 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } virtual bool sizeMattersThs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } virtual int instrCount() const override { return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10); @@ -1816,7 +1789,6 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } virtual bool sizeMattersThs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } virtual int instrCount() const override { return 10; } // Removed before matters AstNode* fromp() const { @@ -1888,7 +1860,6 @@ public: virtual string name() const override { return m_name; } // * = Var name virtual bool hasDType() const override { return true; } virtual void name(const string& name) override { m_name = name; } - virtual V3Hash sameHash() const override { return V3Hash(m_name); } virtual bool same(const AstNode* samep) const override { const AstCMethodHard* asamep = static_cast(samep); return (m_name == asamep->m_name); @@ -2273,7 +2244,6 @@ public: } virtual string name() const override { return m_name; } // * = Scope name ASTNODE_NODE_FUNCS(DefParam) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } AstNode* rhsp() const { return op1p(); } // op1 = Assign from string path() const { return m_path; } @@ -2410,9 +2380,6 @@ public: } ASTNODE_NODE_FUNCS(VarRef) virtual void dump(std::ostream& str) const override; - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(varp()->name()), V3Hash(hiernameToProt())); - } virtual bool same(const AstNode* samep) const override { return same(static_cast(samep)); } @@ -2469,7 +2436,6 @@ public: virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(V3Hash(varp()), V3Hash(dotted())); } virtual bool same(const AstNode* samep) const override { const AstVarXRef* asamep = static_cast(samep); return (hiernameToProt() == asamep->hiernameToProt() @@ -2545,7 +2511,6 @@ public: ASTNODE_NODE_FUNCS(Arg) virtual string name() const override { return m_name; } // * = Pin name, ""=go by number virtual void name(const string& name) override { m_name = name; } - virtual V3Hash sameHash() const override { return V3Hash(); } void exprp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expression connected to pin, nullptr if unconnected AstNode* exprp() const { return op1p(); } @@ -2695,7 +2660,6 @@ public: } virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } - virtual V3Hash sameHash() const override { return V3Hash(m_name); } virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return false; } @@ -3005,7 +2969,6 @@ public: ASTNODE_NODE_FUNCS(ParseRef) virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } // * = Var name - virtual V3Hash sameHash() const override { return V3Hash(V3Hash(m_expect), V3Hash(m_name)); } virtual bool same(const AstNode* samep) const override { const AstParseRef* asamep = static_cast(samep); return (expect() == asamep->expect() && m_name == asamep->m_name); @@ -3047,7 +3010,6 @@ public: return (m_classOrPackageNodep == static_cast(samep)->m_classOrPackageNodep); } - virtual V3Hash sameHash() const override { return V3Hash(m_classOrPackageNodep); } virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } // * = Var name AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } @@ -3171,7 +3133,6 @@ public: addNOp2p(exprp); } ASTNODE_NODE_FUNCS(WithParse) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstNode* funcrefp() const { return op1p(); } @@ -3192,7 +3153,6 @@ public: , m_name{name} , m_index(index) {} ASTNODE_NODE_FUNCS(LambdaArgRef) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual string emitVerilog() override { return name(); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } @@ -3220,7 +3180,6 @@ public: addNOp3p(exprp); } ASTNODE_NODE_FUNCS(With) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool hasDType() const override { return true; } virtual const char* broken() const override { @@ -3269,7 +3228,6 @@ public: , m_edgeType{VEdgeType::ET_NEVER} {} ASTNODE_NODE_FUNCS(SenItem) virtual void dump(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(edgeType()); } virtual bool same(const AstNode* samep) const override { return edgeType() == static_cast(samep)->edgeType(); } @@ -3306,7 +3264,6 @@ public: ASTNODE_NODE_FUNCS(SenTree) virtual void dump(std::ostream& str) const override; virtual bool maybePointedTo() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } bool isMulti() const { return m_multi; } // op1 = Sensitivity list AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); } @@ -3379,7 +3336,6 @@ public: addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(AlwaysPublic) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list @@ -3525,7 +3481,6 @@ public: virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; @@ -3543,7 +3498,6 @@ public: , m_name{name} {} ASTNODE_NODE_FUNCS(Comment) virtual string name() const override { return m_name; } // * = Text - virtual V3Hash sameHash() const override { return V3Hash(); } // Ignore name in comments virtual bool same(const AstNode* samep) const override { return true; } // Ignore name in comments @@ -3623,7 +3577,6 @@ public: const string& hier() const { return m_hier; } void hier(const string& flag) { m_hier = flag; } void comment(const string& flag) { m_text = flag; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { const AstCoverDecl* asamep = static_cast(samep); return (fileline() == asamep->fileline() && linescov() == asamep->linescov() @@ -3657,7 +3610,6 @@ public: } virtual void dump(std::ostream& str) const override; virtual int instrCount() const override { return 1 + 2 * instrCountLd(); } - virtual V3Hash sameHash() const override { return V3Hash(declp()); } virtual bool same(const AstNode* samep) const override { return declp() == static_cast(samep)->declp(); } @@ -3681,7 +3633,6 @@ public: } ASTNODE_NODE_FUNCS(CoverToggle) virtual int instrCount() const override { return 3 + instrCountBranch() + instrCountLd(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return true; } @@ -3703,7 +3654,6 @@ public: setOp1p(lhsp); } ASTNODE_NODE_FUNCS(Delay) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstNode* lhsp() const { return op1p(); } // op2 = Statements to evaluate @@ -3820,7 +3770,6 @@ public: ASTNODE_NODE_FUNCS(SFormatF) virtual string name() const override { return m_text; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool hasDType() const override { return true; } virtual bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); @@ -3882,7 +3831,6 @@ public: } // SPECIAL: $display has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(displayType()); } virtual bool same(const AstNode* samep) const override { return displayType() == static_cast(samep)->displayType(); } @@ -3915,7 +3863,6 @@ public: virtual bool isPredictOptimizable() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool cleanOut() const { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } VDumpCtlType ctlType() const { return m_ctlType; } AstNode* exprp() const { return op1p(); } // op2 = Expressions to output @@ -3949,7 +3896,6 @@ public: } // SPECIAL: $display has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(displayType()); } virtual bool same(const AstNode* samep) const override { return displayType() == static_cast(samep)->displayType(); } @@ -3988,7 +3934,6 @@ public: virtual bool isOutputter() const override { return false; } virtual bool cleanOut() const { return false; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter AstSFormatF* fmtp() const { return VN_CAST(op1p(), SFormatF); } @@ -4012,7 +3957,6 @@ public: virtual bool isPure() const override { return true; } virtual bool isOutputter() const override { return false; } virtual int instrCount() const override { return 0; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* lhsp() const { return op1p(); } // op1 = Expressions to eval void lhsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to eval @@ -4054,7 +3998,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } @@ -4077,7 +4020,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op1p(); } AstNode* filenamep() const { return op2p(); } @@ -4100,7 +4042,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op1p(); } AstNode* filenamep() const { return op2p(); } @@ -4121,7 +4062,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } @@ -4150,7 +4090,6 @@ public: virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: makes output virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* memp() const { return op1p(); } void memp(AstNode* nodep) { setOp1p(nodep); } @@ -4180,7 +4119,6 @@ public: virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } @@ -4204,7 +4142,6 @@ public: virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } @@ -4231,7 +4168,6 @@ public: virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: makes output virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNode* nodep) { setOp2p(nodep); } @@ -4265,7 +4201,6 @@ public: virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: makes output virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); } @@ -4301,7 +4236,6 @@ public: virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: makes output virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); } @@ -4332,7 +4266,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return isHex() == static_cast(samep)->isHex(); } @@ -4380,7 +4313,6 @@ public: virtual bool isPure() const override { return false; } // Though deleted before opt virtual bool isOutputter() const override { return true; } // Though deleted before opt virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(m_off); } virtual bool same(const AstNode* samep) const override { return m_off == static_cast(samep)->m_off; } @@ -4401,7 +4333,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* lhsp() const { return op1p(); } }; @@ -4423,7 +4354,6 @@ public: virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } virtual bool cleanOut() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* lhsp() const { return op1p(); } }; @@ -4445,7 +4375,6 @@ public: virtual bool isHeavy() const override { return true; } virtual bool isPredictOptimizable() const override { return false; } virtual bool cleanOut() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* searchp() const { return op1p(); } // op1 = Search expression void searchp(AstNode* nodep) { setOp1p(nodep); } @@ -4471,7 +4400,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual bool cleanOut() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); } @@ -4498,7 +4426,6 @@ public: AstNode* bodysp() const { return op4p(); } // op4 = body of loop virtual bool isGateOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4516,7 +4443,6 @@ public: return false; } // Not relevant - converted to FOR virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4550,7 +4476,6 @@ public: void addIncsp(AstNode* newp) { addOp4p(newp); } virtual bool isGateOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // Stop statement searchback here virtual void addBeforeStmt(AstNode* newp, AstNode* belowp) override; @@ -4564,7 +4489,6 @@ public: : ASTGEN_SUPER(fl) {} ASTNODE_NODE_FUNCS(Break) virtual string verilogKwd() const override { return "break"; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool isBrancher() const override { return true; // SPECIAL: We don't process code after breaks } @@ -4576,7 +4500,6 @@ public: : ASTGEN_SUPER(fl) {} ASTNODE_NODE_FUNCS(Continue) virtual string verilogKwd() const override { return "continue"; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool isBrancher() const override { return true; // SPECIAL: We don't process code after breaks } @@ -4621,7 +4544,6 @@ public: } ASTNODE_NODE_FUNCS(Return) virtual string verilogKwd() const override { return "return"; } - virtual V3Hash sameHash() const override { return V3Hash(); } AstNode* lhsp() const { return op1p(); } virtual bool isBrancher() const override { return true; // SPECIAL: We don't process code after breaks @@ -4674,7 +4596,6 @@ public: ASTNODE_NODE_FUNCS(JumpBlock) virtual int instrCount() const override { return 0; } virtual bool maybePointedTo() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // op1 = Statements AstNode* stmtsp() const { return op1p(); } // op1 = List of statements @@ -4709,7 +4630,6 @@ public: } virtual void dump(std::ostream& str) const override; virtual int instrCount() const override { return 0; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return blockp() == static_cast(samep)->blockp(); } @@ -4737,7 +4657,6 @@ public: } virtual void dump(std::ostream& str) const override; virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(labelp()); } virtual bool same(const AstNode* samep) const override { return labelp() == static_cast(samep)->labelp(); } @@ -4795,7 +4714,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4815,7 +4733,6 @@ public: virtual bool cleanOut() const override { return true; } virtual int instrCount() const override { return widthInstrs(); } AstNode* defaultp() const { return op1p(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; class AstSetAssoc final : public AstNodeMath { @@ -4838,7 +4755,6 @@ public: AstNode* lhsp() const { return op1p(); } AstNode* keyp() const { return op2p(); } AstNode* valuep() const { return op3p(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4860,7 +4776,6 @@ public: virtual int instrCount() const override { return widthInstrs(); } AstNode* lhsp() const { return op1p(); } // op1 = expression AstNode* rhsp() const { return op2p(); } // op2 = expression - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4882,7 +4797,6 @@ public: virtual int instrCount() const override { return widthInstrs(); } AstNode* lhsp() const { return op1p(); } // op1 = expression AstNode* rhsp() const { return op2p(); } // op2 = expression - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4974,7 +4888,6 @@ public: ASTNODE_NODE_FUNCS(InitItem) virtual bool maybePointedTo() const override { return true; } virtual bool hasDType() const override { return false; } // See valuep()'s dtype instead - virtual V3Hash sameHash() const override { return V3Hash(); } AstNode* valuep() const { return op1p(); } // op1 = Value void valuep(AstNode* nodep) { addOp1p(nodep); } }; @@ -5012,7 +4925,6 @@ public: } } virtual bool hasDType() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { // Only works if exact same children, instead should override comparison // of children list, and instead use map-vs-map key/value compare @@ -5061,7 +4973,6 @@ public: AstNew(FileLine* fl, AstNode* pinsp) : ASTGEN_SUPER(fl, false, "new", pinsp) {} ASTNODE_NODE_FUNCS(New) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool cleanOut() const { return true; } virtual bool same(const AstNode* samep) const override { return true; } virtual bool hasDType() const override { return true; } @@ -5079,7 +4990,6 @@ public: setNOp1p(rhsp); } ASTNODE_NODE_FUNCS(NewCopy) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual string emitVerilog() override { return "new"; } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } @@ -5100,7 +5010,6 @@ public: setNOp2p(rhsp); } ASTNODE_NODE_FUNCS(NewDynamic) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual string emitVerilog() override { return "new"; } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } @@ -5121,7 +5030,6 @@ public: , m_pragType{pragType} {} ASTNODE_NODE_FUNCS(Pragma) AstPragmaType pragType() const { return m_pragType; } // *=type of the pragma - virtual V3Hash sameHash() const override { return V3Hash(pragType()); } virtual bool isPredictOptimizable() const override { return false; } virtual bool same(const AstNode* samep) const override { return pragType() == static_cast(samep)->pragType(); @@ -5145,7 +5053,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } void timeunit(const VTimescale& flag) { m_timeunit = flag; } VTimescale timeunit() const { return m_timeunit; } }; @@ -5163,7 +5070,6 @@ public: virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const override { return true; } virtual int instrCount() const override { return 0; } // Rarely executes - virtual V3Hash sameHash() const override { return V3Hash(fileline()->lineno()); } virtual bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } @@ -5182,7 +5088,6 @@ public: virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const override { return true; } virtual int instrCount() const override { return 0; } // Rarely executes - virtual V3Hash sameHash() const override { return V3Hash(fileline()->lineno()); } virtual bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } @@ -5205,7 +5110,6 @@ public: virtual bool cleanOut() const override { return true; } virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(fileline()->lineno()); } virtual bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } @@ -5226,7 +5130,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return false; } virtual int instrCount() const override { return 0; } - virtual V3Hash sameHash() const override { return V3Hash(); } AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } AstNode* stmtsp() const { return op2p(); } }; @@ -5249,7 +5152,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } AstNode* unitsp() const { return op1p(); } AstNode* precisionp() const { return op2p(); } AstNode* suffixp() const { return op3p(); } @@ -5338,7 +5240,6 @@ public: virtual void dump(std::ostream& str) const override; virtual int instrCount() const override { return 10 + 2 * instrCountLd(); } virtual bool hasDType() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(declp()); } virtual bool same(const AstNode* samep) const override { return declp() == static_cast(samep)->declp(); } @@ -5413,7 +5314,6 @@ public: AstNode* fromp() const { return op1p(); } AstNode* dimp() const { return op2p(); } AstAttrType attrType() const { return m_attrType; } - virtual V3Hash sameHash() const override { return V3Hash(m_attrType); } virtual void dump(std::ostream& str = std::cout) const override; }; @@ -5432,7 +5332,6 @@ public: dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(ScopeName) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return m_dpiExport == static_cast(samep)->m_dpiExport; } @@ -5517,7 +5416,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* seedp() const { return op1p(); } bool reset() const { return m_reset; } @@ -5565,7 +5463,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountTime(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual void dump(std::ostream& str = std::cout) const override; void timeunit(const VTimescale& flag) { m_timeunit = flag; } @@ -5587,7 +5484,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountTime(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual void dump(std::ostream& str = std::cout) const override; void timeunit(const VTimescale& flag) { m_timeunit = flag; } @@ -5613,7 +5509,6 @@ public: virtual bool isSubstOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -6175,7 +6070,6 @@ public: virtual bool cleanOut() const override { return true; } virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast - virtual V3Hash sameHash() const override { return V3Hash(size()); } virtual bool same(const AstNode* samep) const override { return size() == static_cast(samep)->size(); } @@ -6198,7 +6092,6 @@ public: virtual bool cleanOut() const override { return true; } virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -6241,7 +6134,6 @@ public: AstNode* filep() const { return op1p(); } void strp(AstNode* nodep) { setOp2p(nodep); } AstNode* strp() const { return op2p(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8364,7 +8256,6 @@ public: AstNode* exprp() const { return op1p(); } // op1 = expression AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8388,7 +8279,6 @@ public: AstNode* ticksp() const { return op2p(); } // op2 = ticks or nullptr means 1 AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8410,7 +8300,6 @@ public: AstNode* exprp() const { return op1p(); } // op1 = expression AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8430,7 +8319,6 @@ public: virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } virtual int instrCount() const override { return 0; } AstNode* exprp() const { return op1p(); } // op1 = expression - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8452,7 +8340,6 @@ public: AstNode* exprp() const { return op1p(); } // op1 = expression AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8527,7 +8414,6 @@ public: void rhsp(AstNode* nodep) { return setOp2p(nodep); } AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8591,7 +8477,6 @@ public: } ASTNODE_BASE_FUNCS(NodeCoverOrAssert) virtual string name() const override { return m_name; } // * = Var name - virtual V3Hash sameHash() const override { return V3Hash(name()); } virtual bool same(const AstNode* samep) const override { return samep->name() == name(); } virtual void name(const string& name) override { m_name = name; } virtual void dump(std::ostream& str = std::cout) const override; @@ -8750,7 +8635,6 @@ public: virtual bool isPredictOptimizable() const override { return false; } virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8771,7 +8655,6 @@ public: ASTNODE_BASE_FUNCS(NodeFile) virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void tblockp(AstTextBlock* tblockp) { setOp1p(tblockp); } AstTextBlock* tblockp() { return VN_CAST(op1p(), TextBlock); } @@ -8885,7 +8768,6 @@ public: } virtual bool maybePointedTo() const override { return true; } virtual void dump(std::ostream& str = std::cout) const override; - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { const AstCFunc* asamep = static_cast(samep); return ((funcType() == asamep->funcType()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) @@ -9023,7 +8905,6 @@ public: } ASTNODE_NODE_FUNCS(CReturn) virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstNode* lhsp() const { return op1p(); } @@ -9055,7 +8936,6 @@ public: virtual bool cleanOut() const override { return m_cleanOut; } virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void addBodysp(AstNode* nodep) { addNOp1p(nodep); } AstNode* bodysp() const { return op1p(); } // op1 = expressions to print @@ -9073,7 +8953,6 @@ public: ASTNODE_NODE_FUNCS(CReset) virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstVarRef* varrefp() const { return VN_CAST(op1p(), VarRef); } // op1 = varref to reset }; @@ -9092,7 +8971,6 @@ public: ASTNODE_NODE_FUNCS(CStmt) virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void addBodysp(AstNode* nodep) { addNOp1p(nodep); } AstNode* bodysp() const { return op1p(); } // op1 = expressions to print diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 4fc8f5e6c..b859b455c 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -132,8 +132,7 @@ private: // Remove calls to empty function UASSERT_OBJ(!oldfuncp->user3(), oldfuncp, "Should not be processed yet"); - UINFO(5, " Drop empty CFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " " - << oldfuncp << endl); + UINFO(5, " Drop empty CFunc " << itr.first << " " << oldfuncp << endl); oldfuncp->user3SetOnce(); // Mark replaced m_call.replaceFunc(oldfuncp, nullptr); oldfuncp->unlinkFrBack(); @@ -161,10 +160,8 @@ private: if (!newfuncp->sameTree(oldfuncp)) continue; // Different functions // Replace calls to oldfuncp with calls to newfuncp - UINFO(5, " Replace CFunc " << std::hex << V3Hash(newfuncp->user4p()) << " " - << newfuncp << endl); - UINFO(5, " with " << std::hex << V3Hash(oldfuncp->user4p()) << " " - << oldfuncp << endl); + UINFO(5, " Replace CFunc " << newIt->first << " " << newfuncp << endl); + UINFO(5, " with " << oldIt->first << " " << oldfuncp << endl); ++m_cfuncsCombined; oldfuncp->user3SetOnce(); // Mark replaced m_call.replaceFunc(oldfuncp, newfuncp); diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp index e6aa43d36..061e659db 100644 --- a/src/V3DupFinder.cpp +++ b/src/V3DupFinder.cpp @@ -30,11 +30,6 @@ //###################################################################### // V3DupFinder class functions -bool V3DupFinder::sameNodes(AstNode* node1p, AstNode* node2p) { - return m_hasher(node1p) == m_hasher(node2p) // Same hash - && node1p->sameTree(node2p); // Same tree -} - V3DupFinder::iterator V3DupFinder::findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp) { const auto& er = equal_range(m_hasher(nodep)); for (iterator it = er.first; it != er.second; ++it) { diff --git a/src/V3DupFinder.h b/src/V3DupFinder.h index 43a63be0d..0b512462e 100644 --- a/src/V3DupFinder.h +++ b/src/V3DupFinder.h @@ -67,10 +67,6 @@ public: // Insert node into data structure iterator insert(AstNode* nodep) { return emplace(m_hasher(nodep), nodep); } - // Check if nodes are the same (same as node1p->sameTree(node2p), - // but first checks the hashes are equal for speed) - bool sameNodes(AstNode* node1p, AstNode* node2p); - // Return duplicate, if one was inserted, with optional user check for sameness iterator findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp = nullptr); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index a23c89485..f9144db8d 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -919,16 +919,28 @@ private: VL_DEBUG_FUNC; // Declare debug() - bool sameHash(AstNode* node1p, AstNode* node2p) { - return node1p // - && node2p // - && !node1p->sameHash().isIllegal() // - && !node2p->sameHash().isIllegal() // - && m_dupFinder.sameNodes(node1p, node2p); - } - bool same(AstNode* node1p, AstNode* node2p) { - return node1p == node2p || sameHash(node1p, node2p); + // Regarding the complexity of this funcition 'same': + // Applying this comparison function to a a set of n trees pairwise is O(n^2) in the + // number of comparisons (number of pairs). AstNode::sameTree itself, is O(sizeOfTree) in + // the worst case, which happens if the operands of sameTree are indeed identical copies, + // which means this line is O(n^2*sizeOfTree), iff you are comparing identical copies of + // the same tree. In practice the identity comparison over the pointers, and the short + // circuiting in sameTree means that for comparing the same tree instance to itself, or + // trees of different types/shapes is a lot closer to O(1), so this 'same' function is + // Omega(n^2) and O(n^2*sizeOfTree), and in practice as we are mostly comparing the same + // instance to itself or different trees, the complexity should be closer to the lower + // bound. + // + // Also if you see where this 'same' function is used within isSame, it's only ever + // comparing AstActive nodes, which are very likely not to compare equals (and for the + // purposes of V3Gate, we probably only care about them either being identical instances, + // or having the same sensitivities anyway, so if this becomes a problem, it can be + // improved which should also speed things up), and AstNodeMath for if conditions, which + // are hopefully small, and to be safe they should probably be only considered same when + // identical instances (otherwise if writing the condition between 2 ifs don't really + // merge). + return node1p == node2p || (node1p && node1p->sameTree(node2p)); } public: diff --git a/src/V3Hash.cpp b/src/V3Hash.cpp new file mode 100644 index 000000000..2f1b33003 --- /dev/null +++ b/src/V3Hash.cpp @@ -0,0 +1,27 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hash calculation +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* + +#include "V3Hash.h" + +#include +#include + +V3Hash::V3Hash(const std::string& val) + : m_value{static_cast(std::hash{}(val))} {} + +std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) { + return os << std::hex << std::setw(8) << std::setfill('0') << rhs.value(); +} diff --git a/src/V3Hash.h b/src/V3Hash.h new file mode 100644 index 000000000..41a81140c --- /dev/null +++ b/src/V3Hash.h @@ -0,0 +1,65 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hash calculation +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* + +#ifndef VERILATOR_V3HASH_H_ +#define VERILATOR_V3HASH_H_ + +#include +#include + +//###################################################################### +// V3Hash -- Generic hashing + +class V3Hash final { + // A 32-bit hash value. A value of 0 is illegal. + uint32_t m_value; + +public: + // METHODS + uint32_t value() const { return m_value; } + + // OPERATORS + bool operator==(const V3Hash& rh) const { return m_value == rh.m_value; } + bool operator!=(const V3Hash& rh) const { return m_value != rh.m_value; } + bool operator<(const V3Hash& rh) const { return m_value < rh.m_value; } + V3Hash operator+(uint32_t value) const { + const uint64_t prod = (static_cast(m_value) * 31) + value; + return V3Hash(static_cast(prod ^ (prod >> 32))); + } + V3Hash operator+(int32_t value) const { return *this + static_cast(value); } + V3Hash operator+(const V3Hash& that) const { return *this + that.m_value; } + + V3Hash& operator+=(const V3Hash& that) { + *this = *this + that.m_value; + return *this; + } + V3Hash& operator+=(uint32_t value) { return *this += V3Hash(value); } + V3Hash& operator+=(int32_t value) { return *this += V3Hash(value); } + V3Hash& operator+=(const std::string& that) { return *this += V3Hash(that); } + + // CONSTRUCTORS + V3Hash() + : m_value{1} {} + explicit V3Hash(uint32_t val) + : m_value{val | 1} {} + explicit V3Hash(int32_t val) + : m_value{static_cast(val)} {} + explicit V3Hash(const std::string& val); +}; + +std::ostream& operator<<(std::ostream& os, const V3Hash& rhs); + +#endif // Guard diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 4a8f51742..625e923a3 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -1,6 +1,6 @@ // -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* -// DESCRIPTION: Verilator: Hashed common code into functions +// DESCRIPTION: Verilator: AstNode hash computation // // Code available from: https://verilator.org // @@ -19,6 +19,8 @@ #include "V3Hasher.h" +#include + //###################################################################### // Visitor that computes node hashes @@ -29,38 +31,426 @@ private: // AstUser4InUse in V3Hasher.h // STATE - V3Hash m_lowerHash; // Hash of the statement we're building + V3Hash m_hash; // Hash value accumulator const bool m_cacheInUser4; // Use user4 to cache each V3Hash? // METHODS VL_DEBUG_FUNC; // Declare debug() - //-------------------- - virtual void visit(AstVar*) override {} - virtual void visit(AstTypedef*) override {} - virtual void visit(AstParamTypeDType*) override {} + V3Hash hashNodeAndIterate(AstNode* nodep, bool hashDType, bool hashChildren, + std::function&& f) { + if (m_cacheInUser4 && nodep->user4()) { + return V3Hash(nodep->user4()); + } else { + VL_RESTORER(m_hash); + // Reset accumulator + m_hash = V3Hash(nodep->type()); // Node type + f(); // Node specific hash + if (hashDType && nodep != nodep->dtypep()) iterateNull(nodep->dtypep()); // Node dtype + if (hashChildren) iterateChildrenConst(nodep); // Children + if (m_cacheInUser4) nodep->user4(m_hash.value()); + return m_hash; + } + } + + // VISITORS + + constexpr static bool HASH_DTYPE = true; + constexpr static bool HASH_CHILDREN = true; + + // Each visitor below contributes to the hash any node specific content + // that is not dependent on either of the following, as these are + // included by default by hashNode: + // - Node type (as given by AstNode::type()) + // - Node dtype (unless !hashDType) + // - child nodes (unless !hashChildren) + // + // The hash must be stable, which means in particular it cannot rely on + // pointer values, or any other value that might differ between separate + // invocations of Verilator over the same design. + // + // Note there is a circularity problem where some child nodes can back + // to their ancestral nodes via member pointers, which can lead to an + // infinite traversal. To break this, nodes that are subject to such + // referencing and represent code which can reasonably be assumed not to + // be equivalent to any other code, are hashed either by name (e.g.: + // AstNodeModule), or by unique identifier (e.g.: AstNodeUOrStructDType). + + //------------------------------------------------------------ + // AstNode - Warns to help find missing cases virtual void visit(AstNode* nodep) override { - V3Hash thisHash; - if (!m_cacheInUser4 || !nodep->user4()) { - VL_RESTORER(m_lowerHash); - { - m_lowerHash = nodep->sameHash(); - UASSERT_OBJ(!m_lowerHash.isIllegal(), nodep, - "sameHash function undefined (returns 0) for node under CFunc."); - // For identical nodes, the type should be the same thus - // dtypep should be the same too - m_lowerHash = V3Hash(m_lowerHash, - V3Hash(V3Hash(nodep->type() << 6), V3Hash(nodep->dtypep()))); - // Now update m_lowerHash for our children's (and next children) contributions - iterateChildrenConst(nodep); - // Store the hash value - if (m_cacheInUser4) { nodep->user4(m_lowerHash.fullValue()); } - thisHash = m_lowerHash; +#if VL_DEBUG + UINFO(0, "%Warning: Hashing node as AstNode: " << nodep); +#endif + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + + //------------------------------------------------------------ + // AstNodeDType + virtual void visit(AstNodeArrayDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + iterateNull(nodep->virtRefDTypep()); + m_hash += nodep->left(); + m_hash += nodep->right(); + }); + } + virtual void visit(AstNodeUOrStructDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, false, [=]() { // + m_hash += nodep->uniqueNum(); + }); + } + virtual void visit(AstParamTypeDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + m_hash += nodep->varType(); + }); + } + virtual void visit(AstMemberDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstDefImplicitDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->uniqueNum(); + }); + } + virtual void visit(AstAssocArrayDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + iterateNull(nodep->virtRefDTypep()); + iterateNull(nodep->virtRefDType2p()); + }); + } + virtual void visit(AstDynArrayDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->virtRefDTypep()); + }); + } + virtual void visit(AstUnsizedArrayDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->virtRefDTypep()); + }); + } + virtual void visit(AstBasicDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + m_hash += nodep->keyword(); + m_hash += nodep->nrange().left(); + m_hash += nodep->nrange().right(); + }); + } + virtual void visit(AstConstDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + iterateNull(nodep->virtRefDTypep()); + }); + } + virtual void visit(AstClassRefDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->classp()); + }); + } + virtual void visit(AstIfaceRefDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->cellp()); + }); + } + virtual void visit(AstQueueDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->virtRefDTypep()); + }); + } + virtual void visit(AstRefDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->typedefp()); + iterateNull(nodep->refDTypep()); + }); + } + virtual void visit(AstVoidDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstEnumDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, false, [=]() { // + m_hash += nodep->uniqueNum(); + }); + } + + //------------------------------------------------------------ + // AstNodeMath + virtual void visit(AstNodeMath* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstConst* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->num().toHash(); + }); + } + virtual void visit(AstNullCheck* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstCCast* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->size(); + }); + } + virtual void visit(AstVarRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + if (nodep->varScopep()) { + iterateNull(nodep->varScopep()); + } else { + iterateNull(nodep->varp()); + m_hash += nodep->hiernameToProt(); } - } - // Update what will become the above node's hash - m_lowerHash += m_cacheInUser4 ? V3Hash(nodep->user4()) : thisHash; + }); + } + virtual void visit(AstVarXRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + iterateNull(nodep->varp()); + m_hash += nodep->dotted(); + }); + } + virtual void visit(AstMemberSel* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstFScanF* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + virtual void visit(AstSScanF* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + virtual void visit(AstTestPlusArgs* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + + //------------------------------------------------------------ + // AstNodeStmt + virtual void visit(AstNodeStmt* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstNodeText* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + virtual void visit(AstNodeCCall* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->funcp()); + }); + } + virtual void visit(AstNodeFTaskRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + iterateNull(nodep->taskp()); + iterateNull(nodep->classOrPackagep()); + }); + } + virtual void visit(AstCMethodHard* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstCoverInc* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->declp()); + }); + } + virtual void visit(AstDisplay* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->displayType(); + }); + } + virtual void visit(AstMonitorOff* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->off(); + }); + } + virtual void visit(AstJumpGo* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->labelp()); + }); + } + virtual void visit(AstTraceInc* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->declp()); + }); + } + virtual void visit(AstNodeCoverOrAssert* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + + //------------------------------------------------------------ + // AstNode direct descendents + virtual void visit(AstNodeRange* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstNodeModule* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() { + m_hash += nodep->origName(); + m_hash += nodep->hierName(); + }); + } + virtual void visit(AstNodePreSel* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstClassExtends* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstSelLoopVars* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstDefParam* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstArg* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstParseRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->expect(); + m_hash += nodep->name(); + }); + } + virtual void visit(AstClassOrPackageRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + iterateNull(nodep->classOrPackageNodep()); + }); + } + virtual void visit(AstSenItem* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->edgeType(); + }); + } + virtual void visit(AstSenTree* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstSFormatF* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + virtual void visit(AstElabDisplay* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->displayType(); + }); + } + virtual void visit(AstInitItem* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstInitArray* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstPragma* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->pragType(); + }); + } + virtual void visit(AstAttrOf* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->attrType(); + }); + } + virtual void visit(AstNodeFile* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstCFunc* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstVar* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + m_hash += nodep->varType(); + }); + } + virtual void visit(AstScope* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->aboveScopep()); + }); + } + virtual void visit(AstVarScope* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + iterateNull(nodep->varp()); + iterateNull(nodep->scopep()); + }); + } + virtual void visit(AstEnumItem* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstTypedef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstTypedefFwd* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstActive* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + iterateNull(nodep->sensesp()); + }); + } + virtual void visit(AstCell* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->modp()); + }); + } + virtual void visit(AstCellInline* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->scopep()); + }); + } + virtual void visit(AstNodeFTask* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstModport* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstModportVarRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->varp()); + }); + } + virtual void visit(AstModportFTaskRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->ftaskp()); + }); + } + virtual void visit(AstNodeProcedure* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstNodeBlock* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstPin* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + m_hash += nodep->pinNum(); + }); } public: @@ -73,7 +463,7 @@ public: : m_cacheInUser4{false} { iterate(const_cast(nodep)); } - V3Hash finalHash() const { return m_lowerHash; } + V3Hash finalHash() const { return m_hash; } virtual ~HasherVisitor() override = default; }; diff --git a/src/V3Hasher.h b/src/V3Hasher.h index fc90de27f..6207515f1 100644 --- a/src/V3Hasher.h +++ b/src/V3Hasher.h @@ -25,6 +25,7 @@ #include "V3Error.h" #include "V3Ast.h" +#include "V3Hash.h" //============================================================================ diff --git a/src/V3Number.cpp b/src/V3Number.cpp index a5f7491d9..f880996c1 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -883,7 +883,7 @@ string V3Number::toString() const { return str; } -uint32_t V3Number::toHash() const { return m_value[0]; } +V3Hash V3Number::toHash() const { return V3Hash(m_width * (m_value[0] | 1)); } uint32_t V3Number::edataWord(int eword) const { UASSERT(!isFourState(), "edataWord with 4-state " << *this); diff --git a/src/V3Number.h b/src/V3Number.h index ab1bc4dd2..fd0f41f93 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -21,6 +21,7 @@ #include "verilatedos.h" #include "V3Error.h" +#include "V3Hash.h" #include #include @@ -298,7 +299,7 @@ public: string toDecimalS() const; // return ASCII signed decimal number string toDecimalU() const; // return ASCII unsigned decimal number double toDouble() const; - uint32_t toHash() const; + V3Hash toHash() const; uint32_t edataWord(int eword) const; uint8_t dataByte(int byte) const; uint32_t countBits(const V3Number& ctrl) const; diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index 7c42f868c..e1bae6365 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -88,8 +88,8 @@ private: iterateChildren(nodep); V3Hash hash = V3Hasher::uncachedHash(m_cfilep); - m_hashValuep->addText(fl, cvtToStr(hash.fullValue()) + ";\n"); - m_cHashValuep->addText(fl, cvtToStr(hash.fullValue()) + "U;\n"); + m_hashValuep->addText(fl, cvtToStr(hash.value()) + ";\n"); + m_cHashValuep->addText(fl, cvtToStr(hash.value()) + "U;\n"); m_foundTop = true; } diff --git a/src/V3SenTree.h b/src/V3SenTree.h index 78d5f3a34..5abca02f6 100644 --- a/src/V3SenTree.h +++ b/src/V3SenTree.h @@ -37,7 +37,7 @@ private: // TYPES struct HashSenTree { size_t operator()(const AstSenTree* kp) const { - return V3Hasher::uncachedHash(kp).fullValue(); + return V3Hasher::uncachedHash(kp).value(); } }; From 63782556aeaf90642b1199a6481d719f678940d6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 21 May 2021 20:47:53 -0400 Subject: [PATCH 47/80] Internals: Fix some pylint warnings --- Makefile.in | 5 ++--- docs/bin/vl_sphinx_extract | 3 ++- docs/bin/vl_sphinx_fix | 2 +- docs/guide/conf.py | 9 ++++----- docs/guide/warnings.rst | 2 +- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Makefile.in b/Makefile.in index 0e0d7607a..03d032718 100644 --- a/Makefile.in +++ b/Makefile.in @@ -479,9 +479,8 @@ PY_PROGRAMS = \ examples/xml_py/vl_file_copy \ examples/xml_py/vl_hier_graph \ docs/guide/conf.py \ - docs/guide/vl_sphinx_extract \ - docs/guide/vl_sphinx_extract \ - docs/guide/vl_doxygen_filter \ + docs/bin/vl_sphinx_extract \ + docs/bin/vl_sphinx_fix \ src/astgen \ src/bisonpre \ src/config_rev \ diff --git a/docs/bin/vl_sphinx_extract b/docs/bin/vl_sphinx_extract index 068ad8b35..1b2c27d07 100755 --- a/docs/bin/vl_sphinx_extract +++ b/docs/bin/vl_sphinx_extract @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# pylint: disable=C0112,C0114,C0116,C0301,R0903 +# pylint: disable=C0112,C0114,C0115,C0116,C0301,R0201,R0903 # -*- Python -*- See copyright, etc below ###################################################################### @@ -8,6 +8,7 @@ import re ####################################################################### + class VlSphinxExtract: debug = 0 SkipBasenames = {} diff --git a/docs/bin/vl_sphinx_fix b/docs/bin/vl_sphinx_fix index cedbc0d63..ed6d06107 100755 --- a/docs/bin/vl_sphinx_fix +++ b/docs/bin/vl_sphinx_fix @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# pylint: disable=C0112,C0114,C0116,C0301,R0903 +# pylint: disable=C0112,C0114,C0115,C0116,C0301,R0903 # -*- Python -*- See copyright, etc below ###################################################################### diff --git a/docs/guide/conf.py b/docs/guide/conf.py index 1d30f1d51..060d7a106 100644 --- a/docs/guide/conf.py +++ b/docs/guide/conf.py @@ -1,4 +1,4 @@ -# pylint: disable=E402 +# pylint: disable=C0103,C0114,C0116,E0402,W0622 # # Configuration file for Verilator's Sphinx documentation builder. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 @@ -12,11 +12,10 @@ from datetime import datetime import os import re -import shutil import sys sys.path.insert(0, os.path.abspath('./_ext')) -import sphinx_rtd_theme +import sphinx_rtd_theme # pylint: disable=wrong-import-position, def get_vlt_version(): @@ -94,7 +93,7 @@ today_fmt = datetime.now().strftime("%F") # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True -# TODO could use this for internals<->guide references +# Could use this for internals<->guide references # intersphinx_mapping = { 'sphinx': ('https://sphinx-doc.org/', None), } # ---------------------------------------------------------------------- @@ -208,7 +207,7 @@ spelling_ignore_contributor_names = True # ---------------------------------------------------------------------- # -- Options for doxygen -#if shutil.which("doxygen"): +# if shutil.which("doxygen"): # breathe_projects = { # "verilated": "../_build/doxygen/verilated/xml", # } diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 3e0840c89..ee76aeece 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -809,7 +809,7 @@ List Of Warnings This is considered bad style, as the consumer of a given signal may be unaware of the inconsistent clocking, causing clock domain crossing - bugs. + or timing bugs. Faulty example: From 61c9866a1e1e8d5b7bf37377cdf34f7bcaca963c Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 22 May 2021 11:13:02 +0100 Subject: [PATCH 48/80] Internals: Generate ASTGEN_SUPER_* macros instead of expanding. (#2975) astgen now generates ASTGEN_SUPER_* macros, instead of expanding the ASTGEN_SUPER itself. This means that V3AstNodes.h itself can be included in V3Ast.h, which helps IDEs (namely CLion) find definitions in V3AstNodes.h a lot better. Albeit this is a little bit more boilerplate, writing constructors of Ast nodes should be a lot rarer than trying to find their definitions, so hopefully this is an improvement overall. astgen will error if the developer calls the wrong superclass constructor. --- src/V3Ast.h | 2 +- src/V3AstNodes.cpp | 4 +- src/V3AstNodes.h | 843 ++++++++++++++++++++++----------------------- src/astgen | 27 +- 4 files changed, 439 insertions(+), 437 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 827b9649a..d915ff156 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2916,7 +2916,7 @@ public: //###################################################################### -#include "V3AstNodes__gen.h" +#include "V3AstNodes.h" //###################################################################### // Inline AstNVisitor METHODS diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index a5c17b50a..4a6f99d6d 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -25,6 +25,8 @@ #include "V3String.h" #include "V3EmitCBase.h" +#include "V3AstNodes__gen_macros.h" // Generated by 'astgen' + #include #include @@ -214,7 +216,7 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { } AstExecGraph::AstExecGraph(FileLine* fileline) - : AstNode{AstType::atExecGraph, fileline} { + : ASTGEN_SUPER_ExecGraph(fileline) { m_depGraphp = new V3Graph; } AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index d88e700fe..8a2da1368 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -40,9 +40,9 @@ ASTNODE_NODE_FUNCS_NO_DTOR(name) //###################################################################### -// Macros replaced by 'astgen' +// Macros generated by 'astgen' -#define ASTGEN_SUPER(...) // Roughly: (AstType::at, ...) +#include "V3AstNodes__gen_macros.h" //###################################################################### //=== Ast* : Specific types @@ -66,96 +66,96 @@ private: public: AstConst(FileLine* fl, const V3Number& num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(num) { initWithNumber(); } class WidthedValue {}; // for creator type-overload selection AstConst(FileLine* fl, WidthedValue, int width, uint32_t value) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, width, value) { initWithNumber(); } class DtypedValue {}; // for creator type-overload selection AstConst(FileLine* fl, DtypedValue, AstNodeDType* nodedtypep, uint32_t value) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, nodedtypep->width(), value, nodedtypep->widthSized()) { initWithNumber(); } class StringToParse {}; // for creator type-overload selection AstConst(FileLine* fl, StringToParse, const char* sourcep) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, sourcep) { initWithNumber(); } class VerilogStringLiteral {}; // for creator type-overload selection AstConst(FileLine* fl, VerilogStringLiteral, const string& str) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(V3Number::VerilogStringLiteral(), this, str) { initWithNumber(); } AstConst(FileLine* fl, uint32_t num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 32, num) { dtypeSetLogicUnsized(m_num.width(), 0, VSigning::UNSIGNED); } class Unsized32 {}; // for creator type-overload selection AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 32, num) { m_num.width(32, false); dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::UNSIGNED); } class Signed32 {}; // for creator type-overload selection AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 32, num) { m_num.width(32, true); dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::SIGNED); } class Unsized64 {}; // for creator type-overload selection AstConst(FileLine* fl, Unsized64, vluint64_t num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 64, 0) { m_num.setQuad(num); dtypeSetLogicSized(64, VSigning::UNSIGNED); } class SizedEData {}; // for creator type-overload selection AstConst(FileLine* fl, SizedEData, vluint64_t num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, VL_EDATASIZE, 0) { m_num.setQuad(num); dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); } class RealDouble {}; // for creator type-overload selection AstConst(FileLine* fl, RealDouble, double num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 64) { m_num.setDouble(num); dtypeSetDouble(); } class String {}; // for creator type-overload selection AstConst(FileLine* fl, String, const string& num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(V3Number::String(), this, num) { dtypeSetString(); } class BitFalse {}; AstConst(FileLine* fl, BitFalse) // Shorthand const 0, dtype should be a logic of size 1 - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 1, 0) { dtypeSetBit(); } // Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1 class BitTrue {}; AstConst(FileLine* fl, BitTrue, bool on = true) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 1, on) { dtypeSetBit(); } class Null {}; AstConst(FileLine* fl, Null) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(V3Number::Null{}, this) { dtypeSetBit(); // Events 1 bit, objects 64 bits, so autoExtend=1 and use bit here initWithNumber(); @@ -186,17 +186,17 @@ class AstRange final : public AstNodeRange { // Range specification, for use under variables and cells public: AstRange(FileLine* fl, AstNode* leftp, AstNode* rightp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Range(fl) { setOp2p(leftp); setOp3p(rightp); } AstRange(FileLine* fl, int left, int right) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Range(fl) { setOp2p(new AstConst(fl, left)); setOp3p(new AstConst(fl, right)); } AstRange(FileLine* fl, const VNumRange& range) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Range(fl) { setOp2p(new AstConst(fl, range.left())); setOp3p(new AstConst(fl, range.right())); } @@ -233,7 +233,7 @@ class AstBracketRange final : public AstNodeRange { // unknown until lhsp type is determined public: AstBracketRange(FileLine* fl, AstNode* elementsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BracketRange(fl) { setOp1p(elementsp); } ASTNODE_NODE_FUNCS(BracketRange) @@ -250,7 +250,7 @@ class AstUnsizedRange final : public AstNodeRange { // Unsized range specification, for open arrays public: explicit AstUnsizedRange(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_UnsizedRange(fl) {} ASTNODE_NODE_FUNCS(UnsizedRange) virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitVerilog() { return "[]"; } @@ -261,7 +261,7 @@ class AstGatePin final : public AstNodeMath { // Possibly expand a gate primitive input pin value to match the range of the gate primitive public: AstGatePin(FileLine* fl, AstNode* lhsp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_GatePin(fl) { setOp1p(lhsp); setOp2p(rangep); } @@ -282,7 +282,7 @@ class AstClassPackage final : public AstNodeModule { = nullptr; // Class package this is under (weak pointer, hard link is other way) public: AstClassPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_ClassPackage(fl, name) {} ASTNODE_NODE_FUNCS(ClassPackage) virtual string verilogKwd() const override { return "/*class*/package"; } virtual const char* broken() const override; @@ -303,7 +303,7 @@ class AstClass final : public AstNodeModule { public: AstClass(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_Class(fl, name) {} ASTNODE_NODE_FUNCS(Class) virtual string verilogKwd() const override { return "class"; } virtual bool isHeavy() const override { return true; } @@ -345,7 +345,7 @@ class AstClassExtends final : public AstNode { // during early parse, then moves to dtype public: AstClassExtends(FileLine* fl, AstNode* classOrPkgsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ClassExtends(fl) { setNOp2p(classOrPkgsp); // Only for parser } ASTNODE_NODE_FUNCS(ClassExtends) @@ -370,7 +370,7 @@ private: public: AstParamTypeDType(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ParamTypeDType(fl) , m_varType{type} , m_name{name} { childDTypep(dtp); // Only for parser @@ -419,7 +419,7 @@ private: public: AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Typedef(fl) , m_name{name} { childDTypep(dtp); // Only for parser addAttrsp(attrsp); @@ -453,7 +453,7 @@ private: public: AstTypedefFwd(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TypedefFwd(fl) , m_name{name} {} ASTNODE_NODE_FUNCS(TypedefFwd) // METHODS @@ -474,7 +474,7 @@ private: public: AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_DefImplicitDType(fl) , m_name{name} , m_containerp{containerp} , m_uniqueNum{uniqueNumInc()} { @@ -521,7 +521,7 @@ private: AstNodeDType* m_keyDTypep; // Keys of this type (after widthing) public: AstAssocArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeDType* keyDtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_AssocArrayDType(fl) { childDTypep(dtp); // Only for parser keyChildDTypep(keyDtp); // Only for parser refDTypep(nullptr); @@ -590,7 +590,7 @@ class AstBracketArrayDType final : public AstNodeDType { // Children: DTYPE (the key) public: AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* elementsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BracketArrayDType(fl) { setOp1p(dtp); // Only for parser setOp2p(elementsp); // Only for parser } @@ -621,13 +621,13 @@ private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) public: AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_DynArrayDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); dtypep(nullptr); // V3Width will resolve } AstDynArrayDType(FileLine* fl, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_DynArrayDType(fl) { refDTypep(dtp); dtypep(nullptr); // V3Width will resolve } @@ -679,7 +679,7 @@ class AstPackArrayDType final : public AstNodeArrayDType { // Children: RANGE (array bounds) public: AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_PackArrayDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); setOp2p(rangep); @@ -688,7 +688,7 @@ public: widthForce(width, width); } AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_PackArrayDType(fl) { refDTypep(dtp); setOp2p(rangep); dtypep(this); @@ -707,7 +707,7 @@ class AstUnpackArrayDType final : public AstNodeArrayDType { bool m_isCompound = false; // Non-POD subDType, or parent requires compound public: AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UnpackArrayDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); setOp2p(rangep); @@ -717,7 +717,7 @@ public: widthFromSub(subDTypep()); } AstUnpackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UnpackArrayDType(fl) { refDTypep(dtp); setOp2p(rangep); dtypep(this); @@ -744,7 +744,7 @@ private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) public: AstUnsizedArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UnsizedArrayDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); dtypep(nullptr); // V3Width will resolve @@ -803,24 +803,24 @@ private: // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) public: AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(kwd, signst, 0, -1, nullptr); } AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(AstBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, nullptr); } AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(AstBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, nullptr); } AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(kwd, numer, wantwidth, widthmin, nullptr); } AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(kwd, numer, range.elements(), widthmin, nullptr); m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be } @@ -951,7 +951,7 @@ private: AstNodeDType* m_refDTypep; // Inherit from this base data type public: AstConstDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ConstDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); // V3Width will resolve dtypep(nullptr); // V3Width will resolve @@ -1004,7 +1004,7 @@ private: AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy public: AstClassRefDType(FileLine* fl, AstClass* classp, AstNode* paramsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ClassRefDType(fl) , m_classp{classp} { dtypep(this); addNOp4p(paramsp); @@ -1057,14 +1057,14 @@ private: AstModport* m_modportp = nullptr; // nullptr = unlinked or no modport public: AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_IfaceRefDType(fl) , m_modportFileline{nullptr} , m_cellName{cellName} , m_ifaceName{ifaceName} , m_modportName{""} {} AstIfaceRefDType(FileLine* fl, FileLine* modportFl, const string& cellName, const string& ifaceName, const string& modport) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_IfaceRefDType(fl) , m_modportFileline{modportFl} , m_cellName{cellName} , m_ifaceName{ifaceName} @@ -1107,14 +1107,14 @@ private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) public: AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* boundp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_QueueDType(fl) { setNOp2p(boundp); childDTypep(dtp); // Only for parser refDTypep(nullptr); dtypep(nullptr); // V3Width will resolve } AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_QueueDType(fl) { setNOp2p(boundp); refDTypep(dtp); dtypep(dtp); @@ -1181,17 +1181,17 @@ private: AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy public: AstRefDType(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_RefDType(fl) , m_name{name} {} AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstNode* paramsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_RefDType(fl) , m_name{name} { setNOp3p(classOrPackagep); addNOp4p(paramsp); } class FlagTypeOfExpr {}; // type(expr) for parser only AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_RefDType(fl) { setOp2p(typeofp); } ASTNODE_NODE_FUNCS(RefDType) @@ -1276,7 +1276,7 @@ class AstStructDType final : public AstNodeUOrStructDType { public: // VSigning below is mispurposed to indicate if packed or not AstStructDType(FileLine* fl, VSigning numericUnpack) - : ASTGEN_SUPER(fl, numericUnpack) {} + : ASTGEN_SUPER_StructDType(fl, numericUnpack) {} ASTNODE_NODE_FUNCS(StructDType) virtual string verilogKwd() const override { return "struct"; } }; @@ -1286,7 +1286,7 @@ public: // UNSUP: bool isTagged; // VSigning below is mispurposed to indicate if packed or not AstUnionDType(FileLine* fl, VSigning numericUnpack) - : ASTGEN_SUPER(fl, numericUnpack) {} + : ASTGEN_SUPER_UnionDType(fl, numericUnpack) {} ASTNODE_NODE_FUNCS(UnionDType) virtual string verilogKwd() const override { return "union"; } }; @@ -1302,14 +1302,14 @@ private: // UNSUP: int m_randType; // Randomization type (IEEE) public: AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MemberDType(fl) , m_name{name} { childDTypep(dtp); // Only for parser dtypep(nullptr); // V3Width will resolve refDTypep(nullptr); } AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MemberDType(fl) , m_name{name} { UASSERT(dtp, "AstMember created with no dtype"); refDTypep(dtp); @@ -1362,7 +1362,7 @@ class AstVoidDType final : public AstNodeDType { // For e.g. a function returning void public: explicit AstVoidDType(FileLine* fl) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_VoidDType(fl) { dtypep(this); } ASTNODE_NODE_FUNCS(VoidDType) @@ -1392,7 +1392,7 @@ private: public: // Parents: ENUM AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_EnumItem(fl) , m_name{name} { addNOp1p(rangep); addNOp2p(initp); @@ -1414,7 +1414,7 @@ private: AstNodeModule* m_classOrPackagep; // Package hierarchy public: AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_EnumItemRef(fl) , m_itemp{itemp} , m_classOrPackagep{classOrPackagep} { dtypeFrom(m_itemp); @@ -1452,7 +1452,7 @@ private: public: AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* itemsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_EnumDType(fl) , m_uniqueNum{uniqueNumInc()} { childDTypep(dtp); // Only for parser refDTypep(nullptr); @@ -1513,7 +1513,7 @@ class AstParseTypeDType final : public AstNodeDType { // e.g. the data type is a container of any data type public: explicit AstParseTypeDType(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_ParseTypeDType(fl) {} ASTNODE_NODE_FUNCS(ParseTypeDType) AstNodeDType* dtypep() const { return nullptr; } // METHODS @@ -1547,11 +1547,11 @@ private: public: AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER(fl, fromp, bitp) { + : ASTGEN_SUPER_ArraySel(fl, fromp, bitp) { init(fromp); } AstArraySel(FileLine* fl, AstNode* fromp, int bit) - : ASTGEN_SUPER(fl, fromp, new AstConst(fl, bit)) { + : ASTGEN_SUPER_ArraySel(fl, fromp, new AstConst(fl, bit)) { init(fromp); } ASTNODE_NODE_FUNCS(ArraySel) @@ -1592,7 +1592,7 @@ private: public: AstAssocSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER(fl, fromp, bitp) { + : ASTGEN_SUPER_AssocSel(fl, fromp, bitp) { init(fromp); } ASTNODE_NODE_FUNCS(AssocSel) @@ -1621,7 +1621,7 @@ class AstWordSel final : public AstNodeSel { // Select a single word from a multi-word wide value public: AstWordSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER(fl, fromp, bitp) { + : ASTGEN_SUPER_WordSel(fl, fromp, bitp) { dtypeSetUInt32(); // Always used on WData arrays so returns edata size } ASTNODE_NODE_FUNCS(WordSel) @@ -1648,7 +1648,7 @@ class AstSelLoopVars final : public AstNode { // Unlike normal selects elements is a list public: AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SelLoopVars(fl) { setOp1p(fromp); addNOp2p(elementsp); } @@ -1663,7 +1663,7 @@ class AstSelExtract final : public AstNodePreSel { // Range extraction, gets replaced with AstSel public: AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) - : ASTGEN_SUPER(fl, fromp, msbp, lsbp) {} + : ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {} ASTNODE_NODE_FUNCS(SelExtract) AstNode* leftp() const { return rhsp(); } AstNode* rightp() const { return thsp(); } @@ -1674,7 +1674,7 @@ class AstSelBit final : public AstNodePreSel { // Gets replaced during link with AstArraySel or AstSel public: AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER(fl, fromp, bitp, nullptr) { + : ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, "not coded to create after dtypes resolved"); } @@ -1687,7 +1687,7 @@ class AstSelPlus final : public AstNodePreSel { // Gets replaced during link with AstSel public: AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER(fl, fromp, bitp, widthp) {} + : ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {} ASTNODE_NODE_FUNCS(SelPlus) AstNode* bitp() const { return rhsp(); } AstNode* widthp() const { return thsp(); } @@ -1698,7 +1698,7 @@ class AstSelMinus final : public AstNodePreSel { // Gets replaced during link with AstSel public: AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER(fl, fromp, bitp, widthp) {} + : ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {} ASTNODE_NODE_FUNCS(SelMinus) AstNode* bitp() const { return rhsp(); } AstNode* widthp() const { return thsp(); } @@ -1715,14 +1715,14 @@ private: int m_declElWidth; // If a packed array, the number of bits per element public: AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) - : ASTGEN_SUPER(fl, fromp, lsbp, widthp) + : ASTGEN_SUPER_Sel(fl, fromp, lsbp, widthp) , m_declElWidth{1} { if (VN_IS(widthp, Const)) { dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(), VSigning::UNSIGNED); } } AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) - : ASTGEN_SUPER(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) + : ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) , m_declElWidth{1} { dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED); } @@ -1771,8 +1771,8 @@ private: VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid public: AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange) - : ASTGEN_SUPER(fl, fromp, new AstConst(fl, declRange.lo()), - new AstConst(fl, declRange.elements())) + : ASTGEN_SUPER_SliceSel(fl, fromp, new AstConst(fl, declRange.lo()), + new AstConst(fl, declRange.elements())) , m_declRange{declRange} {} ASTNODE_NODE_FUNCS(SliceSel) virtual void dump(std::ostream& str) const override; @@ -1808,12 +1808,12 @@ class AstMethodCall final : public AstNodeFTaskRef { public: AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, name, pinsp) { + : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { setOp2p(fromp); dtypep(nullptr); // V3Width will resolve } AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, name, pinsp) { + : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { setOp2p(fromp); } ASTNODE_NODE_FUNCS(MethodCall) @@ -1844,14 +1844,14 @@ private: public: AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false) + : ASTGEN_SUPER_CMethodHard(fl, false) , m_name{name} { setOp1p(fromp); dtypep(nullptr); // V3Width will resolve addNOp2p(pinsp); } AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false) + : ASTGEN_SUPER_CMethodHard(fl, false) , m_name{name} { setOp1p(fromp); addNOp2p(pinsp); @@ -1970,7 +1970,7 @@ private: public: AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -1984,7 +1984,7 @@ public: } } AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -1998,7 +1998,7 @@ public: } } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -2007,7 +2007,7 @@ public: m_declKwd = AstBasicDTypeKwd::LOGIC; } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -2016,7 +2016,7 @@ public: m_declKwd = AstBasicDTypeKwd::BIT; } AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -2237,7 +2237,7 @@ private: string m_path; // Dotted cellname to set parameter of public: AstDefParam(FileLine* fl, const string& path, const string& name, AstNode* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_DefParam(fl) { setOp1p(rhsp); m_name = name; m_path = path; @@ -2254,7 +2254,7 @@ class AstImplicit final : public AstNode { // Parents: MODULE public: AstImplicit(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Implicit(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(Implicit) @@ -2274,7 +2274,7 @@ private: public: AstScope(FileLine* fl, AstNodeModule* modp, const string& name, AstScope* aboveScopep, AstCell* aboveCellp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Scope(fl) , m_name{name} , m_aboveScopep{aboveScopep} , m_aboveCellp{aboveCellp} @@ -2307,7 +2307,7 @@ class AstTopScope final : public AstNode { // Children: SCOPEs public: AstTopScope(FileLine* fl, AstScope* ascopep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_TopScope(fl) { addNOp2p(ascopep); } ASTNODE_NODE_FUNCS(TopScope) @@ -2329,7 +2329,7 @@ private: bool m_trace : 1; // Tracing is turned on for this scope public: AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_VarScope(fl) , m_scopep{scopep} , m_varp{varp} { m_circular = false; @@ -2368,14 +2368,14 @@ class AstVarRef final : public AstNodeVarRef { // A reference to a variable (lvalue or rvalue) public: AstVarRef(FileLine* fl, const string& name, const VAccess& access) - : ASTGEN_SUPER(fl, name, nullptr, access) {} + : ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {} // This form only allowed post-link because output/wire compression may // lead to deletion of AstVar's AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) - : ASTGEN_SUPER(fl, varp->name(), varp, access) {} + : ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {} // This form only allowed post-link (see above) AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) - : ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), access) { + : ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) { varScopep(varscp); } ASTNODE_NODE_FUNCS(VarRef) @@ -2418,10 +2418,10 @@ private: string m_inlinedDots; // Dotted hierarchy flattened out public: AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access) - : ASTGEN_SUPER(fl, name, nullptr, access) + : ASTGEN_SUPER_VarXRef(fl, name, nullptr, access) , m_dotted{dotted} {} AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access) - : ASTGEN_SUPER(fl, varp->name(), varp, access) + : ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access) , m_dotted{dotted} { dtypeFrom(varp); } @@ -2455,13 +2455,13 @@ private: bool m_svImplicit = false; // Pin is SystemVerilog .name'ed public: AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Pin(fl) , m_pinNum{pinNum} , m_name{name} { setNOp1p(exprp); } AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Pin(fl) , m_pinNum{pinNum} , m_name{varname->name()} { setNOp1p(exprp); @@ -2504,7 +2504,7 @@ private: string m_name; // Pin name, or "" for number based interconnect public: AstArg(FileLine* fl, const string& name, AstNode* exprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Arg(fl) , m_name{name} { setNOp1p(exprp); } @@ -2523,7 +2523,7 @@ private: bool m_isProgram; // Module represents a program public: AstModule(FileLine* fl, const string& name, bool program = false) - : ASTGEN_SUPER(fl, name) + : ASTGEN_SUPER_Module(fl, name) , m_isProgram{program} {} ASTNODE_NODE_FUNCS(Module) virtual string verilogKwd() const override { return m_isProgram ? "program" : "module"; } @@ -2534,7 +2534,7 @@ class AstNotFoundModule final : public AstNodeModule { // A missing module declaration public: AstNotFoundModule(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_NotFoundModule(fl, name) {} ASTNODE_NODE_FUNCS(NotFoundModule) virtual string verilogKwd() const override { return "/*not-found-*/ module"; } virtual bool timescaleMatters() const override { return false; } @@ -2544,7 +2544,7 @@ class AstPackage final : public AstNodeModule { // A package declaration public: AstPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_Package(fl, name) {} ASTNODE_NODE_FUNCS(Package) virtual string verilogKwd() const override { return "package"; } virtual bool timescaleMatters() const override { return !isDollarUnit(); } @@ -2556,7 +2556,7 @@ class AstPrimitive final : public AstNodeModule { // A primitive declaration public: AstPrimitive(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_Primitive(fl, name) {} ASTNODE_NODE_FUNCS(Primitive) virtual string verilogKwd() const override { return "primitive"; } virtual bool timescaleMatters() const override { return false; } @@ -2567,7 +2567,7 @@ class AstPackageExportStarStar final : public AstNode { public: // cppcheck-suppress noExplicitConstructor AstPackageExportStarStar(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_PackageExportStarStar(fl) {} ASTNODE_NODE_FUNCS(PackageExportStarStar) }; @@ -2578,7 +2578,7 @@ private: AstPackage* m_packagep; // Package hierarchy public: AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_PackageExport(fl) , m_name{name} , m_packagep{packagep} {} ASTNODE_NODE_FUNCS(PackageExport) @@ -2602,7 +2602,7 @@ private: AstPackage* m_packagep; // Package hierarchy public: AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_PackageImport(fl) , m_name{name} , m_packagep{packagep} {} ASTNODE_NODE_FUNCS(PackageImport) @@ -2623,7 +2623,7 @@ class AstIface final : public AstNodeModule { // A module declaration public: AstIface(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_Iface(fl, name) {} ASTNODE_NODE_FUNCS(Iface) // Interfaces have `timescale applicability but lots of code seems to // get false warnings if we enable this @@ -2639,13 +2639,13 @@ private: AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection public: AstMemberSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MemberSel(fl) , m_name{name} { setOp1p(fromp); dtypep(nullptr); // V3Width will resolve } AstMemberSel(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MemberSel(fl) , m_name{dtp->name()} { setOp1p(fromp); dtypep(dtp); @@ -2686,7 +2686,7 @@ private: AstNodeFTask* m_ftaskp = nullptr; // Link to the function public: AstModportFTaskRef(FileLine* fl, const string& name, bool isExport) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ModportFTaskRef(fl) , m_name{name} , m_export{isExport} {} ASTNODE_NODE_FUNCS(ModportFTaskRef) @@ -2715,7 +2715,7 @@ private: AstVar* m_varp = nullptr; // Link to the actual Var public: AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ModportVarRef(fl) , m_name{name} , m_direction{direction} {} ASTNODE_NODE_FUNCS(ModportVarRef) @@ -2740,7 +2740,7 @@ private: string m_name; // Name of the modport public: AstModport(FileLine* fl, const string& name, AstNode* varsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Modport(fl) , m_name{name} { addNOp1p(varsp); } @@ -2756,7 +2756,7 @@ private: string m_name; // Name of the reference public: AstIntfRef(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_IntfRef(fl) , m_name{name} {} virtual string name() const override { return m_name; } ASTNODE_NODE_FUNCS(IntfRef) @@ -2776,7 +2776,7 @@ private: public: AstCell(FileLine* fl, FileLine* mfl, const string& instName, const string& modName, AstPin* pinsp, AstPin* paramsp, AstRange* rangep) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Cell(fl) , m_modNameFileline{mfl} , m_name{instName} , m_origName{instName} @@ -2838,7 +2838,7 @@ private: public: AstCellInline(FileLine* fl, const string& name, const string& origModName, const VTimescale& timeunit) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CellInline(fl) , m_name{name} , m_origModName{origModName} , m_timeunit{timeunit} {} @@ -2864,7 +2864,7 @@ private: string m_name; // Cell name public: AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CellRef(fl) , m_name{name} { addNOp1p(cellp); addNOp2p(exprp); @@ -2882,7 +2882,7 @@ private: string m_name; // Array name public: AstCellArrayRef(FileLine* fl, const string& name, AstNode* selectExprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CellArrayRef(fl) , m_name{name} { addNOp1p(selectExprp); } @@ -2898,7 +2898,7 @@ private: string m_name; // Var name public: AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* crp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_UnlinkedRef(fl) , m_name{name} { addNOp1p(refp); addNOp2p(crp); @@ -2917,7 +2917,7 @@ private: string m_name; // Binding to name public: AstBind(FileLine* fl, const string& name, AstNode* cellsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Bind(fl) , m_name{name} { UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound"); addNOp1p(cellsp); @@ -2936,7 +2936,7 @@ private: string m_name; // Name of pin public: AstPort(FileLine* fl, int pinnum, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Port(fl) , m_pinNum{pinnum} , m_name{name} {} ASTNODE_NODE_FUNCS(Port) @@ -2960,7 +2960,7 @@ private: public: AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr, AstNodeFTaskRef* ftaskrefp = nullptr) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ParseRef(fl) , m_expect{expect} , m_name{name} { setNOp1p(lhsp); @@ -2990,7 +2990,7 @@ private: public: AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep, AstNode* paramsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ClassOrPackageRef(fl) , m_name{name} , m_classOrPackageNodep{classOrPackageNodep} { addNOp4p(paramsp); @@ -3026,7 +3026,7 @@ class AstDot final : public AstNode { bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) public: AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Dot(fl) , m_colon{colon} { setOp1p(lhsp); setOp2p(rhsp); @@ -3048,7 +3048,7 @@ class AstUnbounded final : public AstNodeMath { // Due to where is used, treated as Signed32 public: explicit AstUnbounded(FileLine* fl) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Unbounded(fl) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(Unbounded) @@ -3063,7 +3063,7 @@ class AstTask final : public AstNodeFTask { // A task inside a module public: AstTask(FileLine* fl, const string& name, AstNode* stmtp) - : ASTGEN_SUPER(fl, name, stmtp) {} + : ASTGEN_SUPER_Task(fl, name, stmtp) {} ASTNODE_NODE_FUNCS(Task) }; @@ -3071,7 +3071,7 @@ class AstFunc final : public AstNodeFTask { // A function inside a module public: AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp) - : ASTGEN_SUPER(fl, name, stmtp) { + : ASTGEN_SUPER_Func(fl, name, stmtp) { addNOp1p(fvarsp); } ASTNODE_NODE_FUNCS(Func) @@ -3082,11 +3082,11 @@ class AstTaskRef final : public AstNodeFTaskRef { // A reference to a task public: AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER(fl, true, namep, pinsp) { + : ASTGEN_SUPER_TaskRef(fl, true, namep, pinsp) { statement(true); } AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, true, name, pinsp) {} + : ASTGEN_SUPER_TaskRef(fl, true, name, pinsp) {} ASTNODE_NODE_FUNCS(TaskRef) }; @@ -3094,9 +3094,9 @@ class AstFuncRef final : public AstNodeFTaskRef { // A reference to a function public: AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, namep, pinsp) {} + : ASTGEN_SUPER_FuncRef(fl, false, namep, pinsp) {} AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, name, pinsp) {} + : ASTGEN_SUPER_FuncRef(fl, false, name, pinsp) {} ASTNODE_NODE_FUNCS(FuncRef) virtual bool hasDType() const override { return true; } }; @@ -3110,7 +3110,7 @@ private: string m_cname; // Name of function on c side public: AstDpiExport(FileLine* fl, const string& vname, const string& cname) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_DpiExport(fl) , m_name{vname} , m_cname{cname} {} ASTNODE_NODE_FUNCS(DpiExport) @@ -3127,7 +3127,7 @@ class AstWithParse final : public AstNodeStmt { // Children: funcref, math public: AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_WithParse(fl) { statement(stmt); setOp1p(funcrefp); addNOp2p(exprp); @@ -3149,7 +3149,7 @@ private: public: AstLambdaArgRef(FileLine* fl, const string& name, bool index) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_LambdaArgRef(fl) , m_name{name} , m_index(index) {} ASTNODE_NODE_FUNCS(LambdaArgRef) @@ -3174,7 +3174,7 @@ class AstWith final : public AstNodeStmt { public: AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_With(fl) { addOp1p(indexArgRefp); addOp2p(valueArgRefp); addNOp3p(exprp); @@ -3207,24 +3207,24 @@ public: class Settle {}; // for creator type-overload selection class Never {}; // for creator type-overload selection AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* varrefp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{edgeType} { setOp1p(varrefp); } AstSenItem(FileLine* fl, Combo) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_COMBO} {} AstSenItem(FileLine* fl, Illegal) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_ILLEGAL} {} AstSenItem(FileLine* fl, Initial) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_INITIAL} {} AstSenItem(FileLine* fl, Settle) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_SETTLE} {} AstSenItem(FileLine* fl, Never) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_NEVER} {} ASTNODE_NODE_FUNCS(SenItem) virtual void dump(std::ostream& str) const override; @@ -3258,7 +3258,7 @@ private: bool m_multi = false; // Created from combo logic by ORing multiple clock domains public: AstSenTree(FileLine* fl, AstSenItem* sensesp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SenTree(fl) { addNOp1p(sensesp); } ASTNODE_NODE_FUNCS(SenTree) @@ -3279,14 +3279,14 @@ public: class AstFinal final : public AstNodeProcedure { public: AstFinal(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) {} + : ASTGEN_SUPER_Final(fl, bodysp) {} ASTNODE_NODE_FUNCS(Final) }; class AstInitial final : public AstNodeProcedure { public: AstInitial(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) {} + : ASTGEN_SUPER_Initial(fl, bodysp) {} ASTNODE_NODE_FUNCS(Initial) }; @@ -3295,7 +3295,7 @@ class AstAlways final : public AstNodeProcedure { public: AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) + : ASTGEN_SUPER_Always(fl, bodysp) , m_keyword{keyword} { addNOp1p(sensesp); } @@ -3312,7 +3312,7 @@ class AstAlwaysPostponed final : public AstNodeProcedure { public: AstAlwaysPostponed(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) {} + : ASTGEN_SUPER_AlwaysPostponed(fl, bodysp) {} ASTNODE_NODE_FUNCS(AlwaysPostponed) }; @@ -3320,7 +3320,7 @@ class AstAlwaysPost final : public AstNodeProcedure { // Like always but post assignments for memory assignment IFs public: AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) { + : ASTGEN_SUPER_AlwaysPost(fl, bodysp) { addNOp1p(sensesp); } ASTNODE_NODE_FUNCS(AlwaysPost) @@ -3331,7 +3331,7 @@ class AstAlwaysPublic final : public AstNodeStmt { // Body statements are just AstVarRefs to the public signals public: AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_AlwaysPublic(fl) { addNOp1p(sensesp); addNOp2p(bodysp); } @@ -3348,7 +3348,7 @@ public: class AstAssign final : public AstNodeAssign { public: AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Assign(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Assign) @@ -3363,7 +3363,7 @@ class AstAssignAlias final : public AstNodeAssign { // If both sides are wires, there's no LHS vs RHS, public: AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignAlias(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignAlias) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { V3ERROR_NA_RETURN(nullptr); @@ -3374,7 +3374,7 @@ public: class AstAssignDly final : public AstNodeAssign { public: AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignDly) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignDly(this->fileline(), lhsp, rhsp); @@ -3388,7 +3388,7 @@ class AstAssignW final : public AstNodeAssign { // Like assign, but wire/assign's in verilog, the only setting of the specified variable public: AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignW) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignW(this->fileline(), lhsp, rhsp); @@ -3408,7 +3408,7 @@ class AstAssignVarScope final : public AstNodeAssign { // Assign two VarScopes to each other public: AstAssignVarScope(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) { dtypeFrom(rhsp); } ASTNODE_NODE_FUNCS(AssignVarScope) @@ -3424,7 +3424,7 @@ private: public: AstPull(FileLine* fl, AstNode* lhsp, bool direction) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Pull(fl) { setOp1p(lhsp); m_direction = direction; } @@ -3441,7 +3441,7 @@ class AstAssignPre final : public AstNodeAssign { // Like Assign, but predelayed assignment requiring special order handling public: AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignPre) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignPre(this->fileline(), lhsp, rhsp); @@ -3453,7 +3453,7 @@ class AstAssignPost final : public AstNodeAssign { // Like Assign, but predelayed assignment requiring special order handling public: AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignPost) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignPost(this->fileline(), lhsp, rhsp); @@ -3467,7 +3467,7 @@ class AstExprStmt final : public AstNodeMath { // resultp is evaluated AFTER the statement(s). public: AstExprStmt(FileLine* fl, AstNode* stmtsp, AstNode* resultp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ExprStmt(fl) { addOp1p(stmtsp); setOp2p(resultp); // Possibly in future nullptr could mean return rhsp() dtypeFrom(resultp); @@ -3493,7 +3493,7 @@ private: string m_name; // Text of comment public: AstComment(FileLine* fl, const string& name, bool showAt = false) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Comment(fl) , m_showAt{showAt} , m_name{name} {} ASTNODE_NODE_FUNCS(Comment) @@ -3510,7 +3510,7 @@ class AstCond final : public AstNodeCond { // Children: MATH public: AstCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : ASTGEN_SUPER(fl, condp, expr1p, expr2p) {} + : ASTGEN_SUPER_Cond(fl, condp, expr1p, expr2p) {} ASTNODE_NODE_FUNCS(Cond) virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { return new AstCond(this->fileline(), condp, expr1p, expr2p); @@ -3523,7 +3523,7 @@ class AstCondBound final : public AstNodeCond { // Children: MATH public: AstCondBound(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : ASTGEN_SUPER(fl, condp, expr1p, expr2p) {} + : ASTGEN_SUPER_CondBound(fl, condp, expr1p, expr2p) {} ASTNODE_NODE_FUNCS(CondBound) virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { return new AstCondBound(this->fileline(), condp, expr1p, expr2p); @@ -3546,7 +3546,7 @@ private: public: AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov, int offset) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CoverDecl(fl) { m_page = page; m_text = comment; m_linescov = linescov; @@ -3598,7 +3598,7 @@ private: AstCoverDecl* m_declp; // [After V3Coverage] Pointer to declaration public: AstCoverInc(FileLine* fl, AstCoverDecl* declp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CoverInc(fl) , m_declp{declp} {} ASTNODE_NODE_FUNCS(CoverInc) virtual const char* broken() const override { @@ -3626,7 +3626,7 @@ class AstCoverToggle final : public AstNodeStmt { // Children: AstCoverInc, orig var, change det var public: AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNode* origp, AstNode* changep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CoverToggle(fl) { setOp1p(incp); setOp2p(origp); setOp3p(changep); @@ -3650,7 +3650,7 @@ class AstDelay final : public AstNodeStmt { // Delay statement public: AstDelay(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Delay(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(Delay) @@ -3667,7 +3667,7 @@ class AstGenCase final : public AstNodeCase { // casesp Children: CASEITEMs public: AstGenCase(FileLine* fl, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER(fl, exprp, casesp) {} + : ASTGEN_SUPER_GenCase(fl, exprp, casesp) {} ASTNODE_NODE_FUNCS(GenCase) }; @@ -3685,7 +3685,7 @@ private: bool m_priorityPragma = false; // priority case public: AstCase(FileLine* fl, VCaseType casex, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER(fl, exprp, casesp) + : ASTGEN_SUPER_Case(fl, exprp, casesp) , m_casex{casex} {} ASTNODE_NODE_FUNCS(Case) virtual string verilogKwd() const override { @@ -3720,7 +3720,7 @@ private: bool m_ignoreOverlap = false; // Default created by assertions; ignore overlaps public: AstCaseItem(FileLine* fl, AstNode* condsp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CaseItem(fl) { addNOp1p(condsp); addNOp2p(bodysp); } @@ -3747,7 +3747,7 @@ public: class NoFormat {}; AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SFormatF(fl) , m_text{text} , m_hidden{hidden} , m_hasFormat{true} @@ -3758,7 +3758,7 @@ public: } AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', bool hidden = true) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SFormatF(fl) , m_text{""} , m_hidden{hidden} , m_hasFormat{false} @@ -3802,14 +3802,14 @@ private: public: AstDisplay(FileLine* fl, AstDisplayType dispType, const string& text, AstNode* filep, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Display(fl) { setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); setNOp3p(filep); m_displayType = dispType; } AstDisplay(FileLine* fl, AstDisplayType dispType, AstNode* filep, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Display(fl) { setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); setNOp3p(filep); m_displayType = dispType; @@ -3852,7 +3852,7 @@ class AstDumpCtl final : public AstNodeStmt { VDumpCtlType m_ctlType; // Type of operation public: AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = nullptr) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_DumpCtl(fl) , m_ctlType{ctlType} { setNOp1p(exprp); } @@ -3877,7 +3877,7 @@ private: public: AstElabDisplay(FileLine* fl, AstDisplayType dispType, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ElabDisplay(fl) { setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp)); m_displayType = dispType; } @@ -3913,12 +3913,12 @@ class AstSFormat final : public AstNodeStmt { public: AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SFormat(fl) { setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); setOp3p(lhsp); } AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SFormat(fl) { setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); setOp3p(lhsp); } @@ -3947,7 +3947,7 @@ class AstSysFuncAsTask final : public AstNodeStmt { // Children: a system function public: AstSysFuncAsTask(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SysFuncAsTask(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(SysFuncAsTask) @@ -3967,7 +3967,7 @@ class AstSysIgnore final : public AstNodeStmt { // Children: varrefs or exprs public: AstSysIgnore(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SysIgnore(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(SysIgnore) @@ -3988,7 +3988,7 @@ class AstFClose final : public AstNodeStmt { // Children: file which must be a varref public: AstFClose(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FClose(fl) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FClose) @@ -4007,7 +4007,7 @@ class AstFOpen final : public AstNodeStmt { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) public: AstFOpen(FileLine* fl, AstNode* filep, AstNode* filenamep, AstNode* modep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FOpen(fl) { setOp1p(filep); setOp2p(filenamep); setOp3p(modep); @@ -4030,7 +4030,7 @@ class AstFOpenMcd final : public AstNodeStmt { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) public: AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FOpenMcd(fl) { setOp1p(filep); setOp2p(filenamep); } @@ -4052,7 +4052,7 @@ class AstFFlush final : public AstNodeStmt { // Children: file which must be a varref public: AstFFlush(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FFlush(fl) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FFlush) @@ -4075,7 +4075,7 @@ class AstFRead final : public AstNodeMath { // Children: count public: AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, AstNode* startp, AstNode* countp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FRead(fl) { setOp1p(memp); setOp2p(filep); setNOp3p(startp); @@ -4106,7 +4106,7 @@ class AstFRewind final : public AstNodeMath { // Children: file which must be a varref public: AstFRewind(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FRewind(fl) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FRewind) @@ -4129,7 +4129,7 @@ class AstFTell final : public AstNodeMath { // Children: file which must be a varref public: AstFTell(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FTell(fl) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FTell) @@ -4154,7 +4154,7 @@ class AstFSeek final : public AstNodeMath { // Children: operation public: AstFSeek(FileLine* fl, AstNode* filep, AstNode* offset, AstNode* operation) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FSeek(fl) { setOp2p(filep); setNOp3p(offset); setNOp4p(operation); @@ -4186,7 +4186,7 @@ private: public: AstFScanF(FileLine* fl, const string& text, AstNode* filep, AstNode* exprsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_FScanF(fl) , m_text{text} { addNOp1p(exprsp); setNOp2p(filep); @@ -4221,7 +4221,7 @@ private: public: AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SScanF(fl) , m_text{text} { addNOp1p(exprsp); setOp2p(fromp); @@ -4281,7 +4281,7 @@ class AstReadMem final : public AstNodeReadWriteMem { public: AstReadMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) - : ASTGEN_SUPER(fl, hex, filenamep, memp, lsbp, msbp) {} + : ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {} ASTNODE_NODE_FUNCS(ReadMem); virtual string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); } virtual const char* cFuncPrefixp() const override { return "VL_READMEM_"; } @@ -4291,7 +4291,7 @@ class AstWriteMem final : public AstNodeReadWriteMem { public: AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) - : ASTGEN_SUPER(fl, hex, filenamep, memp, lsbp, msbp) {} + : ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {} ASTNODE_NODE_FUNCS(WriteMem) virtual string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); } virtual const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; } @@ -4302,7 +4302,7 @@ class AstMonitorOff final : public AstNodeStmt { public: AstMonitorOff(FileLine* fl, bool off) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MonitorOff(fl) , m_off{off} {} ASTNODE_NODE_FUNCS(MonitorOff) virtual string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } @@ -4323,7 +4323,7 @@ class AstSystemT final : public AstNodeStmt { // $system used as task public: AstSystemT(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SystemT(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(SystemT) @@ -4341,7 +4341,7 @@ class AstSystemF final : public AstNodeMath { // $system used as function public: AstSystemF(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SystemF(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(SystemF) @@ -4363,7 +4363,7 @@ class AstValuePlusArgs final : public AstNodeMath { // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs public: AstValuePlusArgs(FileLine* fl, AstNode* searchp, AstNode* outp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ValuePlusArgs(fl) { setOp1p(searchp); setOp2p(outp); } @@ -4390,7 +4390,7 @@ private: public: AstTestPlusArgs(FileLine* fl, const string& text) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TestPlusArgs(fl) , m_text{text} {} ASTNODE_NODE_FUNCS(TestPlusArgs) virtual string name() const override { return m_text; } @@ -4410,14 +4410,14 @@ public: class AstGenFor final : public AstNodeFor { public: AstGenFor(FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) - : ASTGEN_SUPER(fl, initsp, condp, incsp, bodysp) {} + : ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, bodysp) {} ASTNODE_NODE_FUNCS(GenFor) }; class AstForeach final : public AstNodeStmt { public: AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Foreach(fl) { setOp1p(arrayp); addNOp4p(bodysp); } @@ -4432,7 +4432,7 @@ public: class AstRepeat final : public AstNodeStmt { public: AstRepeat(FileLine* fl, AstNode* countp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Repeat(fl) { setOp2p(countp); addNOp3p(bodysp); } @@ -4449,7 +4449,7 @@ public: class AstWait final : public AstNodeStmt { public: AstWait(FileLine* fl, AstNode* condp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Wait(fl) { setOp2p(condp); addNOp3p(bodysp); } @@ -4460,7 +4460,7 @@ public: class AstWhile final : public AstNodeStmt { public: AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp, AstNode* incsp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_While(fl) { setOp2p(condp); addNOp3p(bodysp); addNOp4p(incsp); @@ -4486,7 +4486,7 @@ public: class AstBreak final : public AstNodeStmt { public: explicit AstBreak(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_Break(fl) {} ASTNODE_NODE_FUNCS(Break) virtual string verilogKwd() const override { return "break"; } virtual bool isBrancher() const override { @@ -4497,7 +4497,7 @@ public: class AstContinue final : public AstNodeStmt { public: explicit AstContinue(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_Continue(fl) {} ASTNODE_NODE_FUNCS(Continue) virtual string verilogKwd() const override { return "continue"; } virtual bool isBrancher() const override { @@ -4510,7 +4510,7 @@ private: string m_name; // Name of block public: AstDisable(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Disable(fl) , m_name{name} {} ASTNODE_NODE_FUNCS(Disable) virtual string name() const override { return m_name; } // * = Block name @@ -4524,7 +4524,7 @@ class AstDisableFork final : public AstNodeStmt { // A "disable fork" statement public: explicit AstDisableFork(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_DisableFork(fl) {} ASTNODE_NODE_FUNCS(DisableFork) }; @@ -4532,14 +4532,14 @@ class AstWaitFork final : public AstNodeStmt { // A "wait fork" statement public: explicit AstWaitFork(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_WaitFork(fl) {} ASTNODE_NODE_FUNCS(WaitFork) }; class AstReturn final : public AstNodeStmt { public: explicit AstReturn(FileLine* fl, AstNode* lhsp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Return(fl) { setNOp1p(lhsp); } ASTNODE_NODE_FUNCS(Return) @@ -4553,7 +4553,7 @@ public: class AstGenIf final : public AstNodeIf { public: AstGenIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) - : ASTGEN_SUPER(fl, condp, ifsp, elsesp) {} + : ASTGEN_SUPER_GenIf(fl, condp, ifsp, elsesp) {} ASTNODE_NODE_FUNCS(GenIf) }; @@ -4564,7 +4564,7 @@ private: bool m_priorityPragma; // priority case public: AstIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp = nullptr) - : ASTGEN_SUPER(fl, condp, ifsp, elsesp) { + : ASTGEN_SUPER_If(fl, condp, ifsp, elsesp) { m_uniquePragma = false; m_unique0Pragma = false; m_priorityPragma = false; @@ -4588,7 +4588,7 @@ private: public: // After construction must call ->labelp to associate with appropriate label AstJumpBlock(FileLine* fl, AstNode* stmtsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_JumpBlock(fl) { addNOp1p(stmtsp); } virtual const char* broken() const override; @@ -4616,7 +4616,7 @@ private: AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration public: AstJumpLabel(FileLine* fl, AstJumpBlock* blockp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_JumpLabel(fl) , m_blockp{blockp} {} ASTNODE_NODE_FUNCS(JumpLabel) virtual bool maybePointedTo() const override { return true; } @@ -4645,7 +4645,7 @@ private: AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration public: AstJumpGo(FileLine* fl, AstJumpLabel* labelp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_JumpGo(fl) , m_labelp{labelp} {} ASTNODE_NODE_FUNCS(JumpGo); virtual const char* broken() const override { @@ -4674,7 +4674,7 @@ class AstChangeXor final : public AstNodeBiComAsv { // Children: VARREF public: AstChangeXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ChangeXor(fl, lhsp, rhsp) { dtypeSetUInt32(); // Always used on, and returns word entities } ASTNODE_NODE_FUNCS(ChangeXor) @@ -4702,7 +4702,7 @@ private: public: // Null lhs+rhs used to indicate change needed with no spec vars AstChangeDet(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool clockReq) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ChangeDet(fl) { setNOp1p(lhsp); setNOp2p(rhsp); m_clockReq = clockReq; @@ -4723,7 +4723,7 @@ class AstConsAssoc final : public AstNodeMath { // Children: expression (elements or other queues) public: AstConsAssoc(FileLine* fl, AstNode* defaultp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ConsAssoc(fl) { setNOp1p(defaultp); } ASTNODE_NODE_FUNCS(ConsAssoc) @@ -4741,7 +4741,7 @@ class AstSetAssoc final : public AstNodeMath { // Children: expression (elements or other queues) public: AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SetAssoc(fl) { setOp1p(lhsp); setNOp2p(keyp); setOp3p(valuep); @@ -4764,7 +4764,7 @@ class AstConsDynArray final : public AstNodeMath { // Children: expression (elements or other queues) public: explicit AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ConsDynArray(fl) { setNOp1p(lhsp); setNOp2p(rhsp); } @@ -4785,7 +4785,7 @@ class AstConsQueue final : public AstNodeMath { // Children: expression (elements or other queues) public: explicit AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ConsQueue(fl) { setNOp1p(lhsp); setNOp2p(rhsp); } @@ -4811,7 +4811,7 @@ public: // Node that simply puts name into the output stream AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, bool implied = false) - : ASTGEN_SUPER(fl, name, stmtsp) + : ASTGEN_SUPER_Begin(fl, name, stmtsp) , m_generate{generate} , m_implied{implied} {} ASTNODE_NODE_FUNCS(Begin) @@ -4834,7 +4834,7 @@ private: public: // Node that simply puts name into the output stream AstFork(FileLine* fl, const string& name, AstNode* stmtsp) - : ASTGEN_SUPER(fl, name, stmtsp) {} + : ASTGEN_SUPER_Fork(fl, name, stmtsp) {} ASTNODE_NODE_FUNCS(Fork) virtual void dump(std::ostream& str) const override; VJoinType joinType() const { return m_joinType; } @@ -4844,7 +4844,7 @@ public: class AstInside final : public AstNodeMath { public: AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Inside(fl) { addOp1p(exprp); addOp2p(itemsp); dtypeSetBit(); @@ -4861,7 +4861,7 @@ public: class AstInsideRange final : public AstNodeMath { public: AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_InsideRange(fl) { addOp1p(lhsp); addOp2p(rhsp); } @@ -4882,7 +4882,7 @@ class AstInitItem final : public AstNode { public: // Parents: INITARRAY AstInitItem(FileLine* fl, AstNode* valuep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_InitItem(fl) { addOp1p(valuep); } ASTNODE_NODE_FUNCS(InitItem) @@ -4906,7 +4906,7 @@ private: KeyItemMap m_map; // Node value for each array index public: AstInitArray(FileLine* fl, AstNodeArrayDType* newDTypep, AstNode* defaultp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_InitArray(fl) { dtypep(newDTypep); addNOp1p(defaultp); } @@ -4971,7 +4971,7 @@ class AstNew final : public AstNodeFTaskRef { // Children: varref|arraysel, math public: AstNew(FileLine* fl, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, "new", pinsp) {} + : ASTGEN_SUPER_New(fl, false, "new", pinsp) {} ASTNODE_NODE_FUNCS(New) virtual bool cleanOut() const { return true; } virtual bool same(const AstNode* samep) const override { return true; } @@ -4985,7 +4985,7 @@ class AstNewCopy final : public AstNodeMath { // Children: varref|arraysel, math public: AstNewCopy(FileLine* fl, AstNode* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_NewCopy(fl) { dtypeFrom(rhsp); // otherwise V3Width will resolve setNOp1p(rhsp); } @@ -5004,7 +5004,7 @@ class AstNewDynamic final : public AstNodeMath { // Children: varref|arraysel, math public: AstNewDynamic(FileLine* fl, AstNode* sizep, AstNode* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_NewDynamic(fl) { dtypeFrom(rhsp); // otherwise V3Width will resolve setNOp1p(sizep); setNOp2p(rhsp); @@ -5026,7 +5026,7 @@ public: // Pragmas don't result in any output code, they're just flags that affect // other processing in verilator. AstPragma(FileLine* fl, AstPragmaType pragType) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Pragma(fl) , m_pragType{pragType} {} ASTNODE_NODE_FUNCS(Pragma) AstPragmaType pragType() const { return m_pragType; } // *=type of the pragma @@ -5042,7 +5042,7 @@ class AstPrintTimeScale final : public AstNodeStmt { VTimescale m_timeunit; // Parent module time unit public: explicit AstPrintTimeScale(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_PrintTimeScale(fl) {} ASTNODE_NODE_FUNCS(PrintTimeScale) virtual void name(const string& name) override { m_name = name; } virtual string name() const override { return m_name; } // * = Var name @@ -5060,7 +5060,7 @@ public: class AstStop final : public AstNodeStmt { public: AstStop(FileLine* fl, bool maybe) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_Stop(fl) {} ASTNODE_NODE_FUNCS(Stop) virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } @@ -5078,7 +5078,7 @@ public: class AstFinish final : public AstNodeStmt { public: explicit AstFinish(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_Finish(fl) {} ASTNODE_NODE_FUNCS(Finish) virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } @@ -5098,7 +5098,7 @@ class AstNullCheck final : public AstNodeUniop { // Children: VarRef or something returning pointer public: AstNullCheck(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_NullCheck(fl, lhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(NullCheck) @@ -5119,7 +5119,7 @@ class AstTimingControl final : public AstNodeStmt { // Parents: stmtlist public: AstTimingControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_TimingControl(fl) { setNOp1p(sensesp); setNOp2p(stmtsp); } @@ -5139,7 +5139,7 @@ class AstTimeFormat final : public AstNodeStmt { public: AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp, AstNode* widthp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_TimeFormat(fl) { setOp1p(unitsp); setOp2p(precisionp); setOp3p(suffixp); @@ -5178,7 +5178,7 @@ public: AstVar* varp, // For input/output state etc AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange, bool isScoped) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TraceDecl(fl) , m_showname{showname} , m_bitRange{bitRange} , m_arrayRange{arrayRange} @@ -5223,7 +5223,7 @@ private: const bool m_full; // Is this a full vs incremental dump public: AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TraceInc(fl) , m_declp{declp} , m_full{full} { dtypeFrom(declp); @@ -5265,7 +5265,7 @@ private: public: AstActive(FileLine* fl, const string& name, AstSenTree* sensesp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Active(fl) { m_name = name; // Copy it UASSERT(sensesp, "Sensesp required arg"); m_sensesp = sensesp; @@ -5305,7 +5305,7 @@ private: public: AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_AttrOf(fl) { setNOp1p(fromp); setNOp2p(dimp); m_attrType = attrtype; @@ -5328,7 +5328,7 @@ private: public: explicit AstScopeName(FileLine* fl) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ScopeName(fl) { dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(ScopeName) @@ -5361,7 +5361,7 @@ public: class AstUdpTable final : public AstNode { public: AstUdpTable(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UdpTable(fl) { addNOp1p(bodysp); } ASTNODE_NODE_FUNCS(UdpTable) @@ -5374,7 +5374,7 @@ class AstUdpTableLine final : public AstNode { public: AstUdpTableLine(FileLine* fl, const string& text) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_UdpTableLine(fl) , m_text{text} {} ASTNODE_NODE_FUNCS(UdpTableLine) virtual string name() const override { return m_text; } @@ -5393,12 +5393,12 @@ private: public: class Reset {}; AstRand(FileLine* fl, Reset, AstNodeDType* dtp, bool reset) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Rand(fl) , m_reset{reset} { dtypep(dtp); } AstRand(FileLine* fl, AstNode* seedp, bool urandom) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Rand(fl) , m_urandom(urandom) { setNOp1p(seedp); } @@ -5408,9 +5408,9 @@ public: : (m_urandom ? "%f$urandom()" : "%f$random()"); } virtual string emitC() override { - return m_reset - ? "VL_RAND_RESET_%nq(%nw, %P)" - : seedp() ? "VL_RANDOM_SEEDED_%nq%lq(%nw, %P, %li)" : "VL_RANDOM_%nq(%nw, %P)"; + return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" + : seedp() ? "VL_RANDOM_SEEDED_%nq%lq(%nw, %P, %li)" + : "VL_RANDOM_%nq(%nw, %P)"; } virtual bool cleanOut() const override { return true; } virtual bool isGateOptimizable() const override { return false; } @@ -5426,7 +5426,7 @@ class AstURandomRange final : public AstNodeBiop { // $urandom_range public: explicit AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) { dtypeSetUInt32(); // Says IEEE } ASTNODE_NODE_FUNCS(URandomRange) @@ -5452,7 +5452,7 @@ class AstTime final : public AstNodeTermop { VTimescale m_timeunit; // Parent module time unit public: AstTime(FileLine* fl, const VTimescale& timeunit) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Time(fl) , m_timeunit{timeunit} { dtypeSetUInt64(); } @@ -5473,7 +5473,7 @@ class AstTimeD final : public AstNodeTermop { VTimescale m_timeunit; // Parent module time unit public: AstTimeD(FileLine* fl, const VTimescale& timeunit) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TimeD(fl) , m_timeunit{timeunit} { dtypeSetDouble(); } @@ -5495,7 +5495,7 @@ class AstUCFunc final : public AstNodeMath { // Perhaps this should be an AstNodeListop; but there's only one list math right now public: AstUCFunc(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UCFunc(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(UCFunc) @@ -5518,7 +5518,7 @@ public: class AstNegate final : public AstNodeUniop { public: AstNegate(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Negate(fl, lhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Negate) @@ -5533,7 +5533,7 @@ public: class AstNegateD final : public AstNodeUniop { public: AstNegateD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_NegateD(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(NegateD) @@ -5550,7 +5550,7 @@ public: class AstRedAnd final : public AstNodeUniop { public: AstRedAnd(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RedAnd(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedAnd) @@ -5564,7 +5564,7 @@ public: class AstRedOr final : public AstNodeUniop { public: AstRedOr(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RedOr(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedOr) @@ -5578,7 +5578,7 @@ public: class AstRedXor final : public AstNodeUniop { public: AstRedXor(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RedXor(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedXor) @@ -5598,7 +5598,7 @@ class AstLenN final : public AstNodeUniop { // Length of a string public: AstLenN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_LenN(fl, lhsp) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(LenN) @@ -5612,7 +5612,7 @@ public: class AstLogNot final : public AstNodeUniop { public: AstLogNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_LogNot(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogNot) @@ -5627,7 +5627,7 @@ public: class AstNot final : public AstNodeUniop { public: AstNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Not(fl, lhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Not) @@ -5643,9 +5643,9 @@ class AstExtend final : public AstNodeUniop { // Expand a value into a wider entity by 0 extension. Width is implied from nodep->width() public: AstExtend(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_Extend(fl, lhsp) {} AstExtend(FileLine* fl, AstNode* lhsp, int width) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Extend(fl, lhsp) { dtypeSetLogicSized(width, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(Extend) @@ -5663,10 +5663,10 @@ class AstExtendS final : public AstNodeUniop { // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() public: AstExtendS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_ExtendS(fl, lhsp) {} AstExtendS(FileLine* fl, AstNode* lhsp, int width) // Important that widthMin be correct, as opExtend requires it after V3Expand - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_ExtendS(fl, lhsp) { dtypeSetLogicSized(width, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ExtendS) @@ -5687,7 +5687,7 @@ class AstSigned final : public AstNodeUniop { // $signed(lhs) public: AstSigned(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Signed(fl, lhsp) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, "not coded to create after dtypes resolved"); } @@ -5707,7 +5707,7 @@ class AstUnsigned final : public AstNodeUniop { // $unsigned(lhs) public: AstUnsigned(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Unsigned(fl, lhsp) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, "not coded to create after dtypes resolved"); } @@ -5727,7 +5727,7 @@ class AstRToIS final : public AstNodeUniop { // $rtoi(lhs) public: AstRToIS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RToIS(fl, lhsp) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(RToIS) @@ -5743,7 +5743,7 @@ class AstRToIRoundS final : public AstNodeUniop { // Convert real to integer, with arbitrary sized output (not just "integer" format) public: AstRToIRoundS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RToIRoundS(fl, lhsp) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(RToIRoundS) @@ -5761,7 +5761,7 @@ class AstIToRD final : public AstNodeUniop { // $itor where lhs is unsigned public: AstIToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_IToRD(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(IToRD) @@ -5777,7 +5777,7 @@ class AstISToRD final : public AstNodeUniop { // $itor where lhs is signed public: AstISToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_ISToRD(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(ISToRD) @@ -5793,7 +5793,7 @@ public: class AstRealToBits final : public AstNodeUniop { public: AstRealToBits(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RealToBits(fl, lhsp) { dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(RealToBits) @@ -5810,7 +5810,7 @@ public: class AstBitsToRealD final : public AstNodeUniop { public: AstBitsToRealD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_BitsToRealD(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(BitsToRealD) @@ -5828,7 +5828,7 @@ public: class AstCLog2 final : public AstNodeUniop { public: AstCLog2(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CLog2(fl, lhsp) {} ASTNODE_NODE_FUNCS(CLog2) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCLog2(lhs); } virtual string emitVerilog() override { return "%f$clog2(%l)"; } @@ -5842,11 +5842,12 @@ class AstCountBits final : public AstNodeQuadop { // Number of bits set in vector public: AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p) - : ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), ctrl1p->cloneTree(false)) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), + ctrl1p->cloneTree(false)) {} AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p) - : ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p) - : ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} ASTNODE_NODE_FUNCS(CountBits) virtual void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1, const V3Number& ctrl2, const V3Number& ctrl3) override { @@ -5869,7 +5870,7 @@ class AstCountOnes final : public AstNodeUniop { // Number of bits set in vector public: AstCountOnes(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CountOnes(fl, lhsp) {} ASTNODE_NODE_FUNCS(CountOnes) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCountOnes(lhs); @@ -5885,7 +5886,7 @@ class AstIsUnknown final : public AstNodeUniop { // True if any unknown bits public: AstIsUnknown(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_IsUnknown(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(IsUnknown) @@ -5902,7 +5903,7 @@ class AstIsUnbounded final : public AstNodeUniop { // True if is unmbounded ($) public: AstIsUnbounded(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_IsUnbounded(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(IsUnbounded) @@ -5920,7 +5921,7 @@ class AstOneHot final : public AstNodeUniop { // True if only single bit set in vector public: AstOneHot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_OneHot(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(OneHot) @@ -5936,7 +5937,7 @@ class AstOneHot0 final : public AstNodeUniop { // True if only single bit, or no bits set in vector public: AstOneHot0(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_OneHot0(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(OneHot0) @@ -5953,13 +5954,13 @@ class AstCast final : public AstNode { // Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc public: AstCast(FileLine* fl, AstNode* lhsp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Cast(fl) { setOp1p(lhsp); setOp2p(dtp); dtypeFrom(dtp); } AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Cast(fl) { setOp1p(lhsp); dtypeFrom(dtp); } @@ -5987,7 +5988,7 @@ class AstCastDynamic final : public AstNodeBiop { // value reading from. Suggest use fromp()/top() instead of lhsp/rhsp(). public: AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_CastDynamic(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(CastDynamic) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { V3ERROR_NA; @@ -6012,7 +6013,7 @@ class AstCastParse final : public AstNode { // Cast to appropriate type, where we haven't determined yet what the data type is public: AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CastParse(fl) { setOp1p(lhsp); setOp2p(dtp); } @@ -6030,7 +6031,7 @@ class AstCastSize final : public AstNode { // Cast to specific size; signed/twostate inherited from lower element per IEEE public: AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CastSize(fl) { setOp1p(lhsp); setOp2p(rhsp); } @@ -6051,7 +6052,7 @@ private: public: AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth = -1) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_CCast(fl, lhsp) { m_size = setwidth; if (setwidth) { if (minwidth == -1) minwidth = setwidth; @@ -6059,7 +6060,7 @@ public: } } AstCCast(FileLine* fl, AstNode* lhsp, AstNode* typeFromp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_CCast(fl, lhsp) { dtypeFrom(typeFromp); m_size = width(); } @@ -6082,7 +6083,7 @@ class AstCvtPackString final : public AstNodeUniop { // Convert to Verilator Packed String (aka verilog "string") public: AstCvtPackString(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_CvtPackString(fl, lhsp) { dtypeSetString(); } ASTNODE_NODE_FUNCS(CvtPackString) @@ -6098,7 +6099,7 @@ public: class AstFEof final : public AstNodeUniop { public: AstFEof(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_FEof(fl, lhsp) {} ASTNODE_NODE_FUNCS(FEof) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } virtual string emitVerilog() override { return "%f$feof(%l)"; } @@ -6116,7 +6117,7 @@ public: class AstFError final : public AstNodeMath { public: AstFError(FileLine* fl, AstNode* filep, AstNode* strp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FError(fl) { setOp1p(filep); setOp2p(strp); } @@ -6140,7 +6141,7 @@ public: class AstFGetC final : public AstNodeUniop { public: AstFGetC(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_FGetC(fl, lhsp) {} ASTNODE_NODE_FUNCS(FGetC) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } virtual string emitVerilog() override { return "%f$fgetc(%l)"; } @@ -6159,7 +6160,7 @@ public: class AstFUngetC final : public AstNodeBiop { public: AstFUngetC(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_FUngetC(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(FUngetC) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { V3ERROR_NA; @@ -6202,7 +6203,7 @@ public: class AstLogD final : public AstNodeSystemUniop { public: AstLogD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_LogD(fl, lhsp) {} ASTNODE_NODE_FUNCS(LogD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::log(lhs.toDouble())); @@ -6213,7 +6214,7 @@ public: class AstLog10D final : public AstNodeSystemUniop { public: AstLog10D(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_Log10D(fl, lhsp) {} ASTNODE_NODE_FUNCS(Log10D) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::log10(lhs.toDouble())); @@ -6225,7 +6226,7 @@ public: class AstExpD final : public AstNodeSystemUniop { public: AstExpD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_ExpD(fl, lhsp) {} ASTNODE_NODE_FUNCS(ExpD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::exp(lhs.toDouble())); @@ -6237,7 +6238,7 @@ public: class AstSqrtD final : public AstNodeSystemUniop { public: AstSqrtD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_SqrtD(fl, lhsp) {} ASTNODE_NODE_FUNCS(SqrtD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::sqrt(lhs.toDouble())); @@ -6249,7 +6250,7 @@ public: class AstFloorD final : public AstNodeSystemUniop { public: AstFloorD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_FloorD(fl, lhsp) {} ASTNODE_NODE_FUNCS(FloorD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::floor(lhs.toDouble())); @@ -6261,7 +6262,7 @@ public: class AstCeilD final : public AstNodeSystemUniop { public: AstCeilD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CeilD(fl, lhsp) {} ASTNODE_NODE_FUNCS(CeilD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::ceil(lhs.toDouble())); @@ -6273,7 +6274,7 @@ public: class AstSinD final : public AstNodeSystemUniop { public: AstSinD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_SinD(fl, lhsp) {} ASTNODE_NODE_FUNCS(SinD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::sin(lhs.toDouble())); @@ -6285,7 +6286,7 @@ public: class AstCosD final : public AstNodeSystemUniop { public: AstCosD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CosD(fl, lhsp) {} ASTNODE_NODE_FUNCS(CosD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::cos(lhs.toDouble())); @@ -6297,7 +6298,7 @@ public: class AstTanD final : public AstNodeSystemUniop { public: AstTanD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_TanD(fl, lhsp) {} ASTNODE_NODE_FUNCS(TanD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::tan(lhs.toDouble())); @@ -6309,7 +6310,7 @@ public: class AstAsinD final : public AstNodeSystemUniop { public: AstAsinD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AsinD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AsinD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::asin(lhs.toDouble())); @@ -6321,7 +6322,7 @@ public: class AstAcosD final : public AstNodeSystemUniop { public: AstAcosD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AcosD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AcosD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::acos(lhs.toDouble())); @@ -6333,7 +6334,7 @@ public: class AstAtanD final : public AstNodeSystemUniop { public: AstAtanD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AtanD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AtanD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::atan(lhs.toDouble())); @@ -6345,7 +6346,7 @@ public: class AstSinhD final : public AstNodeSystemUniop { public: AstSinhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_SinhD(fl, lhsp) {} ASTNODE_NODE_FUNCS(SinhD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::sinh(lhs.toDouble())); @@ -6357,7 +6358,7 @@ public: class AstCoshD final : public AstNodeSystemUniop { public: AstCoshD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CoshD(fl, lhsp) {} ASTNODE_NODE_FUNCS(CoshD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::cosh(lhs.toDouble())); @@ -6369,7 +6370,7 @@ public: class AstTanhD final : public AstNodeSystemUniop { public: AstTanhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_TanhD(fl, lhsp) {} ASTNODE_NODE_FUNCS(TanhD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::tanh(lhs.toDouble())); @@ -6381,7 +6382,7 @@ public: class AstAsinhD final : public AstNodeSystemUniop { public: AstAsinhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AsinhD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AsinhD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::asinh(lhs.toDouble())); @@ -6393,7 +6394,7 @@ public: class AstAcoshD final : public AstNodeSystemUniop { public: AstAcoshD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AcoshD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AcoshD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::acosh(lhs.toDouble())); @@ -6405,7 +6406,7 @@ public: class AstAtanhD final : public AstNodeSystemUniop { public: AstAtanhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AtanhD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AtanhD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::atanh(lhs.toDouble())); @@ -6417,7 +6418,7 @@ class AstToLowerN final : public AstNodeUniop { // string.tolower() public: AstToLowerN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_ToLowerN(fl, lhsp) { dtypeSetString(); } ASTNODE_NODE_FUNCS(ToLowerN) @@ -6434,7 +6435,7 @@ class AstToUpperN final : public AstNodeUniop { // string.toupper() public: AstToUpperN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_ToUpperN(fl, lhsp) { dtypeSetString(); } ASTNODE_NODE_FUNCS(ToUpperN) @@ -6452,7 +6453,7 @@ class AstTimeImport final : public AstNodeUniop { VTimescale m_timeunit; // Parent module time unit public: AstTimeImport(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_TimeImport(fl, lhsp) {} ASTNODE_NODE_FUNCS(TimeImport) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } virtual string emitVerilog() override { return "%l"; } @@ -6474,7 +6475,7 @@ private: FmtType m_fmt; // Operation type public: AstAtoN(FileLine* fl, AstNode* lhsp, FmtType fmt) - : ASTGEN_SUPER(fl, lhsp) + : ASTGEN_SUPER_AtoN(fl, lhsp) , m_fmt{fmt} { fmt == ATOREAL ? dtypeSetDouble() : dtypeSetSigned32(); } @@ -6516,7 +6517,7 @@ public: class AstLogOr final : public AstNodeBiop { public: AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogOr) @@ -6539,7 +6540,7 @@ public: class AstLogAnd final : public AstNodeBiop { public: AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LogAnd(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogAnd) @@ -6562,7 +6563,7 @@ public: class AstLogEq final : public AstNodeBiCom { public: AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LogEq(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogEq) @@ -6585,7 +6586,7 @@ public: class AstLogIf final : public AstNodeBiop { public: AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LogIf(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogIf) @@ -6608,7 +6609,7 @@ public: class AstOr final : public AstNodeBiComAsv { public: AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Or(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Or) @@ -6630,7 +6631,7 @@ public: class AstAnd final : public AstNodeBiComAsv { public: AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_And(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(And) @@ -6652,7 +6653,7 @@ public: class AstXor final : public AstNodeBiComAsv { public: AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Xor(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Xor) @@ -6674,7 +6675,7 @@ public: class AstEq final : public AstNodeBiCom { public: AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Eq(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Eq) @@ -6698,7 +6699,7 @@ public: class AstEqD final : public AstNodeBiCom { public: AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_EqD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqD) @@ -6722,7 +6723,7 @@ public: class AstEqN final : public AstNodeBiCom { public: AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_EqN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqN) @@ -6746,7 +6747,7 @@ public: class AstNeq final : public AstNodeBiCom { public: AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Neq(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Neq) @@ -6768,7 +6769,7 @@ public: class AstNeqD final : public AstNodeBiCom { public: AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_NeqD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqD) @@ -6792,7 +6793,7 @@ public: class AstNeqN final : public AstNodeBiCom { public: AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_NeqN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqN) @@ -6816,7 +6817,7 @@ public: class AstLt final : public AstNodeBiop { public: AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Lt(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Lt) @@ -6838,7 +6839,7 @@ public: class AstLtD final : public AstNodeBiop { public: AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LtD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtD) @@ -6862,7 +6863,7 @@ public: class AstLtS final : public AstNodeBiop { public: AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LtS(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtS) @@ -6885,7 +6886,7 @@ public: class AstLtN final : public AstNodeBiop { public: AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LtN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtN) @@ -6909,7 +6910,7 @@ public: class AstGt final : public AstNodeBiop { public: AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Gt(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Gt) @@ -6931,7 +6932,7 @@ public: class AstGtD final : public AstNodeBiop { public: AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GtD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtD) @@ -6955,7 +6956,7 @@ public: class AstGtS final : public AstNodeBiop { public: AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GtS(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtS) @@ -6978,7 +6979,7 @@ public: class AstGtN final : public AstNodeBiop { public: AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GtN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtN) @@ -7002,7 +7003,7 @@ public: class AstGte final : public AstNodeBiop { public: AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Gte(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Gte) @@ -7026,7 +7027,7 @@ public: class AstGteD final : public AstNodeBiop { public: AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GteD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteD) @@ -7050,7 +7051,7 @@ public: class AstGteS final : public AstNodeBiop { public: AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GteS(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteS) @@ -7073,7 +7074,7 @@ public: class AstGteN final : public AstNodeBiop { public: AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GteN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteN) @@ -7097,7 +7098,7 @@ public: class AstLte final : public AstNodeBiop { public: AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Lte(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Lte) @@ -7121,7 +7122,7 @@ public: class AstLteD final : public AstNodeBiop { public: AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LteD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteD) @@ -7145,7 +7146,7 @@ public: class AstLteS final : public AstNodeBiop { public: AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LteS(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteS) @@ -7168,7 +7169,7 @@ public: class AstLteN final : public AstNodeBiop { public: AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LteN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteN) @@ -7192,7 +7193,7 @@ public: class AstShiftL final : public AstNodeBiop { public: AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ShiftL(fl, lhsp, rhsp) { if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ShiftL) @@ -7216,7 +7217,7 @@ public: class AstShiftR final : public AstNodeBiop { public: AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ShiftR(fl, lhsp, rhsp) { if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ShiftR) @@ -7243,7 +7244,7 @@ class AstShiftRS final : public AstNodeBiop { // Output data type's width determines which bit is used for sign extension public: AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) { // Important that widthMin be correct, as opExtend requires it after V3Expand if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED); } @@ -7267,7 +7268,7 @@ public: class AstAdd final : public AstNodeBiComAsv { public: AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Add(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Add) @@ -7289,7 +7290,7 @@ public: class AstAddD final : public AstNodeBiComAsv { public: AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_AddD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(AddD) @@ -7313,7 +7314,7 @@ public: class AstSub final : public AstNodeBiop { public: AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Sub(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Sub) @@ -7335,7 +7336,7 @@ public: class AstSubD final : public AstNodeBiop { public: AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_SubD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(SubD) @@ -7359,7 +7360,7 @@ public: class AstMul final : public AstNodeBiComAsv { public: AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Mul(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Mul) @@ -7382,7 +7383,7 @@ public: class AstMulD final : public AstNodeBiComAsv { public: AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_MulD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(MulD) @@ -7406,7 +7407,7 @@ public: class AstMulS final : public AstNodeBiComAsv { public: AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_MulS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(MulS) @@ -7431,7 +7432,7 @@ public: class AstDiv final : public AstNodeBiop { public: AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Div(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Div) @@ -7453,7 +7454,7 @@ public: class AstDivD final : public AstNodeBiop { public: AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_DivD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(DivD) @@ -7477,7 +7478,7 @@ public: class AstDivS final : public AstNodeBiop { public: AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_DivS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(DivS) @@ -7500,7 +7501,7 @@ public: class AstModDiv final : public AstNodeBiop { public: AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ModDiv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(ModDiv) @@ -7522,7 +7523,7 @@ public: class AstModDivS final : public AstNodeBiop { public: AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ModDivS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(ModDivS) @@ -7545,7 +7546,7 @@ public: class AstPow final : public AstNodeBiop { public: AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Pow(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Pow) @@ -7568,7 +7569,7 @@ public: class AstPowD final : public AstNodeBiop { public: AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_PowD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(PowD) @@ -7591,7 +7592,7 @@ public: class AstPowSU final : public AstNodeBiop { public: AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_PowSU(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(PowSU) @@ -7617,7 +7618,7 @@ public: class AstPowSS final : public AstNodeBiop { public: AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_PowSS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(PowSS) @@ -7643,7 +7644,7 @@ public: class AstPowUS final : public AstNodeBiop { public: AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_PowUS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(PowUS) @@ -7674,7 +7675,7 @@ class AstPreAdd final : public AstNodeTriop { // Children: thsp: tree with AstVarRef LValue that is stored after operation public: AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {} + : ASTGEN_SUPER_PreAdd(fl, lhsp, rhsp, thsp) {} ASTNODE_NODE_FUNCS(PreAdd) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override { @@ -7699,7 +7700,7 @@ class AstPreSub final : public AstNodeTriop { // Children: thsp: tree with AstVarRef LValue that is stored after operation public: AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {} + : ASTGEN_SUPER_PreSub(fl, lhsp, rhsp, thsp) {} ASTNODE_NODE_FUNCS(PreSub) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override { @@ -7724,7 +7725,7 @@ class AstPostAdd final : public AstNodeTriop { // Children: thsp: tree with AstVarRef LValue that is stored after operation public: AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {} + : ASTGEN_SUPER_PostAdd(fl, lhsp, rhsp, thsp) {} ASTNODE_NODE_FUNCS(PostAdd) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override { @@ -7749,7 +7750,7 @@ class AstPostSub final : public AstNodeTriop { // Children: thsp: tree with AstVarRef LValue that is stored after operation public: AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {} + : ASTGEN_SUPER_PostSub(fl, lhsp, rhsp, thsp) {} ASTNODE_NODE_FUNCS(PostSub) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override { @@ -7769,7 +7770,7 @@ public: class AstEqCase final : public AstNodeBiCom { public: AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_EqCase(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqCase) @@ -7791,7 +7792,7 @@ public: class AstNeqCase final : public AstNodeBiCom { public: AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_NeqCase(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqCase) @@ -7814,7 +7815,7 @@ class AstEqWild final : public AstNodeBiop { // Note wildcard operator rhs differs from lhs public: AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_EqWild(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqWild) @@ -7838,7 +7839,7 @@ public: class AstNeqWild final : public AstNodeBiop { public: AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_NeqWild(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqWild) @@ -7861,7 +7862,7 @@ class AstConcat final : public AstNodeBiop { // If you're looking for {#{}}, see AstReplicate public: AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Concat(fl, lhsp, rhsp) { if (lhsp->dtypep() && rhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(), VSigning::UNSIGNED); @@ -7887,7 +7888,7 @@ class AstConcatN final : public AstNodeBiop { // String concatenate public: AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ConcatN(fl, lhsp, rhsp) { dtypeSetString(); } ASTNODE_NODE_FUNCS(ConcatN) @@ -7912,7 +7913,7 @@ class AstReplicate final : public AstNodeBiop { // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() public: AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) { if (lhsp) { if (const AstConst* constp = VN_CAST(rhsp, Const)) { dtypeSetLogicSized(lhsp->width() * constp->toUInt(), VSigning::UNSIGNED); @@ -7941,7 +7942,7 @@ class AstReplicateN final : public AstNodeBiop { // String replicate public: AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ReplicateN(fl, lhsp, rhsp) { dtypeSetString(); } AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount) @@ -7967,7 +7968,7 @@ class AstStreamL final : public AstNodeStream { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() public: AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_StreamL(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(StreamL) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstStreamL(this->fileline(), lhsp, rhsp); @@ -7988,7 +7989,7 @@ class AstStreamR final : public AstNodeStream { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() public: AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_StreamR(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(StreamR) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstStreamR(this->fileline(), lhsp, rhsp); @@ -8011,7 +8012,7 @@ class AstBufIf1 final : public AstNodeBiop { // bit enables respective rhsp bit public: AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_BufIf1(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(BufIf1) @@ -8033,7 +8034,7 @@ public: class AstFGetS final : public AstNodeBiop { public: AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_FGetS(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(FGetS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstFGetS(this->fileline(), lhsp, rhsp); @@ -8074,7 +8075,7 @@ public: class AstAtan2D final : public AstNodeSystemBiop { public: AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_Atan2D(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(Atan2D) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAtan2D(this->fileline(), lhsp, rhsp); @@ -8089,7 +8090,7 @@ public: class AstHypotD final : public AstNodeSystemBiop { public: AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_HypotD(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(HypotD) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstHypotD(this->fileline(), lhsp, rhsp); @@ -8105,7 +8106,7 @@ class AstPutcN final : public AstNodeTriop { // Verilog string.putc() public: AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER(fl, lhsp, rhsp, ths) { + : ASTGEN_SUPER_PutcN(fl, lhsp, rhsp, ths) { dtypeSetString(); } ASTNODE_NODE_FUNCS(PutcN) @@ -8131,7 +8132,7 @@ class AstGetcN final : public AstNodeBiop { // Verilog string.getc() public: AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GetcN(fl, lhsp, rhsp) { dtypeSetBitSized(8, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(GetcN) @@ -8158,7 +8159,7 @@ class AstGetcRefN final : public AstNodeBiop { // Spec says is of type byte (not string of single character) public: AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GetcRefN(fl, lhsp, rhsp) { dtypeSetBitSized(8, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(GetcRefN) @@ -8183,7 +8184,7 @@ class AstSubstrN final : public AstNodeTriop { // Verilog string.substr() public: AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER(fl, lhsp, rhsp, ths) { + : ASTGEN_SUPER_SubstrN(fl, lhsp, rhsp, ths) { dtypeSetString(); } ASTNODE_NODE_FUNCS(SubstrN) @@ -8211,7 +8212,7 @@ private: bool m_ignoreCase; // True for str.icompare() public: AstCompareNN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool ignoreCase) - : ASTGEN_SUPER(fl, lhsp, rhsp) + : ASTGEN_SUPER_CompareNN(fl, lhsp, rhsp) , m_ignoreCase{ignoreCase} { dtypeSetUInt32(); } @@ -8244,7 +8245,7 @@ class AstFell final : public AstNodeMath { // Children: expression public: AstFell(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Fell(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Fell) @@ -8265,7 +8266,7 @@ class AstPast final : public AstNodeMath { // Children: expression public: AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Past(fl) { addOp1p(exprp); addNOp2p(ticksp); } @@ -8288,7 +8289,7 @@ class AstRose final : public AstNodeMath { // Children: expression public: AstRose(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Rose(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Rose) @@ -8309,7 +8310,7 @@ class AstSampled final : public AstNodeMath { // Children: expression public: AstSampled(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Sampled(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Sampled) @@ -8328,7 +8329,7 @@ class AstStable final : public AstNodeMath { // Children: expression public: AstStable(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Stable(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Stable) @@ -8349,7 +8350,7 @@ class AstPattern final : public AstNodeMath { // Children: expression, AstPattern, AstPatReplicate public: AstPattern(FileLine* fl, AstNode* itemsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Pattern(fl) { addNOp2p(itemsp); } ASTNODE_NODE_FUNCS(Pattern) @@ -8374,7 +8375,7 @@ private: public: AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_PatMember(fl) { addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); } ASTNODE_NODE_FUNCS(PatMember) @@ -8398,7 +8399,7 @@ class AstImplication final : public AstNodeMath { // Children: expression public: AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Implication(fl) { setOp1p(lhs); setOp2p(rhs); } @@ -8426,7 +8427,7 @@ class AstClocking final : public AstNode { // Children: Assertions public: AstClocking(FileLine* fl, AstSenItem* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Clocking(fl) { addOp1p(sensesp); addNOp2p(bodysp); } @@ -8445,7 +8446,7 @@ class AstPropClocked final : public AstNode { // Children: SENITEM, Properties public: AstPropClocked(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_PropClocked(fl) { addNOp1p(sensesp); addNOp2p(disablep); addOp3p(propp); @@ -8492,7 +8493,7 @@ public: ASTNODE_NODE_FUNCS(Assert) AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, const string& name = "") - : ASTGEN_SUPER(fl, propp, passsp, immediate, name) { + : ASTGEN_SUPER_Assert(fl, propp, passsp, immediate, name) { addNOp3p(failsp); } AstNode* failsp() const { return op3p(); } // op3 = if assertion fails @@ -8504,7 +8505,7 @@ public: ASTNODE_NODE_FUNCS(AssertIntrinsic) AstAssertIntrinsic(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, const string& name = "") - : ASTGEN_SUPER(fl, propp, passsp, immediate, name) { + : ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, immediate, name) { addNOp3p(failsp); } AstNode* failsp() const { return op3p(); } // op3 = if assertion fails @@ -8515,7 +8516,7 @@ public: ASTNODE_NODE_FUNCS(Cover) AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, bool immediate, const string& name = "") - : ASTGEN_SUPER(fl, propp, stmtsp, immediate, name) {} + : ASTGEN_SUPER_Cover(fl, propp, stmtsp, immediate, name) {} AstNode* coverincp() const { return op3p(); } // op3 = coverage node void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node virtual bool immediate() const { return false; } @@ -8525,7 +8526,7 @@ class AstRestrict final : public AstNodeCoverOrAssert { public: ASTNODE_NODE_FUNCS(Restrict) AstRestrict(FileLine* fl, AstNode* propp) - : ASTGEN_SUPER(fl, propp, nullptr, false, "") {} + : ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {} }; //====================================================================== @@ -8546,7 +8547,7 @@ public: class AstText final : public AstNodeSimpleText { public: AstText(FileLine* fl, const string& textp, bool tracking = false) - : ASTGEN_SUPER(fl, textp, tracking) {} + : ASTGEN_SUPER_Text(fl, textp, tracking) {} ASTNODE_NODE_FUNCS(Text) }; @@ -8556,7 +8557,7 @@ private: public: explicit AstTextBlock(FileLine* fl, const string& textp = "", bool tracking = false, bool commas = false) - : ASTGEN_SUPER(fl, textp, tracking) + : ASTGEN_SUPER_TextBlock(fl, textp, tracking) , m_commas(commas) {} ASTNODE_NODE_FUNCS(TextBlock) void commas(bool flag) { m_commas = flag; } @@ -8571,7 +8572,7 @@ public: class AstScCtor final : public AstNodeText { public: AstScCtor(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScCtor(fl, textp) {} ASTNODE_NODE_FUNCS(ScCtor) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8580,7 +8581,7 @@ public: class AstScDtor final : public AstNodeText { public: AstScDtor(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScDtor(fl, textp) {} ASTNODE_NODE_FUNCS(ScDtor) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8589,7 +8590,7 @@ public: class AstScHdr final : public AstNodeText { public: AstScHdr(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScHdr(fl, textp) {} ASTNODE_NODE_FUNCS(ScHdr) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8598,7 +8599,7 @@ public: class AstScImp final : public AstNodeText { public: AstScImp(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScImp(fl, textp) {} ASTNODE_NODE_FUNCS(ScImp) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8607,7 +8608,7 @@ public: class AstScImpHdr final : public AstNodeText { public: AstScImpHdr(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScImpHdr(fl, textp) {} ASTNODE_NODE_FUNCS(ScImpHdr) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8616,7 +8617,7 @@ public: class AstScInt final : public AstNodeText { public: AstScInt(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScInt(fl, textp) {} ASTNODE_NODE_FUNCS(ScInt) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8626,7 +8627,7 @@ class AstUCStmt final : public AstNodeStmt { // User $c statement public: AstUCStmt(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UCStmt(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(UCStmt) @@ -8668,7 +8669,7 @@ class AstVFile final : public AstNodeFile { // Parents: NETLIST public: AstVFile(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_VFile(fl, name) {} ASTNODE_NODE_FUNCS(VFile) virtual void dump(std::ostream& str = std::cout) const override; }; @@ -8685,7 +8686,7 @@ private: bool m_support : 1; ///< Support file (non systemc) public: AstCFile(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) + : ASTGEN_SUPER_CFile(fl, name) , m_slow{false} , m_source{false} , m_support{false} {} @@ -8734,7 +8735,7 @@ private: bool m_dpiImportWrapper : 1; // Wrapper from dpi import public: AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "") - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CFunc(fl) { m_funcType = AstCFuncType::FT_NORMAL; m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed m_isStatic = VBoolOrUnknown::BU_UNKNOWN; // Unknown until see where thisp needed @@ -8856,7 +8857,7 @@ class AstCCall final : public AstNodeCCall { // Children: Args to the function public: AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER(fl, funcp, argsp) {} + : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} ASTNODE_NODE_FUNCS(CCall) }; @@ -8866,7 +8867,7 @@ class AstCMethodCall final : public AstNodeCCall { // Children: Args to the function public: AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER(fl, funcp, argsp) { + : ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) { setOp1p(fromp); } ASTNODE_NODE_FUNCS(CMethodCall) @@ -8887,7 +8888,7 @@ class AstCNew final : public AstNodeCCall { // Children: Args to the function public: AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER(fl, funcp, argsp) { + : ASTGEN_SUPER_CNew(fl, funcp, argsp) { statement(false); } virtual bool hasDType() const override { return true; } @@ -8900,7 +8901,7 @@ class AstCReturn final : public AstNodeStmt { // Children: Math public: AstCReturn(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CReturn(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(CReturn) @@ -8917,14 +8918,14 @@ private: public: // Emit C textual math function (like AstUCFunc) AstCMath(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CMath(fl) , m_cleanOut{true} , m_pure{false} { addOp1p(exprsp); dtypeFrom(exprsp); } AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CMath(fl) , m_cleanOut{cleanOut} , m_pure{true} { addNOp1p(new AstText(fl, textStmt, true)); @@ -8947,7 +8948,7 @@ class AstCReset final : public AstNodeStmt { // Reset variable at startup public: AstCReset(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CReset(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(CReset) @@ -8961,11 +8962,11 @@ class AstCStmt final : public AstNodeStmt { // Emit C statement public: AstCStmt(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CStmt(fl) { addNOp1p(exprsp); } AstCStmt(FileLine* fl, const string& textStmt) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CStmt(fl) { addNOp1p(new AstText(fl, textStmt, true)); } ASTNODE_NODE_FUNCS(CStmt) @@ -8985,7 +8986,7 @@ private: public: AstCUse(FileLine* fl, VUseType useType, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CUse(fl) , m_useType{useType} , m_name{name} {} ASTNODE_NODE_FUNCS(CUse) @@ -9002,7 +9003,7 @@ private: public: explicit AstMTaskBody(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_MTaskBody(fl) {} ASTNODE_NODE_FUNCS(MTaskBody); virtual const char* broken() const override { BROKEN_RTN(!m_execMTaskp); @@ -9043,7 +9044,7 @@ class AstSplitPlaceholder final : public AstNode { public: // Dummy node used within V3Split; never exists outside of V3Split. explicit AstSplitPlaceholder(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_SplitPlaceholder(fl) {} ASTNODE_NODE_FUNCS(SplitPlaceholder) }; @@ -9062,7 +9063,7 @@ class AstTypeTable final : public AstNode { public: explicit AstTypeTable(FileLine* fl) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_TypeTable(fl) { for (int i = 0; i < AstBasicDTypeKwd::_ENUM_MAX; ++i) m_basicps[i] = nullptr; } ASTNODE_NODE_FUNCS(TypeTable) @@ -9098,7 +9099,7 @@ private: bool m_timescaleSpecified = false; // Input HDL specified timescale public: AstNetlist() - : ASTGEN_SUPER(new FileLine(FileLine::builtInFilename())) {} + : ASTGEN_SUPER_Netlist(new FileLine(FileLine::builtInFilename())) {} ASTNODE_NODE_FUNCS(Netlist) virtual const char* broken() const override { BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); @@ -9153,6 +9154,4 @@ public: //###################################################################### -#undef ASTGEN_SUPER - #endif // Guard diff --git a/src/astgen b/src/astgen index a5057b7a8..a66bf3526 100755 --- a/src/astgen +++ b/src/astgen @@ -621,7 +621,7 @@ def write_types(filename): fh.write(" }\n") -def write_header(filename): +def write_macros(filename): with open_file(filename) as fh: typen = "None" base = "None" @@ -629,10 +629,7 @@ def write_header(filename): in_filename = "V3AstNodes.h" ifile = Args.I + "/" + in_filename with open(ifile) as ifh: - - fh.write("#line 1 \"../" + in_filename + "\"\n") - - for line in 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) @@ -644,14 +641,18 @@ def write_header(filename): if match: typen = match.group(1) base = match.group(4) + if not typen.startswith("Node"): + macro = "#define ASTGEN_SUPER_{t}(...) {b}(AstType::at{t}, __VA_ARGS__)\n" \ + .format(b=base, t=typen) + fh.write(macro) - # Substitute macros - line = re.sub(r'\bASTGEN_SUPER\s*\(', - base + "(AstType::at" + typen + ", ", line) - - # Emit the line - fh.write(line) - + 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) ###################################################################### # main @@ -708,7 +709,7 @@ if Args.classes: write_visitor("V3Ast__gen_visitor.h") write_impl("V3Ast__gen_impl.h") write_types("V3Ast__gen_types.h") - write_header("V3AstNodes__gen.h") + write_macros("V3AstNodes__gen_macros.h") for cpt in Args.infiles: if not re.search(r'.cpp$', cpt): From a43eba7011647714cf421414050d3769e08adc7a Mon Sep 17 00:00:00 2001 From: github action Date: Sat, 22 May 2021 10:14:07 +0000 Subject: [PATCH 49/80] Apply clang-format --- src/V3AstNodes.h | 6 +++--- src/astgen | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 8a2da1368..9cc94e42d 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5408,9 +5408,9 @@ public: : (m_urandom ? "%f$urandom()" : "%f$random()"); } virtual string emitC() override { - return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" - : seedp() ? "VL_RANDOM_SEEDED_%nq%lq(%nw, %P, %li)" - : "VL_RANDOM_%nq(%nw, %P)"; + return m_reset + ? "VL_RAND_RESET_%nq(%nw, %P)" + : seedp() ? "VL_RANDOM_SEEDED_%nq%lq(%nw, %P, %li)" : "VL_RANDOM_%nq(%nw, %P)"; } virtual bool cleanOut() const override { return true; } virtual bool isGateOptimizable() const override { return false; } diff --git a/src/astgen b/src/astgen index a66bf3526..a2cf43088 100755 --- a/src/astgen +++ b/src/astgen @@ -649,11 +649,14 @@ def write_macros(filename): 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)) + 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) + ###################################################################### # main From 2dd5ef5e8b152863ebcb1d3e79e1d591593a365e Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 22 May 2021 12:27:32 +0100 Subject: [PATCH 50/80] Internals: Move --coverage and --savable check out of V3EmitC (#2976) --- src/V3EmitC.cpp | 5 +---- src/V3Options.cpp | 4 ++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 08f186b3e..b5c88dadc 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3120,10 +3120,7 @@ void EmitCImp::emitIntTop(AstNodeModule*) { } if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); - if (v3Global.opt.coverage()) { - puts("#include \"verilated_cov.h\"\n"); - if (v3Global.opt.savable()) v3error("--coverage and --savable not supported together"); - } + if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); if (v3Global.dpi()) { // do this before including our main .h file so that any references to // types defined in svdpi.h are available diff --git a/src/V3Options.cpp b/src/V3Options.cpp index f816b7d41..d292b4096 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -787,6 +787,10 @@ void V3Options::notify() { cmdfl->v3warn(E_UNSUPPORTED, "--main not usable with SystemC. Suggest see examples for sc_main()."); } + + if (coverage() && savable()) { + cmdfl->v3error("--coverage and --savable not supported together"); + } } //###################################################################### From ef9f477df2143ad6431073fc4cfea84e5f12d46f Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 22 May 2021 18:50:55 +0100 Subject: [PATCH 51/80] Make _ctror_var_reset and _configure_coverage static. (#2977) Another step towards #2958/#2140. Make the mentioned generated functions static for modules (but not for classes). --- src/V3CCtors.cpp | 150 ++++++++++++++++++++++++++++------------------- src/V3EmitC.cpp | 38 ++++++------ 2 files changed, 110 insertions(+), 78 deletions(-) diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 2aa30b2f7..b8b989aeb 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -32,63 +32,99 @@ #include "V3CCtors.h" #include -#include +#include + +class VCtorType final { +public: + enum en : uint8_t { MODULE, CLASS, COVERAGE }; -class V3CCtorsVisitor final { private: - string m_basename; - string m_argsp; - string m_callargsp; - AstNodeModule* m_modp; // Current module - AstCFunc* m_tlFuncp; // Top level function being built - AstCFunc* m_funcp; // Current function + enum en m_e; + +public: + // cppcheck-suppress noExplicitConstructor + inline VCtorType(en _e) + : m_e{_e} {} + bool isClass() const { return m_e == CLASS; } + bool isCoverage() const { return m_e == COVERAGE; } +}; + +class V3CCtorsBuilder final { +private: + AstNodeModule* const m_modp; // Current module/class + const string m_basename; + const VCtorType m_type; // What kind of constructor are we creating + std::list m_newFunctions; // Created functions, latest is at back int m_numStmts = 0; // Number of statements output - int m_funcNum = 0; // Function number being built + + AstCFunc* makeNewFunc() { + const int funcNum = m_newFunctions.size(); + const string funcName = m_basename + "_" + cvtToStr(funcNum); + AstCFunc* const funcp = new AstCFunc(m_modp->fileline(), funcName, nullptr, "void"); + funcp->isStatic(!m_type.isClass()); // Class constructors are non static + funcp->declPrivate(true); + funcp->slow(!m_type.isClass()); // Only classes construct on fast path + string preventUnusedStmt; + if (m_type.isClass()) { + funcp->argTypes(EmitCBaseVisitor::symClassVar()); + preventUnusedStmt = "if (false && vlSymsp) {}"; + } else if (m_type.isCoverage()) { + funcp->argTypes(EmitCBaseVisitor::prefixNameProtect(m_modp) + "* self, " + + EmitCBaseVisitor::symClassVar() + ", bool first"); + preventUnusedStmt = "if (false && self && vlSymsp && first) {}"; + } else { // Module + funcp->argTypes(EmitCBaseVisitor::prefixNameProtect(m_modp) + "* self"); + preventUnusedStmt = "if (false && self) {}"; + } + preventUnusedStmt += " // Prevent unused\n"; + funcp->addStmtsp(new AstCStmt(m_modp->fileline(), preventUnusedStmt)); + m_modp->addStmtp(funcp); + m_numStmts = 0; + return funcp; + } public: void add(AstNode* nodep) { - if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) { - m_funcp = nullptr; + if (v3Global.opt.outputSplitCFuncs() && m_numStmts > v3Global.opt.outputSplitCFuncs()) { + m_newFunctions.push_back(makeNewFunc()); } - if (!m_funcp) { - m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum), - nullptr, "void"); - m_funcp->isStatic(false); - m_funcp->declPrivate(true); - m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path - m_funcp->argTypes(m_argsp); - m_modp->addStmtp(m_funcp); - - // Add a top call to it - AstCCall* callp = new AstCCall(m_modp->fileline(), m_funcp); - callp->argTypes(m_callargsp); - - m_tlFuncp->addStmtsp(callp); - m_numStmts = 0; - } - m_funcp->addStmtsp(nodep); + m_newFunctions.back()->addStmtsp(nodep); m_numStmts += 1; } - V3CCtorsVisitor(AstNodeModule* nodep, const string& basename, const string& argsp = "", - const string& callargsp = "", const string& stmt = "") { - m_basename = basename; - m_argsp = argsp; - m_callargsp = callargsp; - m_modp = nodep; - m_tlFuncp = new AstCFunc(nodep->fileline(), basename, nullptr, "void"); - m_tlFuncp->declPrivate(true); - m_tlFuncp->isStatic(false); - m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path - m_tlFuncp->argTypes(m_argsp); - if (stmt != "") m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); - m_funcp = m_tlFuncp; - m_modp->addStmtp(m_tlFuncp); + V3CCtorsBuilder(AstNodeModule* nodep, const string& basename, VCtorType type) + : m_modp(nodep) + , m_basename{basename} + , m_type(type) { + // Note: The constructor is always called, even if empty, so we must always create at least + // one. + m_newFunctions.push_back(makeNewFunc()); } - ~V3CCtorsVisitor() = default; + + ~V3CCtorsBuilder() { + if (m_newFunctions.size() == 1) { + // No split was necessary, rename the one function to the basename + m_newFunctions.front()->name(m_basename); + } else { + // Split was necessary, create root function and call all others from that + AstCFunc* const rootFuncp = makeNewFunc(); + rootFuncp->name(m_basename); + for (AstCFunc* const funcp : m_newFunctions) { + AstCCall* const callp = new AstCCall(m_modp->fileline(), funcp); + if (m_type.isClass()) { + callp->argTypes("vlSymsp"); + } else if (m_type.isCoverage()) { + callp->argTypes("self, vlSymsp, first"); + } else { // Module + callp->argTypes("self"); + } + rootFuncp->addStmtsp(callp); + } + } + }; private: - VL_UNCOPYABLE(V3CCtorsVisitor); + VL_UNCOPYABLE(V3CCtorsBuilder); }; //###################################################################### @@ -140,32 +176,24 @@ void V3CCtors::cctorsAll() { modp = VN_CAST(modp->nextp(), NodeModule)) { // Process each module in turn { - V3CCtorsVisitor var_reset( - modp, "_ctor_var_reset", - (VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""), - (VN_IS(modp, Class) ? "vlSymsp" : ""), - (VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : "")); + V3CCtorsBuilder var_reset(modp, "_ctor_var_reset", + VN_IS(modp, Class) ? VCtorType::CLASS : VCtorType::MODULE); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { - if (AstVar* varp = VN_CAST(np, Var)) { + if (AstVar* const varp = VN_CAST(np, Var)) { if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) { - var_reset.add( - new AstCReset(varp->fileline(), - new AstVarRef(varp->fileline(), varp, VAccess::WRITE))); + const auto vrefp = new AstVarRef(varp->fileline(), varp, VAccess::WRITE); + var_reset.add(new AstCReset(varp->fileline(), vrefp)); } } } } if (v3Global.opt.coverage()) { - V3CCtorsVisitor configure_coverage( - modp, "_configure_coverage", EmitCBaseVisitor::symClassVar() + ", bool first", - "vlSymsp, first", "if (false && vlSymsp && first) {} // Prevent unused\n"); + V3CCtorsBuilder configure_coverage(modp, "_configure_coverage", VCtorType::COVERAGE); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { - if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) { - AstNode* backp = coverp->backp(); - coverp->unlinkFrBack(); - configure_coverage.add(coverp); - np = backp; + if (AstCoverDecl* const coverp = VN_CAST(np, CoverDecl)) { + np = coverp->backp(); + configure_coverage.add(coverp->unlinkFrBack()); } } } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index b5c88dadc..d71fdd96b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -459,7 +459,7 @@ public: iterateChildren(nodep); } virtual void visit(AstCoverDecl* nodep) override { - puts("__vlCoverInsert("); // As Declared in emitCoverageDecl + puts("self->__vlCoverInsert("); // As Declared in emitCoverageDecl puts("&(vlSymsp->__Vcoverage["); puts(cvtToStr(nodep->dataDeclThisp()->binNum())); puts("])"); @@ -1753,7 +1753,9 @@ class EmitCImp final : EmitCStmts { } void emitVarReset(AstVar* varp) { - AstNodeDType* dtypep = varp->dtypep()->skipRefp(); + AstNodeDType* const dtypep = varp->dtypep()->skipRefp(); + const string varNameProtected + = VN_IS(m_modp, Class) ? varp->nameProtect() : "self->" + varp->nameProtect(); if (varp->isIO() && m_modp->isTop() && optSystemC()) { // System C top I/O doesn't need loading, as the lower level subinst code does it.} } else if (varp->isParam()) { @@ -1766,44 +1768,44 @@ class EmitCImp final : EmitCStmts { if (initarp->defaultp()) { puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst())); puts("; ++__Vi) {\n"); - emitSetVarConstant(varp->nameProtect() + "[__Vi]", + emitSetVarConstant(varNameProtected + "[__Vi]", VN_CAST(initarp->defaultp(), Const)); puts("}\n"); } const AstInitArray::KeyItemMap& mapr = initarp->map(); for (const auto& itr : mapr) { AstNode* valuep = itr.second->valuep(); - emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(itr.first) + "]", + emitSetVarConstant(varNameProtected + "[" + cvtToStr(itr.first) + "]", VN_CAST(valuep, Const)); } } else { varp->v3fatalSrc("InitArray under non-arrayed var"); } } else { - puts(emitVarResetRecurse(varp, dtypep, 0, "")); + puts(emitVarResetRecurse(varp, varNameProtected, dtypep, 0, "")); } } - string emitVarResetRecurse(AstVar* varp, AstNodeDType* dtypep, int depth, - const string& suffix) { + string emitVarResetRecurse(const AstVar* varp, const string& varNameProtected, + AstNodeDType* dtypep, int depth, const string& suffix) { dtypep = dtypep->skipRefp(); AstBasicDType* basicp = dtypep->basicp(); // Returns string to do resetting, empty to do nothing (which caller should handle) if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, + return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1, suffix + ".atDefault()" + cvtarray); } else if (VN_IS(dtypep, ClassRefDType)) { return ""; // Constructor does it } else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, + return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1, suffix + ".atDefault()" + cvtarray); } else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, + return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1, suffix + ".atDefault()" + cvtarray); } else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp, @@ -1811,8 +1813,8 @@ class EmitCImp final : EmitCStmts { string ivar = string("__Vi") + cvtToStr(depth); string pre = ("for (int " + ivar + "=" + cvtToStr(0) + "; " + ivar + "<" + cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n"); - string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, - suffix + "[" + ivar + "]"); + string below = emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), + depth + 1, suffix + "[" + ivar + "]"); string post = "}\n"; return below.empty() ? "" : pre + below + post; } else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) { @@ -1832,17 +1834,17 @@ class EmitCImp final : EmitCStmts { AstConst* const constp = VN_CAST(varp->valuep(), Const); if (!constp) varp->v3fatalSrc("non-const initializer for variable"); for (int w = 0; w < varp->widthWords(); ++w) { - out += varp->nameProtect() + suffix + "[" + cvtToStr(w) + "] = "; + out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = "; out += cvtToStr(constp->num().edataWord(w)) + "U;\n"; } } else { out += zeroit ? "VL_ZERO_RESET_W(" : "VL_RAND_RESET_W("; out += cvtToStr(dtypep->widthMin()); - out += ", " + varp->nameProtect() + suffix + ");\n"; + out += ", " + varNameProtected + suffix + ");\n"; } return out; } else { - string out = varp->nameProtect() + suffix; + string out = varNameProtected + suffix; // If --x-initial-edge is set, we want to force an initial // edge on uninitialized clocks (from 'X' to whatever the // first value is). Since the class is instantiated before @@ -2481,7 +2483,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { puts("\n"); } putsDecoration("// Reset structure values\n"); - puts(protect("_ctor_var_reset") + "();\n"); + puts(protect("_ctor_var_reset") + "(this);\n"); emitTextSection(AstType::atScCtor); if (modp->isTop() && v3Global.opt.mtasks()) { @@ -2524,7 +2526,9 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) { puts("if (false && first) {} // Prevent unused\n"); puts("this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it. puts("if (false && this->__VlSymsp) {} // Prevent unused\n"); - if (v3Global.opt.coverage()) { puts(protect("_configure_coverage") + "(vlSymsp, first);\n"); } + if (v3Global.opt.coverage()) { + puts(protect("_configure_coverage") + "(this, vlSymsp, first);\n"); + } if (modp->isTop() && !v3Global.rootp()->timeunit().isNone()) { puts("vlSymsp->_vm_contextp__->timeunit(" + cvtToStr(v3Global.rootp()->timeunit().powerOfTen()) + ");\n"); From f4c1a7efebbcab90a421d83628ee921521427c7e Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 29 May 2021 23:46:15 +0100 Subject: [PATCH 52/80] Emit: Fix indent tracking when // inside string literal (#2990) // was so far unconditionally treated as comment. c443e229eea8473d755e43c9f0c914a796898948 introduced a string literal in the output that contained a http:// url, which broke the indent tracking. No functional change intended --- src/V3File.cpp | 6 +++++- src/V3File.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/V3File.cpp b/src/V3File.cpp index 63920e061..2372de6a9 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -715,9 +715,13 @@ void V3OutFormatter::puts(const char* strg) { break; case ' ': wordstart = true; break; case '\t': wordstart = true; break; + case '"': + wordstart = false; + m_inStringLiteral = !m_inStringLiteral; + break; case '/': if (m_lang == LA_C || m_lang == LA_VERILOG) { - if (cp > strg && cp[-1] == '/') { + if (cp > strg && cp[-1] == '/' && !m_inStringLiteral) { // Output ignoring contents to EOL cp++; while (*cp && cp[1] && cp[1] != '\n') putcNoTracking(*cp++); diff --git a/src/V3File.h b/src/V3File.h index b198a10b4..9d22a77b0 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -121,6 +121,7 @@ private: int m_column = 0; int m_nobreak = false; // Basic operator or begin paren, don't break next bool m_prependIndent = true; + bool m_inStringLiteral = false; int m_indentLevel = 0; // Current {} indentation std::stack m_parenVec; // Stack of columns where last ( was int m_bracketLevel = 0; // Intenting = { block, indicates number of {'s seen. From e4dcbb22e33f762e3c18a6f3d5f9b50cf3ee9401 Mon Sep 17 00:00:00 2001 From: Pieter Kapsenberg Date: Sun, 30 May 2021 17:19:35 -0700 Subject: [PATCH 53/80] Fix unused variable warnings (#2991) --- include/verilated.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index 123ea92c5..1bd54bb25 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -2489,8 +2489,7 @@ static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs, WDataInP } return VL_CLEAN_II(obits, obits, lhs << rwp[0]); } -static inline IData VL_SHIFTL_IIQ(int obits, int lbits, int rbits, IData lhs, - QData rhs) VL_MT_SAFE { +static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; return VL_CLEAN_II(obits, obits, lhs << rhs); } @@ -2503,8 +2502,7 @@ static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, WDataInP // Above checks rwp[1]==0 so not needed in below shift return VL_CLEAN_QQ(obits, obits, lhs << (static_cast(rwp[0]))); } -static inline QData VL_SHIFTL_QQQ(int obits, int lbits, int rbits, QData lhs, - QData rhs) VL_MT_SAFE { +static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs << rhs); } @@ -2569,11 +2567,11 @@ static inline QData VL_SHIFTR_QQW(int obits, int, int rbits, QData lhs, WDataInP // Above checks rwp[1]==0 so not needed in below shift return VL_CLEAN_QQ(obits, obits, lhs >> (static_cast(rwp[0]))); } -static inline IData VL_SHIFTR_IIQ(int obits, int, int rbits, IData lhs, QData rhs) VL_MT_SAFE { +static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs >> rhs); } -static inline QData VL_SHIFTR_QQQ(int obits, int, int rbits, QData lhs, QData rhs) VL_MT_SAFE { +static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs >> rhs); } From e1f9fffb42c86ab0cf750383f2015fbeb8e0a353 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 31 May 2021 13:40:22 +0100 Subject: [PATCH 54/80] Fix --protect-ids when using SV classes (#2994) A few names were incorrectly mangled, which made --protect-ids produce invalid output when certain SV class constructs were uses. Now fixed and added a few extra tests to catch this. --- Changes | 1 + src/V3File.cpp | 4 ++- src/V3Task.cpp | 3 +- test_regress/t/t_class_extends_protect_ids.pl | 34 +++++++++++++++++++ test_regress/t/t_class_local_protect_ids.pl | 33 ++++++++++++++++++ .../t/t_class_static_method_protect_ids.pl | 33 ++++++++++++++++++ test_regress/t/t_class_virtual_protect_ids.pl | 33 ++++++++++++++++++ 7 files changed, 139 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_class_extends_protect_ids.pl create mode 100755 test_regress/t/t_class_local_protect_ids.pl create mode 100755 test_regress/t/t_class_static_method_protect_ids.pl create mode 100755 test_regress/t/t_class_virtual_protect_ids.pl diff --git a/Changes b/Changes index e3de48608..27e95dc8f 100644 --- a/Changes +++ b/Changes @@ -18,6 +18,7 @@ Verilator 4.203 devel * Split always blocks to better respect --output-split-cfuncs. [Geza Lore] * Fix initialization of assoc in assoc array (#2914). [myftptoyman] * Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] +* Fix --protect-ids when using SV classes (#2994). [Geza Lore] Verilator 4.202 2021-04-24 diff --git a/src/V3File.cpp b/src/V3File.cpp index 2372de6a9..285ba5dbf 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -1016,7 +1016,8 @@ public: } } string protectWordsIf(const string& old, bool doIt) { - // Split at " " (for traces), "." (for scopes), or "->" (for scopes) + // Split at " " (for traces), "." (for scopes), "->" (for scopes), "::" (for superclass + // reference) if (!(doIt && v3Global.opt.protectIds())) return old; string out; string::size_type start = 0; @@ -1028,6 +1029,7 @@ public: trySep(old, start, " ", pos /*ref*/, separator /*ref*/); trySep(old, start, ".", pos /*ref*/, separator /*ref*/); trySep(old, start, "->", pos /*ref*/, separator /*ref*/); + trySep(old, start, "::", pos /*ref*/, separator /*ref*/); if (pos == string::npos) break; out += protectIf(old.substr(start, pos - start), true) + separator; start = pos + separator.length(); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 66cbd18b3..9dcfc0c04 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1157,7 +1157,8 @@ private: cfuncp->argTypes(EmitCBaseVisitor::symClassVar()); if (cfuncp->name() == "new") { cfuncp->addInitsp( - new AstCStmt(nodep->fileline(), "_ctor_var_reset(vlSymsp);\n")); + new AstCStmt(nodep->fileline(), + VIdProtect::protect("_ctor_var_reset") + "(vlSymsp);\n")); } } } diff --git a/test_regress/t/t_class_extends_protect_ids.pl b/test_regress/t/t_class_extends_protect_ids.pl new file mode 100755 index 000000000..b48534f3c --- /dev/null +++ b/test_regress/t/t_class_extends_protect_ids.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 2021 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); + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +top_filename("t/t_class_extends.v"); + +compile( + make_flags => 'VM_PARALLEL_BUILDS=1', # bug2775 + verilator_flags2 => ["--protect-ids", + "--protect-key SECRET_KEY"] + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_local_protect_ids.pl b/test_regress/t/t_class_local_protect_ids.pl new file mode 100755 index 000000000..a1bab0242 --- /dev/null +++ b/test_regress/t/t_class_local_protect_ids.pl @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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); + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +top_filename("t/t_class_local.v"); + +compile( + verilator_flags2 => ["--protect-ids", + "--protect-key SECRET_KEY"] + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_static_method_protect_ids.pl b/test_regress/t/t_class_static_method_protect_ids.pl new file mode 100755 index 000000000..876725638 --- /dev/null +++ b/test_regress/t/t_class_static_method_protect_ids.pl @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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); + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +top_filename("t/t_class_static_method.v"); + +compile( + verilator_flags2 => ["--protect-ids", + "--protect-key SECRET_KEY"] + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_virtual_protect_ids.pl b/test_regress/t/t_class_virtual_protect_ids.pl new file mode 100755 index 000000000..ff478e073 --- /dev/null +++ b/test_regress/t/t_class_virtual_protect_ids.pl @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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); + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +top_filename("t/t_class_virtual.v"); + +compile( + verilator_flags2 => ["--protect-ids", + "--protect-key SECRET_KEY"] + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; From 2143bcfad5baefa3b05c3f568d6ecf4796f2199e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 31 May 2021 22:46:41 -0400 Subject: [PATCH 55/80] Fix constant function calls with uninit value (#2995). --- Changes | 1 + src/V3Simulate.h | 11 +++++++++++ test_regress/t/t_func_uninit.pl | 21 +++++++++++++++++++++ test_regress/t/t_func_uninit.v | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100755 test_regress/t/t_func_uninit.pl create mode 100644 test_regress/t/t_func_uninit.v diff --git a/Changes b/Changes index 27e95dc8f..a5d688d56 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 4.203 devel * Fix initialization of assoc in assoc array (#2914). [myftptoyman] * Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] * Fix --protect-ids when using SV classes (#2994). [Geza Lore] +* Fix constant function calls with uninit value (#2995). [yanx21] Verilator 4.202 2021-04-24 diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 02e6692cc..b992f9292 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -979,6 +979,17 @@ private: } SimStackNode stackNode(nodep, &tconnects); m_callStack.push_front(&stackNode); + // Clear output variable + if (auto* const basicp = VN_CAST(funcp->fvarp(), Var)->basicp()) { + AstConst cnst(funcp->fvarp()->fileline(), AstConst::WidthedValue(), basicp->widthMin(), + 0); + if (basicp->isZeroInit()) { + cnst.num().setAllBits0(); + } else { + cnst.num().setAllBitsX(); + } + newValue(funcp->fvarp(), &cnst); + } // Evaluate the function iterate(funcp); m_callStack.pop_front(); diff --git a/test_regress/t/t_func_uninit.pl b/test_regress/t/t_func_uninit.pl new file mode 100755 index 000000000..2cb5eeaff --- /dev/null +++ b/test_regress/t/t_func_uninit.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 2021 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_func_uninit.v b/test_regress/t/t_func_uninit.v new file mode 100644 index 000000000..c9eb85468 --- /dev/null +++ b/test_regress/t/t_func_uninit.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +function int zeroed; +endfunction + +function automatic integer what_bit; + input [31:0] a; + // what_bit = 0; + for (int i = 31; i >= 0; i = i - 1) begin + if (a[i] == 1'b1) begin + what_bit = i; + end + end +endfunction + +module t(/*AUTOARG*/); + + parameter ZERO = zeroed(); + + parameter PP = what_bit(0); + + initial begin + if (ZERO != 0) $stop; + if (PP != 'x) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 1f331bd94f13e7e28c61a8262fa3d1398b7e6b1a Mon Sep 17 00:00:00 2001 From: Julien Margetts <56540603+margej@users.noreply.github.com> Date: Tue, 1 Jun 2021 14:01:18 +0100 Subject: [PATCH 56/80] Fix part select issues in LATCH warning. (#2948) (#2938) --- src/V3Active.cpp | 18 +++++++++--------- src/V3Ast.h | 4 ++++ src/V3Unknown.cpp | 1 + test_regress/t/t_lint_latch_4.pl | 17 +++++++++++++++++ test_regress/t/t_lint_latch_4.v | 27 +++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 9 deletions(-) create mode 100755 test_regress/t/t_lint_latch_4.pl create mode 100644 test_regress/t/t_lint_latch_4.v diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 221bada4f..3e9ee98ad 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -309,16 +309,16 @@ private: } } virtual void visit(AstNodeIf* nodep) { - LatchDetectGraphVertex* parentp = m_graph.currentp(); - LatchDetectGraphVertex* branchp = m_graph.addPathVertex(parentp, "BRANCH", true); - m_graph.addPathVertex(branchp, "IF"); - iterateAndNextNull(nodep->ifsp()); - m_graph.addPathVertex(branchp, "ELSE"); - iterateAndNextNull(nodep->elsesp()); - m_graph.currentp(parentp); + if (!nodep->isBoundsCheck()) { + LatchDetectGraphVertex* parentp = m_graph.currentp(); + LatchDetectGraphVertex* branchp = m_graph.addPathVertex(parentp, "BRANCH", true); + m_graph.addPathVertex(branchp, "IF"); + iterateAndNextNull(nodep->ifsp()); + m_graph.addPathVertex(branchp, "ELSE"); + iterateAndNextNull(nodep->elsesp()); + m_graph.currentp(parentp); + } } - // Empty visitors, speed things up - virtual void visit(AstNodeMath* nodep) {} //-------------------- virtual void visit(AstNode* nodep) { iterateChildren(nodep); } diff --git a/src/V3Ast.h b/src/V3Ast.h index d915ff156..8ac87c735 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2216,12 +2216,14 @@ public: class AstNodeIf VL_NOT_FINAL : public AstNodeStmt { private: VBranchPred m_branchPred; // Branch prediction as taken/untaken? + bool m_isBoundsCheck; // True if this if node was inserted for array bounds checking protected: AstNodeIf(AstType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) : AstNodeStmt{t, fl} { setOp1p(condp); addNOp2p(ifsp); addNOp3p(elsesp); + isBoundsCheck(false); } public: @@ -2238,6 +2240,8 @@ public: virtual bool same(const AstNode* samep) const override { return true; } void branchPred(VBranchPred flag) { m_branchPred = flag; } VBranchPred branchPred() const { return m_branchPred; } + void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; } + bool isBoundsCheck() const { return m_isBoundsCheck; } }; class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 5878a70c9..e79db26eb 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -127,6 +127,7 @@ private: new AstAssign(fl, prep, new AstVarRef(fl, varp, VAccess::READ)))), nullptr); newp->branchPred(VBranchPred::BP_LIKELY); + newp->isBoundsCheck(true); if (debug() >= 9) newp->dumpTree(cout, " _new: "); abovep->addNextStmt(newp, abovep); prep->user2p(newp); // Save so we may LogAnd it next time diff --git a/test_regress/t/t_lint_latch_4.pl b/test_regress/t/t_lint_latch_4.pl new file mode 100755 index 000000000..629a44bbb --- /dev/null +++ b/test_regress/t/t_lint_latch_4.pl @@ -0,0 +1,17 @@ +#!/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 => 1); + +lint( + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_latch_4.v b/test_regress/t/t_lint_latch_4.v new file mode 100644 index 000000000..e7182f4ca --- /dev/null +++ b/test_regress/t/t_lint_latch_4.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module for Issue#2938 +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2021 by Julien Margetts (Originally provided by YanJiun) + +module test ( + input [2:0] a, + input [3:0] c, + + output reg [7:0] b +); + + integer i; + + always @ (*) + begin + case(a) + {3'b000}: b = 8'd1; + {3'b001}: + for(i=0;i<4;i=i+1) b[i*2+:2] = 2'(c[i]); + {3'b010}: b = 8'd3; + {3'b011}: b = 8'd4; + default : b = 0; + endcase + end + +endmodule From 9f5eb8f66e79b1650981d078a99ef10435adb8ff Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 3 Jun 2021 21:15:42 -0400 Subject: [PATCH 57/80] Commentary --- Changes | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index a5d688d56..45501947e 100644 --- a/Changes +++ b/Changes @@ -13,11 +13,26 @@ Verilator 4.203 devel **Minor:** -* Add --reloop-limit argument (#2943). [Geza Lore] +* Add --reloop-limit argument (#2943) (#2960). [Geza Lore] +* Add TRACE_THREADS to CMake (#2934). [Jonathan Drolet] * Optimize large lookup tables to static data (#2925). [Geza Lore] +* Optimize reloop to accept constant index offsets (#2939). [Geza Lore] * Split always blocks to better respect --output-split-cfuncs. [Geza Lore] +* Support ignoring "`pragma protect ..." (#2886). [Udi Finkelstein] +* Support --trace-fst for SystemC with CMake (#2927). [Jonathan Drolet] +* Update cmake latest C++ Standard Compilation flag (#2951). [Ameya Vikram Singh] +* Fix assertion failure in bitOpTree optimization (#2891) (#2899). [Raynard Qiao] +* Fix DPI functions not seen as vpiModule (#2893). [Todd Strader] +* Fix bounds check in VL_SEL_IWII (#2910). [Krzysztof Bieganski] * Fix initialization of assoc in assoc array (#2914). [myftptoyman] +* Fix make support for gmake 3.x (#2920) (#2921). [Philipp Wagner] +* Fix VPI memory access for packed arrays (#2922). [Todd Strader] +* Fix split procedures to better respect --output-split-cfuncs (#2942). [Geza Lore] +* Fix to emit 'else if' without nesting (#2944). [Geza Lore] +* Fix part select issues in LATCH warning (#2948) (#2938). [Julien Margetts] +* Fix to not emit empty files with low split limits (#2961). [Geza Lore] * Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] +* Fix unused variable warnings (#2991). [Pieter Kapsenberg] * Fix --protect-ids when using SV classes (#2994). [Geza Lore] * Fix constant function calls with uninit value (#2995). [yanx21] From fb561d925a00715568c5688050d582691ea91a81 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 3 Jun 2021 21:19:11 -0400 Subject: [PATCH 58/80] Commentary (#2996) --- docs/guide/exe_verilator.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index eedfd9683..379971315 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -418,8 +418,11 @@ Summary: fairly standard across Verilog tools. The file may contain :code:`//` comments which are ignored to the end of - the line. Any :code:`$VAR`, :code:`$(VAR)`, or :code:`${VAR}` will be - replaced with the specified environment variable. + the line. It may also contain :code:`/* .. */` comments which are + ignored, be cautious that wildcards are not handled in -f files, and + that :code:`directory/*` is the beginning of a comment, not a wildcard. + Any :code:`$VAR`, :code:`$(VAR)`, or :code:`${VAR}` will be replaced + with the specified environment variable. .. option:: -FI From eea7e1bd2a4aaadf20b012bf6e08ed9836baf1e3 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 4 Jun 2021 15:00:13 +0100 Subject: [PATCH 59/80] Do not emit leading spaces on blank lines (#3007) --- src/V3File.cpp | 2 +- test_regress/t/t_debug_emitv.out | 2 +- test_regress/t/t_dpi_arg_inout_type__Dpi.out | 8 ++++---- test_regress/t/t_dpi_arg_inout_unpack__Dpi.out | 8 ++++---- test_regress/t/t_dpi_arg_input_type__Dpi.out | 8 ++++---- test_regress/t/t_dpi_arg_input_unpack__Dpi.out | 8 ++++---- test_regress/t/t_dpi_arg_output_type__Dpi.out | 8 ++++---- test_regress/t/t_dpi_arg_output_unpack__Dpi.out | 8 ++++---- test_regress/t/t_dpi_result_type__Dpi.out | 8 ++++---- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/V3File.cpp b/src/V3File.cpp index 285ba5dbf..43c07ac17 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -692,7 +692,7 @@ int V3OutFormatter::endLevels(const char* strg) { } void V3OutFormatter::puts(const char* strg) { - if (m_prependIndent) { + if (m_prependIndent && strg[0] != '\n') { putsNoTracking(indentSpaces(endLevels(strg))); m_prependIndent = false; } diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index e37daa2fd..aeee81350 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -45,7 +45,7 @@ module Vt_debug_emitv; $display("stmt"); $display("stmt"); end - + ???? // CFUNC '_final_TOP' $_CSTMT(Vt_debug_emitv* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; ); diff --git a/test_regress/t/t_dpi_arg_inout_type__Dpi.out b/test_regress/t/t_dpi_arg_inout_type__Dpi.out index 3f0f7e242..01379ddcd 100644 --- a/test_regress/t/t_dpi_arg_inout_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_inout_type__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_array_2_state_1(svBitVecVal* x); extern void e_array_2_state_128(svBitVecVal* x); @@ -79,7 +79,7 @@ extern "C" { extern void e_union_4_state_33(svLogicVecVal* x); extern void e_union_4_state_64(svLogicVecVal* x); extern void e_union_4_state_65(svLogicVecVal* x); - + // DPI IMPORTS extern void check_exports(); extern void i_array_2_state_1(svBitVecVal* x); @@ -148,7 +148,7 @@ extern "C" { extern void i_union_4_state_33(svLogicVecVal* x); extern void i_union_4_state_64(svLogicVecVal* x); extern void i_union_4_state_65(svLogicVecVal* x); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out b/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out index 918872073..e4f0d5949 100644 --- a/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_bit121_0d(svBitVecVal* val); extern void e_bit121_1d(svBitVecVal* val); @@ -93,7 +93,7 @@ extern "C" { extern void e_time_1d(svLogicVecVal* val); extern void e_time_2d(svLogicVecVal* val); extern void e_time_3d(svLogicVecVal* val); - + // DPI IMPORTS extern void check_exports(); extern void* get_non_null(); @@ -177,7 +177,7 @@ extern "C" { extern void i_time_1d(svLogicVecVal* val); extern void i_time_2d(svLogicVecVal* val); extern void i_time_3d(svLogicVecVal* val); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_input_type__Dpi.out b/test_regress/t/t_dpi_arg_input_type__Dpi.out index ea56ffe00..632b44b9c 100644 --- a/test_regress/t/t_dpi_arg_input_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_input_type__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_array_2_state_1(const svBitVecVal* i); extern void e_array_2_state_128(const svBitVecVal* i); @@ -79,7 +79,7 @@ extern "C" { extern void e_union_4_state_33(const svLogicVecVal* i); extern void e_union_4_state_64(const svLogicVecVal* i); extern void e_union_4_state_65(const svLogicVecVal* i); - + // DPI IMPORTS extern void check_exports(); extern void i_array_2_state_1(const svBitVecVal* i); @@ -148,7 +148,7 @@ extern "C" { extern void i_union_4_state_33(const svLogicVecVal* i); extern void i_union_4_state_64(const svLogicVecVal* i); extern void i_union_4_state_65(const svLogicVecVal* i); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_input_unpack__Dpi.out b/test_regress/t/t_dpi_arg_input_unpack__Dpi.out index f6eee80e8..0867d13f0 100644 --- a/test_regress/t/t_dpi_arg_input_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_input_unpack__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_bit121_0d(const svBitVecVal* val); extern void e_bit121_1d(const svBitVecVal* val); @@ -93,7 +93,7 @@ extern "C" { extern void e_time_1d(const svLogicVecVal* val); extern void e_time_2d(const svLogicVecVal* val); extern void e_time_3d(const svLogicVecVal* val); - + // DPI IMPORTS extern void check_exports(); extern void* get_non_null(); @@ -177,7 +177,7 @@ extern "C" { extern void i_time_1d(const svLogicVecVal* val); extern void i_time_2d(const svLogicVecVal* val); extern void i_time_3d(const svLogicVecVal* val); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_output_type__Dpi.out b/test_regress/t/t_dpi_arg_output_type__Dpi.out index f2bc7f4c6..1a9db977f 100644 --- a/test_regress/t/t_dpi_arg_output_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_output_type__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_array_2_state_1(svBitVecVal* o); extern void e_array_2_state_128(svBitVecVal* o); @@ -79,7 +79,7 @@ extern "C" { extern void e_union_4_state_33(svLogicVecVal* o); extern void e_union_4_state_64(svLogicVecVal* o); extern void e_union_4_state_65(svLogicVecVal* o); - + // DPI IMPORTS extern void check_exports(); extern void i_array_2_state_1(svBitVecVal* o); @@ -148,7 +148,7 @@ extern "C" { extern void i_union_4_state_33(svLogicVecVal* o); extern void i_union_4_state_64(svLogicVecVal* o); extern void i_union_4_state_65(svLogicVecVal* o); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_output_unpack__Dpi.out b/test_regress/t/t_dpi_arg_output_unpack__Dpi.out index e3a2729a4..24675921e 100644 --- a/test_regress/t/t_dpi_arg_output_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_output_unpack__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_bit121_0d(svBitVecVal* val); extern void e_bit121_1d(svBitVecVal* val); @@ -93,7 +93,7 @@ extern "C" { extern void e_time_1d(svLogicVecVal* val); extern void e_time_2d(svLogicVecVal* val); extern void e_time_3d(svLogicVecVal* val); - + // DPI IMPORTS extern void check_exports(); extern void* get_non_null(); @@ -177,7 +177,7 @@ extern "C" { extern void i_time_1d(svLogicVecVal* val); extern void i_time_2d(svLogicVecVal* val); extern void i_time_3d(svLogicVecVal* val); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_result_type__Dpi.out b/test_regress/t/t_dpi_result_type__Dpi.out index e5d541f43..cd2d0ecc8 100644 --- a/test_regress/t/t_dpi_result_type__Dpi.out +++ b/test_regress/t/t_dpi_result_type__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern svBitVecVal e_array_2_state_1(); extern svBitVecVal e_array_2_state_32(); @@ -46,7 +46,7 @@ extern "C" { extern svBitVecVal e_union_2_state_1(); extern svBitVecVal e_union_2_state_32(); extern void e_void(); - + // DPI IMPORTS extern void check_exports(); extern svBitVecVal i_array_2_state_1(); @@ -82,7 +82,7 @@ extern "C" { extern svBitVecVal i_union_2_state_1(); extern svBitVecVal i_union_2_state_32(); extern void i_void(); - + #ifdef __cplusplus } #endif From fa063574d0a4e80ff1d11fa2bbd365fd27a1c6b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Fri, 4 Jun 2021 18:04:55 +0200 Subject: [PATCH 60/80] Fix Makefiles to support Windows EXEEXT usage (#3008). --- Makefile.in | 25 +++++++++++++------------ docs/CONTRIBUTORS | 1 + src/Makefile.in | 18 +++++++++--------- src/Makefile_obj.in | 2 +- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/Makefile.in b/Makefile.in index 03d032718..fb2bf08a8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -44,6 +44,7 @@ srcdir = @srcdir@ VPATH = @srcdir@ HOST = @HOST@ +EXEEXT = @EXEEXT@ DOXYGEN = doxygen INSTALL = @INSTALL@ @@ -203,9 +204,9 @@ INST_PROJ_FILES = \ include/vltstd/*.[chv]* \ INST_PROJ_BIN_FILES = \ - bin/verilator_bin \ - bin/verilator_bin_dbg \ - bin/verilator_coverage_bin_dbg \ + bin/verilator_bin$(EXEEXT) \ + bin/verilator_bin_dbg$(EXEEXT) \ + bin/verilator_coverage_bin_dbg$(EXEEXT) \ EXAMPLES_FIRST = \ examples/make_hello_c \ @@ -221,10 +222,10 @@ all: all_nomsg msg_test all_nomsg: verilator_exe $(VL_INST_MAN_FILES) .PHONY:verilator_exe -.PHONY:verilator_bin -.PHONY:verilator_bin_dbg -.PHONY:verilator_coverage_bin_dbg -verilator_exe verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg: +.PHONY:verilator_bin$(EXEEXT) +.PHONY:verilator_bin_dbg$(EXEEXT) +.PHONY:verilator_coverage_bin_dbg$(EXEEXT) +verilator_exe verilator_bin$(EXEEXT) verilator_bin_dbg$(EXEEXT) verilator_coverage_bin_dbg$(EXEEXT): @echo ------------------------------------------------------------ @echo "making verilator in src" $(MAKE) -C src $(OBJCACHE_JOBS) $(CI_MAKE_SRC_TARGET) @@ -280,7 +281,7 @@ verilator.pdf: Makefile $(MAKE) -C docs verilator.pdf # See uninstall also - don't put wildcards in this variable, it might uninstall other stuff -VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg \ +VL_INST_BIN_FILES = verilator verilator_bin$(EXEEXT) verilator_bin_dbg$(EXEEXT) verilator_coverage_bin_dbg$(EXEEXT) \ verilator_coverage verilator_gantt verilator_includer verilator_profcfunc # Some scripts go into both the search path and pkgdatadir, # so they can be found by the user, and under $VERILATOR_ROOT. @@ -305,9 +306,9 @@ installbin: ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_coverage $(DESTDIR)$(bindir)/verilator_coverage ) ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_gantt $(DESTDIR)$(bindir)/verilator_gantt ) ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc ) - ( cd bin ; $(INSTALL_PROGRAM) verilator_bin $(DESTDIR)$(bindir)/verilator_bin ) - ( cd bin ; $(INSTALL_PROGRAM) verilator_bin_dbg $(DESTDIR)$(bindir)/verilator_bin_dbg ) - ( cd bin ; $(INSTALL_PROGRAM) verilator_coverage_bin_dbg $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg ) + ( cd bin ; $(INSTALL_PROGRAM) verilator_bin$(EXEEXT) $(DESTDIR)$(bindir)/verilator_bin$(EXEEXT) ) + ( cd bin ; $(INSTALL_PROGRAM) verilator_bin_dbg$(EXEEXT) $(DESTDIR)$(bindir)/verilator_bin_dbg$(EXEEXT) ) + ( cd bin ; $(INSTALL_PROGRAM) verilator_coverage_bin_dbg$(EXEEXT) $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg$(EXEEXT) ) $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/bin ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer ) @@ -458,7 +459,7 @@ clang-tidy: $(CLANGTIDY_DEP) analyzer-src: -rm -rf src/obj_dbg - scan-build $(MAKE) -k verilator_coverage_bin_dbg verilator_bin_dbg + scan-build $(MAKE) -k verilator_coverage_bin_dbg$(EXEEXT) verilator_bin_dbg$(EXEEXT) analyzer-include: -rm -rf examples/*/obj* diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 3293cb65f..8c038e1c3 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -58,6 +58,7 @@ Marshal Qiao Matthew Ballance Michael Killough Mike Popoloski +Miodrag Milanović Morten Borup Petersen Nandu Raj Nathan Kohagen diff --git a/src/Makefile.in b/src/Makefile.in index 5dadd276a..2d47f7fc3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -47,25 +47,25 @@ obj_dbg: .SUFFIXES: -.PHONY: ../bin/verilator_bin ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg +.PHONY: ../bin/verilator_bin$(EXEEXT) ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT) -opt: ../bin/verilator_bin +opt: ../bin/verilator_bin$(EXEEXT) ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build -../bin/verilator_bin: ../bin/verilator_bin_dbg - -cp -p $<$(EXEEXT) $@$(EXEEXT).tmp - -mv -f $@$(EXEEXT).tmp $@$(EXEEXT) +../bin/verilator_bin$(EXEEXT): ../bin/verilator_bin_dbg$(EXEEXT) + -cp -p $< $@.tmp + -mv -f $@.tmp $@ else -../bin/verilator_bin: obj_opt ../bin prefiles +../bin/verilator_bin$(EXEEXT): obj_opt ../bin prefiles $(MAKE) -C obj_opt -j 1 TGT=../$@ -f ../Makefile_obj serial $(MAKE) -C obj_opt TGT=../$@ -f ../Makefile_obj endif -dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg -../bin/verilator_bin_dbg: obj_dbg ../bin prefiles +dbg: ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT) +../bin/verilator_bin_dbg$(EXEEXT): obj_dbg ../bin prefiles $(MAKE) -C obj_dbg -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj -../bin/verilator_coverage_bin_dbg: obj_dbg ../bin prefiles +../bin/verilator_coverage_bin_dbg$(EXEEXT): obj_dbg ../bin prefiles $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index e431515ba..fcd977e14 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -72,7 +72,7 @@ CFG_LIBS = @CFG_LIBS@ #### End of system configuration section. #### VPATH += . $(bldsrc) $(srcdir) -TGT = ../../verilator_bin +TGT = ../../verilator_bin$(EXEEXT) ################# ifeq ($(VL_DEBUG),) From 258d9adfeaa0c04b641ea40e69234b929800abac Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 5 Jun 2021 17:40:56 +0100 Subject: [PATCH 61/80] Aid IDE code linking in V3AstNodes.h (#3009) --- src/V3Ast.h | 70 +--------------------------------- src/V3AstInlines.h | 93 ++++++++++++++++++++++++++++++++++++++++++++++ src/V3AstNodes.h | 3 ++ 3 files changed, 97 insertions(+), 69 deletions(-) create mode 100644 src/V3AstInlines.h diff --git a/src/V3Ast.h b/src/V3Ast.h index 8ac87c735..1753b7075 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2918,10 +2918,6 @@ public: virtual void dump(std::ostream& str) const override; }; -//###################################################################### - -#include "V3AstNodes.h" - //###################################################################### // Inline AstNVisitor METHODS @@ -2947,71 +2943,7 @@ inline AstNode* AstNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { } //###################################################################### -// Inline ACCESSORS -inline int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } -inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } -inline bool AstNode::width1() const { // V3Const uses to know it can optimize - return dtypep() && dtypep()->width() == 1; -} -inline int AstNode::widthInstrs() const { - return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); -} -inline bool AstNode::isDouble() const { - return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble(); -} -inline bool AstNode::isString() const { - return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); -} -inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } - -inline bool AstNode::isZero() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero()); -} -inline bool AstNode::isNeqZero() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero()); -} -inline bool AstNode::isOne() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne()); -} -inline bool AstNode::isAllOnes() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes()); -} -inline bool AstNode::isAllOnesV() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV()); -} -inline bool AstNode::sameTree(const AstNode* node2p) const { - return sameTreeIter(this, node2p, true, false); -} -inline bool AstNode::sameGateTree(const AstNode* node2p) const { - return sameTreeIter(this, node2p, true, true); -} - -inline void AstNodeVarRef::varp(AstVar* varp) { - m_varp = varp; - dtypeFrom(varp); -} - -inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } - -inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); } -inline int AstNodeArrayDType::left() const { return rangep()->leftConst(); } -inline int AstNodeArrayDType::right() const { return rangep()->rightConst(); } -inline int AstNodeArrayDType::hi() const { return rangep()->hiConst(); } -inline int AstNodeArrayDType::lo() const { return rangep()->loConst(); } -inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); } -inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange{left(), right()}; } - -inline const char* AstNodeFTaskRef::broken() const { - BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; -} - -inline void AstIfaceRefDType::cloneRelink() { - if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep(); - if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep(); - if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); -} +#include "V3AstNodes.h" #endif // Guard diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h new file mode 100644 index 000000000..2ee0ff9ae --- /dev/null +++ b/src/V3AstInlines.h @@ -0,0 +1,93 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Ast node inline functions +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* + +#ifndef VERILATOR_V3ASTINLINES_H_ +#define VERILATOR_V3ASTINLINES_H_ + +#ifndef VERILATOR_V3ASTNODES_H_ +#error "Use V3Ast.h as the include" +#include "V3AstNodes.h" // This helps code analysis tools pick up symbols in V3Ast.h and V3AstNodes.h +#endif + +//###################################################################### +// Inline ACCESSORS + +inline int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } +inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } +inline bool AstNode::width1() const { // V3Const uses to know it can optimize + return dtypep() && dtypep()->width() == 1; +} +inline int AstNode::widthInstrs() const { + return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); +} +inline bool AstNode::isDouble() const { + return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble(); +} +inline bool AstNode::isString() const { + return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); +} +inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } + +inline bool AstNode::isZero() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero()); +} +inline bool AstNode::isNeqZero() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero()); +} +inline bool AstNode::isOne() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne()); +} +inline bool AstNode::isAllOnes() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes()); +} +inline bool AstNode::isAllOnesV() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV()); +} +inline bool AstNode::sameTree(const AstNode* node2p) const { + return sameTreeIter(this, node2p, true, false); +} +inline bool AstNode::sameGateTree(const AstNode* node2p) const { + return sameTreeIter(this, node2p, true, true); +} + +inline void AstNodeVarRef::varp(AstVar* varp) { + m_varp = varp; + dtypeFrom(varp); +} + +inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } + +inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); } +inline int AstNodeArrayDType::left() const { return rangep()->leftConst(); } +inline int AstNodeArrayDType::right() const { return rangep()->rightConst(); } +inline int AstNodeArrayDType::hi() const { return rangep()->hiConst(); } +inline int AstNodeArrayDType::lo() const { return rangep()->loConst(); } +inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); } +inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange{left(), right()}; } + +inline const char* AstNodeFTaskRef::broken() const { + BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} + +inline void AstIfaceRefDType::cloneRelink() { + if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep(); + if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep(); + if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); +} + +#endif // Guard diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 9cc94e42d..deba4c885 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -19,6 +19,7 @@ #ifndef VERILATOR_V3AST_H_ #error "Use V3Ast.h as the include" +#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h #endif //###################################################################### @@ -9154,4 +9155,6 @@ public: //###################################################################### +#include "V3AstInlines.h" + #endif // Guard From 1f19e8e2064658f5e0949c644b4ad2b3889343cd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 6 Jun 2021 09:17:56 -0400 Subject: [PATCH 62/80] Tests: Add test case for #2895. --- test_regress/t/t_unpacked_str_init2.pl | 20 +++++++++++++ test_regress/t/t_unpacked_str_init2.v | 39 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100755 test_regress/t/t_unpacked_str_init2.pl create mode 100644 test_regress/t/t_unpacked_str_init2.v diff --git a/test_regress/t/t_unpacked_str_init2.pl b/test_regress/t/t_unpacked_str_init2.pl new file mode 100755 index 000000000..235ca326a --- /dev/null +++ b/test_regress/t/t_unpacked_str_init2.pl @@ -0,0 +1,20 @@ +#!/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); + +# TODO change to compile() +lint( + ); + +# No execute, not self-checking + +ok(1); +1; diff --git a/test_regress/t/t_unpacked_str_init2.v b/test_regress/t/t_unpacked_str_init2.v new file mode 100644 index 000000000..9481aafb8 --- /dev/null +++ b/test_regress/t/t_unpacked_str_init2.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2018 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// issue2895 + +module t (/*AUTOARG*/); + + localparam string REG_X [0:31] = '{"zero", "ra", "sp", "gp", "tp", "t0", + "t1", "t2", "s0/fp", "s1", "a0", "a1", + "a2", "a3", "a4", "a5", "a6", "a7", "s2", + "s3", "s4", "s5", "s6", "s7", "s8", "s9", + "s10", "s11", "t3", "t4", "t5", "t6"}; + + function string reg_x (logic [4:0] r, bit abi=1'b0); + reg_x = abi ? REG_X[r] : $sformatf("x%0d", r); + endfunction + + // the issue is triggered by a second function containing a case statement + function string f2 (logic [4:0] r, bit abi=0); + case (r) + 5'd0: f2 = $sformatf("nop"); + 5'd1: f2 = $sformatf("reg %s", reg_x(r[4:0], abi)); + default: f2 = $sformatf("ILLEGAL"); + endcase + endfunction + + initial begin + for (int unsigned i = 0; i < 32; ++i) begin + $display("REGX: %s", reg_x(i[4:0], 1'b1)); + end + $display("OP: %s", f2(5'd7)); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From b0c1ac7ea23ca406548550146592a5283cfa6dc4 Mon Sep 17 00:00:00 2001 From: Martin Schmidt Date: Sun, 6 Jun 2021 15:27:44 +0200 Subject: [PATCH 63/80] Add support of --trace-structs parameter for CMake (#2986) --- docs/CONTRIBUTORS | 1 + src/V3EmitCMake.cpp | 2 ++ verilator-config.cmake.in | 17 ++++++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 8c038e1c3..1da70dd75 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -55,6 +55,7 @@ Marco Widmer Markus Krause Marlon James Marshal Qiao +Martin Schmidt Matthew Ballance Michael Killough Mike Popoloski diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index e8ff6e06d..a2aa6bd78 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -115,6 +115,8 @@ class CMakeEmitter final { cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); *of << "# Threaded tracing output mode? 0/1/N threads (from --trace-threads)\n"; cmake_set_raw(*of, name + "_TRACE_THREADS", cvtToStr(v3Global.opt.traceThreads())); + *of << "# Struct output mode? 0/1 (from --trace-structs)\n"; + cmake_set_raw(*of, name + "_TRACE_STRUCTS", cvtToStr(v3Global.opt.traceStructs())); *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; cmake_set_raw(*of, name + "_TRACE_VCD", (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD)) diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index f91fab2d1..c75e469d4 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -119,8 +119,15 @@ define_property(TARGET FULL_DOCS "Verilator SystemC enabled" ) +define_property(TARGET + PROPERTY VERILATOR_TRACE_STRUCTS + BRIEF_DOCS "Verilator trace structs enabled" + FULL_DOCS "Verilator trace structs enabled" +) + + function(verilate TARGET) - cmake_parse_arguments(VERILATE "COVERAGE;TRACE;TRACE_FST;SYSTEMC" + cmake_parse_arguments(VERILATE "COVERAGE;TRACE;TRACE_FST;SYSTEMC;TRACE_STRUCTS" "PREFIX;TOP_MODULE;THREADS;TRACE_THREADS;DIRECTORY" "SOURCES;VERILATOR_ARGS;INCLUDE_DIRS;OPT_SLOW;OPT_FAST;OPT_GLOBAL" ${ARGN}) @@ -168,6 +175,10 @@ function(verilate TARGET) list(APPEND VERILATOR_ARGS --cc) endif() + if (VERILATE_TRACE_STRUCTS) + list(APPEND VERILATOR_ARGS --trace-structs) + endif() + foreach(INC ${VERILATE_INCLUDE_DIRS}) list(APPEND VERILATOR_ARGS -y "${INC}") endforeach() @@ -277,6 +288,10 @@ function(verilate TARGET) set_property(TARGET ${TARGET} PROPERTY VERILATOR_SYSTEMC ON) endif() + if (${VERILATE_PREFIX}_TRACE_STRUCTS) + set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_STRUCTS ON) + endif() + # Add the compile flags only on Verilated sources target_include_directories(${TARGET} PUBLIC ${VDIR}) target_sources(${TARGET} PRIVATE ${GENERATED_SOURCES} "${VCMAKE_COPY}" From 1e89392e76189d3967308e894ddf0d13323500f0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 6 Jun 2021 10:27:01 -0400 Subject: [PATCH 64/80] Add --expand-limit argument (#3005). --- Changes | 1 + bin/verilator | 1 + docs/guide/exe_verilator.rst | 6 +++++ src/V3Expand.cpp | 33 ++++++++++++++++++++++++++- src/V3Options.cpp | 2 ++ src/V3Options.h | 2 ++ test_regress/t/t_flag_expand_limit.pl | 20 ++++++++++++++++ test_regress/t/t_flag_expand_limit.v | 27 ++++++++++++++++++++++ test_regress/t/t_reloop_cam.pl | 1 + 9 files changed, 92 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_flag_expand_limit.pl create mode 100644 test_regress/t/t_flag_expand_limit.v diff --git a/Changes b/Changes index 45501947e..315b9d191 100644 --- a/Changes +++ b/Changes @@ -14,6 +14,7 @@ Verilator 4.203 devel **Minor:** * Add --reloop-limit argument (#2943) (#2960). [Geza Lore] +* Add --expand-limit argument (#3005). [Julien Margetts] * Add TRACE_THREADS to CMake (#2934). [Jonathan Drolet] * Optimize large lookup tables to static data (#2925). [Geza Lore] * Optimize reloop to accept constant index offsets (#2939). [Geza Lore] diff --git a/bin/verilator b/bin/verilator index 706de8e28..61064a9b4 100755 --- a/bin/verilator +++ b/bin/verilator @@ -315,6 +315,7 @@ detailed descriptions of these arguments. -E Preprocess, but do not compile --error-limit Abort after this number of errors --exe Link to create executable + --expand-limit Set expand optimization limit -F Parse arguments from a file, relatively -f Parse arguments from a file -FI Force include of a file diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 379971315..d7eebe90d 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -403,6 +403,12 @@ Summary: files on the command line that implement the main loop for your simulation. +.. option:: --expand-limit + + Rarely needed. Fine-tune optimizations to set the maximum size of an + expression in 32-bit words to expand into separate word-based + statements. + .. option:: -F Read the specified file, and act as if all text inside it was specified diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 2ec552cfe..dd5a5ec42 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -30,6 +30,7 @@ #include "V3Global.h" #include "V3Expand.h" +#include "V3Stats.h" #include "V3Ast.h" #include @@ -45,10 +46,24 @@ private: // STATE AstNode* m_stmtp = nullptr; // Current statement + VDouble0 m_statWides; // Statistic tracking + VDouble0 m_statWideWords; // Statistic tracking + VDouble0 m_statWideLimited; // Statistic tracking // METHODS VL_DEBUG_FUNC; // Declare debug() + bool doExpand(AstNode* nodep) { + ++m_statWides; + if (nodep->widthWords() <= v3Global.opt.expandLimit()) { + m_statWideWords += nodep->widthWords(); + return true; + } else { + ++m_statWideLimited; + return false; + } + } + int longOrQuadWidth(AstNode* nodep) { return (nodep->width() + (VL_EDATASIZE - 1)) & ~(VL_EDATASIZE - 1); } @@ -204,6 +219,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstConst* rhsp) { UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl); + if (!doExpand(nodep)) return false; // -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}} if (rhsp->num().isFourState()) { rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible? @@ -219,6 +235,7 @@ private: //-------- Uniops bool expandWide(AstNodeAssign* nodep, AstVarRef* rhsp) { UINFO(8, " Wordize ASSIGN(VARREF) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, newAstWordSelClone(rhsp, w)); } @@ -228,6 +245,7 @@ private: UINFO(8, " Wordize ASSIGN(ARRAYSEL) " << nodep << endl); UASSERT_OBJ(!VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType), nodep, "ArraySel with unpacked arrays should have been removed in V3Slice"); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, newAstWordSelClone(rhsp, w)); } @@ -236,6 +254,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstNot* rhsp) { UINFO(8, " Wordize ASSIGN(NOT) " << nodep << endl); // -> {for each_word{ ASSIGN(WORDSEL(wide,#),NOT(WORDSEL(lhs,#))) }} + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstNot(rhsp->fileline(), newAstWordSelClone(rhsp->lhsp(), w))); @@ -245,6 +264,7 @@ private: //-------- Biops bool expandWide(AstNodeAssign* nodep, AstAnd* rhsp) { UINFO(8, " Wordize ASSIGN(AND) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstAnd(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), @@ -254,6 +274,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstOr* rhsp) { UINFO(8, " Wordize ASSIGN(OR) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstOr(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), @@ -263,6 +284,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstXor* rhsp) { UINFO(8, " Wordize ASSIGN(XOR) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstXor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), @@ -273,6 +295,7 @@ private: //-------- Triops bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) { UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstCond(nodep->fileline(), rhsp->condp()->cloneTree(true), @@ -417,6 +440,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstSel* rhsp) { UASSERT_OBJ(nodep->widthMin() == rhsp->widthConst(), nodep, "Width mismatch"); + if (!doExpand(nodep)) return false; if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) { int lsb = rhsp->lsbConst(); UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep << endl); @@ -647,6 +671,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) { UINFO(8, " Wordize ASSIGN(CONCAT) " << nodep << endl); + if (!doExpand(rhsp)) return false; // Lhs or Rhs may be word, long, or quad. // newAstWordSelClone nicely abstracts the difference. int rhsshift = rhsp->rhsp()->widthMin(); @@ -701,6 +726,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) { UINFO(8, " Wordize ASSIGN(REPLICATE) " << nodep << endl); + if (!doExpand(rhsp)) return false; AstNode* lhsp = rhsp->lhsp(); int lhswidth = lhsp->widthMin(); const AstConst* constp = VN_CAST(rhsp->rhsp(), Const); @@ -857,6 +883,7 @@ private: iterateChildren(nodep); bool did = false; if (nodep->isWide() && ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel))) + && ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel))) && !AstVar::scVarRecurse(nodep->lhsp()) // Need special function for SC && !AstVar::scVarRecurse(nodep->rhsp())) { if (AstConst* rhsp = VN_CAST(nodep->rhsp(), Const)) { @@ -897,7 +924,11 @@ private: public: // CONSTRUCTORS explicit ExpandVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ExpandVisitor() override = default; + virtual ~ExpandVisitor() override { + V3Stats::addStat("Optimizations, expand wides", m_statWides); + V3Stats::addStat("Optimizations, expand wide words", m_statWideWords); + V3Stats::addStat("Optimizations, expand limited", m_statWideLimited); + } }; //---------------------------------------------------------------------- diff --git a/src/V3Options.cpp b/src/V3Options.cpp index d292b4096..4cb886835 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1060,6 +1060,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-E", Set, &m_preprocOnly); DECL_OPTION("-error-limit", CbVal, static_cast(&V3Error::errorLimit)); DECL_OPTION("-exe", OnOff, &m_exe); + DECL_OPTION("-expand-limit", CbVal, + [this, fl](const char* valp) { m_expandLimit = std::atoi(valp); }); DECL_OPTION("-F", CbVal, [this, fl, &optdir](const char* valp) { parseOptsFile(fl, parseFileArg(optdir, valp), true); diff --git a/src/V3Options.h b/src/V3Options.h index 4d3bd8612..dff879acf 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -285,6 +285,7 @@ private: int m_convergeLimit = 100; // main switch: --converge-limit int m_coverageMaxWidth = 256; // main switch: --coverage-max-width int m_dumpTree = 0; // main switch: --dump-tree + int m_expandLimit = 64; // main switch: --expand-limit int m_gateStmts = 100; // main switch: --gate-stmts int m_ifDepth = 0; // main switch: --if-depth int m_inlineMult = 2000; // main switch: --inline-mult @@ -482,6 +483,7 @@ public: int coverageMaxWidth() const { return m_coverageMaxWidth; } int dumpTree() const { return m_dumpTree; } bool dumpTreeAddrids() const { return m_dumpTreeAddrids; } + int expandLimit() const { return m_expandLimit; } int gateStmts() const { return m_gateStmts; } int ifDepth() const { return m_ifDepth; } int inlineMult() const { return m_inlineMult; } diff --git a/test_regress/t/t_flag_expand_limit.pl b/test_regress/t/t_flag_expand_limit.pl new file mode 100755 index 000000000..6270f76ca --- /dev/null +++ b/test_regress/t/t_flag_expand_limit.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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); + +compile( + verilator_flags2 => ['--expand-limit 1 --stats'], + ); + +file_grep($Self->{stats}, qr/Optimizations, expand limited\s+(\d+)/i, 4); + +ok(1); +1; diff --git a/test_regress/t/t_flag_expand_limit.v b/test_regress/t/t_flag_expand_limit.v new file mode 100644 index 000000000..0640ce15a --- /dev/null +++ b/test_regress/t/t_flag_expand_limit.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// issue3005 + +module t #(parameter NV = 2000) + ( + input a, + input w1, + input [127:0] w2, + output [ 31:0] o, + + input [319:0] bi, + output [319:0] bo + ); + + // verilator lint_off WIDTH + wire [NV-1:0] d = a ? NV'(0) : {NV{w2}}; + // verilator lint_on WIDTH + assign o = d[31:0]; + + assign bo = ~bi; + +endmodule diff --git a/test_regress/t/t_reloop_cam.pl b/test_regress/t/t_reloop_cam.pl index e6d8da916..7046308bc 100755 --- a/test_regress/t/t_reloop_cam.pl +++ b/test_regress/t/t_reloop_cam.pl @@ -12,6 +12,7 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["-unroll-count 1024", + "--expand-limit 1024", $Self->wno_unopthreads_for_few_cores(), "--stats"], ); From 2158a4573e87ab8afd089840d028cc09b01a70a1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 6 Jun 2021 10:27:44 -0400 Subject: [PATCH 65/80] Tests: Reenable 18.04 MT (#2963). --- ci/ci-script.bash | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ci/ci-script.bash b/ci/ci-script.bash index 54eeb1756..498531eed 100755 --- a/ci/ci-script.bash +++ b/ci/ci-script.bash @@ -85,24 +85,16 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then # Run the specified test case $TESTS in dist-vlt-0) - if [[ "$CI_RUNS_ON" != "ubuntu-18.04" || "$CXX" != "clang++" ]]; then # issue #2963 "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=0/2 - fi ;; dist-vlt-1) - if [[ "$CI_RUNS_ON" != "ubuntu-18.04" || "$CXX" != "clang++" ]]; then # issue #2963 "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=1/2 - fi ;; vltmt-0) - if [[ "$CI_RUNS_ON" != "ubuntu-18.04" || "$CXX" != "clang++" ]]; then # issue #2963 "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2 - fi ;; vltmt-1) - if [[ "$CI_RUNS_ON" != "ubuntu-18.04" || "$CXX" != "clang++" ]]; then # issue #2963 "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2 - fi ;; coverage-all) nodist/code_coverage --stages 1- From 8f2e4f6bb0b66427f9a7a42303626e4f8b00d66a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 6 Jun 2021 10:32:50 -0400 Subject: [PATCH 66/80] Fix clang warning. --- src/V3Options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 4cb886835..49a65e5ac 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1061,7 +1061,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-error-limit", CbVal, static_cast(&V3Error::errorLimit)); DECL_OPTION("-exe", OnOff, &m_exe); DECL_OPTION("-expand-limit", CbVal, - [this, fl](const char* valp) { m_expandLimit = std::atoi(valp); }); + [this](const char* valp) { m_expandLimit = std::atoi(valp); }); DECL_OPTION("-F", CbVal, [this, fl, &optdir](const char* valp) { parseOptsFile(fl, parseFileArg(optdir, valp), true); From 31bb73e3de461d2b0990fa5a6d61e4b639a35402 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 6 Jun 2021 19:32:48 -0400 Subject: [PATCH 67/80] Fix MCD close also closing stdout (#2931). --- Changes | 1 + include/verilated_imp.h | 11 ++++++++--- test_regress/t/t_sys_file_basic_mcd.out | 1 + test_regress/t/t_sys_file_basic_mcd.pl | 2 ++ test_regress/t/t_sys_file_basic_mcd.v | 16 ++++++++++++++-- test_regress/t/t_sys_file_basic_mcd_test5.dat | 1 + 6 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 test_regress/t/t_sys_file_basic_mcd_test5.dat diff --git a/Changes b/Changes index 315b9d191..0bc065689 100644 --- a/Changes +++ b/Changes @@ -28,6 +28,7 @@ Verilator 4.203 devel * Fix initialization of assoc in assoc array (#2914). [myftptoyman] * Fix make support for gmake 3.x (#2920) (#2921). [Philipp Wagner] * Fix VPI memory access for packed arrays (#2922). [Todd Strader] +* Fix MCD close also closing stdout (#2931). [Alexander Grobman] * Fix split procedures to better respect --output-split-cfuncs (#2942). [Geza Lore] * Fix to emit 'else if' without nesting (#2944). [Geza Lore] * Fix part select issues in LATCH warning (#2948) (#2938). [Julien Margetts] diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 584213b38..b4d13e0e0 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -333,17 +333,20 @@ public: // But only for verilated*.cpp } void fdClose(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) { const VerilatedLockGuard lock(m_fdMutex); - if ((fdi & (1 << 31)) != 0) { + if (VL_BITISSET_I(fdi, 31)) { // Non-MCD case IData idx = VL_MASK_I(31) & fdi; if (VL_UNLIKELY(idx >= m_fdps.size())) return; + if (VL_UNLIKELY(idx <= 2)) return; // stdout/stdin/stderr if (VL_UNLIKELY(!m_fdps[idx])) return; // Already free std::fclose(m_fdps[idx]); m_fdps[idx] = (FILE*)0; m_fdFree.push_back(idx); } else { // MCD case - for (int i = 0; (fdi != 0) && (i < 31); i++, fdi >>= 1) { + // Starts at 1 to skip stdout + fdi >>= 1; + for (int i = 1; (fdi != 0) && (i < 31); i++, fdi >>= 1) { if (fdi & VL_MASK_I(1)) { std::fclose(m_fdps[i]); m_fdps[i] = nullptr; @@ -375,7 +378,9 @@ private: } } else { // MCD Case - for (size_t i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) { + if (fdi & 1) fp.push_back(stdout); + fdi >>= 1; + for (size_t i = 1; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) { if (fdi & VL_MASK_I(1)) fp.push_back(m_fdps[i]); } } diff --git a/test_regress/t/t_sys_file_basic_mcd.out b/test_regress/t/t_sys_file_basic_mcd.out index bac06f7e9..636fdaca3 100644 --- a/test_regress/t/t_sys_file_basic_mcd.out +++ b/test_regress/t/t_sys_file_basic_mcd.out @@ -1,2 +1,3 @@ Sean Connery was the best Bond. +To file and to stdout *-* All Finished *-* diff --git a/test_regress/t/t_sys_file_basic_mcd.pl b/test_regress/t/t_sys_file_basic_mcd.pl index 106810fa0..e77ffbc08 100755 --- a/test_regress/t/t_sys_file_basic_mcd.pl +++ b/test_regress/t/t_sys_file_basic_mcd.pl @@ -24,6 +24,8 @@ files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test2_1.dat", "$Self->{t_dir}/t_sys_file_basic_mcd_test2_1.dat"); files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test2_2.dat", "$Self->{t_dir}/t_sys_file_basic_mcd_test2_2.dat"); +files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test5.dat", + "$Self->{t_dir}/t_sys_file_basic_mcd_test5.dat"); ok(1); 1; diff --git a/test_regress/t/t_sys_file_basic_mcd.v b/test_regress/t/t_sys_file_basic_mcd.v index 16742829a..54d0aba21 100644 --- a/test_regress/t/t_sys_file_basic_mcd.v +++ b/test_regress/t/t_sys_file_basic_mcd.v @@ -30,7 +30,7 @@ module t; if (fd_fail != 0) fail("Able to allocate MCD descriptor when fully utilized."); // Return descriptor back to pool - fd_close = fd[0]; + fd_close = fd[0]; $fclose(fd_close); // Re-attempt MCD allocation; should pass at this point. fd_success = $fopen($sformatf("%s/yet_another_file.dat", `STR(`TEST_OBJ_DIR))); @@ -76,12 +76,21 @@ module t; int fd; // Wide filename fd = $fopen({`STR(`TEST_OBJ_DIR), - "some_very_large_filename_that_no_one_would_ever_use_", + "/some_very_large_filename_that_no_one_would_ever_use_", "except_to_purposefully_break_my_beautiful_code.dat"}); if (fd == 0) fail("Long filename could not be opened."); $fclose(fd); end endtask + task automatic test5; begin + int fd_all; + fd_all = $fopen({`STR(`TEST_OBJ_DIR), "/t_sys_file_basic_mcd_test5.dat"}); + if (fd_all == 0) fail("could not be opened."); + fd_all |= 1; + $fdisplay(fd_all, "To file and to stdout"); + $fclose(fd_all); + end endtask + initial begin // Test1: Validate file descriptor region. @@ -96,6 +105,9 @@ module t; // Test4: Validate filename lengths test4; + // Test5: OR with stdout + test5; + $write("*-* All Finished *-*\n"); $finish(0); // Test arguments to finish diff --git a/test_regress/t/t_sys_file_basic_mcd_test5.dat b/test_regress/t/t_sys_file_basic_mcd_test5.dat new file mode 100644 index 000000000..a623ecae3 --- /dev/null +++ b/test_regress/t/t_sys_file_basic_mcd_test5.dat @@ -0,0 +1 @@ +To file and to stdout From 0edf1f0c94fc9a51d1b8c5b6311dac5d6f3161f5 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 7 Jun 2021 00:56:30 +0100 Subject: [PATCH 68/80] Add ccache-report target to standard Makefile (#3011) Using the standard model Makefile, when in addition to an explicit target, the target 'ccache-report' is also given, a summary of ccache hits/misses during this invocation of 'make' will be prited at the end of the build. --- Makefile.in | 6 +- bin/verilator_ccache_report | 59 +++++++++++++++++++ docs/guide/faq.rst | 2 +- docs/guide/simulating.rst | 29 +++++++++ include/verilated.mk.in | 33 +++++++++++ test_regress/driver.pl | 4 ++ test_regress/t/t_ccache_report.pl | 49 +++++++++++++++ ...t_ccache_report__ccache_report_initial.out | 9 +++ ...t_ccache_report__ccache_report_rebuild.out | 5 ++ test_regress/t/t_flag_help.pl | 28 ++++++--- 10 files changed, 213 insertions(+), 11 deletions(-) create mode 100755 bin/verilator_ccache_report create mode 100755 test_regress/t/t_ccache_report.pl create mode 100644 test_regress/t/t_ccache_report__ccache_report_initial.out create mode 100644 test_regress/t/t_ccache_report__ccache_report_rebuild.out diff --git a/Makefile.in b/Makefile.in index fb2bf08a8..fcee49bca 100644 --- a/Makefile.in +++ b/Makefile.in @@ -131,6 +131,7 @@ DISTFILES1 = $(INFOS) .gitignore \ verilator-config.cmake.in \ verilator-config-version.cmake.in \ bin/verilator \ + bin/verilator_ccache_report \ bin/verilator_coverage \ bin/verilator_difftree \ bin/verilator_gantt \ @@ -194,6 +195,7 @@ DISTFILES2 = \ INST_PROJ_FILES = \ bin/verilator \ + bin/verilator_ccache_report \ bin/verilator_coverage \ bin/verilator_gantt \ bin/verilator_includer \ @@ -282,7 +284,7 @@ verilator.pdf: Makefile # See uninstall also - don't put wildcards in this variable, it might uninstall other stuff VL_INST_BIN_FILES = verilator verilator_bin$(EXEEXT) verilator_bin_dbg$(EXEEXT) verilator_coverage_bin_dbg$(EXEEXT) \ - verilator_coverage verilator_gantt verilator_includer verilator_profcfunc + verilator_ccache_report verilator_coverage verilator_gantt verilator_includer verilator_profcfunc # Some scripts go into both the search path and pkgdatadir, # so they can be found by the user, and under $VERILATOR_ROOT. @@ -311,6 +313,7 @@ installbin: ( cd bin ; $(INSTALL_PROGRAM) verilator_coverage_bin_dbg$(EXEEXT) $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg$(EXEEXT) ) $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/bin ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer ) + ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_ccache_report $(DESTDIR)$(pkgdatadir)/bin/verilator_ccache_report ) # Man files can either be part of the original kit, or built in current directory # So important we use $^ so VPATH is searched @@ -477,6 +480,7 @@ clang-format: $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES) PY_PROGRAMS = \ + bin/verilator_ccache_report \ examples/xml_py/vl_file_copy \ examples/xml_py/vl_hier_graph \ docs/guide/conf.py \ diff --git a/bin/verilator_ccache_report b/bin/verilator_ccache_report new file mode 100755 index 000000000..d5dc1e5d7 --- /dev/null +++ b/bin/verilator_ccache_report @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# pylint: disable=C0103,C0114,C0115,C0116,C0123,C0301,R0902,R0913,R0914,R0912,R0915,W0621 +###################################################################### + +import argparse +import collections +import re + +parser = argparse.ArgumentParser( + allow_abbrev=False, + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Report ccache behavior of a Verilated model build.""", + epilog= + """Copyright 2002-2021 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""") + +parser.add_argument('-o', type=argparse.FileType('w'), metavar="OUTFILE", + required=True, + help='output file') +parser.add_argument('logfile', type=argparse.FileType('r'), + help='ccache log file') + +args = parser.parse_args() + +results = {} + +for line in args.logfile: + line = line.strip() + match = re.match(r'.*Object file: (.*)$', line) + if match: + obj = match.group(1) + match = re.match(r'.*Result: (.*)$', line) + if match: + results[obj] = match.group(1) + +args.o.write("#" * 80 + "\n") +args.o.write("ccache report (from verilator_ccache_report) :\n") + +if not results: + args.o.write("\nAll object files up to date\n") +else: + args.o.write("\nCompiled object files:\n") + width = max(len(_) for _ in results) + 1 + for k in sorted(results.keys()): + args.o.write("{:{width}} : {}\n".format(k, results[k], width=width)) + + args.o.write("\nSummary:\n") + counts = collections.Counter(_ for _ in results.values()) + total = sum(counts.values()) + width = max(len(_) for _ in results.values()) + 1 + for k in sorted(counts.keys()): + c = counts[k] + args.o.write("{:{width}}| {} ({:.2%})\n".format(k, c, c / total, width=width)) + +args.o.write("#" * 80 + "\n") diff --git a/docs/guide/faq.rst b/docs/guide/faq.rst index 5628828ec..c3ffd5b76 100644 --- a/docs/guide/faq.rst +++ b/docs/guide/faq.rst @@ -387,7 +387,7 @@ How do I get faster build times? identical source builds, even across different users. If ccache was installed when Verilator was built it is used, or see OBJCACHE environment variable to override this. Also see the - :vlopt:`--output-split` option. + :vlopt:`--output-split` option and :ref: `Profiling ccache efficiency` * To reduce the compile time of classes that use a Verilated module (e.g. a top CPP file) you may wish to add a diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index 39ebf1464..3033a5c22 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -316,6 +316,35 @@ statistics. For more information see :command:`verilator_gantt`. +.. _Profiling ccache efficiency: + +Profiling ccache efficiency +=========================== + +The Verilator generated Makefile provides support for basic profiling of +ccache behavior during the build. This can be used to track down files that +might be unnecessarily rebuilt, though as of today even small code changes +will usually require rebuilding a large number of files. Improving ccache +efficiency during the edit/compile/test loop is an active area of +development. + +To get a basic report of how well ccache is doing, add the `ccache-report` +target when invoking the generated Makefile: + +.. code-block:: bash + + make -C obj_dir -f Vout.mk Vout ccache-report + +This will print a report based on all executions of ccache during this +invocation of Make. The report is also written to a file, in this example +`obj_dir/Vout__cache_report.txt`. + +To use the `ccache-report` target, at least one other explicit build target +must be specified, and OBJCACHE must be set to 'ccache'. + +This feature is currently experimental and might change in subsequent +releases. + .. _Save/Restore: Save/Restore diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 2edde9c11..c183d1d7c 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -10,6 +10,7 @@ ###################################################################### PERL = @PERL@ +PYTHON3 = @PYTHON3@ CXX = @CXX@ LINK = @CXX@ AR = ar @@ -35,6 +36,7 @@ CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@ VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage VERILATOR_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer +VERILATOR_CCACHE_REPORT = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_ccache_report ###################################################################### # Make checks @@ -254,6 +256,37 @@ endif #.cpp.o: # $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< +###################################################################### +### ccache report + +ifneq ($(findstring ccache-report,$(MAKECMDGOALS)),) + ifneq ($(OBJCACHE),ccache) + $(error ccache-report requires OBJCACHE to equal 'ccache') + endif + VK_OTHER_GOALS := $(strip $(subst ccache-report,,$(MAKECMDGOALS))) + ifeq ($(VK_OTHER_GOALS),) + $(error ccache-report must be used with at least one other explicit target) + endif + + # Report ccache behaviour for this invocation of make + export CCACHE_LOGFILE := $(VM_PREFIX).ccache-log + VK_CCACHE_REPORT := $(VM_PREFIX)__ccache_report.txt + # Truncate logfile + $(shell echo "" > $(CCACHE_LOGFILE)) + # Remove previous report + $(shell rm -f $(VK_CCACHE_REPORT)) + +$(VK_CCACHE_REPORT): $(VK_OBJS) + $(VERILATOR_CCACHE_REPORT) -o $@ $(CCACHE_LOGFILE) + +.PHONY: ccache-report +ccache-report: $(VK_CCACHE_REPORT) + @cat $< + +# ccache-report runs last +ccache-report: $(VK_OTHER_GOALS) +endif + ###################################################################### ### Debugging diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 37d0f3a3c..54dd82683 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2304,6 +2304,10 @@ sub cfg_with_threaded { return 1; # C++11 now always required } +sub cfg_with_ccache { + return `grep "OBJCACHE \?= ccache" "$ENV{VERILATOR_ROOT}/include/verilated.mk"` ne ""; +} + sub tries { # Number of retries when reading logfiles, generally only need many # retries when system is busy running a lot of tests diff --git a/test_regress/t/t_ccache_report.pl b/test_regress/t/t_ccache_report.pl new file mode 100755 index 000000000..1e36b8b1a --- /dev/null +++ b/test_regress/t/t_ccache_report.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 2021 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); + +if (!$Self->cfg_with_ccache) { + skip("Requires configuring with ccache"); +} + +top_filename("t_a1_first_cc.v"); + +# This test requires rebuilding the object files to check the ccache log +foreach my $filename (glob ("$Self->{obj_dir}/*.o")) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +compile( + verilator_flags2 => ['--trace'], + make_flags => "ccache-report" + ); + +my $report = "$Self->{obj_dir}/$Self->{VM_PREFIX}__ccache_report.txt"; + +# We do not actually want to make this test depend on whether the file was +# cached or not, so trim the report to ignore actual caching behaviour +run(cmd => ["sed", "-i", "-e", "'s/ : .*/ : IGNORED/; /^Summary/,\$d;'", $report]); + +files_identical($report, "t/$Self->{name}__ccache_report_initial.out"); + +# Now rebuild again (should be all up to date) +run( + logfile => "$Self->{obj_dir}/rebuild.log", + cmd => ["make", "-C", $Self->{obj_dir}, + "-f", "$Self->{VM_PREFIX}.mk", + $Self->{VM_PREFIX}, "ccache-report"] + ); + +files_identical($report, "t/$Self->{name}__ccache_report_rebuild.out"); + +ok(1); +1; diff --git a/test_regress/t/t_ccache_report__ccache_report_initial.out b/test_regress/t/t_ccache_report__ccache_report_initial.out new file mode 100644 index 000000000..88f2fe542 --- /dev/null +++ b/test_regress/t/t_ccache_report__ccache_report_initial.out @@ -0,0 +1,9 @@ +################################################################################ +ccache report (from verilator_ccache_report) : + +Compiled object files: +Vt_ccache_report__ALL.o : IGNORED +Vt_ccache_report__main.o : IGNORED +verilated.o : IGNORED +verilated_vcd_c.o : IGNORED + diff --git a/test_regress/t/t_ccache_report__ccache_report_rebuild.out b/test_regress/t/t_ccache_report__ccache_report_rebuild.out new file mode 100644 index 000000000..767cd181a --- /dev/null +++ b/test_regress/t/t_ccache_report__ccache_report_rebuild.out @@ -0,0 +1,5 @@ +################################################################################ +ccache report (from verilator_ccache_report) : + +All object files up to date +################################################################################ diff --git a/test_regress/t/t_flag_help.pl b/test_regress/t/t_flag_help.pl index f3dc0cca4..cb38bfb87 100755 --- a/test_regress/t/t_flag_help.pl +++ b/test_regress/t/t_flag_help.pl @@ -10,23 +10,33 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(dist => 1); +# See also t_flag_version.pl + +sub check { + my $interpreter = shift; + my $prog = shift; + + run(fails => 0, + cmd => [$interpreter, $prog, "--help"], + logfile => "$Self->{obj_dir}/t_help.log", + tee => 0, + verilator_run => 1, + ); + + file_grep("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i); +} + foreach my $prog ( - # See also t_flag_version.pl "../bin/verilator", "../bin/verilator_coverage", "../bin/verilator_difftree", "../bin/verilator_gantt", "../bin/verilator_profcfunc", ) { - run(fails => 0, - cmd => ["perl", $prog, - "--help"], - logfile => "$Self->{obj_dir}/t_help.log", - tee => 0, - verilator_run => 1, - ); - file_grep("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i); + check("perl", $prog); } +check("python3", "../bin/verilator_ccache_report"); + ok(1); 1; From c238d3da766bd4e2f76fb43c0d8a53640f60443c Mon Sep 17 00:00:00 2001 From: github action Date: Sun, 6 Jun 2021 23:57:41 +0000 Subject: [PATCH 69/80] Apply clang-format --- bin/verilator_ccache_report | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/verilator_ccache_report b/bin/verilator_ccache_report index d5dc1e5d7..580790230 100755 --- a/bin/verilator_ccache_report +++ b/bin/verilator_ccache_report @@ -18,10 +18,13 @@ Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -parser.add_argument('-o', type=argparse.FileType('w'), metavar="OUTFILE", +parser.add_argument('-o', + type=argparse.FileType('w'), + metavar="OUTFILE", required=True, help='output file') -parser.add_argument('logfile', type=argparse.FileType('r'), +parser.add_argument('logfile', + type=argparse.FileType('r'), help='ccache log file') args = parser.parse_args() @@ -54,6 +57,9 @@ else: width = max(len(_) for _ in results.values()) + 1 for k in sorted(counts.keys()): c = counts[k] - args.o.write("{:{width}}| {} ({:.2%})\n".format(k, c, c / total, width=width)) + args.o.write("{:{width}}| {} ({:.2%})\n".format(k, + c, + c / total, + width=width)) args.o.write("#" * 80 + "\n") From b976b8dac98972549ca33384c7a33cfbc6654efd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 6 Jun 2021 22:09:30 -0400 Subject: [PATCH 70/80] Fix slowdown in elaboration (#2911). --- Changes | 1 + src/V3Width.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 0bc065689..ecf0750f9 100644 --- a/Changes +++ b/Changes @@ -25,6 +25,7 @@ Verilator 4.203 devel * Fix assertion failure in bitOpTree optimization (#2891) (#2899). [Raynard Qiao] * Fix DPI functions not seen as vpiModule (#2893). [Todd Strader] * Fix bounds check in VL_SEL_IWII (#2910). [Krzysztof Bieganski] +* Fix slowdown in elaboration (#2911). [Nathan Graybeal] * Fix initialization of assoc in assoc array (#2914). [myftptoyman] * Fix make support for gmake 3.x (#2920) (#2921). [Philipp Wagner] * Fix VPI memory access for packed arrays (#2922). [Todd Strader] diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 22e15d1c7..08204e1d0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -492,7 +492,7 @@ private: // signed: Unsigned (11.8.1) // width: LHS + RHS AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); - userIterateAndNext(vdtypep, WidthVP(SELF, BOTH).p()); + userIterate(vdtypep, WidthVP(SELF, BOTH).p()); if (VN_IS(vdtypep, QueueDType)) { // Queue "element 0" is lhsp, so we need to swap arguments auto* newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), @@ -2457,7 +2457,7 @@ private: AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); AstBasicDType* basicp = fromDtp ? fromDtp->basicp() : nullptr; UINFO(9, " from dt " << fromDtp << endl); - userIterateAndNext(fromDtp, WidthVP(SELF, BOTH).p()); + userIterate(fromDtp, WidthVP(SELF, BOTH).p()); if (AstEnumDType* adtypep = VN_CAST(fromDtp, EnumDType)) { methodCallEnum(nodep, adtypep); } else if (AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType)) { @@ -3310,7 +3310,9 @@ private: while (const AstConstDType* vdtypep = VN_CAST(dtypep, ConstDType)) { dtypep = vdtypep->subDTypep()->skipRefp(); } - userIterateAndNext(dtypep, WidthVP(SELF, BOTH).p()); + + userIterate(dtypep, WidthVP(SELF, BOTH).p()); + if (auto* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) { VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { From 6fd48da7cfae906901fc34ee9a88af3ba81a60ac Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 7 Jun 2021 07:47:15 -0400 Subject: [PATCH 71/80] Untabify cmakefiles. No functional change. --- examples/cmake_hello_sc/CMakeLists.txt | 6 +++--- examples/cmake_tracing_sc/CMakeLists.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/cmake_hello_sc/CMakeLists.txt b/examples/cmake_hello_sc/CMakeLists.txt index 490391c12..f85d05c6d 100644 --- a/examples/cmake_hello_sc/CMakeLists.txt +++ b/examples/cmake_hello_sc/CMakeLists.txt @@ -38,9 +38,9 @@ find_package(SystemCLanguage QUIET) add_executable(example ../make_hello_sc/sc_main.cpp) set_property( - TARGET example - PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD} - ) + TARGET example + PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD} + ) # Add the Verilated circuit to the target verilate(example SYSTEMC diff --git a/examples/cmake_tracing_sc/CMakeLists.txt b/examples/cmake_tracing_sc/CMakeLists.txt index a06af17f8..4651d1709 100644 --- a/examples/cmake_tracing_sc/CMakeLists.txt +++ b/examples/cmake_tracing_sc/CMakeLists.txt @@ -38,9 +38,9 @@ find_package(SystemCLanguage QUIET) add_executable(example ../make_tracing_sc/sc_main.cpp) set_property( - TARGET example - PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD} - ) + TARGET example + PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD} + ) # Add the Verilated circuit to the target verilate(example SYSTEMC COVERAGE TRACE From 809701d7c6b09e69831e8dfd0b247c4920030f17 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 8 Jun 2021 23:01:30 +0100 Subject: [PATCH 72/80] Add missing 'inline' to function in verilated.h Otherwise we get a separate copy of this function in every compilation unit including this header. --- include/verilated.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated.h b/include/verilated.h index 1bd54bb25..fcd87fb8d 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -1795,7 +1795,7 @@ static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_M } return owp; } -static void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE { +static inline void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE { EData carry = 1; for (int i = 0; i < words; ++i) { EData word = ~owp_lwp[i] + carry; From 5555f20bd2fd6ed58fc4c04a271036f9134b3123 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 9 Jun 2021 18:26:29 +0100 Subject: [PATCH 73/80] Improve ccache-report --- bin/verilator_ccache_report | 58 ++++++++++++++----- include/verilated.mk.in | 17 ++++-- test_regress/t/t_ccache_report.pl | 3 +- ...t_ccache_report__ccache_report_initial.out | 11 ++-- 4 files changed, 62 insertions(+), 27 deletions(-) diff --git a/bin/verilator_ccache_report b/bin/verilator_ccache_report index 580790230..764accd27 100755 --- a/bin/verilator_ccache_report +++ b/bin/verilator_ccache_report @@ -4,8 +4,11 @@ import argparse import collections +import pathlib import re +from datetime import datetime + parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, @@ -23,22 +26,33 @@ parser.add_argument('-o', metavar="OUTFILE", required=True, help='output file') -parser.add_argument('logfile', - type=argparse.FileType('r'), - help='ccache log file') +parser.add_argument('logdir', type=pathlib.Path, help='log directory') args = parser.parse_args() results = {} +elapsed = {} -for line in args.logfile: - line = line.strip() - match = re.match(r'.*Object file: (.*)$', line) - if match: - obj = match.group(1) - match = re.match(r'.*Result: (.*)$', line) - if match: - results[obj] = match.group(1) + +def toDateTime(s): + return datetime.strptime(s, "%Y-%m-%dT%H:%M:%S.%f") + + +for logfile in args.logdir.iterdir(): + with logfile.open() as fh: + start = None + obj = None + for line in fh: + line = line.strip() + match = re.match(r'\[(\S+)\s.*Object file: (.*)$', line) + if match: + start = toDateTime(match.group(1)) + obj = match.group(2) + match = re.match(r'\[(\S+)\s.*Result: (.*)$', line) + if match: + assert obj is not None + elapsed[obj] = toDateTime(match.group(1)) - start + results[obj] = match.group(2) args.o.write("#" * 80 + "\n") args.o.write("ccache report (from verilator_ccache_report) :\n") @@ -47,19 +61,33 @@ if not results: args.o.write("\nAll object files up to date\n") else: args.o.write("\nCompiled object files:\n") - width = max(len(_) for _ in results) + 1 + wnames = max(len(_) for _ in results) + 1 + wresults = max(len(_) for _ in results.values()) + 1 for k in sorted(results.keys()): - args.o.write("{:{width}} : {}\n".format(k, results[k], width=width)) + args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format( + k, + results[k], + elapsed[k].total_seconds(), + wnames=wnames, + wresults=wresults)) args.o.write("\nSummary:\n") counts = collections.Counter(_ for _ in results.values()) total = sum(counts.values()) - width = max(len(_) for _ in results.values()) + 1 for k in sorted(counts.keys()): c = counts[k] args.o.write("{:{width}}| {} ({:.2%})\n".format(k, c, c / total, - width=width)) + width=wresults)) + + args.o.write("\nLongest:\n") + longest = sorted(list(elapsed.items()), + key=lambda kv: -kv[1].total_seconds()) + for i, (k, v) in enumerate(longest): + args.o.write("{:{width}}| {}s\n".format(k, + v.total_seconds(), + width=wnames)) + if i > 4: break args.o.write("#" * 80 + "\n") diff --git a/include/verilated.mk.in b/include/verilated.mk.in index c183d1d7c..bc543442b 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -269,15 +269,20 @@ ifneq ($(findstring ccache-report,$(MAKECMDGOALS)),) endif # Report ccache behaviour for this invocation of make - export CCACHE_LOGFILE := $(VM_PREFIX).ccache-log + VK_CCACHE_LOGDIR := ccache-logs VK_CCACHE_REPORT := $(VM_PREFIX)__ccache_report.txt - # Truncate logfile - $(shell echo "" > $(CCACHE_LOGFILE)) - # Remove previous report - $(shell rm -f $(VK_CCACHE_REPORT)) + # Remove previous logfiles and report + $(shell rm -rf $(VK_CCACHE_LOGDIR) $(VK_CCACHE_REPORT)) + +$(VK_CCACHE_LOGDIR): + mkdir -p $@ + +$(VK_OBJS): | $(VK_CCACHE_LOGDIR) + +$(VK_OBJS): export CCACHE_LOGFILE=$(VK_CCACHE_LOGDIR)/$@.log $(VK_CCACHE_REPORT): $(VK_OBJS) - $(VERILATOR_CCACHE_REPORT) -o $@ $(CCACHE_LOGFILE) + $(VERILATOR_CCACHE_REPORT) -o $@ $(VK_CCACHE_LOGDIR) .PHONY: ccache-report ccache-report: $(VK_CCACHE_REPORT) diff --git a/test_regress/t/t_ccache_report.pl b/test_regress/t/t_ccache_report.pl index 1e36b8b1a..d874fd27c 100755 --- a/test_regress/t/t_ccache_report.pl +++ b/test_regress/t/t_ccache_report.pl @@ -31,8 +31,7 @@ my $report = "$Self->{obj_dir}/$Self->{VM_PREFIX}__ccache_report.txt"; # We do not actually want to make this test depend on whether the file was # cached or not, so trim the report to ignore actual caching behaviour -run(cmd => ["sed", "-i", "-e", "'s/ : .*/ : IGNORED/; /^Summary/,\$d;'", $report]); - +run(cmd => ["sed", "-i", "-e", "'s/ : .*/ : IGNORED/; /|/s/.*/IGNORED/;'", $report]); files_identical($report, "t/$Self->{name}__ccache_report_initial.out"); # Now rebuild again (should be all up to date) diff --git a/test_regress/t/t_ccache_report__ccache_report_initial.out b/test_regress/t/t_ccache_report__ccache_report_initial.out index 88f2fe542..2a6c77138 100644 --- a/test_regress/t/t_ccache_report__ccache_report_initial.out +++ b/test_regress/t/t_ccache_report__ccache_report_initial.out @@ -2,8 +2,11 @@ ccache report (from verilator_ccache_report) : Compiled object files: -Vt_ccache_report__ALL.o : IGNORED -Vt_ccache_report__main.o : IGNORED -verilated.o : IGNORED -verilated_vcd_c.o : IGNORED +Vt_ccache_report__ALL.o : IGNORED +Summary: +IGNORED + +Longest: +IGNORED +################################################################################ From 24b3816f5e955c14673e5e94d8491d8a74d89fa8 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 9 Jun 2021 21:03:32 +0100 Subject: [PATCH 74/80] Improve distribution of V3Hash/V3Hasher - Better combining, without multiplication, which means a 0 hash value is now allowed. - Do not OR in bottom bits (this was used to avoid a 0 hash but had the side effect of hashing 0 and 1 to the same value, which are actually common inputs. - Hash whole content of V3Number. This does not seem to be noticeable in runtime, but quite often the bottom word can be a special value like zero while the rest of the content varies. --- src/V3Hash.h | 44 ++++++++++++++++++++++++-------------------- src/V3Number.cpp | 7 ++++++- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/V3Hash.h b/src/V3Hash.h index 41a81140c..6bb2963ba 100644 --- a/src/V3Hash.h +++ b/src/V3Hash.h @@ -24,40 +24,44 @@ // V3Hash -- Generic hashing class V3Hash final { - // A 32-bit hash value. A value of 0 is illegal. - uint32_t m_value; + uint32_t m_value; // The 32-bit hash value. public: + // CONSTRUCTORS + V3Hash() + : m_value{0} {} + explicit V3Hash(uint32_t val) + : m_value{val + 0x9e3779b9} {} // This is the same as 'V3Hash() + val' + explicit V3Hash(int32_t val) + : m_value{static_cast(val)} {} + explicit V3Hash(size_t val) + : m_value{static_cast(val)} {} + explicit V3Hash(const std::string& val); + // METHODS uint32_t value() const { return m_value; } // OPERATORS + // Comparisons bool operator==(const V3Hash& rh) const { return m_value == rh.m_value; } bool operator!=(const V3Hash& rh) const { return m_value != rh.m_value; } bool operator<(const V3Hash& rh) const { return m_value < rh.m_value; } - V3Hash operator+(uint32_t value) const { - const uint64_t prod = (static_cast(m_value) * 31) + value; - return V3Hash(static_cast(prod ^ (prod >> 32))); - } - V3Hash operator+(int32_t value) const { return *this + static_cast(value); } - V3Hash operator+(const V3Hash& that) const { return *this + that.m_value; } - V3Hash& operator+=(const V3Hash& that) { - *this = *this + that.m_value; - return *this; + // '+' combines hashes + V3Hash operator+(const V3Hash& that) const { + return V3Hash(m_value ^ (that.m_value + 0x9e3779b9 + (m_value << 6) + (m_value >> 2))); } + V3Hash operator+(uint32_t value) const { return *this + V3Hash(value); } + V3Hash operator+(int32_t value) const { return *this + V3Hash(value); } + V3Hash operator+(size_t value) const { return *this + V3Hash(value); } + V3Hash operator+(const std::string& value) const { return *this + V3Hash(value); } + + // '+=' combines in place + V3Hash& operator+=(const V3Hash& that) { return *this = *this + that; } V3Hash& operator+=(uint32_t value) { return *this += V3Hash(value); } V3Hash& operator+=(int32_t value) { return *this += V3Hash(value); } + V3Hash& operator+=(size_t value) { return *this += V3Hash(value); } V3Hash& operator+=(const std::string& that) { return *this += V3Hash(that); } - - // CONSTRUCTORS - V3Hash() - : m_value{1} {} - explicit V3Hash(uint32_t val) - : m_value{val | 1} {} - explicit V3Hash(int32_t val) - : m_value{static_cast(val)} {} - explicit V3Hash(const std::string& val); }; std::ostream& operator<<(std::ostream& os, const V3Hash& rhs); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index f880996c1..6abe9d4ae 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -24,6 +24,7 @@ #include #include #include +#include constexpr int MAX_SPRINTF_DOUBLE_SIZE = 1100; // Maximum characters with a sprintf %e/%f/%g (really 1079) @@ -883,7 +884,11 @@ string V3Number::toString() const { return str; } -V3Hash V3Number::toHash() const { return V3Hash(m_width * (m_value[0] | 1)); } +V3Hash V3Number::toHash() const { + V3Hash hash(m_width); + for (int i = 0; i < words(); ++i) { hash += m_value[i]; } + return hash; +} uint32_t V3Number::edataWord(int eword) const { UASSERT(!isFourState(), "edataWord with 4-state " << *this); From 7ef9b32faaea94d97715f7e608d4aebed3ec39fb Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 9 Jun 2021 21:42:08 +0100 Subject: [PATCH 75/80] CI: Use separate ccache instances for each job --- .github/workflows/build.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca1b4f3f7..d4581f7eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,6 @@ env: CI_COMMIT: ${{ github.sha }} CCACHE_COMPRESS: 1 CCACHE_DIR: ${{ github.workspace }}/.ccache - CCACHE_MAXSIZE: 2Gi # 2GiB for clang and gcc, 4GiB in total jobs: @@ -31,7 +30,7 @@ jobs: - id: generate name: Run 'generate_matrix.sh' run: | - if [ '${{ github.event_name}}' = 'pull_request' ]; then + if [ '${{ github.event_name }}' = 'pull_request' ]; then matrix='[ "ubuntu-20.04" ]' else matrix='[ "ubuntu-16.04", "ubuntu-18.04", "ubuntu-20.04" ]' @@ -57,7 +56,8 @@ jobs: CI_MAKE_SRC_TARGET: ${{ matrix.debug }} CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cxx }} - CACHE_KEY: ${{ matrix.os }}-${{ matrix.compiler.cc }} + CACHE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.debug }} + CCACHE_MAXSIZE: 256Mi # Per build matrix entry steps: - name: Checkout @@ -77,7 +77,9 @@ jobs: - name: Build run: | + ccache -z ./ci/ci-script.bash + ccache -s tar cvzf verilator-${{ matrix.os}}-${CI_COMMIT}-${{ matrix.compiler.cc }}-${{ matrix.debug }}.tgz ./bin - uses: actions/upload-artifact@v2 @@ -107,7 +109,8 @@ jobs: CI_RUNS_ON: ${{ matrix.os }} CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cxx }} - CACHE_KEY: ${{ matrix.os }}-${{ matrix.compiler.cc }} + CACHE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.suite }} + CCACHE_MAXSIZE: 256Mi # Per build matrix entry steps: - name: Checkout @@ -134,4 +137,7 @@ jobs: - name: Test env: TESTS: ${{ matrix.suite }} - run: ./ci/ci-script.bash + run: | + ccache -z + ./ci/ci-script.bash + ccache -s From 58b4ed09953fb162127b5fb93a08f561d9ea3911 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 9 Jun 2021 22:44:26 +0100 Subject: [PATCH 76/80] CI: Do not limit parallelism Free accounts can run up to 20 jobs, pro ones 40. There does not seem to be a reason to limit ourselves to 8. --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4581f7eb..78d4c60c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,7 +91,6 @@ jobs: needs: [ Matrix, Build ] strategy: fail-fast: false - max-parallel: 8 matrix: os: ${{ fromJson(needs.Matrix.outputs.matrix) }} compiler: From ac19d552b1cfaf72efd30feb96ba2bb0ca72a059 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 9 Jun 2021 21:44:37 +0100 Subject: [PATCH 77/80] CI: Change name and commit message of formatting job The format job actually runs more than just clang-format these days. Change message to hint more directly towards what it does. Change job name to 'format'. --- .github/workflows/{clang-format.yml => format.yml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{clang-format.yml => format.yml} (93%) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/format.yml similarity index 93% rename from .github/workflows/clang-format.yml rename to .github/workflows/format.yml index 88a3c897c..6d6d68887 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/format.yml @@ -1,7 +1,7 @@ # DESCRIPTION: Github actions config # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -name: clang-format +name: format on: push: @@ -38,6 +38,6 @@ jobs: - name: Push run: | if [ -n "$(git status --porcelain)" ]; then - git commit . -m "Apply clang-format" && + git commit . -m "Apply 'make format'" && git push origin fi From d22df4e90756b609a4b9f4cdf66a0e622cf78b18 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Wed, 9 Jun 2021 23:51:03 +0100 Subject: [PATCH 78/80] CI: Add extra dist-vlt shard for better load balancing --- .github/workflows/build.yml | 1 + ci/ci-script.bash | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78d4c60c0..fba21f0da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -99,6 +99,7 @@ jobs: suite: - dist-vlt-0 - dist-vlt-1 + - dist-vlt-2 - vltmt-0 - vltmt-1 runs-on: ${{ matrix.os }} diff --git a/ci/ci-script.bash b/ci/ci-script.bash index 498531eed..70ded6d2c 100755 --- a/ci/ci-script.bash +++ b/ci/ci-script.bash @@ -85,10 +85,13 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then # Run the specified test case $TESTS in dist-vlt-0) - "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=0/2 + "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=0/3 ;; dist-vlt-1) - "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=1/2 + "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=1/3 + ;; + dist-vlt-2) + "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=2/3 ;; vltmt-0) "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2 From 1abd339863f64b7bbcb97f7619dde2381e6b06c1 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 10 Jun 2021 01:04:43 +0100 Subject: [PATCH 79/80] CI: fix caching in coverage build --- .github/workflows/coverage.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 81ce290f8..42c0d40cb 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -13,7 +13,6 @@ env: CI_COMMIT: ${{ github.sha }} CCACHE_COMPRESS: 1 CCACHE_DIR: ${{ github.workspace }}/.ccache - CCACHE_MAXSIZE: 2Gi # 2GiB for clang and gcc, 4GiB in total COVERAGE: 1 jobs: @@ -24,7 +23,8 @@ jobs: env: CI_BUILD_STAGE_NAME: build CI_RUNS_ON: ubuntu-20.04 - CACHE_KEY: ubuntu-20.04-${{ matrix.compiler.cc }}-coverage + CACHE_KEY: coverage-build + CCACHE_MAXSIZE: 512Mi steps: - name: Checkout @@ -37,7 +37,7 @@ jobs: with: path: ${{ github.workspace }}/.ccache key: ${{ env.CACHE_KEY }}-${{ env.cache-name }}-${{ github.sha }} - restore-keys: coverage-${{ env.cache-name }} + restore-keys: ${{ env.CACHE_KEY }}-${{ env.cache-name }} - name: Install packages for build env: @@ -46,7 +46,9 @@ jobs: - name: Build run: | + ccache -z ./ci/ci-script.bash + ccache -s tar cvzf verilator-${CI_COMMIT}-coverage.tgz bin src/obj*/*.o src/obj*/*.gcno - uses: actions/upload-artifact@v2 @@ -80,7 +82,8 @@ jobs: env: CI_BUILD_STAGE_NAME: test CI_RUNS_ON: ubuntu-20.04 - CACHE_KEY: ubuntu-20.04-${{ matrix.compiler.cc }}-coverage + CACHE_KEY: coverage-test-${{ matrix.test }}${{ matrix.num }} + CCACHE_MAXSIZE: 512Mi # Per build matrix entry steps: - name: Checkout @@ -93,7 +96,7 @@ jobs: with: path: ${{ github.workspace }}/.ccache key: ${{ env.CACHE_KEY }}-${{ env.cache-name }}-${{ github.sha }} - restore-keys: coverage-${{ env.cache-name }} + restore-keys: ${{ env.CACHE_KEY }}-${{ env.cache-name }} - uses: actions/download-artifact@v2 @@ -106,4 +109,7 @@ jobs: - name: Test env: TESTS: coverage-${{ matrix.test }}${{ matrix.num }} - run: ./ci/ci-script.bash + run: | + ccache -z + ./ci/ci-script.bash + ccache -s From e3341e9a7ce09592e498b23bf759ef16b09cbcc1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 12 Jun 2021 12:36:03 -0400 Subject: [PATCH 80/80] Verison bump --- Changes | 7 +++++-- configure.ac | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index ecf0750f9..d0d49ab8d 100644 --- a/Changes +++ b/Changes @@ -8,11 +8,12 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! -Verilator 4.203 devel +Verilator 4.204 2021-06-12 ========================== **Minor:** +* Add 'make ccache-report' (#3011). [Geza Lore] * Add --reloop-limit argument (#2943) (#2960). [Geza Lore] * Add --expand-limit argument (#3005). [Julien Margetts] * Add TRACE_THREADS to CMake (#2934). [Jonathan Drolet] @@ -22,6 +23,7 @@ Verilator 4.203 devel * Support ignoring "`pragma protect ..." (#2886). [Udi Finkelstein] * Support --trace-fst for SystemC with CMake (#2927). [Jonathan Drolet] * Update cmake latest C++ Standard Compilation flag (#2951). [Ameya Vikram Singh] +* Prep work towards better ccache hashing/performance. [Geza Lore] * Fix assertion failure in bitOpTree optimization (#2891) (#2899). [Raynard Qiao] * Fix DPI functions not seen as vpiModule (#2893). [Todd Strader] * Fix bounds check in VL_SEL_IWII (#2910). [Krzysztof Bieganski] @@ -38,6 +40,7 @@ Verilator 4.203 devel * Fix unused variable warnings (#2991). [Pieter Kapsenberg] * Fix --protect-ids when using SV classes (#2994). [Geza Lore] * Fix constant function calls with uninit value (#2995). [yanx21] +* Fix Makefiles to support Windows EXEEXT usage (#3008). [Miodrag Milanovic] Verilator 4.202 2021-04-24 @@ -363,7 +366,7 @@ Verilator 4.034 2020-05-03 * Support event data type (with some restrictions). * Support $root. (#2150) [Keyi Zhang] * Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. -* Fix build of fast path tracing code to use OPT_FAST. (#2245) [Geza Lore] +* Add support of --trace-structs for CMake (#2986). [Martin Schmidt] * Fix arrayed instances connecting to slices. (#2263) [Don/engr248] * Fix error on unpacked connecting to packed. (#2288) [Joseph Shaker] * Fix logical not optimization with empty begin. (#2291) [Baltazar Ortiz] diff --git a/configure.ac b/configure.ac index 00fc24e25..ee5043af4 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.203 devel], +AC_INIT([Verilator],[4.204 2021-06-12], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file