Support `systemc_interface and related inside `class`.
This commit is contained in:
parent
6edf2f80a2
commit
b4ef6ce860
1
Changes
1
Changes
|
@ -20,6 +20,7 @@ Verilator 5.035 devel
|
|||
**Other:**
|
||||
|
||||
* Support force/release with a variable reference (#5721) (#5810). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Support `systemc_interface and related inside `class`.
|
||||
* Add multi-thread hierarchical simulation (#2583) (#5871). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Add check for `let` misused in statement context (#5733).
|
||||
* Add used language to `--preproc-resolve` output (#5795). [Kamil Rakoczy, Antmicro Ltd.]
|
||||
|
|
|
@ -107,48 +107,60 @@ or "`ifdef`"'s may break other tools.
|
|||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the output .h file's header. Must be placed as a module
|
||||
item, e.g., directly inside a module/endmodule pair. Despite the name of
|
||||
this macro, this also works in pure C++ code.
|
||||
or class item, e.g., directly inside a module/endmodule or
|
||||
class/endclass pair. Despite the name of this macro, this also works in
|
||||
pure C++ code.
|
||||
|
||||
.. option:: `systemc_class_name
|
||||
|
||||
Inside one of the :option:`\`systemc_... <\`systemc_header>` text
|
||||
blocks, replaced with the C++ class name generated for the given
|
||||
containing SystemVerilog class or module. Currently this is replaced
|
||||
blindly, ignoring quoting or other escapes; this behavior may change in
|
||||
the future. This attribute is indented only to be used internally in
|
||||
`verilated_std.sv`.
|
||||
|
||||
.. option:: `systemc_ctor
|
||||
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the C++ class constructor. Must be placed as a module
|
||||
item, e.g., directly inside a module/endmodule pair. Despite the name of
|
||||
this macro, this also works in pure C++ code.
|
||||
verbatim into the C++ class constructor. Must be placed as a module or
|
||||
class item, e.g., directly inside a module/endmodule or class/endclass
|
||||
pair. Despite the name of this macro, this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_dtor
|
||||
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the C++ class destructor. Must be placed as a module
|
||||
item, e.g., directly inside a module/endmodule pair. Despite the name of
|
||||
this macro, this also works in pure C++ code.
|
||||
verbatim into the C++ class destructor. Must be placed as a module or
|
||||
class item, e.g., directly inside a module/endmodule or class/endclass
|
||||
pair. Despite the name of this macro, this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_interface
|
||||
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the C++ class interface. Must be placed as a module item,
|
||||
e.g., directly inside a module/endmodule pair. Despite the name of this
|
||||
macro, this also works in pure C++ code.
|
||||
verbatim into the C++ class interface. Must be placed as a module or
|
||||
class item, e.g., directly inside a module/endmodule or class/endclass
|
||||
pair. Despite the name of this macro, this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_imp_header
|
||||
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the header of all files for this C++ class implementation.
|
||||
Must be placed as a module item, e.g., directly inside a module/endmodule
|
||||
pair. Despite the name of this macro, this also works in pure C++ code.
|
||||
Must be placed as a module or class item, e.g., directly inside a
|
||||
module/endmodule or class/endclass pair. Despite the name of this macro,
|
||||
this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_implementation
|
||||
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into a single file of the C++ class implementation. Must be
|
||||
placed as a module item, e.g., directly inside a module/endmodule
|
||||
pair. Despite the name of this macro, this also works in pure C++ code.
|
||||
placed as a module or class item, e.g., directly inside a
|
||||
module/endmodule or class/endclass pair. Despite the name of this macro,
|
||||
this also works in pure C++ code.
|
||||
|
||||
If you will be reading or writing any Verilog variables in the C++
|
||||
functions, the Verilog signals must be declared with a
|
||||
|
|
|
@ -137,7 +137,17 @@ class CCtorsVisitor final : public VNVisitor {
|
|||
AstCFunc* m_cfuncp = nullptr; // Current function
|
||||
V3CCtorsBuilder* m_varResetp = nullptr; // Builder of _ctor_var_reset
|
||||
|
||||
// VISITs
|
||||
// METHODS
|
||||
static void insertSc(AstCFunc* cfuncp, const AstNodeModule* modp, VNType type) {
|
||||
auto textAndFileline = EmitCBaseVisitorConst::textSection(modp, type);
|
||||
if (!textAndFileline.first.empty()) {
|
||||
AstTextBlock* const newp
|
||||
= new AstTextBlock{textAndFileline.second, textAndFileline.first, false, false};
|
||||
cfuncp->addStmtsp(newp);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_varResetp);
|
||||
|
@ -167,6 +177,7 @@ class CCtorsVisitor final : public VNVisitor {
|
|||
// If can be referred to by base pointer, need virtual delete
|
||||
funcp->isVirtual(classp->isExtended());
|
||||
funcp->slow(false);
|
||||
insertSc(funcp, classp, VNType::atScDtor);
|
||||
classp->addStmtsp(funcp);
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +188,7 @@ class CCtorsVisitor final : public VNVisitor {
|
|||
m_varResetp = nullptr;
|
||||
m_cfuncp = nodep;
|
||||
iterateChildren(nodep);
|
||||
if (nodep->name() == "new") insertSc(nodep, m_modp, VNType::atScCtor);
|
||||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
if (nodep->needsCReset()) {
|
||||
|
|
|
@ -285,27 +285,43 @@ void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useT
|
|||
if (nl) puts("\n");
|
||||
}
|
||||
|
||||
std::pair<string, FileLine*> EmitCBaseVisitorConst::textSection(const AstNodeModule* modp,
|
||||
VNType type) {
|
||||
if (!v3Global.hasSCTextSections()) return std::make_pair("", nullptr);
|
||||
string text;
|
||||
FileLine* fl = nullptr;
|
||||
int last_line = -999;
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (nodep->type() != type) continue;
|
||||
if (const AstNodeText* const textp = VN_CAST(nodep, NodeText)) {
|
||||
if (text.empty()) {
|
||||
fl = textp->fileline();
|
||||
text += "\n";
|
||||
if (v3Global.opt.decoration())
|
||||
text += "\n//*** Below code from `systemc in Verilog file\n";
|
||||
}
|
||||
if (last_line + 1 != nodep->fileline()->lineno() && v3Global.opt.decoration())
|
||||
text += "// From `systemc at " + nodep->fileline()->ascii() + "\n";
|
||||
last_line = textp->fileline()->lineno();
|
||||
text += textp->text();
|
||||
}
|
||||
}
|
||||
if (!text.empty()) {
|
||||
if (v3Global.opt.decoration()) text += "//*** Above code from `systemc in Verilog file\n";
|
||||
text += "\n";
|
||||
// Substitute `systemc_class_name
|
||||
string::size_type pos;
|
||||
while ((pos = text.find("`systemc_class_name")) != string::npos) {
|
||||
text.replace(pos, std::strlen("`systemc_class_name"),
|
||||
EmitCBase::prefixNameProtect(modp));
|
||||
}
|
||||
}
|
||||
return std::make_pair(text, fl);
|
||||
}
|
||||
|
||||
void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) {
|
||||
// Short circuit if nothing to do. This can save a lot of time on large designs as this
|
||||
// function needs to traverse the entire module linearly.
|
||||
if (!v3Global.hasSCTextSections()) return;
|
||||
|
||||
int last_line = -999;
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstNodeText* const textp = VN_CAST(nodep, NodeText)) {
|
||||
if (nodep->type() == type) {
|
||||
if (last_line != nodep->fileline()->lineno()) {
|
||||
if (last_line < 0) {
|
||||
putns(nodep, "\n//*** Below code from `systemc in Verilog file\n");
|
||||
}
|
||||
putsDecoration(nodep, ifNoProtect("// From `systemc at "
|
||||
+ nodep->fileline()->ascii() + "\n"));
|
||||
last_line = nodep->fileline()->lineno();
|
||||
}
|
||||
ofp()->putsNoTracking(textp->text());
|
||||
last_line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (last_line > 0) puts("//*** Above code from `systemc in Verilog file\n\n");
|
||||
auto textAndFileline = textSection(modp, type);
|
||||
if (!textAndFileline.first.empty()) ofp()->putsNoTracking(textAndFileline.first);
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ public:
|
|||
}
|
||||
void emitModCUse(const AstNodeModule* modp, VUseType useType);
|
||||
void emitTextSection(const AstNodeModule* modp, VNType type);
|
||||
static std::pair<string, FileLine*> textSection(const AstNodeModule* modp, VNType type);
|
||||
|
||||
// CONSTRUCTORS
|
||||
EmitCBaseVisitorConst() = default;
|
||||
|
|
|
@ -162,7 +162,7 @@ class LinkCellsVisitor final : public VNVisitor {
|
|||
return modp;
|
||||
}
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
readModNames();
|
||||
iterateChildren(nodep);
|
||||
|
|
|
@ -846,7 +846,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
return hierBlocks.find(name) != hierBlocks.end();
|
||||
}
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Process $unit or other packages
|
||||
// Not needed - dotted references not allowed from inside packages
|
||||
|
@ -1791,7 +1791,7 @@ class LinkDotParamVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
void visit(AstTypeTable*) override {}
|
||||
void visit(AstConstPool*) override {}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
|
@ -1967,7 +1967,7 @@ class LinkDotScopeVisitor final : public VNVisitor {
|
|||
const AstScope* m_scopep = nullptr; // The current scope
|
||||
VSymEnt* m_modSymp = nullptr; // Symbol entry for current module
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Recurse..., backward as must do packages before using packages
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
|
@ -2131,7 +2131,7 @@ class LinkDotIfaceVisitor final : public VNVisitor {
|
|||
LinkDotState* const m_statep; // State to pass between visitors, including symbol table
|
||||
VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
void visit(AstModport* nodep) override {
|
||||
// Modport: Remember its name for later resolution
|
||||
UINFO(5, " fiv: " << nodep << endl);
|
||||
|
@ -2543,7 +2543,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
return result + " ";
|
||||
}
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Recurse..., backward as must do packages before using packages
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
|
|
|
@ -41,7 +41,7 @@ class LinkLValueVisitor final : public VNVisitor {
|
|||
bool m_inInitialStatic = false; // Set if inside AstInitialStatic
|
||||
VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
// Result handing
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
// VarRef: LValue its reference
|
||||
|
|
|
@ -175,7 +175,7 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
<< nodep->warnContextSecondary());
|
||||
}
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
void visit(AstNodeFTask* nodep) override {
|
||||
if (!nodep->user1SetOnce()) { // Process only once.
|
||||
// Mark class methods
|
||||
|
|
|
@ -55,7 +55,7 @@ class LinkResolveVisitor final : public VNVisitor {
|
|||
bool m_underGenFor = false; // Under GenFor
|
||||
bool m_underGenerate = false; // Under GenFor/GenIf
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
// TODO: Most of these visitors are here for historical reasons.
|
||||
// TODO: ExpectDescriptor can move to data type resolution, and the rest
|
||||
// TODO: could move to V3LinkParse to get them out of the way of elaboration
|
||||
|
@ -531,7 +531,7 @@ class LinkBotupVisitor final : public VNVisitorConst {
|
|||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
|
||||
// VISITs
|
||||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override {
|
||||
// Iterate modules backwards, in bottom-up order.
|
||||
iterateChildrenBackwardsConst(nodep);
|
||||
|
|
|
@ -2729,18 +2729,23 @@ non_port_module_item<nodep>: // ==IEEE: non_port_module_item
|
|||
{ $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: interface decls within module decls"); }
|
||||
| timeunits_declaration { $$ = $1; }
|
||||
// // Verilator specific
|
||||
| yaSCHDR { $$ = new AstScHdr{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCINT { $$ = new AstScInt{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCIMP { $$ = new AstScImp{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCIMPH { $$ = new AstScImpHdr{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCCTOR { $$ = new AstScCtor{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCDTOR { $$ = new AstScDtor{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| vlScBlock { $$ = $1; }
|
||||
| yVL_HIER_BLOCK { $$ = new AstPragma{$1, VPragmaType::HIER_BLOCK}; }
|
||||
| yVL_INLINE_MODULE { $$ = new AstPragma{$1, VPragmaType::INLINE_MODULE}; }
|
||||
| yVL_NO_INLINE_MODULE { $$ = new AstPragma{$1, VPragmaType::NO_INLINE_MODULE}; }
|
||||
| yVL_PUBLIC_MODULE { $$ = new AstPragma{$1, VPragmaType::PUBLIC_MODULE}; v3Global.dpi(true); }
|
||||
;
|
||||
|
||||
vlScBlock<nodep>: // Verilator-specific `systemc_* blocks
|
||||
yaSCHDR { $$ = new AstScHdr{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCINT { $$ = new AstScInt{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCIMP { $$ = new AstScImp{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCIMPH { $$ = new AstScImpHdr{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCCTOR { $$ = new AstScCtor{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
| yaSCDTOR { $$ = new AstScDtor{$<fl>1, *$1}; v3Global.setHasSCTextSections(); }
|
||||
;
|
||||
|
||||
|
||||
module_or_generate_item<nodep>: // ==IEEE: module_or_generate_item
|
||||
// // IEEE: parameter_override
|
||||
yDEFPARAM list_of_defparam_assignments ';' { $$ = $2; }
|
||||
|
@ -7372,6 +7377,8 @@ class_item<nodep>: // ==IEEE: class_item
|
|||
// // local_parameter_declaration under parameter_declaration
|
||||
| parameter_declaration ';' { $$ = $1; }
|
||||
| ';' { $$ = nullptr; }
|
||||
// // Verilator specific
|
||||
| vlScBlock { $$ = $1; }
|
||||
//
|
||||
| error ';' { $$ = nullptr; }
|
||||
;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# 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
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,56 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2003-2007 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Although strange, Verilog defines are expanded inside the C blocks
|
||||
// (as the `systemc_* directives are opaque to the preprocessor)
|
||||
`define finished "*-* All Finished *-*\n"
|
||||
|
||||
class Cls;
|
||||
`ifdef verilator
|
||||
`systemc_header
|
||||
#define DID_INT_HEADER 1
|
||||
`systemc_interface
|
||||
#ifndef DID_INT_HEADER
|
||||
#error "`systemc_header didn't work"
|
||||
#endif
|
||||
bool m_did_ctor;
|
||||
uint32_t my_function() {
|
||||
if (!m_did_ctor) vl_fatal(__FILE__, __LINE__, __FILE__, "`systemc_ctor didn't work");
|
||||
return 1;
|
||||
}
|
||||
static void my_imp_function();
|
||||
|
||||
`systemc_imp_header
|
||||
#define DID_IMP_HEADER 1
|
||||
`systemc_implementation
|
||||
|
||||
void `systemc_class_name::my_imp_function() { }
|
||||
|
||||
`systemc_ctor // Works, but using a $c inside a `function new` might be cleaner
|
||||
m_did_ctor = 1;
|
||||
`systemc_dtor
|
||||
printf("In systemc_dtor\n");
|
||||
printf(`finished);
|
||||
`verilog
|
||||
|
||||
`endif // verilator
|
||||
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
int i;
|
||||
|
||||
initial begin
|
||||
Cls c;
|
||||
c = new;
|
||||
i = $c(c, "->my_function()");
|
||||
$c(c, "->my_imp_function();");
|
||||
c = null; // Causes destruction and All Finished
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue