diff --git a/Changes b/Changes index cbee5811d..674cab1c3 100644 --- a/Changes +++ b/Changes @@ -30,6 +30,7 @@ Verilator 4.217 devel * Fix VL_STREAML_FAST_QQI with 64 bit left-hand-side (#3232) (#3235) * Fix $sformat of inputs/outputs (#3236). [Adrien Le Masle] * Fix associative array foreach loop (#3229). +* Fix $random not updating seed (#3238). [Julie Schwartz] * Fix splitting of _eval and other top level functions. [Geza Lore, Shunyao CAD] diff --git a/include/verilated.cpp b/include/verilated.cpp index a9c3907ef..44e131e11 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -337,11 +337,17 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE { return outwp; } -IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE { +IData VL_RANDOM_SEEDED_II(IData& seedr) VL_MT_SAFE { + // $random - seed is a new seed to apply, then we return new seed + Verilated::threadContextp()->randSeed(static_cast(seedr)); + seedr = VL_RANDOM_I(); + return VL_RANDOM_I(); +} +IData VL_URANDOM_SEEDED_II(IData seed) VL_MT_SAFE { + // $urandom - seed is a new seed to apply Verilated::threadContextp()->randSeed(static_cast(seed)); return VL_RANDOM_I(); } - IData VL_RAND_RESET_I(int obits) VL_MT_SAFE { if (Verilated::threadContextp()->randReset() == 0) return 0; IData data = ~0; diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index a40414a7e..d2cac8ac1 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -85,7 +85,8 @@ extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE; inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); } inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); } extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); -extern IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE; +extern IData VL_RANDOM_SEEDED_II(IData& seedr) VL_MT_SAFE; +extern IData VL_URANDOM_SEEDED_II(IData seed) VL_MT_SAFE; inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) { const vluint64_t rnd = vl_rand64(); if (VL_LIKELY(hi > lo)) { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 9b66893d4..aff7fea17 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5577,10 +5577,11 @@ 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(%li)" - : isWide() ? "VL_RANDOM_%nq(%nw, %P)" // - : "VL_RANDOM_%nq()"; + return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" + : seedp() ? (urandom() ? "VL_URANDOM_SEEDED_%nq%lq(%li)" + : "VL_RANDOM_SEEDED_%nq%lq(%li)") + : isWide() ? "VL_RANDOM_%nq(%nw, %P)" // + : "VL_RANDOM_%nq()"; } virtual bool cleanOut() const override { return false; } virtual bool isGateOptimizable() const override { return false; } diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index a480d10e1..541b1334c 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -183,6 +183,13 @@ private: VL_RESTORER(m_setRefLvalue); iterateChildren(nodep); } + virtual void visit(AstRand* nodep) override { + VL_RESTORER(m_setRefLvalue); + { + if (!nodep->urandom()) m_setRefLvalue = VAccess::WRITE; + iterateAndNextNull(nodep->seedp()); + } + } virtual void visit(AstReadMem* nodep) override { VL_RESTORER(m_setRefLvalue); { diff --git a/test_regress/t/t_sys_rand_seed.v b/test_regress/t/t_sys_rand_seed.v index 53dc8eee5..c26867a61 100644 --- a/test_regress/t/t_sys_rand_seed.v +++ b/test_regress/t/t_sys_rand_seed.v @@ -6,16 +6,39 @@ module t; + integer seeda; + integer seedb; + integer seedc; int valuea; int valueb; + int valuec; initial begin - valuea = $random(10); - valueb = $random(10); + // $random unlike $urandom updates the value if given + seeda = 10; + valuea = $random(seeda); + seedb = 10; + valueb = $random(seedb); if (valuea !== valueb) $stop; + + seeda = 10; + valuea = $random(seeda); + seedb = seeda; + valueb = $random(seedb); + seedc = seedb; + valuec = $random(seedc); + if (valuea == valueb && valueb == valuec) $stop; // May false fail 1 in 1^64 + if (seeda == seedb && seedb == seedc) $stop; // May false fail 1 in 1^64 + valuea = $urandom(10); valueb = $urandom(10); if (valuea !== valueb) $stop; + + valuea = $urandom(10); + valueb = $urandom(); + valuec = $urandom(); + if (valuea == valueb && valueb == valuec) $stop; // May false fail 1 in 1^64 + $write("*-* All Finished *-*\n"); $finish; end