From 7dbdb77582551727565b4115369491b38b849011 Mon Sep 17 00:00:00 2001 From: Srinivasan Venkataramanan Date: Fri, 13 Feb 2026 06:59:52 +0530 Subject: [PATCH 1/3] Added support for a new system function to retrieve Seed --- docs/guide/extensions.rst | 9 +++++++++ src/V3AstNodeExpr.h | 20 +++++++++++++++++++- src/V3EmitCFunc.h | 3 +++ src/V3Simulate.h | 3 +++ src/V3Width.cpp | 3 +++ src/verilog.l | 1 + src/verilog.y | 3 ++- test_regress/t/t_get_init_seed.out | 0 test_regress/t/t_get_init_seed.py | 18 ++++++++++++++++++ test_regress/t/t_get_init_seed.v | 26 ++++++++++++++++++++++++++ 10 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 test_regress/t/t_get_init_seed.out create mode 100755 test_regress/t/t_get_init_seed.py create mode 100644 test_regress/t/t_get_init_seed.v diff --git a/docs/guide/extensions.rst b/docs/guide/extensions.rst index 6d764d840..3599de836 100644 --- a/docs/guide/extensions.rst +++ b/docs/guide/extensions.rst @@ -697,3 +697,12 @@ or "`ifdef`"'s may break other tools. following loop at the same statement level should always be fully unrolled by Verilator, ignoring :vlopt:`--unroll-count`. This is similar to clang's ``#pragma clang loop unroll(full)``. + +$get_initial_random_seed() + Returns the initial random seed used for the simulation. This + is the value provided via the :vlopt:`+verilator+seed+\` + runtime option. If no seed is specified, it returns the default + initialization seed (typically 0). + Note that this is NOT in the SystemVerilog IEEE 1800-2023 LRM, but + most commerical simulators support and hence added to Verilator + diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index f228f7ca5..85b435389 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1616,6 +1616,25 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } }; +class AstGetInitialRandomSeed final : public AstNodeExpr { + // Verilog $get_initial_random_seed() + // @astgen +public: + explicit AstGetInitialRandomSeed(FileLine* fl) + : ASTGEN_SUPER_GetInitialRandomSeed(fl) { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_AstGetInitialRandomSeed; + virtual string emitVerilog() override { return "$get_initial_random_seed()"; } + string emitC() final override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual bool isGateOptimizable() const override { return false; } + virtual bool isPredictOptimizable() const override { return true; } + virtual bool isPure() override { return true; } + virtual bool isSystemFunc() const override { return true; } + virtual int instrCount() const override { return INSTR_COUNT_PLI; } + virtual bool sameNode(const AstNode* /*samep*/) const override { return true; } +}; class AstImplication final : public AstNodeExpr { // Verilog Implication Operator // Nonoverlapped "|=>" @@ -5861,5 +5880,4 @@ public: && name() == asamep->name() && dotted() == asamep->dotted()); } }; - #endif // Guard diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index e05785109..9677538ff 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -1340,6 +1340,9 @@ public: / v3Global.rootp()->timeprecision().multiplier())); puts(")"); } + void visit(AstGetInitialRandomSeed* nodep) override { + putns(nodep, "vlSymsp->_vm_contextp__->randSeed()"); + } void visit(AstTimeFormat* nodep) override { putns(nodep, "VL_TIMEFORMAT_IINI("); if (nodep->unitsp()) { diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 27aec9c54..9c2ad02d3 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -1368,6 +1368,9 @@ private: if (jumpingOver()) return; knownBadNodeType(nodep); } + void visit(AstGetInitialRandomSeed* nodep) override { + badNodeType(nodep); + } // ==== // default // These types are definitely not reducible diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ad8607d69..e79084e6a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -500,6 +500,9 @@ class WidthVisitor final : public VNVisitor { void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); } void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); } void visit(AstTimePrecision* nodep) override { nodep->dtypeSetSigned32(); } + void visit(AstGetInitialRandomSeed* nodep) override { + nodep->dtypeSetSigned32(); + } void visit(AstTimeUnit* nodep) override { nodep->replaceWith( new AstConst{nodep->fileline(), AstConst::Signed32{}, nodep->timeunit().powerOfTen()}); diff --git a/src/verilog.l b/src/verilog.l index 6d362e899..57866a227 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -527,6 +527,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$fell" { FL; return yD_FELL; } "$fell_gclk" { FL; return yD_FELL_GCLK; } "$future_gclk" { FL; return yD_FUTURE_GCLK; } + "$get_initial_random_seed" { FL; return yD_GET_INITIAL_RANDOM_SEED; } "$get_coverage" { FL; STR; ERROR_RSVD_WORD("IEEE 1800-2005"); return yaD_PLI; } "$high" { FL; return yD_HIGH; } "$increment" { FL; return yD_INCREMENT; } diff --git a/src/verilog.y b/src/verilog.y index e1a3fcf47..eff8ab9f5 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -775,7 +775,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_WRITEMEMB "$writememb" %token yD_WRITEMEMH "$writememh" %token yD_WRITEO "$writeo" - +%token yD_GET_INITIAL_RANDOM_SEED "$get_initial_random_seed" %token yVL_CLOCKER "/*verilator clocker*/" %token yVL_CLOCK_ENABLE "/*verilator clock_enable*/" %token yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/" @@ -4525,6 +4525,7 @@ system_f_or_t_expr_call: // IEEE: part of system_tf_call (can be tas | yD_TIMEUNIT { $$ = new AstTimeUnit{$1}; } | yD_TIMEUNIT '(' ')' { $$ = new AstTimeUnit{$1}; } | yD_TIMEUNIT '(' idClassSel ')' { $$ = new AstTimeUnit{$1}; DEL($3); } + | yD_GET_INITIAL_RANDOM_SEED parenE { $$ = new AstGetInitialRandomSeed{$1}; } | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::TYPENAME, $3}; } | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC{$1, $5, $3}; } // Arg swap to file first | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_UNPK_DIMENSIONS, $3}; } diff --git a/test_regress/t/t_get_init_seed.out b/test_regress/t/t_get_init_seed.out new file mode 100644 index 000000000..e69de29bb diff --git a/test_regress/t/t_get_init_seed.py b/test_regress/t/t_get_init_seed.py new file mode 100755 index 000000000..872720ddf --- /dev/null +++ b/test_regress/t/t_get_init_seed.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2024 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(fails=False, expect_filename=test.golden_filename) +test.compile(verilator_flags2=['--binary']) +test.execute(all_run_flags=['+verilator+seed+22']) + +test.passes() diff --git a/test_regress/t/t_get_init_seed.v b/test_regress/t/t_get_init_seed.v new file mode 100644 index 000000000..ea0b5d154 --- /dev/null +++ b/test_regress/t/t_get_init_seed.v @@ -0,0 +1,26 @@ +class my_c; + rand bit [5:0] b1; + + function void post_randomize(); + $info ("Random value generated as: 0x%h", b1); + endfunction : post_randomize + +endclass : my_c + +module tb (); + int seed = 1; + + my_c my_c_0; + + initial begin + my_c_0 = new(); + /* verilator lint_off WIDTHTRUNC */ + a1 : assert (my_c_0.randomize()); + #5; + seed = $get_initial_random_seed(); + $display("get_initial_random_seed=%0d", seed); + $write("*-* All Finished *-*\n"); + $finish(2); + end + +endmodule From a555c8204bbad3fb999dd88ebfc1a6ea82794bdd Mon Sep 17 00:00:00 2001 From: github action Date: Sat, 14 Feb 2026 00:58:13 +0000 Subject: [PATCH 2/3] Updated as per review comments - missed in last round, sorry --- docs/guide/extensions.rst | 12 +++++------- src/V3AstNodeExpr.h | 18 +++++++++--------- src/V3EmitCFunc.h | 2 +- src/V3Simulate.h | 4 +--- src/V3Width.cpp | 4 +--- src/verilog.y | 4 ++-- ...t_init_seed.out => t_sys_get_init_seed.out} | 0 ...get_init_seed.py => t_sys_get_init_seed.py} | 0 ...t_get_init_seed.v => t_sys_get_init_seed.v} | 6 ++++++ 9 files changed, 25 insertions(+), 25 deletions(-) rename test_regress/t/{t_get_init_seed.out => t_sys_get_init_seed.out} (100%) rename test_regress/t/{t_get_init_seed.py => t_sys_get_init_seed.py} (100%) rename test_regress/t/{t_get_init_seed.v => t_sys_get_init_seed.v} (69%) diff --git a/docs/guide/extensions.rst b/docs/guide/extensions.rst index 3599de836..9150597f5 100644 --- a/docs/guide/extensions.rst +++ b/docs/guide/extensions.rst @@ -699,10 +699,8 @@ or "`ifdef`"'s may break other tools. to clang's ``#pragma clang loop unroll(full)``. $get_initial_random_seed() - Returns the initial random seed used for the simulation. This - is the value provided via the :vlopt:`+verilator+seed+\` - runtime option. If no seed is specified, it returns the default - initialization seed (typically 0). - Note that this is NOT in the SystemVerilog IEEE 1800-2023 LRM, but - most commerical simulators support and hence added to Verilator - + Returns an integer with the initial random seed used for the simulation. + This is the value provided via the :vlopt:`+verilator+seed+\` + runtime option. If no seed is specified, it returns the default + initialization seed (typically 0). + Note that this is not defined by IEEE 1800-2023, but most simulators support it. diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 85b435389..a27659a32 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1618,22 +1618,21 @@ public: }; class AstGetInitialRandomSeed final : public AstNodeExpr { // Verilog $get_initial_random_seed() - // @astgen public: explicit AstGetInitialRandomSeed(FileLine* fl) : ASTGEN_SUPER_GetInitialRandomSeed(fl) { dtypeSetSigned32(); } ASTGEN_MEMBERS_AstGetInitialRandomSeed; - virtual string emitVerilog() override { return "$get_initial_random_seed()"; } + string emitVerilog() override { return "$get_initial_random_seed()"; } string emitC() final override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return true; } - virtual bool isPure() override { return true; } - virtual bool isSystemFunc() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool sameNode(const AstNode* /*samep*/) const override { return true; } + bool cleanOut() const override { return true; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return true; } + bool isPure() override { return true; } + bool isSystemFunc() const override { return true; } + int instrCount() const override { return INSTR_COUNT_PLI; } + bool sameNode(const AstNode* /*samep*/) const override { return true; } }; class AstImplication final : public AstNodeExpr { // Verilog Implication Operator @@ -5881,3 +5880,4 @@ public: } }; #endif // Guard + diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 9677538ff..f2c6b9af5 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -1341,7 +1341,7 @@ public: puts(")"); } void visit(AstGetInitialRandomSeed* nodep) override { - putns(nodep, "vlSymsp->_vm_contextp__->randSeed()"); + putns(nodep, "vlSymsp->_vm_contextp__->randSeed()"); } void visit(AstTimeFormat* nodep) override { putns(nodep, "VL_TIMEFORMAT_IINI("); diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 9c2ad02d3..506f3e0df 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -1368,9 +1368,7 @@ private: if (jumpingOver()) return; knownBadNodeType(nodep); } - void visit(AstGetInitialRandomSeed* nodep) override { - badNodeType(nodep); - } + void visit(AstGetInitialRandomSeed* nodep) override { badNodeType(nodep); } // ==== // default // These types are definitely not reducible diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e79084e6a..513f4cb89 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -500,9 +500,7 @@ class WidthVisitor final : public VNVisitor { void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); } void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); } void visit(AstTimePrecision* nodep) override { nodep->dtypeSetSigned32(); } - void visit(AstGetInitialRandomSeed* nodep) override { - nodep->dtypeSetSigned32(); - } + void visit(AstGetInitialRandomSeed* nodep) override { nodep->dtypeSetSigned32(); } void visit(AstTimeUnit* nodep) override { nodep->replaceWith( new AstConst{nodep->fileline(), AstConst::Signed32{}, nodep->timeunit().powerOfTen()}); diff --git a/src/verilog.y b/src/verilog.y index eff8ab9f5..db6d78bdd 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -689,6 +689,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_FWRITEB "$fwriteb" %token yD_FWRITEH "$fwriteh" %token yD_FWRITEO "$fwriteo" +%token yD_GET_INITIAL_RANDOM_SEED "$get_initial_random_seed" %token yD_GLOBAL_CLOCK "$global_clock" %token yD_HIGH "$high" %token yD_HYPOT "$hypot" @@ -775,7 +776,6 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_WRITEMEMB "$writememb" %token yD_WRITEMEMH "$writememh" %token yD_WRITEO "$writeo" -%token yD_GET_INITIAL_RANDOM_SEED "$get_initial_random_seed" %token yVL_CLOCKER "/*verilator clocker*/" %token yVL_CLOCK_ENABLE "/*verilator clock_enable*/" %token yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/" @@ -4457,6 +4457,7 @@ system_f_or_t_expr_call: // IEEE: part of system_tf_call (can be tas | yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF{$1, *$5, $3, $6}; } | yD_FSEEK '(' expr ',' expr ',' expr ')' { $$ = new AstFSeek{$1, $3, $5, $7}; } | yD_FTELL '(' expr ')' { $$ = new AstFTell{$1, $3}; } + | yD_GET_INITIAL_RANDOM_SEED parenE { $$ = new AstGetInitialRandomSeed{$1}; } | yD_GLOBAL_CLOCK parenE { $$ = GRAMMARP->createGlobalClockParseRef($1); } | yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, nullptr}; } | yD_HIGH '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, $5}; } @@ -4525,7 +4526,6 @@ system_f_or_t_expr_call: // IEEE: part of system_tf_call (can be tas | yD_TIMEUNIT { $$ = new AstTimeUnit{$1}; } | yD_TIMEUNIT '(' ')' { $$ = new AstTimeUnit{$1}; } | yD_TIMEUNIT '(' idClassSel ')' { $$ = new AstTimeUnit{$1}; DEL($3); } - | yD_GET_INITIAL_RANDOM_SEED parenE { $$ = new AstGetInitialRandomSeed{$1}; } | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::TYPENAME, $3}; } | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC{$1, $5, $3}; } // Arg swap to file first | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_UNPK_DIMENSIONS, $3}; } diff --git a/test_regress/t/t_get_init_seed.out b/test_regress/t/t_sys_get_init_seed.out similarity index 100% rename from test_regress/t/t_get_init_seed.out rename to test_regress/t/t_sys_get_init_seed.out diff --git a/test_regress/t/t_get_init_seed.py b/test_regress/t/t_sys_get_init_seed.py similarity index 100% rename from test_regress/t/t_get_init_seed.py rename to test_regress/t/t_sys_get_init_seed.py diff --git a/test_regress/t/t_get_init_seed.v b/test_regress/t/t_sys_get_init_seed.v similarity index 69% rename from test_regress/t/t_get_init_seed.v rename to test_regress/t/t_sys_get_init_seed.v index ea0b5d154..2db9a1145 100644 --- a/test_regress/t/t_get_init_seed.v +++ b/test_regress/t/t_sys_get_init_seed.v @@ -1,3 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Srinivasan Venkataramanan +// SPDX-License-Identifier: CC0-1.0 + class my_c; rand bit [5:0] b1; From 2f8bdb0008cb4a24c67a61ecef6869a6e3192967 Mon Sep 17 00:00:00 2001 From: github action Date: Sun, 15 Feb 2026 19:01:53 +0000 Subject: [PATCH 3/3] Apply 'make format' --- src/V3AstNodeExpr.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index a27659a32..7b88d8134 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -5880,4 +5880,3 @@ public: } }; #endif // Guard -