2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2012-03-20 21:13:10 +01:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Emit Verilog from tree
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2012-03-20 21:13:10 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2022-01-01 14:26:40 +01:00
|
|
|
// Copyright 2004-2022 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
|
2012-03-20 21:13:10 +01: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
|
2012-03-20 21:13:10 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
|
|
|
|
|
#include "V3EmitXml.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
#include "V3EmitCBase.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3String.h"
|
2012-03-20 21:13:10 +01:00
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// Emit statements and math operators
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class EmitXmlFileVisitor final : public VNVisitor {
|
2017-11-09 03:27:15 +01:00
|
|
|
// NODE STATE
|
2020-04-15 13:58:34 +02:00
|
|
|
// Entire netlist:
|
2017-11-09 03:27:15 +01:00
|
|
|
// AstNode::user1 -> uint64_t, number to connect crossrefs
|
|
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
// MEMBERS
|
2022-01-01 17:46:49 +01:00
|
|
|
V3OutFile* const m_ofp;
|
2020-08-15 19:11:27 +02:00
|
|
|
uint64_t m_id = 0;
|
2012-03-20 21:13:10 +01:00
|
|
|
|
|
|
|
|
// METHODS
|
2018-05-14 12:50:47 +02:00
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2012-03-20 21:13:10 +01:00
|
|
|
|
|
|
|
|
// Outfile methods
|
2020-04-15 13:58:34 +02:00
|
|
|
V3OutFile* ofp() const { return m_ofp; }
|
2012-03-20 21:13:10 +01:00
|
|
|
virtual void puts(const string& str) { ofp()->puts(str); }
|
|
|
|
|
virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
|
|
|
|
|
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-30 00:41:03 +02:00
|
|
|
putsNoTracking(V3OutFormatter::quoteNameControls(str, V3OutFormatter::LA_XML));
|
2019-05-19 22:13:13 +02:00
|
|
|
putsNoTracking("\"");
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XML methods
|
2017-11-09 03:27:15 +01:00
|
|
|
void outputId(AstNode* nodep) {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (!nodep->user1()) nodep->user1(++m_id);
|
2020-04-15 13:58:34 +02:00
|
|
|
puts("\"" + cvtToStr(nodep->user1()) + "\"");
|
2017-11-09 03:27:15 +01:00
|
|
|
}
|
2020-06-02 05:16:02 +02:00
|
|
|
void outputTag(AstNode* nodep, const string& tagin) {
|
|
|
|
|
string tag = tagin;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (tag == "") tag = VString::downcase(nodep->typeName());
|
2022-01-17 22:22:07 +01:00
|
|
|
puts("<" + tag);
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" " + nodep->fileline()->xmlDetailedLocation());
|
|
|
|
|
if (VN_IS(nodep, NodeDType)) {
|
|
|
|
|
puts(" id=");
|
|
|
|
|
outputId(nodep);
|
|
|
|
|
}
|
|
|
|
|
if (nodep->name() != "") {
|
|
|
|
|
puts(" name=");
|
|
|
|
|
putsQuoted(nodep->prettyName());
|
|
|
|
|
}
|
|
|
|
|
if (nodep->tag() != "") {
|
|
|
|
|
puts(" tag=");
|
|
|
|
|
putsQuoted(nodep->tag());
|
|
|
|
|
}
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const AstNodeDType* const dtp = VN_CAST(nodep, NodeDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (dtp->subDTypep()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" sub_dtype_id=");
|
|
|
|
|
outputId(dtp->subDTypep()->skipRefp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->dtypep()) {
|
|
|
|
|
puts(" dtype_id=");
|
|
|
|
|
outputId(nodep->dtypep()->skipRefp());
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2020-06-02 05:16:02 +02:00
|
|
|
void outputChildrenEnd(AstNode* nodep, const string& tagin) {
|
|
|
|
|
string tag = tagin;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (tag == "") tag = VString::downcase(nodep->typeName());
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) {
|
|
|
|
|
puts(">\n");
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
puts("</" + tag + ">\n");
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
puts("/>\n");
|
|
|
|
|
}
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignW* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
outputTag(nodep, "contassign"); // IEEE: vpiContAssign
|
2018-01-31 13:25:10 +01:00
|
|
|
outputChildrenEnd(nodep, "contassign");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCell* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
outputTag(nodep, "instance"); // IEEE: vpiInstance
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" defName=");
|
|
|
|
|
putsQuoted(nodep->modName()); // IEEE vpiDefName
|
|
|
|
|
puts(" origName=");
|
|
|
|
|
putsQuoted(nodep->origName());
|
2018-01-31 13:25:10 +01:00
|
|
|
outputChildrenEnd(nodep, "instance");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeIf* nodep) override {
|
2021-07-25 03:06:06 +02:00
|
|
|
outputTag(nodep, "if");
|
|
|
|
|
puts(">\n");
|
|
|
|
|
iterateAndNextNull(nodep->op1p());
|
|
|
|
|
puts("<begin>\n");
|
|
|
|
|
iterateAndNextNull(nodep->op2p());
|
|
|
|
|
puts("</begin>\n");
|
|
|
|
|
if (nodep->op3p()) {
|
|
|
|
|
puts("<begin>\n");
|
|
|
|
|
iterateAndNextNull(nodep->op3p());
|
|
|
|
|
puts("</begin>\n");
|
|
|
|
|
}
|
|
|
|
|
puts("</if>\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWhile* nodep) override {
|
2021-07-25 03:06:06 +02:00
|
|
|
outputTag(nodep, "while");
|
|
|
|
|
puts(">\n");
|
|
|
|
|
puts("<begin>\n");
|
|
|
|
|
iterateAndNextNull(nodep->op1p());
|
|
|
|
|
puts("</begin>\n");
|
|
|
|
|
if (nodep->op2p()) {
|
|
|
|
|
puts("<begin>\n");
|
|
|
|
|
iterateAndNextNull(nodep->op2p());
|
|
|
|
|
puts("</begin>\n");
|
|
|
|
|
}
|
|
|
|
|
if (nodep->op3p()) {
|
|
|
|
|
puts("<begin>\n");
|
|
|
|
|
iterateAndNextNull(nodep->op3p());
|
|
|
|
|
puts("</begin>\n");
|
|
|
|
|
}
|
|
|
|
|
if (nodep->op4p()) {
|
|
|
|
|
puts("<begin>\n");
|
|
|
|
|
iterateAndNextNull(nodep->op4p());
|
|
|
|
|
puts("</begin>\n");
|
|
|
|
|
}
|
|
|
|
|
puts("</while>\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNetlist* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
puts("<netlist>\n");
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
puts("</netlist>\n");
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConstPool* nodep) override {
|
2021-07-25 03:06:06 +02:00
|
|
|
if (!v3Global.opt.xmlOnly()) {
|
2021-07-25 03:07:07 +02:00
|
|
|
puts("<constpool>\n");
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
puts("</constpool>\n");
|
2021-07-25 03:06:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstInitArray* nodep) override {
|
2021-07-25 03:06:06 +02:00
|
|
|
puts("<initarray>\n");
|
2021-12-11 17:22:04 +01:00
|
|
|
const auto& mapr = nodep->map();
|
|
|
|
|
for (const auto& itr : mapr) {
|
2021-07-25 03:06:06 +02:00
|
|
|
puts("<inititem index=\"");
|
2021-12-11 17:22:04 +01:00
|
|
|
puts(cvtToStr(itr.first));
|
2021-07-25 03:06:06 +02:00
|
|
|
puts("\">\n");
|
2021-12-11 17:22:04 +01:00
|
|
|
iterateChildren(itr.second);
|
2021-07-25 03:06:06 +02:00
|
|
|
puts("</inititem>\n");
|
|
|
|
|
}
|
|
|
|
|
puts("</initarray>\n");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeModule* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
outputTag(nodep, "");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" origName=");
|
|
|
|
|
putsQuoted(nodep->origName());
|
|
|
|
|
if (nodep->level() == 1
|
|
|
|
|
|| nodep->level() == 2) // ==2 because we don't add wrapper when in XML mode
|
2019-05-19 22:13:13 +02:00
|
|
|
puts(" topModule=\"1\""); // IEEE vpiTopModule
|
2019-12-30 12:55:36 +01:00
|
|
|
if (nodep->modPublic()) puts(" public=\"true\"");
|
2019-05-19 22:13:13 +02:00
|
|
|
outputChildrenEnd(nodep, "");
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVar* nodep) override {
|
2022-01-02 19:56:40 +01:00
|
|
|
const VVarType typ = nodep->varType();
|
2021-06-21 00:32:57 +02:00
|
|
|
const string kw = nodep->verilogKwd();
|
|
|
|
|
const string vt = nodep->dtypep()->name();
|
2018-12-06 13:12:39 +01:00
|
|
|
outputTag(nodep, "");
|
|
|
|
|
if (nodep->isIO()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" dir=");
|
|
|
|
|
putsQuoted(kw);
|
2021-06-19 19:41:19 +02:00
|
|
|
if (nodep->pinNum() != 0) puts(" pinIndex=\"" + cvtToStr(nodep->pinNum()) + "\"");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" vartype=");
|
2022-01-02 19:56:40 +01:00
|
|
|
putsQuoted(!vt.empty() ? vt : typ == VVarType::PORT ? "port" : "unknown");
|
2018-12-06 13:12:39 +01:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" vartype=");
|
|
|
|
|
putsQuoted(!vt.empty() ? vt : kw);
|
2018-12-06 13:12:39 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" origName=");
|
|
|
|
|
putsQuoted(nodep->origName());
|
2019-12-30 12:55:36 +01:00
|
|
|
// Attributes
|
2020-08-16 20:55:46 +02:00
|
|
|
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
|
2020-01-12 10:03:17 +01:00
|
|
|
puts(" clocker=\"true\"");
|
2020-08-16 20:55:46 +02:00
|
|
|
} else if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_NO) {
|
2020-01-12 10:03:17 +01:00
|
|
|
puts(" clocker=\"false\"");
|
2020-08-16 20:55:46 +02:00
|
|
|
}
|
2019-12-30 12:55:36 +01:00
|
|
|
if (nodep->attrClockEn()) puts(" clock_enable=\"true\"");
|
|
|
|
|
if (nodep->attrIsolateAssign()) puts(" isolate_assignments=\"true\"");
|
2021-01-05 20:26:01 +01:00
|
|
|
if (nodep->isLatched()) puts(" latched=\"true\"");
|
2019-12-30 12:55:36 +01:00
|
|
|
if (nodep->isSigPublic()) puts(" public=\"true\"");
|
|
|
|
|
if (nodep->isSigUserRdPublic()) puts(" public_flat_rd=\"true\"");
|
|
|
|
|
if (nodep->isSigUserRWPublic()) puts(" public_flat_rw=\"true\"");
|
2020-08-16 20:55:46 +02:00
|
|
|
if (nodep->isGParam()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" param=\"true\"");
|
2020-08-16 20:55:46 +02:00
|
|
|
} else if (nodep->isParam()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" localparam=\"true\"");
|
2020-08-16 20:55:46 +02:00
|
|
|
}
|
2019-12-30 12:55:36 +01:00
|
|
|
if (nodep->attrScBv()) puts(" sc_bv=\"true\"");
|
|
|
|
|
if (nodep->attrSFormat()) puts(" sformat=\"true\"");
|
2019-05-19 22:13:13 +02:00
|
|
|
outputChildrenEnd(nodep, "");
|
2018-10-30 23:17:37 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstPin* nodep) override {
|
2018-10-27 23:29:00 +02:00
|
|
|
// What we call a pin in verilator is a port in the IEEE spec.
|
|
|
|
|
outputTag(nodep, "port"); // IEEE: vpiPort
|
|
|
|
|
if (nodep->modVarp()->isIO()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" direction=\"" + nodep->modVarp()->direction().xmlKwd() + "\"");
|
2018-10-27 23:29:00 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" portIndex=\"" + cvtToStr(nodep->pinNum()) + "\""); // IEEE: vpiPortIndex
|
2018-10-27 23:29:00 +02:00
|
|
|
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
|
|
|
|
|
outputChildrenEnd(nodep, "port");
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSenItem* nodep) override {
|
2018-01-31 13:29:14 +01:00
|
|
|
outputTag(nodep, "");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule
|
2018-01-31 13:29:14 +01:00
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstModportVarRef* nodep) override {
|
2018-12-10 13:25:44 +01:00
|
|
|
// Dump direction for Modport references
|
2021-06-21 00:32:57 +02:00
|
|
|
const string kw = nodep->direction().xmlKwd();
|
2018-12-10 13:25:44 +01:00
|
|
|
outputTag(nodep, "");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" direction=");
|
|
|
|
|
putsQuoted(kw);
|
2018-12-10 13:25:44 +01:00
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarXRef* nodep) override {
|
2018-12-13 04:12:31 +01:00
|
|
|
outputTag(nodep, "");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" dotted=");
|
|
|
|
|
putsQuoted(nodep->dotted());
|
2018-12-13 04:12:31 +01:00
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeCCall* nodep) override {
|
2021-07-25 03:06:06 +02:00
|
|
|
outputTag(nodep, "");
|
|
|
|
|
puts(" func=");
|
|
|
|
|
putsQuoted(nodep->funcp()->name());
|
|
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2012-03-20 21:13:10 +01:00
|
|
|
|
|
|
|
|
// Data types
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstBasicDType* nodep) override {
|
2019-06-12 13:19:14 +02:00
|
|
|
outputTag(nodep, "basicdtype");
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->isRanged()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" left=\"" + cvtToStr(nodep->left()) + "\"");
|
|
|
|
|
puts(" right=\"" + cvtToStr(nodep->right()) + "\"");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-07-25 03:07:07 +02:00
|
|
|
if (nodep->isSigned()) { puts(" signed=\"true\""); }
|
2019-05-19 22:13:13 +02:00
|
|
|
puts("/>\n");
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstIfaceRefDType* nodep) override {
|
2018-12-11 01:11:35 +01:00
|
|
|
string mpn;
|
|
|
|
|
outputTag(nodep, "");
|
|
|
|
|
if (nodep->isModport()) mpn = nodep->modportName();
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" modportname=");
|
|
|
|
|
putsQuoted(mpn);
|
2018-12-11 01:11:35 +01:00
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstDisplay* nodep) override {
|
2019-01-02 13:16:37 +01:00
|
|
|
outputTag(nodep, "");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" displaytype=");
|
|
|
|
|
putsQuoted(nodep->verilogKwd());
|
2019-01-02 13:16:37 +01:00
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstElabDisplay* nodep) override {
|
2019-08-05 04:34:54 +02:00
|
|
|
outputTag(nodep, "");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" displaytype=");
|
|
|
|
|
putsQuoted(nodep->verilogKwd());
|
2019-08-05 04:34:54 +02:00
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstExtend* nodep) override {
|
2019-01-14 02:59:15 +01:00
|
|
|
outputTag(nodep, "");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" width=");
|
|
|
|
|
putsQuoted(cvtToStr(nodep->width()));
|
|
|
|
|
puts(" widthminv=");
|
|
|
|
|
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
2019-01-14 02:59:15 +01:00
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstExtendS* nodep) override {
|
2019-01-14 02:59:15 +01:00
|
|
|
outputTag(nodep, "");
|
2020-04-15 13:58:34 +02:00
|
|
|
puts(" width=");
|
|
|
|
|
putsQuoted(cvtToStr(nodep->width()));
|
|
|
|
|
puts(" widthminv=");
|
|
|
|
|
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
2019-01-14 02:59:15 +01:00
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2019-01-02 13:16:37 +01:00
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
// Default
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
outputTag(nodep, "");
|
|
|
|
|
outputChildrenEnd(nodep, "");
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
public:
|
2020-08-15 19:11:27 +02:00
|
|
|
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_ofp{ofp} {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(nodep);
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~EmitXmlFileVisitor() override = default;
|
2012-03-20 21:13:10 +01:00
|
|
|
};
|
|
|
|
|
|
2018-11-02 00:53:26 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// List of module files xml visitor
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class ModuleFilesXmlVisitor final : public VNVisitor {
|
2018-11-02 00:53:26 +01:00
|
|
|
private:
|
|
|
|
|
// MEMBERS
|
|
|
|
|
std::ostream& m_os;
|
|
|
|
|
std::set<std::string> m_modulesCovered;
|
|
|
|
|
std::deque<FileLine*> m_nodeModules;
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNetlist* nodep) override {
|
2018-11-02 00:53:26 +01:00
|
|
|
// Children are iterated backwards to ensure correct compilation order
|
|
|
|
|
iterateChildrenBackwards(nodep);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeModule* nodep) override {
|
2018-11-02 00:53:26 +01:00
|
|
|
// Only list modules and interfaces
|
|
|
|
|
// Assumes modules and interfaces list is already sorted level wise
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface))
|
2018-11-02 00:53:26 +01:00
|
|
|
&& m_modulesCovered.insert(nodep->fileline()->filename()).second) {
|
|
|
|
|
m_nodeModules.push_front(nodep->fileline());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//-----
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode*) override {
|
2018-11-02 00:53:26 +01:00
|
|
|
// All modules are present at root so no need to iterate on children
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
ModuleFilesXmlVisitor(AstNetlist* nodep, std::ostream& os)
|
2020-08-22 13:43:56 +02:00
|
|
|
: m_os(os) { // Need () or GCC 4.8 false warning
|
2018-11-02 00:53:26 +01:00
|
|
|
// Operate on whole netlist
|
|
|
|
|
nodep->accept(*this);
|
|
|
|
|
// Xml output
|
2020-04-15 13:58:34 +02:00
|
|
|
m_os << "<module_files>\n";
|
2020-08-16 17:43:49 +02:00
|
|
|
for (const FileLine* ifp : m_nodeModules) {
|
|
|
|
|
m_os << "<file id=\"" << ifp->filenameLetters() << "\" filename=\"" << ifp->filename()
|
|
|
|
|
<< "\" language=\"" << ifp->language().ascii() << "\"/>\n";
|
2018-11-02 00:53:26 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
m_os << "</module_files>\n";
|
2018-11-02 00:53:26 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~ModuleFilesXmlVisitor() override = default;
|
2018-11-02 00:53:26 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Hierarchy of Cells visitor
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class HierCellsXmlVisitor final : public VNVisitor {
|
2018-11-02 00:53:26 +01:00
|
|
|
private:
|
|
|
|
|
// MEMBERS
|
|
|
|
|
std::ostream& m_os;
|
|
|
|
|
std::string m_hier;
|
2020-08-15 19:11:27 +02:00
|
|
|
bool m_hasChildren = false;
|
2018-11-02 00:53:26 +01:00
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConstPool*) override {}
|
2021-07-25 03:06:06 +02:00
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeModule* nodep) override {
|
2018-11-02 00:53:26 +01:00
|
|
|
if (nodep->level() >= 0
|
2020-04-15 13:58:34 +02:00
|
|
|
&& nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode
|
|
|
|
|
m_os << "<cells>\n";
|
2022-01-17 22:22:07 +01:00
|
|
|
m_os << "<cell " << nodep->fileline()->xmlDetailedLocation() //
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
<< " name=\"" << nodep->prettyName() << "\""
|
|
|
|
|
<< " submodname=\"" << nodep->prettyName() << "\""
|
|
|
|
|
<< " hier=\"" << nodep->prettyName() << "\"";
|
|
|
|
|
m_hier = nodep->prettyName() + ".";
|
2018-11-02 00:53:26 +01:00
|
|
|
m_hasChildren = false;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
if (m_hasChildren) {
|
2020-04-15 13:58:34 +02:00
|
|
|
m_os << "</cell>\n";
|
2018-11-02 00:53:26 +01:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
m_os << "/>\n";
|
2018-11-02 00:53:26 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
m_os << "</cells>\n";
|
2018-11-02 00:53:26 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCell* nodep) override {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (nodep->modp()->dead()) return;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!m_hasChildren) m_os << ">\n";
|
2022-01-17 22:22:07 +01:00
|
|
|
m_os << "<cell " << nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name()
|
|
|
|
|
<< "\""
|
2020-04-15 13:58:34 +02:00
|
|
|
<< " submodname=\"" << nodep->modName() << "\""
|
|
|
|
|
<< " hier=\"" << m_hier + nodep->name() << "\"";
|
2021-11-26 23:55:36 +01:00
|
|
|
const std::string hier = m_hier;
|
2018-11-02 00:53:26 +01:00
|
|
|
m_hier += nodep->name() + ".";
|
|
|
|
|
m_hasChildren = false;
|
|
|
|
|
iterateChildren(nodep->modp());
|
|
|
|
|
if (m_hasChildren) {
|
2020-04-15 13:58:34 +02:00
|
|
|
m_os << "</cell>\n";
|
2018-11-02 00:53:26 +01:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
m_os << "/>\n";
|
2018-11-02 00:53:26 +01:00
|
|
|
}
|
|
|
|
|
m_hier = hier;
|
|
|
|
|
m_hasChildren = true;
|
|
|
|
|
}
|
|
|
|
|
//-----
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2018-11-02 00:53:26 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
HierCellsXmlVisitor(AstNetlist* nodep, std::ostream& os)
|
2020-08-22 13:43:56 +02:00
|
|
|
: m_os(os) { // Need () or GCC 4.8 false warning
|
2018-11-02 00:53:26 +01:00
|
|
|
// Operate on whole netlist
|
|
|
|
|
nodep->accept(*this);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~HierCellsXmlVisitor() override = default;
|
2018-11-02 00:53:26 +01:00
|
|
|
};
|
|
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// EmitXml class functions
|
|
|
|
|
|
|
|
|
|
void V3EmitXml::emitxml() {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2012-03-20 21:13:10 +01:00
|
|
|
// All-in-one file
|
2021-06-21 00:32:57 +02:00
|
|
|
const string filename = (v3Global.opt.xmlOutput().empty()
|
|
|
|
|
? v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".xml"
|
|
|
|
|
: v3Global.opt.xmlOutput());
|
2019-11-01 02:17:05 +01:00
|
|
|
V3OutXmlFile of(filename);
|
2012-03-20 21:13:10 +01:00
|
|
|
of.putsHeader();
|
2020-04-15 13:58:34 +02:00
|
|
|
of.puts("<!-- DESCR"
|
|
|
|
|
"IPTION: Verilator output: XML representation of netlist -->\n");
|
2012-03-20 21:13:10 +01:00
|
|
|
of.puts("<verilator_xml>\n");
|
|
|
|
|
{
|
2019-05-19 22:13:13 +02:00
|
|
|
std::stringstream sstr;
|
|
|
|
|
FileLine::fileNameNumMapDumpXml(sstr);
|
|
|
|
|
of.puts(sstr.str());
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2018-11-02 00:53:26 +01:00
|
|
|
{
|
|
|
|
|
std::stringstream sstr;
|
2021-11-26 23:55:36 +01:00
|
|
|
const ModuleFilesXmlVisitor moduleFilesVisitor{v3Global.rootp(), sstr};
|
|
|
|
|
const HierCellsXmlVisitor cellsVisitor{v3Global.rootp(), sstr};
|
2018-11-02 00:53:26 +01:00
|
|
|
of.puts(sstr.str());
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
const EmitXmlFileVisitor visitor{v3Global.rootp(), &of};
|
2012-03-20 21:13:10 +01:00
|
|
|
of.puts("</verilator_xml>\n");
|
|
|
|
|
}
|