forked from github/verilator
Fix empty string literals converting to string types (#3774).
This commit is contained in:
parent
054b792021
commit
f4be3d5d2b
1
Changes
1
Changes
@ -27,6 +27,7 @@ Verilator 5.003 devel
|
|||||||
* Fix tracing parameters overridden with -G (#3723). [Iztok Jeras]
|
* Fix tracing parameters overridden with -G (#3723). [Iztok Jeras]
|
||||||
* Fix wait 0.
|
* Fix wait 0.
|
||||||
* Fix comparing ranged slices of unpacked arrays.
|
* Fix comparing ranged slices of unpacked arrays.
|
||||||
|
* Fix empty string literals converting to string types (#3774). [miree]
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.002 2022-10-29
|
Verilator 5.002 2022-10-29
|
||||||
|
@ -1812,16 +1812,14 @@ std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_MT_SAFE {
|
|||||||
char destout[VL_VALUE_STRING_MAX_CHARS + 1];
|
char destout[VL_VALUE_STRING_MAX_CHARS + 1];
|
||||||
const int obits = lwords * VL_EDATASIZE;
|
const int obits = lwords * VL_EDATASIZE;
|
||||||
int lsb = obits - 1;
|
int lsb = obits - 1;
|
||||||
bool start = true;
|
|
||||||
char* destp = destout;
|
char* destp = destout;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
for (; lsb >= 0; --lsb) {
|
for (; lsb >= 0; --lsb) {
|
||||||
lsb = (lsb / 8) * 8; // Next digit
|
lsb = (lsb / 8) * 8; // Next digit
|
||||||
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
||||||
if (!start || charval) {
|
if (charval) {
|
||||||
*destp++ = (charval == 0) ? ' ' : charval;
|
*destp++ = static_cast<char>(charval);
|
||||||
++len;
|
++len;
|
||||||
start = false; // Drop leading 0s
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::string{destout, len};
|
return std::string{destout, len};
|
||||||
|
@ -100,15 +100,19 @@ void V3Number::v3errorEndFatal(const std::ostringstream& str) const VL_MT_SAFE {
|
|||||||
|
|
||||||
V3Number::V3Number(VerilogStringLiteral, AstNode* nodep, const string& str) {
|
V3Number::V3Number(VerilogStringLiteral, AstNode* nodep, const string& str) {
|
||||||
// Create a number using a verilog string as the value, thus 8 bits per character.
|
// Create a number using a verilog string as the value, thus 8 bits per character.
|
||||||
init(nodep, std::max<int>(str.length() * 8, 1));
|
if (str.empty()) { // IEEE 1800-2017 11.10.3 "" = "\000"
|
||||||
m_data.m_fromString = true;
|
init(nodep, 8);
|
||||||
for (unsigned pos = 0; pos < str.length(); ++pos) {
|
} else {
|
||||||
const int topos = str.length() - 1 - pos;
|
init(nodep, std::max<int>(str.length() * 8, 1));
|
||||||
ValueAndX& v = m_data.num()[topos / 4];
|
for (unsigned pos = 0; pos < str.length(); ++pos) {
|
||||||
for (int bit = 0; bit < 8; ++bit) {
|
const int topos = str.length() - 1 - pos;
|
||||||
if (str[pos] & (1UL << bit)) { v.m_value |= (1UL << (bit + (topos % 4) * 8)); }
|
ValueAndX& v = m_data.num()[topos / 4];
|
||||||
|
for (int bit = 0; bit < 8; ++bit) {
|
||||||
|
if (str[pos] & (1UL << bit)) { v.m_value |= (1UL << (bit + (topos % 4) * 8)); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_data.m_fromString = true;
|
||||||
opCleanThis(true);
|
opCleanThis(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,18 +952,15 @@ int64_t V3Number::toSQuad() const {
|
|||||||
|
|
||||||
string V3Number::toString() const {
|
string V3Number::toString() const {
|
||||||
UASSERT(!isFourState(), "toString with 4-state " << *this);
|
UASSERT(!isFourState(), "toString with 4-state " << *this);
|
||||||
// Spec says always drop leading zeros, this isn't quite right, we space pad.
|
// IEEE says \000 are removed
|
||||||
|
// If used to print a %s space padding is still required after call to here
|
||||||
if (isString()) return m_data.str();
|
if (isString()) return m_data.str();
|
||||||
int bit = width() - 1;
|
int bit = width() - 1;
|
||||||
bool start = true;
|
while ((bit % 8) != 7) ++bit;
|
||||||
while ((bit % 8) != 7) bit++;
|
std::string str;
|
||||||
string str;
|
|
||||||
for (; bit >= 0; bit -= 8) {
|
for (; bit >= 0; bit -= 8) {
|
||||||
const int v = bitsValue(bit - 7, 8);
|
const int v = bitsValue(bit - 7, 8);
|
||||||
if (!start || v) {
|
if (v) str += static_cast<char>(v);
|
||||||
str += static_cast<char>((v == 0) ? ' ' : v);
|
|
||||||
start = false; // Drop leading 0s
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -374,7 +374,15 @@ private:
|
|||||||
void visit(AstRealToBits* nodep) override { visit_Ou64_Lr(nodep); }
|
void visit(AstRealToBits* nodep) override { visit_Ou64_Lr(nodep); }
|
||||||
|
|
||||||
// Output integer, input string
|
// Output integer, input string
|
||||||
void visit(AstLenN* nodep) override { visit_Os32_string(nodep); }
|
void visit(AstLenN* nodep) override {
|
||||||
|
// Widths: 32 bit out
|
||||||
|
UASSERT_OBJ(nodep->lhsp(), nodep, "For unary ops only!");
|
||||||
|
if (m_vup->prelim()) {
|
||||||
|
// See similar handling in visit_cmp_eq_gt where created
|
||||||
|
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
|
||||||
|
nodep->dtypeSetSigned32();
|
||||||
|
}
|
||||||
|
}
|
||||||
void visit(AstPutcN* nodep) override {
|
void visit(AstPutcN* nodep) override {
|
||||||
// CALLER: str.putc()
|
// CALLER: str.putc()
|
||||||
UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!");
|
UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!");
|
||||||
@ -5556,17 +5564,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit_Os32_string(AstNodeUniop* nodep) {
|
|
||||||
// CALLER: LenN
|
|
||||||
// Widths: 32 bit out
|
|
||||||
UASSERT_OBJ(nodep->lhsp(), nodep, "For unary ops only!");
|
|
||||||
if (m_vup->prelim()) {
|
|
||||||
// See similar handling in visit_cmp_eq_gt where created
|
|
||||||
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
|
|
||||||
nodep->dtypeSetSigned32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit_negate_not(AstNodeUniop* nodep, bool real_ok) {
|
void visit_negate_not(AstNodeUniop* nodep, bool real_ok) {
|
||||||
// CALLER: (real_ok=false) Not
|
// CALLER: (real_ok=false) Not
|
||||||
// CALLER: (real_ok=true) Negate - allow real numbers
|
// CALLER: (real_ok=true) Negate - allow real numbers
|
||||||
|
@ -5363,15 +5363,8 @@ str<strp>: // yaSTRING but with \{escapes} need decoded
|
|||||||
|
|
||||||
strAsInt<nodeExprp>:
|
strAsInt<nodeExprp>:
|
||||||
yaSTRING
|
yaSTRING
|
||||||
{ if ($1->empty()) {
|
{ // Numeric context, so IEEE 1800-2017 11.10.3 "" is a "\000"
|
||||||
// else "" is not representable as number as is width 0
|
$$ = new AstConst{$<fl>1, AstConst::VerilogStringLiteral{}, GRAMMARP->deQuote($<fl>1, *$1)}; }
|
||||||
// TODO all strings should be represented this way
|
|
||||||
// until V3Width converts as/if needed to a numerical constant
|
|
||||||
$$ = new AstConst{$<fl>1, AstConst::String{}, GRAMMARP->deQuote($<fl>1, *$1)};
|
|
||||||
} else {
|
|
||||||
$$ = new AstConst{$<fl>1, AstConst::VerilogStringLiteral{}, GRAMMARP->deQuote($<fl>1, *$1)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
strAsIntIgnore<nodeExprp>: // strAsInt, but never matches for when expr shouldn't parse strings
|
strAsIntIgnore<nodeExprp>: // strAsInt, but never matches for when expr shouldn't parse strings
|
||||||
|
@ -65,7 +65,7 @@ hello, from a concatenated string.
|
|||||||
hello, from a concatenated format string [0].
|
hello, from a concatenated format string [0].
|
||||||
extra argument: 0
|
extra argument: 0
|
||||||
0 : pre argument after
|
0 : pre argument after
|
||||||
empty: ><
|
empty: > <
|
||||||
[0] Embedded tab ' ' and <#013> return
|
[0] Embedded tab ' ' and <#013> return
|
||||||
[0] Embedded
|
[0] Embedded
|
||||||
multiline
|
multiline
|
||||||
|
4
test_regress/t/t_string_dyn_num.out
Normal file
4
test_regress/t/t_string_dyn_num.out
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
istr=' ' istr%0=' ' sstr=''
|
||||||
|
istr=' A ' istr%0='A ' sstr='A'
|
||||||
|
istr='B A ' istr%0='B A ' sstr='BA'
|
||||||
|
*-* All Finished *-*
|
22
test_regress/t/t_string_dyn_num.pl
Executable file
22
test_regress/t/t_string_dyn_num.pl
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2022 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
69
test_regress/t/t_string_dyn_num.v
Normal file
69
test_regress/t/t_string_dyn_num.v
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// Use this file as a template for submitting bugs, etc.
|
||||||
|
// This module takes a single clock input, and should either
|
||||||
|
// $write("*-* All Finished *-*\n");
|
||||||
|
// $finish;
|
||||||
|
// on success, or $stop.
|
||||||
|
//
|
||||||
|
// The code as shown applies a random vector to the Test
|
||||||
|
// module, then calculates a CRC on the Test module's outputs.
|
||||||
|
//
|
||||||
|
// **If you do not wish for your code to be released to the public
|
||||||
|
// please note it here, otherwise:**
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2022 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc = 0;
|
||||||
|
|
||||||
|
reg [31:0] istr;
|
||||||
|
string sstr;
|
||||||
|
string v;
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] cyc==%0d istr='%s' sstr='%s'\n", $time, cyc, istr, sstr);
|
||||||
|
`endif
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
sstr <= string'(istr); // Note takes another cycle
|
||||||
|
if (cyc < 10) begin
|
||||||
|
istr <= 32'h00_00_00_00;
|
||||||
|
end
|
||||||
|
else if (cyc == 13) begin
|
||||||
|
// These displays are needed to check padding of %s
|
||||||
|
$display("istr='%s' istr%%0='%0s' sstr='%s'", istr, istr, sstr);
|
||||||
|
if (sstr.len() != 0) $stop;
|
||||||
|
if (sstr != "") $stop;
|
||||||
|
end
|
||||||
|
else if (cyc == 20) begin
|
||||||
|
istr <= 32'h00_00_41_00;
|
||||||
|
end
|
||||||
|
else if (cyc == 23) begin
|
||||||
|
$display("istr='%s' istr%%0='%0s' sstr='%s'", istr, istr, sstr);
|
||||||
|
if (sstr.len() != 1) $stop;
|
||||||
|
if (sstr != "A") $stop;
|
||||||
|
end
|
||||||
|
else if (cyc == 30) begin
|
||||||
|
istr <= 32'h42_00_41_00;
|
||||||
|
end
|
||||||
|
else if (cyc == 33) begin
|
||||||
|
$display("istr='%s' istr%%0='%0s' sstr='%s'", istr, istr, sstr);
|
||||||
|
if (sstr.len() != 2) $stop;
|
||||||
|
if (sstr != "BA") $stop;
|
||||||
|
end
|
||||||
|
else if (cyc == 99) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
@ -1,4 +1,7 @@
|
|||||||
|
> < == >< (or > < also legal)
|
||||||
|
> < == >< (or > < also legal)
|
||||||
|
> < == > <
|
||||||
|
> < == > <
|
||||||
|
> < == > <
|
||||||
>< == ><
|
>< == ><
|
||||||
>< == ><
|
|
||||||
> < == > <
|
|
||||||
*-* All Finished *-*
|
*-* All Finished *-*
|
||||||
|
@ -4,41 +4,84 @@
|
|||||||
// any use, without warranty, 2021 by wilson Snyder.
|
// any use, without warranty, 2021 by wilson Snyder.
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
module t;
|
module t(/*AUTOARG*/
|
||||||
parameter string ES = "";
|
// Outputs
|
||||||
parameter EI = ""; // B is an integer of width 8
|
outempty64
|
||||||
|
);
|
||||||
|
output [63:0] outempty64;
|
||||||
|
|
||||||
parameter string OS = "O";
|
parameter string OS = "O";
|
||||||
parameter OI = "O"; // B is an integer of width 8
|
parameter OI = "O"; // B is an integer of width 8
|
||||||
|
|
||||||
|
// verilator lint_off WIDTH
|
||||||
|
parameter string EMPTYS = "";
|
||||||
|
parameter EMPTYI = ""; // B is an integer of width 8
|
||||||
|
parameter bit [23:0] EMPTY24 = "";
|
||||||
|
parameter bit [63:0] EMPTY64 = "";
|
||||||
|
// verilator lint_on WIDTH
|
||||||
parameter bit [31:0] NEST = "NEST";
|
parameter bit [31:0] NEST = "NEST";
|
||||||
parameter bit [31:0] TEST = "TEST";
|
parameter bit [31:0] TEST = "TEST";
|
||||||
bit [31:0] rest;
|
|
||||||
string s;
|
string s;
|
||||||
|
|
||||||
|
// verilator lint_off WIDTH
|
||||||
|
assign outempty64 = "";
|
||||||
|
// verilator lint_on WIDTH
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
$display(">< == >%s<", "");
|
// IEEE: "Leading 0s are never printed" but that does not mean spaces are not
|
||||||
$display(">< == >%s<", ES);
|
$display(">%s< == >< (or > < also legal)", "\000");
|
||||||
$display("> < == >%s<", EI);
|
$display(">%s< == >< (or > < also legal)", "");
|
||||||
|
$display(">%s< == > <", 32'h0);
|
||||||
|
|
||||||
|
// Numeric context, so IEEE 1800-2017 11.10.3 "" is a "\000"
|
||||||
|
if ($bits("") != 8) $stop;
|
||||||
|
if ("" != "\000") $stop;
|
||||||
|
|
||||||
if ($bits("") != 0) $stop;
|
|
||||||
if ($bits("A") != 8) $stop;
|
if ($bits("A") != 8) $stop;
|
||||||
if ($bits(ES) != 0) $stop;
|
|
||||||
if ($bits(EI) != 8) $stop;
|
|
||||||
if ($bits(OS) != 8) $stop;
|
|
||||||
if ($bits(OI) != 8) $stop;
|
|
||||||
|
|
||||||
if (ES == "TEST") $stop; // Illegal in some simulators as not both strings
|
s = "";
|
||||||
if (EI == "TEST") $stop;
|
if (s.len != 0) $stop;
|
||||||
|
|
||||||
|
// IEEE 1800-2017 6.16 "\000" assigned to string is ignored
|
||||||
|
s = "\000yo\000";
|
||||||
|
if (s.len != 2) $stop;
|
||||||
|
if (s != "yo") $stop;
|
||||||
|
|
||||||
|
if ($bits(EMPTYI) != 8) $stop;
|
||||||
|
if (EMPTYI != "\000") $stop;
|
||||||
|
// verilator lint_off WIDTH
|
||||||
|
if (EMPTYI == "TEST") $stop;
|
||||||
|
if (EMPTYI == TEST) $stop;
|
||||||
|
// verilator lint_on WIDTH
|
||||||
|
|
||||||
|
if ($bits(EMPTY24) != 24) $stop;
|
||||||
|
if (EMPTY24 != 0) $stop;
|
||||||
|
$display(">%s< == > <", EMPTY24);
|
||||||
|
|
||||||
|
if ($bits(EMPTY64) != 64) $stop;
|
||||||
|
if (EMPTY64 != 0) $stop;
|
||||||
|
$display(">%s< == > <", EMPTY64);
|
||||||
|
|
||||||
|
if ($bits(EMPTYS) != 0) $stop;
|
||||||
|
if (EMPTYS == "TEST") $stop; // Illegal in some simulators as not both strings
|
||||||
|
if (EMPTYS == TEST) $stop;
|
||||||
|
$display(">%s< == ><", EMPTYS);
|
||||||
|
|
||||||
|
if ($bits(OS) != 8) $stop;
|
||||||
|
if (OS != "O") $stop;
|
||||||
if (OS == "TEST") $stop; // Illegal in some simulators as not both strings
|
if (OS == "TEST") $stop; // Illegal in some simulators as not both strings
|
||||||
|
if (OS == TEST) $stop;
|
||||||
|
|
||||||
|
if ($bits(OI) != 8) $stop;
|
||||||
|
if (OI != "O") $stop;
|
||||||
|
|
||||||
// verilator lint_off WIDTH
|
// verilator lint_off WIDTH
|
||||||
if (OI == "TEST") $stop;
|
if (OI == "TEST") $stop;
|
||||||
if (rest == "TEST") $stop;
|
|
||||||
|
|
||||||
if (ES == TEST) $stop;
|
|
||||||
if (EI == TEST) $stop;
|
|
||||||
if (OS == TEST) $stop;
|
|
||||||
if (OI == TEST) $stop;
|
if (OI == TEST) $stop;
|
||||||
if (rest == TEST) $stop;
|
// verilator lint_on WIDTH
|
||||||
|
|
||||||
|
if ($bits(outempty64) != 64) $stop;
|
||||||
|
if (outempty64 != 64'h00_00_00_00_00_00_00_00) $stop;
|
||||||
|
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
|
Loading…
Reference in New Issue
Block a user