From 3f7e2074917bc931811dba803711bdba074d415c Mon Sep 17 00:00:00 2001 From: James Cherry Date: Sun, 16 Jun 2019 21:08:00 -0700 Subject: [PATCH] write_verilog --- CMakeLists.txt | 2 + verilog/Verilog.i | 9 ++ verilog/Verilog.tcl | 11 ++ verilog/VerilogWriter.cc | 212 +++++++++++++++++++++++++++++++++++++++ verilog/VerilogWriter.hh | 31 ++++++ 5 files changed, 265 insertions(+) create mode 100644 verilog/VerilogWriter.cc create mode 100644 verilog/VerilogWriter.hh 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