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:**
|
||||
|
||||
* Support get_randstate/set_randstate class method function.
|
||||
* Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk]
|
||||
* Fix crash on duplicate imported modules (#3231). [Robert Balas]
|
||||
* 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[1]) < 10) m_state[1] = ~m_state[1];
|
||||
}
|
||||
// Unused: void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE {
|
||||
// Unused: if (VL_LIKELY(state.length() == sizeof(m_state))) {
|
||||
// Unused: memcpy(m_state, state.data(), sizeof(m_state));
|
||||
// Unused: }
|
||||
// Unused: }
|
||||
// Unused: std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
|
||||
// Unused: std::string result{reinterpret_cast<const char *>(&m_state), sizeof(m_state)};
|
||||
// Unused: return result;
|
||||
// Unused: }
|
||||
std::string VlRNG::get_randstate() const VL_MT_UNSAFE {
|
||||
// Though not stated in IEEE, assumption is the string must be printable
|
||||
const char* const stateCharsp = reinterpret_cast<const char*>(&m_state);
|
||||
static_assert(sizeof(m_state) == 16);
|
||||
std::string result{"R00112233445566770011223344556677"};
|
||||
for (int i = 0; i < sizeof(m_state); ++i) {
|
||||
result[1 + i * 2] = 'a' + ((stateCharsp[i] >> 4) & 15);
|
||||
result[1 + i * 2 + 1] = 'a' + (stateCharsp[i] & 15);
|
||||
}
|
||||
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 {
|
||||
// Return random 32-bits using system library.
|
||||
|
|
|
|||
|
|
@ -161,8 +161,8 @@ public:
|
|||
VlRNG() VL_MT_SAFE;
|
||||
explicit VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {}
|
||||
void srandom(uint64_t n) VL_MT_UNSAFE;
|
||||
// Unused: std::string get_randstate() const VL_MT_UNSAFE;
|
||||
// Unused: void set_randstate(const std::string& state) VL_MT_UNSAFE;
|
||||
std::string get_randstate() const VL_MT_UNSAFE;
|
||||
void set_randstate(const std::string& state) VL_MT_UNSAFE;
|
||||
uint64_t rand64() VL_MT_UNSAFE;
|
||||
// Threadsafe, but requires use on vl_thread_rng
|
||||
static uint64_t vl_thread_rng_rand64() VL_MT_SAFE;
|
||||
|
|
|
|||
|
|
@ -3110,7 +3110,9 @@ private:
|
|||
}
|
||||
} else if (VN_IS(nodep, New) && m_statep->forPrearray()) {
|
||||
// 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
|
||||
} else if (nodep->dotted() == "") {
|
||||
if (nodep->pli()) {
|
||||
|
|
|
|||
|
|
@ -2812,6 +2812,10 @@ private:
|
|||
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 {
|
||||
// Never created before V3Width, so no need to redo it
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep, "CMETHODCALLs should have already been sized");
|
||||
|
|
@ -2878,7 +2882,7 @@ private:
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) {
|
||||
void methodOkArguments(AstNodeFTaskRef* nodep, int minArg, int maxArg) {
|
||||
int narg = 0;
|
||||
for (AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) {
|
||||
if (VN_IS(argp, With)) {
|
||||
|
|
@ -3522,6 +3526,13 @@ private:
|
|||
processFTaskRefArgs(nodep);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -5537,7 +5548,9 @@ private:
|
|||
// For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
|
||||
// Function hasn't been widthed, so make it so.
|
||||
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
|
||||
if (!m_classp) {
|
||||
nodep->v3error("Calling implicit class method " << nodep->prettyNameQ()
|
||||
|
|
@ -5548,8 +5561,35 @@ private:
|
|||
}
|
||||
if (nodep->name() == "randomize") {
|
||||
nodep->taskp(V3Randomize::newRandomizeFunc(m_classp));
|
||||
} else {
|
||||
} else if (nodep->name() == "srandom") {
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -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