2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Emit Verilog from tree
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2004-2025 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2023-10-18 12:37:46 +02:00
|
|
|
#include "V3PchAstMT.h"
|
|
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include "V3EmitV.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include "V3EmitCBase.h"
|
|
|
|
|
|
2025-07-23 18:51:16 +02:00
|
|
|
#include <unordered_map>
|
2006-08-26 13:35:28 +02:00
|
|
|
#include <vector>
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2022-10-12 11:19:21 +02:00
|
|
|
// ######################################################################
|
|
|
|
|
// Emit statements and expressions
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2025-07-30 13:41:21 +02:00
|
|
|
class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
2025-01-25 03:00:45 +01:00
|
|
|
// STATE - across all visitors
|
2025-07-30 13:41:21 +02:00
|
|
|
const bool m_suppressUnknown; // Do not error on unknown node
|
2025-01-25 03:00:45 +01:00
|
|
|
|
|
|
|
|
// STATE - for current visit position (use VL_RESTORER)
|
2025-08-18 01:14:34 +02:00
|
|
|
AstSenTree* m_sentreep = nullptr; // Domain for printing one a ALWAYS under a ACTIVE
|
2025-01-25 03:00:45 +01:00
|
|
|
bool m_suppressSemi = false; // Non-statement, don't print ;
|
|
|
|
|
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
2025-10-10 16:16:15 +02:00
|
|
|
bool m_suppressSampled = false; // Suppress emitting sampled in assertion properties
|
2025-01-25 03:00:45 +01:00
|
|
|
bool m_arrayPost = false; // Print array information that goes after identifier (vs after)
|
2025-10-10 16:16:15 +02:00
|
|
|
bool m_prefixed = true; // Whether constants need to be prefixed
|
2025-01-25 03:00:45 +01:00
|
|
|
std::deque<AstNodeArrayDType*> m_packedps; // Packed arrays to print with BasicDType
|
2025-07-23 18:51:16 +02:00
|
|
|
std::unordered_map<AstJumpBlock*, size_t> m_labelNumbers; // Label numbers for JumpBlocks
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
2008-11-20 13:55:54 +01:00
|
|
|
virtual void puts(const string& str) = 0;
|
|
|
|
|
virtual void putbs(const string& str) = 0;
|
2010-01-07 22:41:19 +01:00
|
|
|
virtual void putfs(AstNode* nodep, const string& str) = 0; // Fileline and node %% mark
|
|
|
|
|
virtual void putqs(AstNode* nodep, const string& str) = 0; // Fileline quiet w/o %% mark
|
2008-11-20 13:55:54 +01:00
|
|
|
virtual void putsNoTracking(const string& str) = 0;
|
2009-12-29 04:19:03 +01:00
|
|
|
virtual void putsQuoted(const string& str) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Quote \ and " for use inside C programs
|
|
|
|
|
// Don't use to quote a filename for #include - #include doesn't \ escape.
|
|
|
|
|
// Duplicate in V3File - here so we can print to string
|
|
|
|
|
putsNoTracking("\"");
|
2019-05-17 03:44:01 +02:00
|
|
|
putsNoTracking(V3OutFormatter::quoteNameControls(str));
|
2019-05-19 22:13:13 +02:00
|
|
|
putsNoTracking("\"");
|
2009-12-29 04:19:03 +01:00
|
|
|
}
|
2012-03-20 21:01:53 +01:00
|
|
|
|
2025-01-25 03:00:45 +01:00
|
|
|
void iterateAndCommaConstNull(AstNode* nodep) {
|
|
|
|
|
for (; nodep; nodep = nodep->nextp()) {
|
|
|
|
|
iterateConst(nodep);
|
|
|
|
|
if (nodep->nextp()) puts(", ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void emitPacked() {
|
|
|
|
|
for (AstNodeArrayDType* packedp : m_packedps) {
|
|
|
|
|
puts(" ");
|
|
|
|
|
iterateConstNull(packedp->rangep());
|
|
|
|
|
}
|
|
|
|
|
m_packedps.clear();
|
|
|
|
|
}
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
void emitNodesWithText(AstNode* nodesp, bool tracking, const std::string& separator) {
|
|
|
|
|
for (AstNode* nodep = nodesp; nodep; nodep = nodep->nextp()) {
|
|
|
|
|
if (const AstText* const textp = VN_CAST(nodep, Text)) {
|
|
|
|
|
if (tracking) {
|
|
|
|
|
puts(textp->text());
|
|
|
|
|
} else {
|
|
|
|
|
putsNoTracking(textp->text());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
iterateConst(nodep);
|
|
|
|
|
}
|
|
|
|
|
if (nodep->nextp()) puts(separator);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-25 03:00:45 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); }
|
|
|
|
|
void visit(AstNodeModule* nodep) override {
|
2025-08-26 04:05:40 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd() + " " + EmitCUtil::prefixNameProtect(nodep) + ";\n");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2020-01-25 15:16:00 +01:00
|
|
|
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPort* nodep) override {}
|
|
|
|
|
void visit(AstNodeFTask* nodep) override {
|
2025-10-10 16:16:15 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(" ");
|
|
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
puts(";\n");
|
2020-04-15 13:58:34 +02:00
|
|
|
// Only putfs the first time for each visitor; later for same node is putqs
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
2025-10-10 16:16:15 +02:00
|
|
|
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-23 20:49:01 +02:00
|
|
|
void visit(AstGenBlock* nodep) override {
|
|
|
|
|
const std::string name = nodep->name().empty() ? "" : " : " + nodep->name();
|
|
|
|
|
putbs("/* generate */ begin" + name + '\n');
|
|
|
|
|
iterateChildrenConst(nodep);
|
|
|
|
|
puts("end" + name + '\n');
|
|
|
|
|
}
|
|
|
|
|
void visit(AstGenCase* nodep) override {
|
|
|
|
|
putfs(nodep, "/* generate */ case (");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
puts(")\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->itemsp());
|
|
|
|
|
putqs(nodep, "endcase\n");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstGenCaseItem* nodep) override {
|
|
|
|
|
if (nodep->condsp()) {
|
|
|
|
|
iterateAndNextConstNull(nodep->condsp());
|
|
|
|
|
} else {
|
|
|
|
|
putbs("default");
|
|
|
|
|
}
|
|
|
|
|
iterateAndNextConstNull(nodep->itemsp());
|
|
|
|
|
}
|
|
|
|
|
void visit(AstGenFor* nodep) override {
|
|
|
|
|
putfs(nodep, "/* generate */ for (");
|
|
|
|
|
{
|
|
|
|
|
VL_RESTORER(m_suppressSemi);
|
|
|
|
|
m_suppressSemi = true;
|
|
|
|
|
iterateAndNextConstNull(nodep->initsp());
|
|
|
|
|
puts(";");
|
|
|
|
|
iterateAndNextConstNull(nodep->condp());
|
|
|
|
|
puts(";");
|
|
|
|
|
iterateAndNextConstNull(nodep->incsp());
|
|
|
|
|
}
|
|
|
|
|
puts(") begin\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->itemsp());
|
|
|
|
|
putqs(nodep, "end\n");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstGenIf* nodep) override {
|
|
|
|
|
putfs(nodep, "");
|
|
|
|
|
puts("/* generate */ if (");
|
|
|
|
|
iterateAndNextConstNull(nodep->condp());
|
|
|
|
|
puts(") begin\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->thensp());
|
|
|
|
|
if (nodep->elsesp()) {
|
|
|
|
|
putqs(nodep, "end else begin\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->elsesp());
|
|
|
|
|
}
|
|
|
|
|
putqs(nodep, "end\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstBegin* nodep) override {
|
2020-02-26 00:57:51 +01:00
|
|
|
if (nodep->name() == "") {
|
2019-05-19 22:13:13 +02:00
|
|
|
putbs("begin\n");
|
|
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
putbs("begin : " + nodep->name() + "\n");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
puts("end\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstFork* nodep) override {
|
2020-04-23 03:31:40 +02:00
|
|
|
if (nodep->name() == "") {
|
|
|
|
|
putbs("fork\n");
|
|
|
|
|
} else {
|
|
|
|
|
putbs("fork : " + nodep->name() + "\n");
|
|
|
|
|
}
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2020-04-23 03:31:40 +02:00
|
|
|
puts(nodep->joinType().verilogKwd());
|
|
|
|
|
puts("\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstFinal* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "final begin\n");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
putqs(nodep, "end\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstInitial* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "initial begin\n");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
putqs(nodep, "end\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstInitialAutomatic* nodep) override { iterateChildrenConst(nodep); }
|
|
|
|
|
void visit(AstInitialStatic* nodep) override { iterateChildrenConst(nodep); }
|
|
|
|
|
void visit(AstAlways* nodep) override {
|
Internals: Make AstAssignW a procedural statement (#6280) (#6556)
Initial idea was to remodel AssignW as Assign under Alway. Trying that
uncovered some issues, the most difficult of them was that a delay
attached to a continuous assignment behaves differently from a delay
attached to a blocking assignment statement, so we need to keep the
knowledge of which flavour an assignment was until V3Timing.
So instead of removing AstAssignW, we always wrap it in an AstAlways,
with a special `keyword()` type. This makes it into a proper procedural
statement, which is almost equivalent to AstAssign, except for the case
when they contain a delay. We still gain the benefits of #6280 and can
simplify some code. Every AstNodeStmt should now be under an
AstNodeProcedure - which we should rename to AstProcess, or an
AstNodeFTask). As a result, V3Table can now handle AssignW for free.
Also uncovered and fixed a bug in handling intra-assignment delays if
a function is present on the RHS of an AssignW.
There is more work to be done towards #6280, and potentially simplifying
AssignW handing, but this is the minimal change required to tick it off
the TODO list for #6280.
2025-10-14 10:05:19 +02:00
|
|
|
if (const AstAssignW* const ap = VN_CAST(nodep->stmtsp(), AssignW)) {
|
|
|
|
|
if (!ap->nextp()) {
|
|
|
|
|
putfs(nodep, "assign ");
|
|
|
|
|
if (AstNode* const tcp = ap->timingControlp()) {
|
|
|
|
|
iterateAndNextConstNull(tcp);
|
|
|
|
|
putbs(" ");
|
|
|
|
|
}
|
|
|
|
|
iterateAndNextConstNull(ap->lhsp());
|
|
|
|
|
putbs(" = ");
|
|
|
|
|
iterateAndNextConstNull(ap->rhsp());
|
|
|
|
|
if (!m_suppressSemi) puts(";\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "always ");
|
2025-08-18 01:14:34 +02:00
|
|
|
if (m_sentreep) {
|
|
|
|
|
iterateAndNextConstNull(m_sentreep);
|
2020-04-15 13:58:34 +02:00
|
|
|
} // In active
|
|
|
|
|
else {
|
2025-08-18 01:14:34 +02:00
|
|
|
iterateAndNextConstNull(nodep->sentreep());
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
putbs(" begin\n");
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
putqs(nodep, "end\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2025-08-19 10:27:59 +02:00
|
|
|
void visit(AstAlwaysPre* nodep) override {
|
|
|
|
|
putfs(nodep, "always /* PRE */ begin\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
|
|
|
|
putqs(nodep, "end\n");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstAlwaysPost* nodep) override {
|
|
|
|
|
putfs(nodep, "always /* POST */ begin\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
|
|
|
|
putqs(nodep, "end\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeAssign* nodep) override {
|
2021-12-17 18:56:33 +01:00
|
|
|
if (VN_IS(nodep, AssignForce)) puts("force ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->lhsp());
|
2021-12-17 18:56:33 +01:00
|
|
|
putfs(nodep, " " + nodep->verilogKwd() + " ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->rhsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_suppressSemi) puts(";\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignDly* nodep) override {
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->lhsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, " <= ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->rhsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(";\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2025-09-22 22:30:26 +02:00
|
|
|
void visit(AstAlias* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putbs("alias ");
|
2025-09-29 19:23:51 +02:00
|
|
|
iterateConst(nodep->itemsp());
|
|
|
|
|
for (AstNode* itemp = nodep->itemsp()->nextp(); itemp; itemp = itemp->nextp()) {
|
|
|
|
|
putfs(nodep, " = ");
|
|
|
|
|
iterateConst(itemp);
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_suppressSemi) puts(";\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignW* nodep) override {
|
Internals: Make AstAssignW a procedural statement (#6280) (#6556)
Initial idea was to remodel AssignW as Assign under Alway. Trying that
uncovered some issues, the most difficult of them was that a delay
attached to a continuous assignment behaves differently from a delay
attached to a blocking assignment statement, so we need to keep the
knowledge of which flavour an assignment was until V3Timing.
So instead of removing AstAssignW, we always wrap it in an AstAlways,
with a special `keyword()` type. This makes it into a proper procedural
statement, which is almost equivalent to AstAssign, except for the case
when they contain a delay. We still gain the benefits of #6280 and can
simplify some code. Every AstNodeStmt should now be under an
AstNodeProcedure - which we should rename to AstProcess, or an
AstNodeFTask). As a result, V3Table can now handle AssignW for free.
Also uncovered and fixed a bug in handling intra-assignment delays if
a function is present on the RHS of an AssignW.
There is more work to be done towards #6280, and potentially simplifying
AssignW handing, but this is the minimal change required to tick it off
the TODO list for #6280.
2025-10-14 10:05:19 +02:00
|
|
|
putfs(nodep, "continuous assign ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->lhsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
putbs(" = ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->rhsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_suppressSemi) puts(";\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstRelease* nodep) override {
|
2021-12-17 18:56:33 +01:00
|
|
|
puts("release ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->lhsp());
|
2021-12-17 18:56:33 +01:00
|
|
|
if (!m_suppressSemi) puts(";\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstBreak*) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putbs("break");
|
|
|
|
|
if (!m_suppressSemi) puts(";\n");
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSenTree* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstSenItem is called for dumping in isolation by V3Order
|
|
|
|
|
putfs(nodep, "@(");
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(expp);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (expp->nextp()) putqs(expp->nextp(), " or ");
|
|
|
|
|
}
|
|
|
|
|
puts(")");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSenItem* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "");
|
2025-01-25 03:00:45 +01:00
|
|
|
if (nodep->edgeType() != VEdgeType::ET_CHANGED) puts(nodep->edgeType().verilogKwd());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->sensp()) puts(" ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2025-09-23 20:49:01 +02:00
|
|
|
void visit(AstCase* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "");
|
2025-09-23 20:49:01 +02:00
|
|
|
if (nodep->priorityPragma()) puts("priority ");
|
|
|
|
|
if (nodep->uniquePragma()) puts("unique ");
|
|
|
|
|
if (nodep->unique0Pragma()) puts("unique0 ");
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(nodep->verilogKwd());
|
|
|
|
|
puts(" (");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(")\n");
|
2025-09-23 20:49:01 +02:00
|
|
|
if (nodep->fullPragma() || nodep->parallelPragma()) {
|
|
|
|
|
puts(" // synopsys");
|
|
|
|
|
if (nodep->fullPragma()) puts(" full_case");
|
|
|
|
|
if (nodep->parallelPragma()) puts(" parallel_case");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->itemsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
putqs(nodep, "endcase\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCaseItem* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->condsp()) {
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->condsp());
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
putbs("default");
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, ": begin ");
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
putqs(nodep, "end\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstComment* nodep) override {
|
2024-01-29 02:24:28 +01:00
|
|
|
puts("// "s + nodep->name() + "\n");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstContinue*) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putbs("continue");
|
|
|
|
|
if (!m_suppressSemi) puts(";\n");
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2025-08-04 14:29:56 +02:00
|
|
|
void visit(AstNodeCoverDecl*) override {} // N/A
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCoverInc*) override {} // N/A
|
|
|
|
|
void visit(AstCoverToggle*) override {} // N/A
|
2008-07-01 20:15:10 +02:00
|
|
|
|
2025-10-13 02:09:03 +02:00
|
|
|
void visit(AstCvtPackString* nodep) override {
|
|
|
|
|
putfs(nodep, "");
|
|
|
|
|
if (AstConst* const lhsConstp = VN_CAST(nodep->lhsp(), Const)) {
|
|
|
|
|
putsQuoted(lhsConstp->num().toString());
|
|
|
|
|
} else {
|
|
|
|
|
puts("string'(");
|
|
|
|
|
iterateAndNextConstNull(nodep->lhsp());
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-14 20:58:11 +01:00
|
|
|
void visit(AstTestPlusArgs* nodep) override {
|
|
|
|
|
putfs(nodep, nodep->verilogKwd());
|
|
|
|
|
putbs("(");
|
|
|
|
|
iterateChildrenConst(nodep);
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstValuePlusArgs* nodep) override {
|
|
|
|
|
putfs(nodep, nodep->verilogKwd());
|
|
|
|
|
putbs("(");
|
2025-10-13 02:09:03 +02:00
|
|
|
iterateConstNull(nodep->searchp());
|
|
|
|
|
putbs(", ");
|
|
|
|
|
iterateConstNull(nodep->outp());
|
2025-02-14 20:58:11 +01:00
|
|
|
puts(")");
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
|
|
|
|
|
AstNode* exprsp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd());
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs("(");
|
2020-04-15 13:58:34 +02:00
|
|
|
if (fileOrStrgp) {
|
2025-01-25 03:00:45 +01:00
|
|
|
iterateConstNull(fileOrStrgp);
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs(", ");
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
putsQuoted(text);
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
|
2020-09-07 18:58:30 +02:00
|
|
|
puts(", ");
|
2025-01-25 03:00:45 +01:00
|
|
|
iterateConstNull(expp);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
puts(");\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstDisable* nodep) override { putbs("disable " + nodep->name() + ";\n"); }
|
|
|
|
|
void visit(AstDisplay* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
2008-07-01 20:15:10 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstElabDisplay* nodep) override {
|
2020-08-15 16:12:55 +02:00
|
|
|
visitNodeDisplay(nodep, nullptr, nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
2019-08-05 04:34:54 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstFScanF* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
|
2008-07-01 20:15:10 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSScanF* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
|
2008-07-01 20:15:10 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSFormat* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
2009-11-24 03:24:55 +01:00
|
|
|
}
|
2025-11-06 14:42:27 +01:00
|
|
|
void visit(AstToStringN* nodep) override { iterateConst(nodep->lhsp()); }
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSFormatF* nodep) override {
|
2020-08-15 16:12:55 +02:00
|
|
|
visitNodeDisplay(nodep, nullptr, nodep->text(), nodep->exprsp());
|
2010-01-18 01:13:44 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstFOpen* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd());
|
2020-05-15 00:03:00 +02:00
|
|
|
putbs("(");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->filenamep());
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs(", ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->modep());
|
2020-05-15 00:03:00 +02:00
|
|
|
puts(");\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstFOpenMcd* nodep) override {
|
2020-05-15 00:03:00 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd());
|
|
|
|
|
putbs("(");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->filenamep());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(");\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstFClose* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd());
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs("(");
|
2022-04-23 15:03:37 +02:00
|
|
|
if (nodep->filep()) iterateAndNextConstNull(nodep->filep());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(");\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstFFlush* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd());
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs("(");
|
2022-04-23 15:03:37 +02:00
|
|
|
if (nodep->filep()) iterateAndNextConstNull(nodep->filep());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(");\n");
|
2008-06-27 14:45:05 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstJumpBlock* nodep) override {
|
2025-07-23 18:51:16 +02:00
|
|
|
// Allocate label number
|
|
|
|
|
const size_t n = m_labelNumbers.size();
|
|
|
|
|
const bool newEntry = m_labelNumbers.emplace(nodep, n).second;
|
|
|
|
|
UASSERT_OBJ(newEntry, nodep, "AstJumpBlock visited twide");
|
|
|
|
|
// Emit
|
|
|
|
|
putbs("begin : label" + std::to_string(n) + "\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
2020-05-07 03:33:05 +02:00
|
|
|
puts("end\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstJumpGo* nodep) override {
|
2025-07-23 18:51:16 +02:00
|
|
|
// Retrieve target label number - Sometimes EmitV is used by debug code,
|
|
|
|
|
// so allow printing with an unknown target
|
|
|
|
|
const auto it = m_labelNumbers.find(nodep->blockp());
|
|
|
|
|
const std::string label
|
|
|
|
|
= it != m_labelNumbers.end() ? "label" + std::to_string(it->second) : "<UNKNOWN>";
|
|
|
|
|
putbs("disable " + label + ";\n");
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeReadWriteMem* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd());
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs("(");
|
2022-04-23 15:03:37 +02:00
|
|
|
if (nodep->filenamep()) iterateAndNextConstNull(nodep->filenamep());
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs(", ");
|
2022-04-23 15:03:37 +02:00
|
|
|
if (nodep->memp()) iterateAndNextConstNull(nodep->memp());
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->lsbp()) {
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs(", ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->lsbp());
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
if (nodep->msbp()) {
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs(", ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->msbp());
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(");\n");
|
2006-12-19 15:09:57 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSysIgnore* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, nodep->verilogKwd());
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs("(");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->exprsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(");\n");
|
2010-12-30 13:55:31 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstRepeat* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "repeat (");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->countp());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(") begin\n");
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "end\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2025-09-29 16:25:25 +02:00
|
|
|
void visit(AstLoop* nodep) override {
|
|
|
|
|
// Special case when the AstLoopTest is first for output readability
|
|
|
|
|
if (AstLoopTest* const testp = VN_CAST(nodep->stmtsp(), LoopTest)) {
|
|
|
|
|
putfs(nodep, "while (");
|
|
|
|
|
iterateConst(testp->condp());
|
|
|
|
|
puts(") begin\n");
|
|
|
|
|
iterateAndNextConstNull(testp->nextp());
|
|
|
|
|
puts("end\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Special case when the AstLoopTest is last for output readability
|
|
|
|
|
if (AstNode* lastp = nodep->stmtsp()) {
|
|
|
|
|
while (AstNode* const nextp = lastp->nextp()) lastp = nextp;
|
|
|
|
|
if (AstLoopTest* const testp = VN_CAST(lastp, LoopTest)) {
|
|
|
|
|
putfs(nodep, "do begin\n");
|
|
|
|
|
for (AstNode* p = nodep->stmtsp(); p != lastp; p = p->nextp()) iterateConst(p);
|
|
|
|
|
puts("end while (");
|
|
|
|
|
iterateConst(testp->condp());
|
|
|
|
|
puts(")\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Generic case
|
|
|
|
|
putfs(nodep, "while (true) begin\n");
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
2025-09-29 16:25:25 +02:00
|
|
|
iterateAndNextConstNull(nodep->contsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "end\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2025-09-29 16:25:25 +02:00
|
|
|
void visit(AstLoopTest* nodep) override {
|
|
|
|
|
putfs(nodep, "if (!(");
|
|
|
|
|
iterateAndNextConstNull(nodep->condp());
|
|
|
|
|
puts(")) break;\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeIf* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "");
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const AstIf* const ifp = VN_CAST(nodep, If)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (ifp->priorityPragma()) puts("priority ");
|
|
|
|
|
if (ifp->uniquePragma()) puts("unique ");
|
|
|
|
|
if (ifp->unique0Pragma()) puts("unique0 ");
|
|
|
|
|
}
|
|
|
|
|
puts("if (");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->condp());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(") begin\n");
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextConstNull(nodep->thensp());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->elsesp()) {
|
|
|
|
|
putqs(nodep, "end\n");
|
|
|
|
|
putqs(nodep, "else begin\n");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->elsesp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
putqs(nodep, "end\n");
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPast* nodep) override {
|
2018-09-23 21:09:47 +02:00
|
|
|
putfs(nodep, "$past(");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
2025-07-02 00:00:04 +02:00
|
|
|
if (nodep->ticksp() || nodep->sentreep()) {
|
2020-09-07 18:58:30 +02:00
|
|
|
puts(", ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->ticksp());
|
2025-07-02 00:00:04 +02:00
|
|
|
if (nodep->sentreep()) {
|
|
|
|
|
puts(", ");
|
|
|
|
|
iterateAndNextConstNull(nodep->sentreep());
|
|
|
|
|
}
|
2018-09-23 21:09:47 +02:00
|
|
|
}
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2025-04-11 18:25:56 +02:00
|
|
|
void visit(AstSampled* nodep) override {
|
2025-10-10 16:16:15 +02:00
|
|
|
if (!m_suppressSampled) {
|
|
|
|
|
putfs(nodep, "$sampled(");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2025-04-11 18:25:56 +02:00
|
|
|
}
|
2025-08-24 03:16:53 +02:00
|
|
|
void visit(AstRising* nodep) override {
|
|
|
|
|
putfs(nodep, "$rising(");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2025-04-11 18:25:56 +02:00
|
|
|
void visit(AstRose* nodep) override {
|
|
|
|
|
putfs(nodep, "$rose(");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
if (nodep->sentreep()) {
|
|
|
|
|
puts(", ");
|
|
|
|
|
iterateAndNextConstNull(nodep->sentreep());
|
|
|
|
|
}
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstFell* nodep) override {
|
|
|
|
|
putfs(nodep, "$fell(");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
if (nodep->sentreep()) {
|
|
|
|
|
puts(", ");
|
|
|
|
|
iterateAndNextConstNull(nodep->sentreep());
|
|
|
|
|
}
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2025-08-24 03:16:53 +02:00
|
|
|
void visit(AstFalling* nodep) override {
|
|
|
|
|
putfs(nodep, "$falling(");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstFuture* nodep) override {
|
|
|
|
|
putfs(nodep, "$future(");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2025-04-11 18:25:56 +02:00
|
|
|
void visit(AstStable* nodep) override {
|
|
|
|
|
putfs(nodep, "$stable(");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
if (nodep->sentreep()) {
|
|
|
|
|
puts(", ");
|
|
|
|
|
iterateAndNextConstNull(nodep->sentreep());
|
|
|
|
|
}
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2025-08-24 03:16:53 +02:00
|
|
|
void visit(AstSteady* nodep) override {
|
|
|
|
|
putfs(nodep, "$steady(");
|
|
|
|
|
iterateAndNextConstNull(nodep->exprp());
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstReturn* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "return ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->lhsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(";\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2024-09-14 02:45:44 +02:00
|
|
|
void visit(AstStop* nodep) override {
|
|
|
|
|
emitVerilogFormat(nodep, nodep->emitVerilog());
|
|
|
|
|
puts(";\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); }
|
2025-10-20 16:16:05 +02:00
|
|
|
void visit(AstFinishFork* nodep) override { putfs(nodep, "$finish;\n"); }
|
2022-10-12 11:19:21 +02:00
|
|
|
void visit(AstStmtExpr* nodep) override {
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep->exprp());
|
2022-10-12 11:19:21 +02:00
|
|
|
puts(";\n");
|
|
|
|
|
}
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
|
|
|
|
|
// Nodes involing AstText
|
|
|
|
|
void visit(AstText* nodep) override {
|
|
|
|
|
// All Text should be under TextBlock/CStmt/CStmtUser/CExpr/CExprUser
|
|
|
|
|
nodep->v3fatalSrc("Text node in unexpected position");
|
2019-09-27 09:44:23 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTextBlock* nodep) override {
|
2025-01-25 03:00:45 +01:00
|
|
|
VL_RESTORER(m_suppressVarSemi);
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
m_suppressVarSemi = !nodep->separator().empty();
|
|
|
|
|
puts(nodep->prefix());
|
|
|
|
|
emitNodesWithText(nodep->nodesp(), true, nodep->separator());
|
|
|
|
|
puts(nodep->suffix());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCStmt* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "$_CSTMT(");
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
emitNodesWithText(nodep->nodesp(), true, "");
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(");\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-10-12 11:19:21 +02:00
|
|
|
void visit(AstCExpr* nodep) override {
|
|
|
|
|
putfs(nodep, "$_CEXPR(");
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
emitNodesWithText(nodep->nodesp(), true, "");
|
2023-10-20 13:13:57 +02:00
|
|
|
puts(")");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
void visit(AstCStmtUser* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "$c(");
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
emitNodesWithText(nodep->nodesp(), false, "");
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(");\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
void visit(AstCExprUser* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "$c(");
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
emitNodesWithText(nodep->nodesp(), false, "");
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(")");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
|
|
|
|
|
void visit(AstScopeName* nodep) override {}
|
2023-05-27 18:43:40 +02:00
|
|
|
void visit(AstExprStmt* nodep) override {
|
|
|
|
|
putfs(nodep, "$_EXPRSTMT(\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
|
|
|
|
putbs(", ");
|
|
|
|
|
puts(");\n");
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-16 17:15:10 +02:00
|
|
|
void visit(AstCMethodHard* nodep) override {
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep->fromp());
|
2022-05-15 17:03:32 +02:00
|
|
|
puts("." + nodep->name() + "(");
|
2025-01-25 03:00:45 +01:00
|
|
|
iterateAndCommaConstNull(nodep->pinsp());
|
2022-05-15 17:03:32 +02:00
|
|
|
puts(")");
|
|
|
|
|
}
|
2023-05-27 18:43:40 +02:00
|
|
|
void visit(AstCMethodCall* nodep) override {
|
|
|
|
|
iterateConst(nodep->fromp());
|
|
|
|
|
puts("." + nodep->name() + "(");
|
2025-01-25 03:00:45 +01:00
|
|
|
iterateAndCommaConstNull(nodep->argsp());
|
2023-05-27 18:43:40 +02:00
|
|
|
puts(")");
|
|
|
|
|
}
|
2022-05-15 17:03:32 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Operators
|
2020-08-15 16:12:55 +02:00
|
|
|
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = nullptr,
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNode* const rhsp = nullptr, AstNode* thsp = nullptr,
|
2020-08-15 16:12:55 +02:00
|
|
|
AstNode* fhsp = nullptr) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Look at emitVerilog() format for term/uni/dual/triops,
|
|
|
|
|
// and write out appropriate text.
|
|
|
|
|
// %f Potential fileline-if-change and line break
|
|
|
|
|
// %l lhsp - if appropriate
|
|
|
|
|
// %r rhsp - if appropriate
|
|
|
|
|
// %t thsp - if appropriate
|
2020-05-10 20:27:22 +02:00
|
|
|
// %o fhsp - if appropriate
|
2019-05-19 22:13:13 +02:00
|
|
|
// %d dtypep - if appropriate
|
|
|
|
|
// %k Potential line break
|
|
|
|
|
bool inPct = false;
|
|
|
|
|
putbs("");
|
2020-08-16 18:54:32 +02:00
|
|
|
for (const char c : format) {
|
2025-02-14 20:58:11 +01:00
|
|
|
if (!inPct && c == '%') {
|
2019-05-19 22:13:13 +02:00
|
|
|
inPct = true;
|
|
|
|
|
} else if (!inPct) { // Normal text
|
2020-04-15 13:58:34 +02:00
|
|
|
string s;
|
2020-08-16 18:54:32 +02:00
|
|
|
s += c;
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(s);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else { // Format character
|
|
|
|
|
inPct = false;
|
2020-08-16 18:54:32 +02:00
|
|
|
switch (c) {
|
2020-04-15 13:58:34 +02:00
|
|
|
case '%': puts("%"); break;
|
|
|
|
|
case 'f': putfs(nodep, ""); break;
|
|
|
|
|
case 'k': putbs(""); break;
|
2019-05-19 22:13:13 +02:00
|
|
|
case 'l': {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(lhsp, nodep, "emitVerilog() references undef node");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(lhsp);
|
2019-05-19 22:13:13 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'r': {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(rhsp, nodep, "emitVerilog() references undef node");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(rhsp);
|
2019-05-19 22:13:13 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 't': {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(thsp, nodep, "emitVerilog() references undef node");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(thsp);
|
2019-05-19 22:13:13 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2020-05-10 20:27:22 +02:00
|
|
|
case 'o': {
|
|
|
|
|
UASSERT_OBJ(thsp, nodep, "emitVerilog() references undef node");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(fhsp);
|
2020-05-10 20:27:22 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
case 'd': {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(nodep->dtypep(), nodep, "emitVerilog() references undef node");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->dtypep());
|
2019-05-19 22:13:13 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2020-08-16 18:54:32 +02:00
|
|
|
default: nodep->v3fatalSrc("Unknown emitVerilog format code: %" << c); break;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeTermop* nodep) override { emitVerilogFormat(nodep, nodep->emitVerilog()); }
|
|
|
|
|
void visit(AstNodeUniop* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeBiop* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeTriop* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(),
|
|
|
|
|
nodep->thsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2025-11-06 14:23:35 +01:00
|
|
|
void visit(AstNodeQuadop* nodep) override {
|
|
|
|
|
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), nodep->thsp(),
|
|
|
|
|
nodep->fhsp());
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstMemberSel* nodep) override {
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep->fromp());
|
2022-08-18 12:33:45 +02:00
|
|
|
puts(".");
|
|
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
}
|
2023-03-15 00:35:40 +01:00
|
|
|
void visit(AstStructSel* nodep) override {
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep->fromp());
|
2023-03-15 00:35:40 +01:00
|
|
|
puts(".");
|
|
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAttrOf* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "$_ATTROF(");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->fromp());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->dimp()) {
|
2020-09-07 18:58:30 +02:00
|
|
|
putbs(", ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->dimp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
puts(")");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstInitArray* nodep) override {
|
2020-10-17 01:26:04 +02:00
|
|
|
putfs(nodep, "'{");
|
2019-11-09 21:34:41 +01:00
|
|
|
int comma = 0;
|
2021-12-11 17:22:04 +01:00
|
|
|
const auto& mapr = nodep->map();
|
2020-11-11 04:10:38 +01:00
|
|
|
for (const auto& itr : mapr) {
|
2019-11-09 21:34:41 +01:00
|
|
|
if (comma++) putbs(", ");
|
2020-11-11 04:10:38 +01:00
|
|
|
puts(cvtToStr(itr.first));
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(":");
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNode* const valuep = itr.second->valuep();
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(valuep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
puts("}");
|
2014-03-31 02:28:51 +02:00
|
|
|
}
|
2025-08-16 00:49:06 +02:00
|
|
|
void visit(AstCond* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putbs("(");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->condp());
|
2020-04-15 13:58:34 +02:00
|
|
|
putfs(nodep, " ? ");
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextConstNull(nodep->thenp());
|
2020-04-15 13:58:34 +02:00
|
|
|
putbs(" : ");
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextConstNull(nodep->elsep());
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(")");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstRange* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
puts("[");
|
2020-12-07 03:13:56 +01:00
|
|
|
if (VN_IS(nodep->leftp(), Const) && VN_IS(nodep->rightp(), Const)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
|
2020-12-07 03:13:56 +01:00
|
|
|
puts(cvtToStr(nodep->leftConst()));
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(":");
|
2020-12-07 03:13:56 +01:00
|
|
|
puts(cvtToStr(nodep->rightConst()));
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->leftp());
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(":");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->rightp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2025-01-25 03:00:45 +01:00
|
|
|
puts("]");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstRand* nodep) override {
|
|
|
|
|
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->seedp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSel* nodep) override {
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->fromp());
|
2025-02-20 19:49:32 +01:00
|
|
|
int offset = 0;
|
|
|
|
|
AstNodeDType* const dtypep = nodep->fromp()->dtypep();
|
|
|
|
|
if (VN_IS(dtypep, BasicDType)) {
|
|
|
|
|
AstBasicDType* const basicDtypep = VN_AS(dtypep, BasicDType);
|
|
|
|
|
offset = basicDtypep->lo();
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
puts("[");
|
2018-02-02 03:32:58 +01:00
|
|
|
if (VN_IS(nodep->lsbp(), Const)) {
|
2025-06-24 17:59:09 +02:00
|
|
|
if (nodep->widthConst() == 1) {
|
2025-02-20 19:49:32 +01:00
|
|
|
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt() + offset));
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2025-06-24 17:59:09 +02:00
|
|
|
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt() + nodep->widthConst() + offset
|
|
|
|
|
- 1));
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(":");
|
2025-02-20 19:49:32 +01:00
|
|
|
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt() + offset));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->lsbp());
|
2025-02-20 19:49:32 +01:00
|
|
|
if (offset != 0) {
|
|
|
|
|
puts(" + ");
|
|
|
|
|
puts(cvtToStr(offset));
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
putfs(nodep, "+:");
|
2025-06-24 17:59:09 +02:00
|
|
|
puts(cvtToStr(nodep->widthConst()));
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
puts("]");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSliceSel* nodep) override {
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->fromp());
|
2017-11-23 20:55:32 +01:00
|
|
|
puts(cvtToStr(nodep->declRange()));
|
|
|
|
|
}
|
2025-03-11 22:53:35 +01:00
|
|
|
void visit(AstThisRef* nodep) override { puts("this"); }
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTypedef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "typedef ");
|
2025-01-25 03:00:45 +01:00
|
|
|
iterateConstNull(nodep->subDTypep());
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" ");
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
puts(";\n");
|
2009-11-07 05:16:06 +01:00
|
|
|
}
|
2025-10-10 16:16:15 +02:00
|
|
|
void visit(AstNodeCoverOrAssert* nodep) override {
|
|
|
|
|
putfs(nodep, nodep->verilogKwd() + " ");
|
|
|
|
|
if (nodep->type() == VAssertType::OBSERVED_DEFERRED_IMMEDIATE) {
|
|
|
|
|
puts("#0 ");
|
|
|
|
|
} else if (nodep->type() == VAssertType::FINAL_DEFERRED_IMMEDIATE) {
|
|
|
|
|
puts("final ");
|
|
|
|
|
} else if (nodep->type() == VAssertType::CONCURRENT) {
|
|
|
|
|
puts("property ");
|
|
|
|
|
}
|
|
|
|
|
iterateConstNull(nodep->sentreep());
|
|
|
|
|
puts("(");
|
2025-11-06 14:42:27 +01:00
|
|
|
if (AstSampled* const sampledp = VN_CAST(nodep->propp(), Sampled)) {
|
|
|
|
|
iterateAndNextConstNull(sampledp->exprp());
|
2025-10-10 16:16:15 +02:00
|
|
|
} else {
|
2025-11-06 14:42:27 +01:00
|
|
|
iterateAndNextConstNull(nodep->propp());
|
2025-10-10 16:16:15 +02:00
|
|
|
}
|
|
|
|
|
if (!VN_IS(nodep, Restrict)) {
|
|
|
|
|
puts(") begin\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->passsp());
|
|
|
|
|
puts("end\n");
|
|
|
|
|
} else {
|
|
|
|
|
puts(");\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (const AstAssert* const assertp = VN_CAST(nodep, Assert)) {
|
|
|
|
|
puts("else begin\n");
|
|
|
|
|
iterateAndNextConstNull(assertp->failsp());
|
|
|
|
|
puts("end\n");
|
|
|
|
|
} else if (const AstAssertIntrinsic* const assertp = VN_CAST(nodep, AssertIntrinsic)) {
|
|
|
|
|
puts("else begin\n");
|
|
|
|
|
iterateAndNextConstNull(assertp->failsp());
|
|
|
|
|
puts("end\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-25 03:00:45 +01:00
|
|
|
void visit(AstAssocArrayDType* nodep) override {
|
|
|
|
|
if (!m_arrayPost) {
|
|
|
|
|
iterateConst(nodep->subDTypep());
|
|
|
|
|
} else {
|
|
|
|
|
VL_RESTORER(m_arrayPost);
|
|
|
|
|
m_arrayPost = false;
|
|
|
|
|
puts("[");
|
|
|
|
|
iterateConst(nodep->keyDTypep());
|
|
|
|
|
puts("]");
|
|
|
|
|
m_arrayPost = true;
|
|
|
|
|
iterateConst(nodep->subDTypep()); // For post's key
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstBasicDType* nodep) override {
|
2025-01-25 03:00:45 +01:00
|
|
|
if (m_arrayPost) return;
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, nodep->prettyName());
|
2025-01-25 03:00:45 +01:00
|
|
|
if (nodep->isSigned() && !nodep->keyword().isDouble()) putfs(nodep, " signed");
|
2025-01-24 13:47:11 +01:00
|
|
|
// Do not emit ranges for integer atoms.
|
|
|
|
|
if (nodep->keyword().isIntNumeric() && !nodep->keyword().isBitLogic()) return;
|
2025-01-25 03:00:45 +01:00
|
|
|
emitPacked();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->rangep()) {
|
|
|
|
|
puts(" ");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->rangep());
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" ");
|
|
|
|
|
} else if (nodep->isRanged()) {
|
|
|
|
|
puts(" [");
|
2020-12-07 03:13:56 +01:00
|
|
|
puts(cvtToStr(nodep->hi()));
|
2022-10-18 23:29:51 +02:00
|
|
|
puts(":");
|
|
|
|
|
puts(cvtToStr(nodep->lo()));
|
|
|
|
|
puts("] ");
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2009-12-29 04:19:03 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConstDType* nodep) override {
|
2025-01-25 03:00:45 +01:00
|
|
|
if (m_arrayPost) return;
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, "const ");
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep->subDTypep());
|
2012-04-14 18:43:03 +02:00
|
|
|
}
|
2025-01-25 03:00:45 +01:00
|
|
|
void visit(AstDynArrayDType* nodep) override {
|
|
|
|
|
if (!m_arrayPost) {
|
|
|
|
|
iterateConst(nodep->subDTypep());
|
|
|
|
|
} else {
|
|
|
|
|
puts("[]");
|
|
|
|
|
iterateConst(nodep->subDTypep()); // For post's key
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void visit(AstEnumDType* nodep) override {
|
|
|
|
|
if (m_arrayPost) return;
|
|
|
|
|
putfs(nodep, "enum ");
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep->subDTypep());
|
2025-01-25 03:00:45 +01:00
|
|
|
puts("{\n");
|
|
|
|
|
iterateAndNextConstNull(nodep->itemsp());
|
|
|
|
|
puts("}");
|
|
|
|
|
}
|
2025-02-14 20:58:11 +01:00
|
|
|
void visit(AstEnumItemRef* nodep) override {
|
|
|
|
|
if (AstNodeModule* const classOrPackagep = nodep->classOrPackagep()) {
|
|
|
|
|
putfs(nodep, classOrPackagep->prettyName());
|
|
|
|
|
puts("::");
|
|
|
|
|
}
|
|
|
|
|
putfs(nodep, nodep->name());
|
|
|
|
|
}
|
2025-01-25 03:00:45 +01:00
|
|
|
void visit(AstEnumItem* nodep) override {
|
|
|
|
|
putfs(nodep, nodep->name());
|
|
|
|
|
iterateConstNull(nodep->rangep());
|
|
|
|
|
puts(" = ");
|
|
|
|
|
iterateConstNull(nodep->valuep());
|
|
|
|
|
if (nodep->nextp()) puts(",");
|
|
|
|
|
puts("\n");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstNodeArrayDType* nodep) override {
|
|
|
|
|
if (!m_arrayPost) {
|
|
|
|
|
if (VN_IS(nodep, PackArrayDType)) {
|
|
|
|
|
// Unpacked ranges handled in BasicDType, as they print "backwards"
|
|
|
|
|
m_packedps.push_back(nodep);
|
|
|
|
|
}
|
|
|
|
|
iterateConst(nodep->subDTypep());
|
|
|
|
|
} else {
|
|
|
|
|
if (VN_IS(nodep, UnpackArrayDType)) {
|
|
|
|
|
VL_RESTORER(m_arrayPost);
|
|
|
|
|
m_arrayPost = false;
|
|
|
|
|
iterateAndNextConstNull(nodep->rangep());
|
|
|
|
|
m_arrayPost = true;
|
|
|
|
|
}
|
|
|
|
|
iterateConst(nodep->subDTypep()); // For post's key
|
|
|
|
|
}
|
2011-07-02 18:45:26 +02:00
|
|
|
}
|
2025-02-21 22:49:14 +01:00
|
|
|
void visit(AstIfaceRefDType* nodep) override {
|
|
|
|
|
if (m_arrayPost) {
|
|
|
|
|
puts(" (");
|
|
|
|
|
if (nodep->cellp()) {
|
|
|
|
|
iterateConst(nodep->cellp());
|
|
|
|
|
} else {
|
|
|
|
|
puts("????");
|
|
|
|
|
}
|
|
|
|
|
puts(")");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
puts(nodep->ifaceName());
|
|
|
|
|
}
|
2024-08-21 11:30:59 +02:00
|
|
|
void visit(AstRefDType* nodep) override {
|
|
|
|
|
if (nodep->subDTypep()) {
|
|
|
|
|
iterateConst(nodep->skipRefp());
|
|
|
|
|
} else {
|
|
|
|
|
puts("\n???? // "s + nodep->prettyTypeName() + " -> UNLINKED\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-18 02:40:03 +02:00
|
|
|
void visit(AstRequireDType* nodep) override { iterateConst(nodep->lhsp()); }
|
2025-02-21 22:49:14 +01:00
|
|
|
void visit(AstModport* nodep) override {
|
|
|
|
|
puts(nodep->verilogKwd());
|
|
|
|
|
puts(" ");
|
|
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
puts(" (\n");
|
|
|
|
|
if (nodep->varsp()) {
|
|
|
|
|
iterateConst(nodep->varsp());
|
|
|
|
|
} else {
|
|
|
|
|
puts("????");
|
|
|
|
|
}
|
|
|
|
|
puts(");\n");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstModportVarRef* nodep) override {
|
|
|
|
|
puts(nodep->direction().verilogKwd());
|
|
|
|
|
puts(" ");
|
|
|
|
|
if (nodep->varp()) {
|
|
|
|
|
VL_RESTORER(m_suppressVarSemi);
|
|
|
|
|
m_suppressVarSemi = true;
|
|
|
|
|
iterateConst(nodep->varp());
|
|
|
|
|
} else {
|
|
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
}
|
|
|
|
|
if (nodep->nextp()) puts(", ");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeUOrStructDType* nodep) override {
|
2025-01-25 03:00:45 +01:00
|
|
|
if (m_arrayPost) return;
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(nodep->verilogKwd() + " ");
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->packed()) puts("packed ");
|
2025-01-25 03:00:45 +01:00
|
|
|
{
|
|
|
|
|
puts("{\n");
|
|
|
|
|
VL_RESTORER(m_packedps);
|
|
|
|
|
m_packedps.clear();
|
|
|
|
|
for (AstMemberDType* itemp = nodep->membersp(); itemp;
|
|
|
|
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
|
|
|
|
iterateConst(itemp);
|
|
|
|
|
}
|
|
|
|
|
puts("}");
|
2023-01-23 04:24:36 +01:00
|
|
|
}
|
2025-01-25 03:00:45 +01:00
|
|
|
emitPacked();
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstMemberDType* nodep) override {
|
2025-01-25 03:00:45 +01:00
|
|
|
if (m_arrayPost) return;
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep->subDTypep());
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(" ");
|
|
|
|
|
puts(nodep->name());
|
2025-01-25 03:00:45 +01:00
|
|
|
puts(";\n");
|
|
|
|
|
}
|
|
|
|
|
void visit(AstQueueDType* nodep) override {
|
|
|
|
|
if (!m_arrayPost) {
|
|
|
|
|
iterateConst(nodep->subDTypep());
|
|
|
|
|
} else {
|
|
|
|
|
VL_RESTORER(m_arrayPost);
|
|
|
|
|
m_arrayPost = false;
|
|
|
|
|
puts("[$");
|
|
|
|
|
if (nodep->boundp()) {
|
|
|
|
|
puts(":");
|
|
|
|
|
iterateConst(nodep->boundp());
|
|
|
|
|
}
|
|
|
|
|
puts("]");
|
|
|
|
|
m_arrayPost = true;
|
|
|
|
|
iterateConst(nodep->subDTypep()); // For post's key
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeFTaskRef* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->dotted() != "") {
|
|
|
|
|
putfs(nodep, nodep->dotted());
|
|
|
|
|
puts(".");
|
|
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
} else {
|
|
|
|
|
putfs(nodep, nodep->prettyName());
|
|
|
|
|
}
|
2025-10-10 16:16:15 +02:00
|
|
|
if (!VN_IS(nodep->taskp(), Property)) {
|
|
|
|
|
puts("(");
|
|
|
|
|
iterateAndNextConstNull(nodep->pinsp());
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2023-08-28 15:44:41 +02:00
|
|
|
void visit(AstCCall* nodep) override {
|
|
|
|
|
puts(nodep->funcp()->name());
|
|
|
|
|
puts("(");
|
|
|
|
|
iterateAndNextConstNull(nodep->argsp());
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstArg* nodep) override { iterateAndNextConstNull(nodep->exprp()); }
|
|
|
|
|
void visit(AstPrintTimeScale* nodep) override {
|
2020-12-08 05:15:29 +01:00
|
|
|
puts(nodep->verilogKwd());
|
|
|
|
|
puts(";\n");
|
|
|
|
|
}
|
2025-10-10 16:16:15 +02:00
|
|
|
void visit(AstPropSpec* nodep) override {
|
|
|
|
|
if (!VN_IS(nodep->propp(), FuncRef)) {
|
|
|
|
|
// Same dumping as in AstSenTree
|
|
|
|
|
putfs(nodep, "@(");
|
|
|
|
|
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
|
|
|
|
|
iterateConst(expp);
|
|
|
|
|
if (expp->nextp()) putqs(expp->nextp(), " or ");
|
|
|
|
|
}
|
|
|
|
|
puts(")");
|
|
|
|
|
}
|
|
|
|
|
if (nodep->disablep()) {
|
|
|
|
|
puts(" disable iff ");
|
|
|
|
|
iterateConst(nodep->disablep());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
puts(" ");
|
|
|
|
|
iterateConstNull(nodep->propp());
|
|
|
|
|
puts("\n");
|
|
|
|
|
}
|
2025-11-06 14:42:27 +01:00
|
|
|
void visit(AstPExpr* nodep) override { iterateConst(nodep->bodyp()); }
|
2025-10-10 16:16:15 +02:00
|
|
|
void visit(AstSExpr* nodep) override {
|
2025-11-06 14:42:27 +01:00
|
|
|
iterateConstNull(nodep->preExprp());
|
2025-10-10 16:16:15 +02:00
|
|
|
{
|
|
|
|
|
VL_RESTORER(m_suppressSemi);
|
|
|
|
|
m_suppressSemi = true;
|
2025-11-06 14:42:27 +01:00
|
|
|
iterateConst(nodep->delayp());
|
2025-10-10 16:16:15 +02:00
|
|
|
}
|
2025-11-06 14:42:27 +01:00
|
|
|
iterateConst(nodep->exprp());
|
2025-10-10 16:16:15 +02:00
|
|
|
}
|
2020-12-08 05:15:29 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Terminals
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarRef* nodep) override {
|
2018-10-15 00:39:33 +02:00
|
|
|
if (nodep->varScopep()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
putfs(nodep, nodep->varScopep()->prettyName());
|
2018-10-15 00:39:33 +02:00
|
|
|
} else {
|
2022-01-10 00:11:24 +01:00
|
|
|
if (nodep->varp()) {
|
2023-09-08 13:34:35 +02:00
|
|
|
if (nodep->selfPointer().isEmpty()) {
|
2022-01-10 00:11:24 +01:00
|
|
|
putfs(nodep, nodep->varp()->prettyName());
|
|
|
|
|
} else {
|
2023-09-08 13:34:35 +02:00
|
|
|
putfs(nodep, nodep->selfPointer().asString());
|
|
|
|
|
putfs(nodep, "->");
|
2022-01-10 00:11:24 +01:00
|
|
|
puts(nodep->varp()->prettyName());
|
|
|
|
|
}
|
2021-06-13 15:33:11 +02:00
|
|
|
} else {
|
2022-01-10 00:11:24 +01:00
|
|
|
putfs(nodep, nodep->name());
|
2021-06-13 15:33:11 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarXRef* nodep) override {
|
2025-02-21 22:49:14 +01:00
|
|
|
putfs(nodep, nodep->prettyName(nodep->dotted()));
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(".");
|
2022-01-10 00:11:24 +01:00
|
|
|
if (nodep->varp()) {
|
|
|
|
|
puts(nodep->varp()->prettyName());
|
|
|
|
|
} else {
|
|
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2025-10-10 16:16:15 +02:00
|
|
|
void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(m_prefixed, true)); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Just iterate
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTopScope* nodep) override { iterateChildrenConst(nodep); }
|
|
|
|
|
void visit(AstScope* nodep) override { iterateChildrenConst(nodep); }
|
|
|
|
|
void visit(AstVar* nodep) override {
|
2020-12-09 00:29:45 +01:00
|
|
|
if (nodep->isIO()) {
|
|
|
|
|
putfs(nodep, nodep->verilogKwd());
|
|
|
|
|
puts(" ");
|
|
|
|
|
}
|
2025-01-25 03:00:45 +01:00
|
|
|
VL_RESTORER(m_arrayPost);
|
|
|
|
|
m_arrayPost = false;
|
|
|
|
|
iterateConstNull(nodep->dtypep()); // Dtype part before identifier
|
|
|
|
|
puts(" ");
|
|
|
|
|
puts(nodep->prettyName());
|
|
|
|
|
m_arrayPost = true;
|
|
|
|
|
iterateConstNull(nodep->dtypep()); // Dtype part after identifier
|
2021-02-28 02:06:46 +01:00
|
|
|
puts(m_suppressVarSemi ? "\n" : ";\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstActive* nodep) override {
|
2025-08-18 01:14:34 +02:00
|
|
|
VL_RESTORER(m_sentreep);
|
|
|
|
|
m_sentreep = nodep->sentreep();
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
2009-12-29 04:19:03 +01:00
|
|
|
}
|
2025-07-16 17:52:56 +02:00
|
|
|
void visit(AstDelay* nodep) override {
|
|
|
|
|
puts(""); // this is for proper alignment
|
2025-10-10 16:16:15 +02:00
|
|
|
if (nodep->isCycleDelay()) {
|
|
|
|
|
puts("##");
|
|
|
|
|
} else {
|
|
|
|
|
puts("#");
|
|
|
|
|
}
|
|
|
|
|
VL_RESTORER(m_prefixed);
|
|
|
|
|
m_prefixed = false;
|
2025-07-16 17:52:56 +02:00
|
|
|
iterateConst(nodep->lhsp());
|
2025-10-10 16:16:15 +02:00
|
|
|
if (!m_suppressSemi) {
|
|
|
|
|
puts(";\n");
|
|
|
|
|
} else {
|
|
|
|
|
puts(" ");
|
|
|
|
|
}
|
2025-07-16 17:52:56 +02:00
|
|
|
iterateAndNextConstNull(nodep->stmtsp());
|
|
|
|
|
}
|
|
|
|
|
void visit(AstCAwait* nodep) override {
|
|
|
|
|
AstCMethodHard* methodp = VN_CAST(nodep->exprp(), CMethodHard);
|
|
|
|
|
UASSERT_OBJ(methodp, nodep, "AstCAwait expression must be an AstCMethodHard");
|
|
|
|
|
puts(""); // this is for proper alignment
|
|
|
|
|
puts("#");
|
|
|
|
|
iterateConst(methodp->pinsp());
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); }
|
2025-01-25 03:00:45 +01:00
|
|
|
void visit(AstVarScope*) override {}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTraceDecl*) override {}
|
|
|
|
|
void visit(AstTraceInc*) override {}
|
2006-08-26 13:35:28 +02:00
|
|
|
// NOPs
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPragma*) override {}
|
2025-10-22 17:04:15 +02:00
|
|
|
void visit(AstStmtPragma*) override {}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCell*) override {} // Handled outside the Visit class
|
2006-08-26 13:35:28 +02:00
|
|
|
// Default
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override {
|
2024-01-29 02:24:28 +01:00
|
|
|
puts("\n???? // "s + nodep->prettyTypeName() + "\n");
|
2022-04-23 15:03:37 +02:00
|
|
|
iterateChildrenConst(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Not v3fatalSrc so we keep processing
|
2020-09-07 18:58:30 +02:00
|
|
|
if (!m_suppressUnknown) {
|
|
|
|
|
nodep->v3error(
|
|
|
|
|
"Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
explicit EmitVBaseVisitorConst(bool suppressUnknown)
|
|
|
|
|
: m_suppressUnknown{suppressUnknown} {}
|
2023-03-18 17:17:25 +01:00
|
|
|
~EmitVBaseVisitorConst() override = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2008-11-20 13:55:54 +01:00
|
|
|
// Emit to an output file
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2023-03-18 17:17:25 +01:00
|
|
|
class EmitVFileVisitor final : public EmitVBaseVisitorConst {
|
2025-07-30 13:41:21 +02:00
|
|
|
// STATE
|
|
|
|
|
V3OutVFile& m_of; // The output file
|
2008-11-20 13:55:54 +01:00
|
|
|
// METHODS
|
2025-07-30 13:41:21 +02:00
|
|
|
void putsNoTracking(const string& str) override { m_of.putsNoTracking(str); }
|
|
|
|
|
void puts(const string& str) override { m_of.puts(str); }
|
|
|
|
|
void putbs(const string& str) override { m_of.putbs(str); }
|
2022-09-16 12:22:11 +02:00
|
|
|
void putfs(AstNode*, const string& str) override { putbs(str); }
|
|
|
|
|
void putqs(AstNode*, const string& str) override { putbs(str); }
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2008-11-20 13:55:54 +01:00
|
|
|
public:
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
EmitVFileVisitor(AstNode* nodep, V3OutVFile& of, bool suppressUnknown)
|
|
|
|
|
: EmitVBaseVisitorConst{suppressUnknown}
|
2025-07-30 13:41:21 +02:00
|
|
|
, m_of{of} {
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(nodep);
|
2008-11-20 13:55:54 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~EmitVFileVisitor() override = default;
|
2008-11-20 13:55:54 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Emit to a stream (perhaps stringstream)
|
|
|
|
|
|
2023-03-18 17:17:25 +01:00
|
|
|
class EmitVStreamVisitor final : public EmitVBaseVisitorConst {
|
2025-07-30 13:41:21 +02:00
|
|
|
// STATE
|
|
|
|
|
V3OutStream m_os; // The output stream formatter
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
const bool m_tracking; // Use line tracking
|
2008-11-20 13:55:54 +01:00
|
|
|
// METHODS
|
2025-07-30 13:41:21 +02:00
|
|
|
void putsNoTracking(const string& str) override { m_os.putsNoTracking(str); }
|
|
|
|
|
void puts(const string& str) override {
|
|
|
|
|
m_tracking ? m_os.puts(str) : m_os.putsNoTracking(str);
|
|
|
|
|
}
|
|
|
|
|
void putbs(const string& str) override {
|
|
|
|
|
m_tracking ? m_os.putbs(str) : m_os.putsNoTracking(str);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void putfs(AstNode*, const string& str) override { putbs(str); }
|
|
|
|
|
void putqs(AstNode*, const string& str) override { putbs(str); }
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2012-03-20 20:57:29 +01:00
|
|
|
public:
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
EmitVStreamVisitor(const AstNode* nodep, std::ostream& os, bool tracking, bool suppressUnknown)
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
: EmitVBaseVisitorConst{suppressUnknown}
|
2025-07-30 13:41:21 +02:00
|
|
|
, m_os{os, V3OutFormatter::LA_VERILOG}
|
|
|
|
|
, m_tracking{tracking} {
|
2023-03-18 17:17:25 +01:00
|
|
|
iterateConst(const_cast<AstNode*>(nodep));
|
2008-11-20 13:55:54 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~EmitVStreamVisitor() override = default;
|
2008-11-20 13:55:54 +01:00
|
|
|
};
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// EmitV class functions
|
|
|
|
|
|
2022-04-23 15:03:37 +02:00
|
|
|
void V3EmitV::verilogForTree(const AstNode* nodep, std::ostream& os) {
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
{ EmitVStreamVisitor{nodep, os, /* tracking: */ false, false}; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3EmitV::debugVerilogForTree(const AstNode* nodep, std::ostream& os) {
|
|
|
|
|
{ EmitVStreamVisitor{nodep, os, /* tracking: */ true, true}; }
|
2021-11-26 16:52:36 +01:00
|
|
|
}
|
2010-01-07 22:41:19 +01:00
|
|
|
|
2019-09-27 09:44:23 +02:00
|
|
|
void V3EmitV::emitvFiles() {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2020-01-22 01:54:14 +01:00
|
|
|
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
|
2021-10-22 14:56:48 +02:00
|
|
|
filep = VN_AS(filep->nextp(), NodeFile)) {
|
2021-11-13 19:50:44 +01:00
|
|
|
AstVFile* const vfilep = VN_CAST(filep, VFile);
|
2019-09-27 09:44:23 +02:00
|
|
|
if (vfilep && vfilep->tblockp()) {
|
2022-11-20 19:11:01 +01:00
|
|
|
V3OutVFile of{vfilep->name()};
|
2025-07-30 13:41:21 +02:00
|
|
|
of.puts("// DESCRIPTION: Verilator generated Verilog\n");
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
EmitVFileVisitor{vfilep->tblockp(), of, false};
|
2019-09-27 09:44:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-07 18:58:30 +02:00
|
|
|
|
2022-01-10 00:11:24 +01:00
|
|
|
void V3EmitV::debugEmitV(const string& filename) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2022-08-30 04:15:06 +02:00
|
|
|
V3OutVFile of{filename};
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
EmitVFileVisitor{v3Global.rootp(), of, true};
|
2020-09-07 18:58:30 +02:00
|
|
|
}
|