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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2021-01-01 16:29:54 +01:00
|
|
|
// Copyright 2004-2021 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 "V3Global.h"
|
2012-08-27 03:13:47 +02:00
|
|
|
#include "V3String.h"
|
2012-03-20 21:13:10 +01:00
|
|
|
#include "V3EmitXml.h"
|
|
|
|
|
#include "V3EmitCBase.h"
|
|
|
|
|
|
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
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class EmitXmlFileVisitor final : public AstNVisitor {
|
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
|
2020-04-15 13:58:34 +02:00
|
|
|
V3OutFile* 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());
|
|
|
|
|
puts("<" + tag + " " + nodep->fileline()->xml());
|
|
|
|
|
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
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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");
|
|
|
|
|
}
|
2021-07-25 03:06:06 +02:00
|
|
|
virtual void visit(AstNodeIf* nodep) override {
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstWhile* nodep) override {
|
|
|
|
|
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");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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
|
|
|
}
|
2021-07-25 03:06:06 +02:00
|
|
|
virtual void visit(AstConstPool* nodep) override {
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstInitArray* nodep) override {
|
|
|
|
|
puts("<initarray>\n");
|
|
|
|
|
const AstInitArray::KeyItemMap& map = nodep->map();
|
|
|
|
|
for (AstInitArray::KeyItemMap::const_iterator it = map.begin(); it != map.end(); ++it) {
|
|
|
|
|
puts("<inititem index=\"");
|
|
|
|
|
puts(cvtToStr(it->first));
|
|
|
|
|
puts("\">\n");
|
|
|
|
|
iterateChildren(it->second);
|
|
|
|
|
puts("</inititem>\n");
|
|
|
|
|
}
|
|
|
|
|
puts("</initarray>\n");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstVar* nodep) override {
|
2021-06-21 00:32:57 +02:00
|
|
|
const AstVarType typ = nodep->varType();
|
|
|
|
|
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=");
|
|
|
|
|
putsQuoted(!vt.empty() ? vt : typ == AstVarType::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
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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, "");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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, "");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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, "");
|
|
|
|
|
}
|
2021-07-25 03:06:06 +02:00
|
|
|
virtual void visit(AstNodeCCall* nodep) override {
|
|
|
|
|
outputTag(nodep, "");
|
|
|
|
|
puts(" func=");
|
|
|
|
|
putsQuoted(nodep->funcp()->name());
|
|
|
|
|
outputChildrenEnd(nodep, "");
|
|
|
|
|
}
|
2012-03-20 21:13:10 +01:00
|
|
|
|
|
|
|
|
// Data types
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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, "");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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, "");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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, "");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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, "");
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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
|
|
|
}
|
2020-11-17 01:56:16 +01:00
|
|
|
virtual ~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
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class ModuleFilesXmlVisitor final : public AstNVisitor {
|
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
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstNetlist* nodep) override {
|
2018-11-02 00:53:26 +01:00
|
|
|
// Children are iterated backwards to ensure correct compilation order
|
|
|
|
|
iterateChildrenBackwards(nodep);
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//-----
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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
|
|
|
}
|
2020-11-17 01:56:16 +01:00
|
|
|
virtual ~ModuleFilesXmlVisitor() override = default;
|
2018-11-02 00:53:26 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Hierarchy of Cells visitor
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class HierCellsXmlVisitor final : public AstNVisitor {
|
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
|
2021-06-13 16:05:55 +02:00
|
|
|
virtual void visit(AstConstPool*) override {}
|
2021-07-25 03:06:06 +02:00
|
|
|
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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";
|
|
|
|
|
m_os << "<cell " << nodep->fileline()->xml() << " "
|
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
|
|
|
<< nodep->fileline()->xmlDetailedLocation() //
|
|
|
|
|
<< " 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
|
|
|
}
|
|
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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";
|
|
|
|
|
m_os << "<cell " << nodep->fileline()->xml() << " "
|
|
|
|
|
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
|
|
|
|
|
<< " submodname=\"" << nodep->modName() << "\""
|
|
|
|
|
<< " hier=\"" << m_hier + nodep->name() << "\"";
|
2018-11-02 00:53:26 +01:00
|
|
|
std::string hier = m_hier;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
//-----
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual 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);
|
|
|
|
|
}
|
2020-11-17 01:56:16 +01:00
|
|
|
virtual ~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-07-12 00:42:01 +02:00
|
|
|
ModuleFilesXmlVisitor moduleFilesVisitor{v3Global.rootp(), sstr};
|
|
|
|
|
HierCellsXmlVisitor cellsVisitor{v3Global.rootp(), sstr};
|
2018-11-02 00:53:26 +01:00
|
|
|
of.puts(sstr.str());
|
|
|
|
|
}
|
2021-07-12 00:42:01 +02:00
|
|
|
EmitXmlFileVisitor visitor{v3Global.rootp(), &of};
|
2012-03-20 21:13:10 +01:00
|
|
|
of.puts("</verilator_xml>\n");
|
|
|
|
|
}
|