Support get_randstate/set_randstate class method function.
This commit is contained in:
parent
250c6950cf
commit
a3640c1767
1
Changes
1
Changes
|
|
@ -18,6 +18,7 @@ Verilator 5.011 devel
|
||||||
|
|
||||||
**Minor:**
|
**Minor:**
|
||||||
|
|
||||||
|
* Support get_randstate/set_randstate class method function.
|
||||||
* Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk]
|
* Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk]
|
||||||
* Fix crash on duplicate imported modules (#3231). [Robert Balas]
|
* Fix crash on duplicate imported modules (#3231). [Robert Balas]
|
||||||
* Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO]
|
* Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO]
|
||||||
|
|
|
||||||
|
|
@ -315,15 +315,28 @@ void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE {
|
||||||
if (VL_COUNTONES_I(m_state[0]) < 10) m_state[0] = ~m_state[0];
|
if (VL_COUNTONES_I(m_state[0]) < 10) m_state[0] = ~m_state[0];
|
||||||
if (VL_COUNTONES_I(m_state[1]) < 10) m_state[1] = ~m_state[1];
|
if (VL_COUNTONES_I(m_state[1]) < 10) m_state[1] = ~m_state[1];
|
||||||
}
|
}
|
||||||
// Unused: void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
|
std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
|
||||||
// Unused: if (VL_LIKELY(state.length() == sizeof(m_state))) {
|
// Though not stated in IEEE, assumption is the string must be printable
|
||||||
// Unused: memcpy(m_state, state.data(), sizeof(m_state));
|
const char* const stateCharsp = reinterpret_cast<const char*>(&m_state);
|
||||||
// Unused: }
|
static_assert(sizeof(m_state) == 16);
|
||||||
// Unused: }
|
std::string result{"R00112233445566770011223344556677"};
|
||||||
// Unused: std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
|
for (int i = 0; i < sizeof(m_state); ++i) {
|
||||||
// Unused: std::string result{reinterpret_cast<const char *>(&m_state), sizeof(m_state)};
|
result[1 + i * 2] = 'a' + ((stateCharsp[i] >> 4) & 15);
|
||||||
// Unused: return result;
|
result[1 + i * 2 + 1] = 'a' + (stateCharsp[i] & 15);
|
||||||
// Unused: }
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
|
||||||
|
if (VL_UNLIKELY((state.length() != 1 + 2 * sizeof(m_state)) || (state[0] != 'R'))) {
|
||||||
|
VL_PRINTF_MT("%%Warning: set_randstate ignored as state string not from get_randstate\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char* const stateCharsp = reinterpret_cast<char*>(&m_state);
|
||||||
|
for (int i = 0; i < sizeof(m_state); ++i) {
|
||||||
|
stateCharsp[i]
|
||||||
|
= (((state[1 + i * 2] - 'a') & 15) << 4) | ((state[1 + i * 2 + 1] - 'a') & 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t vl_sys_rand32() VL_MT_SAFE {
|
static uint32_t vl_sys_rand32() VL_MT_SAFE {
|
||||||
// Return random 32-bits using system library.
|
// Return random 32-bits using system library.
|
||||||
|
|
|
||||||
|
|
@ -161,8 +161,8 @@ public:
|
||||||
VlRNG() VL_MT_SAFE;
|
VlRNG() VL_MT_SAFE;
|
||||||
explicit VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {}
|
explicit VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {}
|
||||||
void srandom(uint64_t n) VL_MT_UNSAFE;
|
void srandom(uint64_t n) VL_MT_UNSAFE;
|
||||||
// Unused: std::string get_randstate() const VL_MT_UNSAFE;
|
std::string get_randstate() const VL_MT_UNSAFE;
|
||||||
// Unused: void set_randstate(const std::string& state) VL_MT_UNSAFE;
|
void set_randstate(const std::string& state) VL_MT_UNSAFE;
|
||||||
uint64_t rand64() VL_MT_UNSAFE;
|
uint64_t rand64() VL_MT_UNSAFE;
|
||||||
// Threadsafe, but requires use on vl_thread_rng
|
// Threadsafe, but requires use on vl_thread_rng
|
||||||
static uint64_t vl_thread_rng_rand64() VL_MT_SAFE;
|
static uint64_t vl_thread_rng_rand64() VL_MT_SAFE;
|
||||||
|
|
|
||||||
|
|
@ -3110,7 +3110,9 @@ private:
|
||||||
}
|
}
|
||||||
} else if (VN_IS(nodep, New) && m_statep->forPrearray()) {
|
} else if (VN_IS(nodep, New) && m_statep->forPrearray()) {
|
||||||
// Resolved in V3Width
|
// Resolved in V3Width
|
||||||
} else if (nodep->name() == "randomize" || nodep->name() == "srandom") {
|
} else if (nodep->name() == "randomize" || nodep->name() == "srandom"
|
||||||
|
|| nodep->name() == "get_randstate"
|
||||||
|
|| nodep->name() == "set_randstate") {
|
||||||
// Resolved in V3Width
|
// Resolved in V3Width
|
||||||
} else if (nodep->dotted() == "") {
|
} else if (nodep->dotted() == "") {
|
||||||
if (nodep->pli()) {
|
if (nodep->pli()) {
|
||||||
|
|
|
||||||
|
|
@ -2812,6 +2812,10 @@ private:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visit(AstCExpr* nodep) override {
|
||||||
|
// Inserted by V3Width only so we know has been resolved
|
||||||
|
userIterateChildren(nodep, WidthVP{SELF, BOTH}.p());
|
||||||
|
}
|
||||||
void visit(AstCMethodHard* nodep) override {
|
void visit(AstCMethodHard* nodep) override {
|
||||||
// Never created before V3Width, so no need to redo it
|
// Never created before V3Width, so no need to redo it
|
||||||
UASSERT_OBJ(nodep->dtypep(), nodep, "CMETHODCALLs should have already been sized");
|
UASSERT_OBJ(nodep->dtypep(), nodep, "CMETHODCALLs should have already been sized");
|
||||||
|
|
@ -2878,7 +2882,7 @@ private:
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) {
|
void methodOkArguments(AstNodeFTaskRef* nodep, int minArg, int maxArg) {
|
||||||
int narg = 0;
|
int narg = 0;
|
||||||
for (AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) {
|
for (AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) {
|
||||||
if (VN_IS(argp, With)) {
|
if (VN_IS(argp, With)) {
|
||||||
|
|
@ -3522,6 +3526,13 @@ private:
|
||||||
processFTaskRefArgs(nodep);
|
processFTaskRefArgs(nodep);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} else if (nodep->name() == "get_randstate" || nodep->name() == "set_randstate") {
|
||||||
|
// See implementations under AstNodeFTaskRef
|
||||||
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'get_randstate'/'set_randstate' called "
|
||||||
|
"on object. Suggest call from inside class.");
|
||||||
|
nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitTrue{}});
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
|
classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -5537,7 +5548,9 @@ private:
|
||||||
// For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
|
// For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
|
||||||
// Function hasn't been widthed, so make it so.
|
// Function hasn't been widthed, so make it so.
|
||||||
UINFO(5, " FTASKREF " << nodep << endl);
|
UINFO(5, " FTASKREF " << nodep << endl);
|
||||||
if (nodep->name() == "randomize" || nodep->name() == "srandom") {
|
if (nodep->name() == "randomize" || nodep->name() == "srandom"
|
||||||
|
|| (!nodep->taskp()
|
||||||
|
&& (nodep->name() == "get_randstate" || nodep->name() == "set_randstate"))) {
|
||||||
// TODO perhaps this should move to V3LinkDot
|
// TODO perhaps this should move to V3LinkDot
|
||||||
if (!m_classp) {
|
if (!m_classp) {
|
||||||
nodep->v3error("Calling implicit class method " << nodep->prettyNameQ()
|
nodep->v3error("Calling implicit class method " << nodep->prettyNameQ()
|
||||||
|
|
@ -5548,8 +5561,35 @@ private:
|
||||||
}
|
}
|
||||||
if (nodep->name() == "randomize") {
|
if (nodep->name() == "randomize") {
|
||||||
nodep->taskp(V3Randomize::newRandomizeFunc(m_classp));
|
nodep->taskp(V3Randomize::newRandomizeFunc(m_classp));
|
||||||
} else {
|
} else if (nodep->name() == "srandom") {
|
||||||
nodep->taskp(V3Randomize::newSRandomFunc(m_classp));
|
nodep->taskp(V3Randomize::newSRandomFunc(m_classp));
|
||||||
|
} else if (nodep->name() == "get_randstate") {
|
||||||
|
methodOkArguments(nodep, 0, 0);
|
||||||
|
m_classp->baseMostClassp()->needRNG(true);
|
||||||
|
v3Global.useRandomizeMethods(true);
|
||||||
|
AstCExpr* const newp
|
||||||
|
= new AstCExpr{nodep->fileline(), "__Vm_rng.get_randstate()", 1, true};
|
||||||
|
newp->dtypeSetString();
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
|
} else if (nodep->name() == "set_randstate") {
|
||||||
|
methodOkArguments(nodep, 1, 1);
|
||||||
|
AstNodeExpr* const expr1p = VN_AS(nodep->pinsp(), Arg)->exprp(); // May edit
|
||||||
|
iterateCheckString(nodep, "LHS", expr1p, BOTH);
|
||||||
|
AstNodeExpr* const exprp = VN_AS(nodep->pinsp(), Arg)->exprp();
|
||||||
|
m_classp->baseMostClassp()->needRNG(true);
|
||||||
|
v3Global.useRandomizeMethods(true);
|
||||||
|
AstCExpr* const newp
|
||||||
|
= new AstCExpr{nodep->fileline(), "__Vm_rng.set_randstate(", 1, true};
|
||||||
|
newp->addExprsp(exprp->unlinkFrBack());
|
||||||
|
newp->addExprsp(new AstText{nodep->fileline(), ")", true});
|
||||||
|
newp->dtypeSetString();
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
UASSERT_OBJ(false, nodep, "Bad case");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
|
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
|
||||||
|
|
|
||||||
|
|
@ -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 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
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2023 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Cls;
|
||||||
|
rand int length;
|
||||||
|
|
||||||
|
function void test;
|
||||||
|
automatic int rand_result, v1, v2;
|
||||||
|
automatic string s;
|
||||||
|
|
||||||
|
// UVM 2023 does a print, so check is ascii
|
||||||
|
$display("get_randstate = '%s'", get_randstate());
|
||||||
|
|
||||||
|
s = get_randstate();
|
||||||
|
|
||||||
|
rand_result = randomize();
|
||||||
|
if (rand_result != 1) $stop;
|
||||||
|
v1 = length;
|
||||||
|
|
||||||
|
set_randstate(s);
|
||||||
|
|
||||||
|
rand_result = randomize();
|
||||||
|
if (rand_result != 1) $stop;
|
||||||
|
v2 = length;
|
||||||
|
|
||||||
|
`ifdef VERILATOR // About half of the other simulators fail at this
|
||||||
|
if (v1 != v2) $stop;
|
||||||
|
`endif
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/);
|
||||||
|
|
||||||
|
automatic int rand_result, v1, v2;
|
||||||
|
automatic string s;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
Cls c;
|
||||||
|
c = new;
|
||||||
|
c.test;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
%Error-UNSUPPORTED: t/t_randstate_obj.v:20:13: Unsupported: 'get_randstate'/'set_randstate' called on object. Suggest call from inside class.
|
||||||
|
: ... In instance t
|
||||||
|
20 | s = c.get_randstate();
|
||||||
|
| ^~~~~~~~~~~~~
|
||||||
|
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||||
|
%Error-UNSUPPORTED: t/t_randstate_obj.v:26:9: Unsupported: 'get_randstate'/'set_randstate' called on object. Suggest call from inside class.
|
||||||
|
: ... In instance t
|
||||||
|
26 | c.set_randstate(s);
|
||||||
|
| ^~~~~~~~~~~~~
|
||||||
|
%Error: Exiting due to
|
||||||
|
|
@ -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 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
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
fails => $Self->{vlt_all},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -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, 2023 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Cls;
|
||||||
|
rand int length;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/);
|
||||||
|
|
||||||
|
automatic int rand_result, v1, v2;
|
||||||
|
automatic string s;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
Cls c;
|
||||||
|
c = new;
|
||||||
|
|
||||||
|
s = c.get_randstate();
|
||||||
|
|
||||||
|
rand_result = c.randomize();
|
||||||
|
if (rand_result != 1) $stop;
|
||||||
|
v1 = c.length;
|
||||||
|
|
||||||
|
c.set_randstate(s);
|
||||||
|
|
||||||
|
rand_result = c.randomize();
|
||||||
|
if (rand_result != 1) $stop;
|
||||||
|
v2 = c.length;
|
||||||
|
|
||||||
|
`ifdef VERILATOR // About half of the other simulators fail at this
|
||||||
|
if (v1 != v2) $stop;
|
||||||
|
`endif
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
%Warning: set_randstate ignored as state string not from get_randstate
|
||||||
|
*-* All Finished *-*
|
||||||
|
|
@ -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 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
|
||||||
|
|
||||||
|
scenarios(vlt => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2023 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Cls;
|
||||||
|
function void test;
|
||||||
|
automatic string s;
|
||||||
|
|
||||||
|
s = get_randstate();
|
||||||
|
// Vlt only result check
|
||||||
|
if (s[0] !== "R") $fatal(2, $sformatf("Bad get_randstate = '%s'", s));
|
||||||
|
|
||||||
|
set_randstate("000bad"); // Bad
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
Cls c;
|
||||||
|
c = new;
|
||||||
|
c.test;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue