From 947b6fd23ff9d8acc5727432cc40d76ba7c30889 Mon Sep 17 00:00:00 2001 From: Ryan Ziegler Date: Sat, 6 Jul 2024 07:12:53 -0500 Subject: [PATCH] Add `--emit-accessors` (#5182) (#5227) --- bin/verilator | 1 + docs/guide/exe_verilator.rst | 6 +++++ src/V3EmitCBase.cpp | 9 ++++++++ src/V3EmitCBase.h | 1 + src/V3EmitCModel.cpp | 11 ++++++++++ src/V3Name.cpp | 4 ++++ src/V3Options.cpp | 1 + src/V3Options.h | 2 ++ test_regress/t/t_emit_accessors.cpp | 34 +++++++++++++++++++++++++++++ test_regress/t/t_emit_accessors.pl | 23 +++++++++++++++++++ test_regress/t/t_emit_accessors.v | 19 ++++++++++++++++ 11 files changed, 111 insertions(+) create mode 100644 test_regress/t/t_emit_accessors.cpp create mode 100755 test_regress/t/t_emit_accessors.pl create mode 100644 test_regress/t/t_emit_accessors.v diff --git a/bin/verilator b/bin/verilator index c9edeec56..b5fbfe521 100755 --- a/bin/verilator +++ b/bin/verilator @@ -357,6 +357,7 @@ detailed descriptions of these arguments. --dumpi-tree-json Enable dumping Ast .tree.json files at level --dumpi- Enable dumping everything in source file at level -E Preprocess, but do not compile + --emit-accessors Emit getter and setter methods for model top class --error-limit Abort after this number of errors --exe Link to create executable --expand-limit Set expand optimization limit diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index a632b4c97..dfc3f5aae 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -483,6 +483,12 @@ Summary: See also :vlopt:`--dump-defines`, :vlopt:`-P`, and :vlopt:`--pp-comments` options. +.. option:: --emit-accessors + + Emit getter and setter methods for each top-level signal in the + model top class. Signals are still available as public members, + but with the `__Vm_sig_` prefix. + .. option:: --error-limit After this number of errors are encountered during Verilator run, exit. diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index fa0a650e8..8a4967112 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -227,6 +227,15 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { } } +void EmitCBaseVisitorConst::emitVarAccessors(const AstVar* nodep) { + assert(nodep->name().rfind("__Vm_sig_") == 0 && nodep->isIO()); + const string privateName = nodep->name(); + const string publicName = nodep->name().substr(strlen("__Vm_sig_")); + + puts("decltype("s + privateName + ") "s + publicName + "() {return "s + privateName + ";}\n"); + puts("void "s + publicName + "(decltype(" + privateName + ") v) {"s + privateName + "=v;}\n"); +} + void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) { bool nl = false; forModCUse(modp, useType, [&](string entry) { diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index efeb7a75f..8cb5581e4 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -118,6 +118,7 @@ public: void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); void emitVarDecl(const AstVar* nodep, bool asRef = false); + void emitVarAccessors(const AstVar* nodep); template static void forModCUse(const AstNodeModule* modp, VUseType useType, F action) { for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) { diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 49dda63c2..d375885e7 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -118,6 +118,17 @@ class EmitCModel final : public EmitCFunc { } } } + if(v3Global.opt.emitAccessors()) { + puts("\n// ACCESSORS\n" + "// The application code should use these methods to\n" + "// propagate new values into/out from the Verilated model\n" + "// instead of using signal variables directly.\n"); + for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstVar* const varp = VN_CAST(nodep, Var)) { + if (varp->isPrimaryIO()) emitVarAccessors(varp); + } + } + } if (optSystemC() && v3Global.usesTiming()) puts("sc_core::sc_event trigger_eval;\n"); // Cells instantiated by the top level (for access to /* verilator public */) diff --git a/src/V3Name.cpp b/src/V3Name.cpp index 7e2a5daff..d0add3d96 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -65,6 +65,10 @@ class NameVisitor final : public VNVisitorConst { nodep->name(newname); nodep->editCountInc(); } else if (VN_IS(nodep, CFunc) && VN_AS(nodep, CFunc)->isConstructor()) { + } else if (v3Global.opt.emitAccessors() && VN_IS(nodep, Var) && VN_AS(nodep, Var)->isSigPublic()) { + const string newname = "__Vm_sig_" + nodep->name(); + nodep->name(newname); + nodep->editCountInc(); } else { renameKeywordCheck(nodep); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index c21639472..9f40d02b3 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1240,6 +1240,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, if (flag) m_std = false; m_preprocOnly = flag; }); + DECL_OPTION("-emit-accessors", OnOff, &m_emitAccessors); DECL_OPTION("-error-limit", CbVal, static_cast(&V3Error::errorLimit)); DECL_OPTION("-exe", OnOff, &m_exe); DECL_OPTION("-expand-limit", CbVal, diff --git a/src/V3Options.h b/src/V3Options.h index cd822c692..1103a2e95 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -250,6 +250,7 @@ private: bool m_decoration = true; // main switch: --decoration bool m_decorationNodes = false; // main switch: --decoration=nodes bool m_dpiHdrOnly = false; // main switch: --dpi-hdr-only + bool m_emitAccessors = false; // main switch: --emit-accessors bool m_exe = false; // main switch: --exe bool m_flatten = false; // main switch: --flatten bool m_hierarchical = false; // main switch: --hierarchical @@ -499,6 +500,7 @@ public: bool dumpTreeDot() const { return m_dumpLevel.count("tree-dot") && m_dumpLevel.at("tree-dot"); } + bool emitAccessors() const { return m_emitAccessors; } bool exe() const { return m_exe; } bool flatten() const { return m_flatten; } bool gmake() const { return m_gmake; } diff --git a/test_regress/t/t_emit_accessors.cpp b/test_regress/t/t_emit_accessors.cpp new file mode 100644 index 000000000..817ae59bf --- /dev/null +++ b/test_regress/t/t_emit_accessors.cpp @@ -0,0 +1,34 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +#include +#include VM_PREFIX_INCLUDE + +int main(int argc, char* argv[]) { + Verilated::debug(0); + Verilated::commandArgs(argc, argv); + + VM_PREFIX* topp = new VM_PREFIX; + CData small_in1 = 0; + CData small_in2 = 1; + IData big_in = 0xffffffff; + + topp->in1(small_in1); + topp->in2(small_in2); + topp->in3(big_in); + topp->in4(big_in); + + topp->eval(); + + assert(topp->out1() == 0); + assert(topp->out2() == 0xffffffff); + assert(topp->out3().at(0) == 1); + + topp->final(); + VL_DO_DANGLING(delete topp, topp); +} diff --git a/test_regress/t/t_emit_accessors.pl b/test_regress/t/t_emit_accessors.pl new file mode 100755 index 000000000..533483c87 --- /dev/null +++ b/test_regress/t/t_emit_accessors.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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( + make_main => 0, + verilator_flags2 => [ + "--emit-accessors", + "--exe", + "$Self->{t_dir}/$Self->{name}.cpp" + ], +); + +ok(1); +1; diff --git a/test_regress/t/t_emit_accessors.v b/test_regress/t/t_emit_accessors.v new file mode 100644 index 000000000..d23055ede --- /dev/null +++ b/test_regress/t/t_emit_accessors.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t_emit_accessors( + input bit in1, + input bit in2, + input logic [31:0] in3, + input logic [31:0] in4, + output bit out1, + output logic [31:0] out2, + output logic [77:0] out3 +); + assign out1 = in1 & in2; + assign out2 = in3 & in4; + assign out3 = 1; +endmodule