diff --git a/Changes b/Changes index 3377a875b..10f50d405 100644 --- a/Changes +++ b/Changes @@ -27,7 +27,8 @@ Verilator 4.215 devel * Fix display of empty string constant (#3207). [Julie Schwartz] * Fix incorrect width after and-or optimization (#3208). [Julie Schwartz] * Fix $fopen etc on integer arrays (#3214). [adrienlemasle] -* Fix %0 format on $value$plusargs. +* Fix $size on dynamic strings (#3216). +* Fix %0 format on $value$plusargs (#3217). Verilator 4.214 2021-10-17 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index efb66f75b..15df19767 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1351,7 +1351,8 @@ private: case AstAttrType::DIM_RIGHT: case AstAttrType::DIM_SIZE: { UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression"); - if (VN_IS(nodep->fromp()->dtypep(), QueueDType)) { + AstNodeDType* const dtypep = nodep->fromp()->dtypep(); + if (VN_IS(dtypep, QueueDType)) { switch (nodep->attrType()) { case AstAttrType::DIM_SIZE: { AstNode* const newp = new AstCMethodHard( @@ -1398,26 +1399,34 @@ private: default: nodep->v3error("Unhandled attribute type"); } } else { - std::pair dimpair - = nodep->fromp()->dtypep()->skipRefp()->dimensions(true); - uint32_t msbdim = dimpair.first + dimpair.second; + const std::pair dimpair = dtypep->skipRefp()->dimensions(true); + const uint32_t msbdim = dimpair.first + dimpair.second; if (!nodep->dimp() || msbdim < 1) { - const int dim = 1; - AstConst* const newp = dimensionValue( - nodep->fileline(), nodep->fromp()->dtypep(), nodep->attrType(), dim); - nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + if (VN_IS(dtypep, BasicDType) && dtypep->basicp()->isString()) { + // IEEE undocumented but $bits(string) must give length(string) * 8 + AstNode* const newp = new AstShiftL{ + nodep->fileline(), + new AstLenN{nodep->fileline(), nodep->fromp()->unlinkFrBack()}, + new AstConst{nodep->fileline(), 3}, // * 8 + 32}; + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { + const int dim = 1; + AstConst* const newp + = dimensionValue(nodep->fileline(), dtypep, nodep->attrType(), dim); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } } else if (VN_IS(nodep->dimp(), Const)) { const int dim = VN_AS(nodep->dimp(), Const)->toSInt(); - AstConst* const newp = dimensionValue( - nodep->fileline(), nodep->fromp()->dtypep(), nodep->attrType(), dim); + AstConst* const newp + = dimensionValue(nodep->fileline(), dtypep, nodep->attrType(), dim); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { // Need a runtime lookup table. Yuk. - UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, - "Unsized expression"); - AstVar* const varp - = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType(), msbdim); + UASSERT_OBJ(nodep->fromp() && dtypep, nodep, "Unsized expression"); + AstVar* const varp = dimensionVarp(dtypep, nodep->attrType(), msbdim); AstNode* const dimp = nodep->dimp()->unlinkFrBack(); AstVarRef* const varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); diff --git a/test_regress/t/t_string_size.out b/test_regress/t/t_string_size.out new file mode 100644 index 000000000..cd674d097 --- /dev/null +++ b/test_regress/t/t_string_size.out @@ -0,0 +1,4 @@ +>< == >< +>< == >< +> < == > < +*-* All Finished *-* diff --git a/test_regress/t/t_string_size.pl b/test_regress/t/t_string_size.pl new file mode 100755 index 000000000..03b63c1a0 --- /dev/null +++ b/test_regress/t/t_string_size.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 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, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_string_size.v b/test_regress/t/t_string_size.v new file mode 100644 index 000000000..f9d87caa3 --- /dev/null +++ b/test_regress/t/t_string_size.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 + +module t; + parameter string ES = ""; + parameter EI = ""; // B is an integer of width 8 + parameter string OS = "O"; + parameter OI = "O"; // B is an integer of width 8 + + initial begin + $display(">< == >%s<", ""); + $display(">< == >%s<", ES); + $display("> < == >%s<", EI); + + if ($bits("") != 0) $stop; + if ($bits("A") != 8) $stop; + if ($bits(ES) != 0) $stop; + if ($bits(OS) != 8) $stop; + if ($bits(OI) != 8) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule