diff --git a/CMakeLists.txt b/CMakeLists.txt
index c3fb06c3..40c152a4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -210,6 +210,7 @@ set(STA_SOURCE
verilog/VerilogReader.cc
verilog/VerilogLex.cc
verilog/VerilogParse.cc
+ verilog/VerilogWriter.cc
)
set(STA_HEADERS
@@ -385,6 +386,7 @@ set(STA_HEADERS
verilog/Verilog.hh
verilog/VerilogReader.hh
+ verilog/VerilogWriter.hh
)
# Source files.
diff --git a/verilog/Verilog.i b/verilog/Verilog.i
index e4896bee..e54a1513 100644
--- a/verilog/Verilog.i
+++ b/verilog/Verilog.i
@@ -19,6 +19,7 @@
// along with this program. If not, see .
#include "VerilogReader.hh"
+#include "VerilogWriter.hh"
#include "Sta.hh"
using sta::Sta;
@@ -48,4 +49,12 @@ delete_verilog_reader()
deleteVerilogReader();
}
+void
+write_verilog_cmd(const char *filename,
+ bool sorted)
+{
+ Network *network = cmdNetwork();
+ writeVerilog(filename, sorted, network);
+}
+
%} // inline
diff --git a/verilog/Verilog.tcl b/verilog/Verilog.tcl
index af9da635..9a25cee2 100644
--- a/verilog/Verilog.tcl
+++ b/verilog/Verilog.tcl
@@ -19,5 +19,16 @@ namespace eval sta {
# Defined by SWIG interface Verilog.i.
define_cmd_args "read_verilog" {filename}
+define_cmd_args "write_verilog" {[-sorted] filename}
+
+proc write_verilog { args } {
+ parse_key_args "write_verilog" args keys {} flags {-sorted}
+
+ set sorted [info exists flags(-sorted)]
+ check_argc_eq1 "write_verilog" $args
+ set filename $args
+ write_verilog_cmd $filename $sorted
+}
+
# sta namespace end
}
diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc
new file mode 100644
index 00000000..f4b8c10d
--- /dev/null
+++ b/verilog/VerilogWriter.cc
@@ -0,0 +1,212 @@
+// OpenSTA, Static Timing Analyzer
+// Copyright (c) 2019, Parallax Software, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include
+#include "Machine.hh"
+#include "Error.hh"
+#include "PortDirection.hh"
+#include "Network.hh"
+#include "NetworkCmp.hh"
+#include "VerilogNamespace.hh"
+#include "VerilogWriter.hh"
+
+namespace sta {
+
+class VerilogWriter
+{
+public:
+ VerilogWriter(const char *filename,
+ bool sorted,
+ FILE *stream,
+ Network *network);
+ void writeModule(Instance *inst);
+
+protected:
+ void writePorts(Cell *cell);
+ void writePortDcls(Cell *cell);
+ const char *verilogPortDir(PortDirection *dir);
+ void writeChildren(Instance *inst);
+ void writeChild(Instance *child);
+
+ const char *filename_;
+ bool sorted_;
+ FILE *stream_;
+ Network *network_;
+
+ Set| written_cells_;
+ Set pending_children_;
+};
+
+void
+writeVerilog(const char *filename,
+ bool sorted,
+ Network *network)
+{
+ FILE *stream = fopen(filename, "w");
+ if (stream) {
+ VerilogWriter writer(filename, sorted, stream, network);
+ writer.writeModule(network->topInstance());
+ fclose(stream);
+ }
+ else
+ throw FileNotWritable(filename);
+}
+
+VerilogWriter::VerilogWriter(const char *filename,
+ bool sorted,
+ FILE *stream,
+ Network *network) :
+ filename_(filename),
+ sorted_(sorted),
+ stream_(stream),
+ network_(network)
+{
+}
+
+void
+VerilogWriter::writeModule(Instance *inst)
+{
+ Cell *cell = network_->cell(inst);
+ fprintf(stream_, "module %s (",
+ network_->name(cell));
+ writePorts(cell);
+ writePortDcls(cell);
+ fprintf(stream_, "\n");
+ writeChildren(inst);
+ fprintf(stream_, "endmodule\n");
+ written_cells_.insert(cell);
+
+ for (auto child : pending_children_) {
+ Cell *child_cell = network_->cell(child);
+ if (!written_cells_.hasKey(child_cell))
+ writeModule(child);
+ }
+}
+
+void
+VerilogWriter::writePorts(Cell *cell)
+{
+ bool first = true;
+ CellPortIterator *port_iter = network_->portIterator(cell);
+ while (port_iter->hasNext()) {
+ Port *port = port_iter->next();
+ if (!first)
+ fprintf(stream_, ",\n ");
+ fprintf(stream_, "%s",
+ network_->name(port));
+ first = false;
+ }
+ delete port_iter;
+ fprintf(stream_, ");\n");
+}
+
+void
+VerilogWriter::writePortDcls(Cell *cell)
+{
+ CellPortIterator *port_iter = network_->portIterator(cell);
+ while (port_iter->hasNext()) {
+ Port *port = port_iter->next();
+ PortDirection *dir = network_->direction(port);
+ if (dir) {
+ fprintf(stream_, " %s",
+ verilogPortDir(dir));
+ if (network_->isBus(port))
+ fprintf(stream_, " [%d:%d]",
+ network_->fromIndex(port),
+ network_->toIndex(port));
+ fprintf(stream_, " %s;\n",
+ network_->name(port));
+ if (dir->isTristate()) {
+ fprintf(stream_, " tri");
+ if (network_->isBus(port))
+ fprintf(stream_, " [%d:%d]",
+ network_->fromIndex(port),
+ network_->toIndex(port));
+ fprintf(stream_, " %s;\n",
+ network_->name(port));
+ }
+ }
+ }
+ delete port_iter;
+}
+
+const char *
+VerilogWriter::verilogPortDir(PortDirection *dir)
+{
+ if (dir == PortDirection::input())
+ return "input";
+ else if (dir == PortDirection::output())
+ return "output";
+ else if (dir == PortDirection::bidirect())
+ return "inout";
+ else if (dir == PortDirection::tristate())
+ return "output";
+ else
+ return nullptr;
+}
+
+void
+VerilogWriter::writeChildren(Instance *inst)
+{
+ Vector children;
+ InstanceChildIterator *child_iter = network_->childIterator(inst);
+ while (child_iter->hasNext()) {
+ Instance *child = child_iter->next();
+ children.push_back(child);
+ if (network_->isHierarchical(child))
+ pending_children_.insert(child);
+ }
+ delete child_iter;
+
+ if (sorted_)
+ sort(children, InstancePathNameLess(network_));
+
+ for (auto child : children)
+ writeChild(child);
+}
+
+void
+VerilogWriter::writeChild(Instance *child)
+{
+ Cell *child_cell = network_->cell(child);
+ const char *child_name = network_->name(child);
+ const char *child_vname = instanceVerilogName(child_name, '\0');
+ fprintf(stream_, " %s %s (",
+ network_->name(child_cell),
+ child_vname);
+ bool first = true;
+ InstancePinIterator *pin_iter = network_->pinIterator(child);
+ while (pin_iter->hasNext()) {
+ Pin *pin = pin_iter->next();
+ Net *net = network_->net(pin);
+ if (net) {
+ const char *net_name = network_->name(net);
+ const char *net_vname = netVerilogName(net_name, '\0');
+ Port *port = network_->port(pin);
+ const char *port_name = network_->name(port);
+ if (!first)
+ fprintf(stream_, ",\n ");
+ fprintf(stream_, ".%s(%s)",
+ port_name,
+ net_vname);
+ first = false;
+ }
+ }
+ delete pin_iter;
+ fprintf(stream_, ");\n");
+}
+
+} // namespace
diff --git a/verilog/VerilogWriter.hh b/verilog/VerilogWriter.hh
new file mode 100644
index 00000000..01e99f03
--- /dev/null
+++ b/verilog/VerilogWriter.hh
@@ -0,0 +1,31 @@
+// OpenSTA, Static Timing Analyzer
+// Copyright (c) 2019, Parallax Software, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#ifndef STA_WRITE_VERILOG_H
+#define STA_WRITE_VERILOG_H
+
+namespace sta {
+
+class Network;
+
+void
+writeVerilog(const char *filename,
+ bool sorted,
+ Network *network);
+
+} // namespace
+
+#endif
|