2018-09-28 17:54:21 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
// Copyright (c) 2025, Parallax Software, Inc.
|
2018-09-28 17:54:21 +02:00
|
|
|
//
|
|
|
|
|
// 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
|
2022-01-04 18:17:08 +01:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2018-09-28 17:54:21 +02:00
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2022-01-04 18:17:08 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2025-01-22 02:54:33 +01:00
|
|
|
//
|
|
|
|
|
// The origin of this software must not be misrepresented; you must not
|
|
|
|
|
// claim that you wrote the original software.
|
|
|
|
|
//
|
|
|
|
|
// Altered source versions must be plainly marked as such, and must not be
|
|
|
|
|
// misrepresented as being the original software.
|
|
|
|
|
//
|
|
|
|
|
// This notice may not be removed or altered from any source distribution.
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2025-01-28 17:11:05 +01:00
|
|
|
#include "VerilogReader.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2023-06-15 17:59:56 +02:00
|
|
|
#include <cstdlib>
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2025-01-25 19:21:40 +01:00
|
|
|
#include "Zlib.hh"
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Debug.hh"
|
|
|
|
|
#include "Report.hh"
|
|
|
|
|
#include "Error.hh"
|
|
|
|
|
#include "Stats.hh"
|
|
|
|
|
#include "Liberty.hh"
|
|
|
|
|
#include "PortDirection.hh"
|
|
|
|
|
#include "Network.hh"
|
|
|
|
|
#include "VerilogNamespace.hh"
|
2022-07-11 17:49:12 +02:00
|
|
|
#include "StringUtil.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
#include "verilog/VerilogReaderPvt.hh"
|
2025-01-22 02:35:21 +01:00
|
|
|
#include "verilog/VerilogScanner.hh"
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
typedef unsigned long long VerilogConstant10;
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2023-03-26 15:34:36 +02:00
|
|
|
static string
|
2025-01-22 02:35:21 +01:00
|
|
|
verilogBusBitName(const string &bus_name,
|
2023-03-26 15:34:36 +02:00
|
|
|
int index);
|
2018-09-28 17:54:21 +02:00
|
|
|
static int
|
|
|
|
|
hierarchyLevel(Net *net,
|
|
|
|
|
Network *network);
|
2025-01-22 02:35:21 +01:00
|
|
|
|
|
|
|
|
VerilogReader *
|
|
|
|
|
makeVerilogReader(NetworkReader *network)
|
|
|
|
|
{
|
|
|
|
|
return new VerilogReader(network);
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
readVerilogFile(const char *filename,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader *verilog_reader)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
return verilog_reader->read(filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-01-22 02:35:21 +01:00
|
|
|
deleteVerilogReader(VerilogReader *verilog_reader)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
delete verilog_reader;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
class VerilogError
|
|
|
|
|
{
|
|
|
|
|
public:
|
2020-12-14 02:21:35 +01:00
|
|
|
VerilogError(int id,
|
|
|
|
|
const char *filename,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line,
|
|
|
|
|
const char *msg,
|
|
|
|
|
bool warn);
|
|
|
|
|
~VerilogError();
|
2021-02-07 18:22:59 +01:00
|
|
|
const char *msg() const { return msg_; }
|
|
|
|
|
const char *filename() const { return filename_; }
|
|
|
|
|
int id() const { return id_; }
|
|
|
|
|
int line() const { return line_; }
|
2018-09-28 17:54:21 +02:00
|
|
|
bool warn() const { return warn_; }
|
|
|
|
|
|
|
|
|
|
private:
|
2020-12-14 02:21:35 +01:00
|
|
|
int id_;
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *filename_;
|
|
|
|
|
int line_;
|
|
|
|
|
const char *msg_;
|
|
|
|
|
bool warn_;
|
|
|
|
|
|
|
|
|
|
friend class VerilogErrorCmp;
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-14 02:21:35 +01:00
|
|
|
VerilogError::VerilogError(int id,
|
|
|
|
|
const char *filename,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line,
|
|
|
|
|
const char *msg,
|
|
|
|
|
bool warn) :
|
2020-12-14 02:21:35 +01:00
|
|
|
id_(id),
|
2018-09-28 17:54:21 +02:00
|
|
|
filename_(filename),
|
|
|
|
|
line_(line),
|
|
|
|
|
msg_(msg),
|
|
|
|
|
warn_(warn)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogError::~VerilogError()
|
|
|
|
|
{
|
|
|
|
|
// filename is owned by VerilogReader.
|
|
|
|
|
stringDelete(msg_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class VerilogErrorCmp
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool operator()(const VerilogError *error1,
|
|
|
|
|
const VerilogError *error2) const
|
|
|
|
|
{
|
|
|
|
|
int file_cmp = strcmp(error1->filename_, error2->filename_);
|
|
|
|
|
if (file_cmp == 0) {
|
|
|
|
|
if (error1->line_ == error2->line_)
|
|
|
|
|
return strcmp(error1->msg_, error2->msg_) < 0;
|
|
|
|
|
else
|
|
|
|
|
return error1->line_ < error2->line_;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return file_cmp < 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2019-06-17 17:32:28 +02:00
|
|
|
VerilogReader::VerilogReader(NetworkReader *network) :
|
|
|
|
|
report_(network->report()),
|
|
|
|
|
debug_(network->debug()),
|
2018-09-28 17:54:21 +02:00
|
|
|
network_(network),
|
2019-03-13 01:25:53 +01:00
|
|
|
library_(nullptr),
|
2018-09-28 17:54:21 +02:00
|
|
|
black_box_index_(0),
|
|
|
|
|
zero_net_name_("zero_"),
|
|
|
|
|
one_net_name_("one_")
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
network->setLinkFunc([=] (const char *top_cell_name,
|
|
|
|
|
bool make_black_boxes) -> Instance* {
|
|
|
|
|
return linkNetwork(top_cell_name, make_black_boxes);
|
|
|
|
|
});
|
|
|
|
|
constant10_max_ = stdstrPrint("%llu", std::numeric_limits<VerilogConstant10>::max());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogReader::~VerilogReader()
|
|
|
|
|
{
|
|
|
|
|
deleteModules();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::deleteModules()
|
|
|
|
|
{
|
2024-12-29 00:48:18 +01:00
|
|
|
for (const auto [name, module] : module_map_)
|
2018-09-28 17:54:21 +02:00
|
|
|
delete module;
|
|
|
|
|
module_map_.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogReader::read(const char *filename)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
gzstream::igzstream stream(filename);
|
2025-01-27 16:33:35 +01:00
|
|
|
if (stream.is_open()) {
|
2020-12-29 19:33:22 +01:00
|
|
|
Stats stats(debug_, report_);
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogScanner scanner(&stream, filename, report_);
|
|
|
|
|
VerilogParse parser(&scanner, this);
|
2018-09-28 17:54:21 +02:00
|
|
|
init(filename);
|
2025-01-22 02:35:21 +01:00
|
|
|
bool success = (parser.parse() == 0);
|
2018-09-28 17:54:21 +02:00
|
|
|
reportStmtCounts();
|
|
|
|
|
stats.report("Read verilog");
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw FileNotReadable(filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::init(const char *filename)
|
|
|
|
|
{
|
2024-12-29 00:48:18 +01:00
|
|
|
filename_ = filename;
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
library_ = network_->findLibrary("verilog");
|
2019-03-13 01:25:53 +01:00
|
|
|
if (library_ == nullptr)
|
2019-05-20 01:06:06 +02:00
|
|
|
library_ = network_->makeLibrary("verilog", nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
// Stats
|
2021-01-05 05:47:37 +01:00
|
|
|
report_stmt_stats_ = debug_->check("verilog", 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
module_count_ = 0;
|
|
|
|
|
inst_mod_count_ = 0;
|
|
|
|
|
inst_lib_count_ = 0;
|
|
|
|
|
inst_lib_net_arrays_ = 0;
|
|
|
|
|
dcl_count_ = 0;
|
|
|
|
|
dcl_bus_count_ = 0;
|
|
|
|
|
dcl_arg_count_ = 0;
|
|
|
|
|
net_scalar_count_ = 0;
|
|
|
|
|
net_part_select_count_ = 0;
|
|
|
|
|
net_bit_select_count_ = 0;
|
|
|
|
|
net_port_ref_scalar_count_ = 0;
|
|
|
|
|
net_port_ref_scalar_net_count_ = 0;
|
|
|
|
|
net_port_ref_bit_count_ = 0;
|
|
|
|
|
net_port_ref_part_count_ = 0;
|
|
|
|
|
net_constant_count_ = 0;
|
|
|
|
|
assign_count_ = 0;
|
|
|
|
|
concat_count_ = 0;
|
|
|
|
|
inst_names_ = 0;
|
|
|
|
|
port_names_ = 0;
|
|
|
|
|
inst_module_names_ = 0;
|
|
|
|
|
net_scalar_names_ = 0;
|
|
|
|
|
net_bus_names_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogModule *
|
|
|
|
|
VerilogReader::module(Cell *cell)
|
|
|
|
|
{
|
|
|
|
|
return module_map_.findKey(cell);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeModule(const string *module_vname,
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNetSeq *ports,
|
|
|
|
|
VerilogStmtSeq *stmts,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
const string module_name = moduleVerilogToSta(module_vname);
|
2023-03-26 15:34:36 +02:00
|
|
|
Cell *cell = network_->findCell(library_, module_name.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
if (cell) {
|
|
|
|
|
VerilogModule *module = module_map_[cell];
|
|
|
|
|
delete module;
|
2019-04-11 05:36:48 +02:00
|
|
|
module_map_.erase(cell);
|
2018-09-28 17:54:21 +02:00
|
|
|
network_->deleteCell(cell);
|
|
|
|
|
}
|
2022-07-11 17:49:12 +02:00
|
|
|
|
|
|
|
|
VerilogModule *module = new VerilogModule(module_name.c_str(), ports, stmts,
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts, filename_, line, this);
|
2024-12-29 00:48:18 +01:00
|
|
|
cell = network_->makeCell(library_, module_name.c_str(), false, filename_.c_str());
|
2022-07-11 17:49:12 +02:00
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
for (VerilogAttrStmt *stmt : *attr_stmts) {
|
|
|
|
|
for (VerilogAttrEntry *entry : *stmt->attrs())
|
2022-07-11 17:49:12 +02:00
|
|
|
network_->setAttribute(cell, entry->key(), entry->value());
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
module_map_[cell] = module;
|
|
|
|
|
makeCellPorts(cell, module, ports);
|
|
|
|
|
module_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
delete module_vname;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeModule(const string *module_name,
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogStmtSeq *port_dcls,
|
|
|
|
|
VerilogStmtSeq *stmts,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line)
|
|
|
|
|
{
|
|
|
|
|
VerilogNetSeq *ports = new VerilogNetSeq;
|
|
|
|
|
// Pull the port names out of the port declarations.
|
2020-02-02 02:13:41 +01:00
|
|
|
for (VerilogStmt *dcl : *port_dcls) {
|
2018-09-28 17:54:21 +02:00
|
|
|
if (dcl->isDeclaration()) {
|
|
|
|
|
VerilogDcl *dcl1 = dynamic_cast<VerilogDcl*>(dcl);
|
2020-02-02 02:13:41 +01:00
|
|
|
for (VerilogDclArg *arg : *dcl1->args()) {
|
2023-02-19 01:20:40 +01:00
|
|
|
VerilogNetNamed *port = new VerilogNetScalar(arg->netName());
|
2018-09-28 17:54:21 +02:00
|
|
|
ports->push_back(port);
|
|
|
|
|
}
|
|
|
|
|
// Add the port declarations to the statements.
|
|
|
|
|
stmts->push_back(dcl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete port_dcls;
|
2025-01-22 02:35:21 +01:00
|
|
|
makeModule(module_name, ports, stmts, attr_stmts, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeCellPorts(Cell *cell,
|
|
|
|
|
VerilogModule *module,
|
|
|
|
|
VerilogNetSeq *ports)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
StdStringSet port_names;
|
2020-02-02 02:13:41 +01:00
|
|
|
for (VerilogNet *mod_port : *ports) {
|
2023-03-26 15:34:36 +02:00
|
|
|
const string &port_name = mod_port->name();
|
|
|
|
|
if (port_names.find(port_name) == port_names.end()) {
|
|
|
|
|
port_names.insert(port_name);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (mod_port->isNamed()) {
|
|
|
|
|
if (mod_port->isNamedPortRef())
|
|
|
|
|
makeNamedPortRefCellPorts(cell, module, mod_port, port_names);
|
|
|
|
|
else
|
2025-01-22 02:35:21 +01:00
|
|
|
makeCellPort(cell, module, mod_port->name());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-12-14 02:21:35 +01:00
|
|
|
warn(165, module->filename(), module->line(),
|
|
|
|
|
"module %s repeated port name %s.",
|
2025-01-22 02:35:21 +01:00
|
|
|
module->name().c_str(),
|
2023-03-26 15:34:36 +02:00
|
|
|
port_name.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
checkModuleDcls(module, port_names);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Port *
|
|
|
|
|
VerilogReader::makeCellPort(Cell *cell,
|
|
|
|
|
VerilogModule *module,
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &port_name)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogDcl *dcl = module->declaration(port_name.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
if (dcl) {
|
|
|
|
|
PortDirection *dir = dcl->direction();
|
|
|
|
|
VerilogDclBus *dcl_bus = dynamic_cast<VerilogDclBus*>(dcl);
|
|
|
|
|
Port *port = dcl->isBus()
|
2025-01-22 02:35:21 +01:00
|
|
|
? network_->makeBusPort(cell, port_name.c_str(), dcl_bus->fromIndex(),
|
2018-09-28 17:54:21 +02:00
|
|
|
dcl_bus->toIndex())
|
2025-01-22 02:35:21 +01:00
|
|
|
: network_->makePort(cell, port_name.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
network_->setDirection(port, dir);
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-12-14 02:21:35 +01:00
|
|
|
warn(166, module->filename(), module->line(),
|
|
|
|
|
"module %s missing declaration for port %s.",
|
2025-01-22 02:35:21 +01:00
|
|
|
module->name().c_str(),
|
|
|
|
|
port_name.c_str());
|
|
|
|
|
return network_->makePort(cell, port_name.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeNamedPortRefCellPorts(Cell *cell,
|
|
|
|
|
VerilogModule *module,
|
|
|
|
|
VerilogNet *mod_port,
|
2025-01-22 02:35:21 +01:00
|
|
|
StdStringSet &port_names)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
PortSeq *member_ports = new PortSeq;
|
|
|
|
|
VerilogNetNameIterator *net_name_iter = mod_port->nameIterator(module,this);
|
|
|
|
|
while (net_name_iter->hasNext()) {
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &net_name = net_name_iter->next();
|
2023-03-26 15:34:36 +02:00
|
|
|
port_names.insert(net_name);
|
2018-09-28 17:54:21 +02:00
|
|
|
Port *port = makeCellPort(cell, module, net_name);
|
|
|
|
|
member_ports->push_back(port);
|
|
|
|
|
}
|
|
|
|
|
delete net_name_iter;
|
|
|
|
|
// Note that the bundle does NOT have a port declaration.
|
2023-03-26 15:34:36 +02:00
|
|
|
network_->makeBundlePort(cell, mod_port->name().c_str(), member_ports);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure each declaration appears in the module port list.
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::checkModuleDcls(VerilogModule *module,
|
2023-03-26 15:34:36 +02:00
|
|
|
set<string> &port_names)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
for (auto const & [port_name, dcl] : *module->declarationMap()) {
|
2018-09-28 17:54:21 +02:00
|
|
|
PortDirection *dir = dcl->direction();
|
|
|
|
|
if (dir->isInput()
|
|
|
|
|
|| dir->isOutput()
|
|
|
|
|
|| dir->isBidirect()) {
|
2023-03-26 15:34:36 +02:00
|
|
|
if (port_names.find(port_name) == port_names.end())
|
2020-12-14 02:21:35 +01:00
|
|
|
linkWarn(197, module->filename(), module->line(),
|
|
|
|
|
"module %s declared signal %s is not in the port list.",
|
2025-01-22 02:35:21 +01:00
|
|
|
module->name().c_str(),
|
|
|
|
|
port_name.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDcl *
|
|
|
|
|
VerilogReader::makeDcl(PortDirection *dir,
|
|
|
|
|
VerilogDclArgSeq *args,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line)
|
|
|
|
|
{
|
|
|
|
|
if (dir->isInternal()) {
|
|
|
|
|
// Prune wire declarations without assigns because they just eat memory.
|
2019-03-13 01:25:53 +01:00
|
|
|
VerilogDclArgSeq *assign_args = nullptr;
|
2020-02-02 02:13:41 +01:00
|
|
|
for (VerilogDclArg *arg : *args) {
|
2018-09-28 17:54:21 +02:00
|
|
|
if (arg->assign()) {
|
2019-03-13 01:25:53 +01:00
|
|
|
if (assign_args == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
assign_args = new VerilogDclArgSeq;
|
|
|
|
|
assign_args->push_back(arg);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
delete arg;
|
|
|
|
|
dcl_arg_count_--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete args;
|
|
|
|
|
if (assign_args) {
|
|
|
|
|
dcl_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
return new VerilogDcl(dir, assign_args, attr_stmts, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2024-04-22 23:54:12 +02:00
|
|
|
else {
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts->deleteContents();
|
|
|
|
|
delete attr_stmts;
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2024-04-22 23:54:12 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
dcl_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
return new VerilogDcl(dir, args, attr_stmts, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDcl *
|
|
|
|
|
VerilogReader::makeDcl(PortDirection *dir,
|
|
|
|
|
VerilogDclArg *arg,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line)
|
|
|
|
|
{
|
|
|
|
|
dcl_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
return new VerilogDcl(dir, arg, attr_stmts, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDclBus *
|
|
|
|
|
VerilogReader::makeDclBus(PortDirection *dir,
|
|
|
|
|
int from_index,
|
|
|
|
|
int to_index,
|
|
|
|
|
VerilogDclArg *arg,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line)
|
|
|
|
|
{
|
|
|
|
|
dcl_bus_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
return new VerilogDclBus(dir, from_index, to_index, arg, attr_stmts,
|
2022-07-11 17:49:12 +02:00
|
|
|
line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDclBus *
|
|
|
|
|
VerilogReader::makeDclBus(PortDirection *dir,
|
|
|
|
|
int from_index,
|
|
|
|
|
int to_index,
|
|
|
|
|
VerilogDclArgSeq *args,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line)
|
|
|
|
|
{
|
|
|
|
|
dcl_bus_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
return new VerilogDclBus(dir, from_index, to_index, args, attr_stmts,
|
2022-07-11 17:49:12 +02:00
|
|
|
line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDclArg *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeDclArg(const string *net_vname)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
dcl_arg_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
const string net_name = netVerilogToSta(net_vname);
|
|
|
|
|
VerilogDclArg *dcl =new VerilogDclArg(net_name);
|
|
|
|
|
delete net_vname;
|
2023-03-26 15:34:36 +02:00
|
|
|
return dcl;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDclArg *
|
|
|
|
|
VerilogReader::makeDclArg(VerilogAssign *assign)
|
|
|
|
|
{
|
|
|
|
|
dcl_arg_count_++;
|
|
|
|
|
return new VerilogDclArg(assign);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetPartSelect *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetPartSelect(const string *net_vname,
|
2018-09-28 17:54:21 +02:00
|
|
|
int from_index,
|
|
|
|
|
int to_index)
|
|
|
|
|
{
|
|
|
|
|
net_part_select_count_++;
|
|
|
|
|
if (report_stmt_stats_)
|
2025-01-22 02:35:21 +01:00
|
|
|
net_bus_names_ += net_vname->size() + 1;
|
|
|
|
|
const string net_name = netVerilogToSta(net_vname);
|
|
|
|
|
VerilogNetPartSelect *select = new VerilogNetPartSelect(net_name,
|
2023-03-26 15:34:36 +02:00
|
|
|
from_index,
|
2023-02-19 01:20:40 +01:00
|
|
|
to_index);
|
2025-01-22 02:35:21 +01:00
|
|
|
delete net_vname;
|
2023-02-19 01:20:40 +01:00
|
|
|
return select;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetConstant *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetConstant(const string *constant,
|
|
|
|
|
int line)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
net_constant_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
return new VerilogNetConstant(constant, this, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetScalar *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetScalar(const string *net_vname)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
net_scalar_count_++;
|
|
|
|
|
if (report_stmt_stats_)
|
2025-01-22 02:35:21 +01:00
|
|
|
net_scalar_names_ += net_vname->size() + 1;
|
|
|
|
|
const string net_name = netVerilogToSta(net_vname);
|
|
|
|
|
VerilogNetScalar *scalar = new VerilogNetScalar(net_name);
|
|
|
|
|
delete net_vname;
|
2023-02-19 01:20:40 +01:00
|
|
|
return scalar;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetBitSelect *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetBitSelect(const string *net_vname,
|
2018-09-28 17:54:21 +02:00
|
|
|
int index)
|
|
|
|
|
{
|
|
|
|
|
net_bit_select_count_++;
|
|
|
|
|
if (report_stmt_stats_)
|
2025-01-22 02:35:21 +01:00
|
|
|
net_bus_names_ += net_vname->size() + 1;
|
|
|
|
|
const string net_name = netVerilogToSta(net_vname);
|
|
|
|
|
VerilogNetBitSelect *select = new VerilogNetBitSelect(net_name, index);
|
|
|
|
|
delete net_vname;
|
2023-02-19 01:20:40 +01:00
|
|
|
return select;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogAssign *
|
|
|
|
|
VerilogReader::makeAssign(VerilogNet *lhs,
|
|
|
|
|
VerilogNet *rhs,
|
|
|
|
|
int line)
|
|
|
|
|
{
|
|
|
|
|
assign_count_++;
|
|
|
|
|
return new VerilogAssign(lhs, rhs, line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogInst *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeModuleInst(const string *module_vname,
|
|
|
|
|
const string *inst_vname,
|
2024-03-09 06:56:25 +01:00
|
|
|
VerilogNetSeq *pins,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2024-03-09 06:56:25 +01:00
|
|
|
const int line)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
const string module_name = moduleVerilogToSta(module_vname);
|
|
|
|
|
const string inst_name = instanceVerilogToSta(inst_vname);
|
2023-03-26 15:34:36 +02:00
|
|
|
Cell *cell = network_->findAnyCell(module_name.c_str());
|
2019-06-16 07:20:54 +02:00
|
|
|
LibertyCell *liberty_cell = nullptr;
|
|
|
|
|
if (cell)
|
|
|
|
|
liberty_cell = network_->libertyCell(cell);
|
2018-09-28 17:54:21 +02:00
|
|
|
// Instances of liberty with scalar ports are special cased
|
|
|
|
|
// to reduce the memory footprint of the verilog parser.
|
|
|
|
|
if (liberty_cell
|
|
|
|
|
&& hasScalarNamedPortRefs(liberty_cell, pins)) {
|
|
|
|
|
int port_count = network_->portBitCount(cell);
|
2025-01-22 02:35:21 +01:00
|
|
|
StdStringSeq net_names(port_count);
|
2020-02-02 02:13:41 +01:00
|
|
|
for (VerilogNet *vnet : *pins) {
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNetPortRefScalarNet *vpin =
|
2020-02-02 02:13:41 +01:00
|
|
|
dynamic_cast<VerilogNetPortRefScalarNet*>(vnet);
|
2023-03-26 15:34:36 +02:00
|
|
|
const char *port_name = vpin->name().c_str();
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &net_name = vpin->netName();
|
2018-09-28 17:54:21 +02:00
|
|
|
Port *port = network_->findPort(cell, port_name);
|
|
|
|
|
LibertyPort *lport = network_->libertyPort(port);
|
|
|
|
|
if (lport->isBus()) {
|
2018-12-05 23:18:41 +01:00
|
|
|
LibertyPortMemberIterator member_iter(lport);
|
|
|
|
|
lport = member_iter.next();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
int pin_index = lport->pinIndex();
|
2025-01-22 02:35:21 +01:00
|
|
|
net_names[pin_index] = net_name;
|
2018-09-28 17:54:21 +02:00
|
|
|
delete vpin;
|
|
|
|
|
net_port_ref_scalar_net_count_--;
|
|
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogInst *inst = new VerilogLibertyInst(liberty_cell, inst_name,
|
|
|
|
|
net_names, attr_stmts, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
delete pins;
|
|
|
|
|
if (report_stmt_stats_) {
|
2023-03-26 15:34:36 +02:00
|
|
|
inst_names_ += inst_name.size() + 1;
|
2018-09-28 17:54:21 +02:00
|
|
|
inst_lib_count_++;
|
|
|
|
|
inst_lib_net_arrays_ += port_count;
|
|
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
delete module_vname;
|
|
|
|
|
delete inst_vname;
|
2019-06-16 07:20:54 +02:00
|
|
|
return inst;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2023-03-26 15:34:36 +02:00
|
|
|
VerilogInst *inst = new VerilogModuleInst(module_name.c_str(),
|
|
|
|
|
inst_name.c_str(),
|
2022-07-11 17:49:12 +02:00
|
|
|
pins,
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts,
|
2022-07-11 17:49:12 +02:00
|
|
|
line);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (report_stmt_stats_) {
|
2023-03-26 15:34:36 +02:00
|
|
|
inst_module_names_ += module_name.size() + 1;
|
|
|
|
|
inst_names_ += inst_name.size() + 1;
|
2018-09-28 17:54:21 +02:00
|
|
|
inst_mod_count_++;
|
|
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
delete module_vname;
|
|
|
|
|
delete inst_vname;
|
2019-06-16 07:20:54 +02:00
|
|
|
return inst;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogReader::hasScalarNamedPortRefs(LibertyCell *liberty_cell,
|
|
|
|
|
VerilogNetSeq *pins)
|
|
|
|
|
{
|
|
|
|
|
if (pins
|
|
|
|
|
&& pins->size() > 0
|
|
|
|
|
&& (*pins)[0]->isNamedPortRef()) {
|
2020-02-02 02:13:41 +01:00
|
|
|
for (VerilogNet *vpin : *pins) {
|
2023-03-26 15:34:36 +02:00
|
|
|
const char *port_name = vpin->name().c_str();
|
2018-09-28 17:54:21 +02:00
|
|
|
LibertyPort *port = liberty_cell->findLibertyPort(port_name);
|
|
|
|
|
if (port) {
|
|
|
|
|
if (!(port->size() == 1
|
|
|
|
|
&& (vpin->isNamedPortRefScalarNet())))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-26 15:34:36 +02:00
|
|
|
VerilogNetPortRef *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetNamedPortRefScalarNet(const string *port_vname)
|
2023-03-26 15:34:36 +02:00
|
|
|
{
|
|
|
|
|
net_port_ref_scalar_net_count_++;
|
|
|
|
|
if (report_stmt_stats_)
|
2025-01-22 02:35:21 +01:00
|
|
|
port_names_ += port_vname->size() + 1;
|
|
|
|
|
const string port_name = portVerilogToSta(port_vname);
|
2023-03-26 15:34:36 +02:00
|
|
|
VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name.c_str());
|
2025-01-22 02:35:21 +01:00
|
|
|
delete port_vname;
|
2023-03-26 15:34:36 +02:00
|
|
|
return ref;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNetPortRef *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetNamedPortRefScalarNet(const string *port_vname,
|
|
|
|
|
const string *net_vname)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
net_port_ref_scalar_net_count_++;
|
|
|
|
|
if (report_stmt_stats_) {
|
2023-02-19 01:20:40 +01:00
|
|
|
if (net_vname)
|
2025-01-22 02:35:21 +01:00
|
|
|
net_scalar_names_ += net_vname->size() + 1;
|
|
|
|
|
port_names_ += port_vname->size() + 1;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
const string port_name = portVerilogToSta(port_vname);
|
|
|
|
|
const string net_name = netVerilogToSta(net_vname);
|
2023-03-26 15:34:36 +02:00
|
|
|
VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name.c_str(),
|
|
|
|
|
net_name.c_str());
|
2025-01-22 02:35:21 +01:00
|
|
|
delete port_vname;
|
|
|
|
|
delete net_vname;
|
2023-02-19 01:20:40 +01:00
|
|
|
return ref;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetPortRef *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetNamedPortRefBitSelect(const string *port_vname,
|
|
|
|
|
const string *bus_vname,
|
2018-09-28 17:54:21 +02:00
|
|
|
int index)
|
|
|
|
|
{
|
|
|
|
|
net_port_ref_scalar_net_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
const string bus_name = portVerilogToSta(bus_vname);
|
|
|
|
|
const string net_name = verilogBusBitName(bus_name, index);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (report_stmt_stats_) {
|
2023-03-26 15:34:36 +02:00
|
|
|
net_scalar_names_ += net_name.length() + 1;
|
2025-01-22 02:35:21 +01:00
|
|
|
port_names_ += port_vname->size() + 1;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
const string port_name = portVerilogToSta(port_vname);
|
2023-03-26 15:34:36 +02:00
|
|
|
VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name.c_str(),
|
|
|
|
|
net_name.c_str());
|
2025-01-22 02:35:21 +01:00
|
|
|
delete port_vname;
|
|
|
|
|
delete bus_vname;
|
2023-02-19 01:20:40 +01:00
|
|
|
return ref;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetPortRef *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetNamedPortRefScalar(const string *port_vname,
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNet *net)
|
|
|
|
|
{
|
|
|
|
|
net_port_ref_scalar_count_++;
|
|
|
|
|
if (report_stmt_stats_)
|
2025-01-22 02:35:21 +01:00
|
|
|
port_names_ += port_vname->size() + 1;
|
|
|
|
|
const string port_name = portVerilogToSta(port_vname);
|
2023-03-26 15:34:36 +02:00
|
|
|
VerilogNetPortRef *ref = new VerilogNetPortRefScalar(port_name.c_str(), net);
|
2025-01-22 02:35:21 +01:00
|
|
|
delete port_vname;
|
2023-02-19 01:20:40 +01:00
|
|
|
return ref;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetPortRef *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetNamedPortRefBit(const string *port_vname,
|
2018-09-28 17:54:21 +02:00
|
|
|
int index,
|
|
|
|
|
VerilogNet *net)
|
|
|
|
|
{
|
|
|
|
|
net_port_ref_bit_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
const string port_name = portVerilogToSta(port_vname);
|
2023-03-26 15:34:36 +02:00
|
|
|
VerilogNetPortRef *ref = new VerilogNetPortRefBit(port_name.c_str(),
|
|
|
|
|
index, net);
|
2025-01-22 02:35:21 +01:00
|
|
|
delete port_vname;
|
2023-02-19 01:20:40 +01:00
|
|
|
return ref;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetPortRef *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::makeNetNamedPortRefPart(const string *port_vname,
|
2018-09-28 17:54:21 +02:00
|
|
|
int from_index,
|
|
|
|
|
int to_index,
|
|
|
|
|
VerilogNet *net)
|
|
|
|
|
{
|
|
|
|
|
net_port_ref_part_count_++;
|
2025-01-22 02:35:21 +01:00
|
|
|
const string port_name = portVerilogToSta(port_vname);
|
|
|
|
|
VerilogNetPortRef *ref = new VerilogNetPortRefPart(port_name,
|
2023-03-26 15:34:36 +02:00
|
|
|
from_index,
|
2023-02-19 01:20:40 +01:00
|
|
|
to_index, net);
|
2025-01-22 02:35:21 +01:00
|
|
|
delete port_vname;
|
2023-02-19 01:20:40 +01:00
|
|
|
return ref;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetConcat *
|
|
|
|
|
VerilogReader::makeNetConcat(VerilogNetSeq *nets)
|
|
|
|
|
{
|
|
|
|
|
concat_count_++;
|
|
|
|
|
return new VerilogNetConcat(nets);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define printClassMemory(name, class_name, count) \
|
2025-01-22 02:35:21 +01:00
|
|
|
report_->reportLine(" %-20s %9d * %3zu = %6.1fMb\n", \
|
2020-12-29 19:33:22 +01:00
|
|
|
name, \
|
|
|
|
|
count, \
|
2025-01-22 02:35:21 +01:00
|
|
|
sizeof(class_name), \
|
2020-12-29 19:33:22 +01:00
|
|
|
(count * sizeof(class_name) * 1e-6))
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
#define printStringMemory(name, count) \
|
2020-12-29 19:33:22 +01:00
|
|
|
report_->reportLine(" %-20s %6.1fMb", name, count * 1e-6)
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::reportStmtCounts()
|
|
|
|
|
{
|
2021-01-05 05:47:37 +01:00
|
|
|
if (debug_->check("verilog", 1)) {
|
2020-12-29 19:33:22 +01:00
|
|
|
report_->reportLine("Verilog stats");
|
2018-09-28 17:54:21 +02:00
|
|
|
printClassMemory("modules", VerilogModule, module_count_);
|
|
|
|
|
printClassMemory("module insts", VerilogModuleInst, inst_mod_count_);
|
|
|
|
|
printClassMemory("liberty insts", VerilogLibertyInst, inst_lib_count_);
|
|
|
|
|
printClassMemory("liberty net arrays", char *, inst_lib_net_arrays_);
|
|
|
|
|
printClassMemory("declarations", VerilogDcl, dcl_count_);
|
|
|
|
|
printClassMemory("bus declarations", VerilogDclBus, dcl_bus_count_);
|
|
|
|
|
printClassMemory("declaration args", VerilogDclArg, dcl_arg_count_);
|
|
|
|
|
printClassMemory("port ref scalar", VerilogNetPortRefScalar,
|
|
|
|
|
net_port_ref_scalar_count_);
|
|
|
|
|
printClassMemory("port ref scalar net", VerilogNetPortRefScalarNet,
|
|
|
|
|
net_port_ref_scalar_net_count_);
|
|
|
|
|
printClassMemory("port ref bit", VerilogNetPortRefBit,
|
|
|
|
|
net_port_ref_bit_count_);
|
|
|
|
|
printClassMemory("port ref part", VerilogNetPortRefPart,
|
|
|
|
|
net_port_ref_part_count_);
|
|
|
|
|
printClassMemory("scalar nets", VerilogNetScalar, net_scalar_count_);
|
|
|
|
|
printClassMemory("bus bit nets",VerilogNetBitSelect,net_bit_select_count_);
|
|
|
|
|
printClassMemory("bus range nets", VerilogNetPartSelect,
|
|
|
|
|
net_part_select_count_);
|
|
|
|
|
printClassMemory("constant nets", VerilogNetConstant, net_constant_count_);
|
|
|
|
|
printClassMemory("concats", VerilogNetConcat, concat_count_);
|
|
|
|
|
printClassMemory("assigns", VerilogAssign, assign_count_);
|
|
|
|
|
printStringMemory("instance names", inst_names_);
|
|
|
|
|
printStringMemory("instance mod names", inst_module_names_);
|
|
|
|
|
printStringMemory("port names", port_names_);
|
|
|
|
|
printStringMemory("net scalar names", net_scalar_names_);
|
|
|
|
|
printStringMemory("net bus names", net_bus_names_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-12-14 02:21:35 +01:00
|
|
|
VerilogReader::error(int id,
|
|
|
|
|
const char *filename,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line,
|
|
|
|
|
const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, fmt);
|
2025-01-22 02:35:21 +01:00
|
|
|
report_->vfileError(id, filename, line, fmt, args);
|
2018-09-28 17:54:21 +02:00
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-12-14 02:21:35 +01:00
|
|
|
VerilogReader::warn(int id,
|
|
|
|
|
const char *filename,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line,
|
|
|
|
|
const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, fmt);
|
2025-01-22 02:35:21 +01:00
|
|
|
report_->vfileWarn(id, filename, line, fmt, args);
|
2018-09-28 17:54:21 +02:00
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogModule::VerilogModule(const string &name,
|
2024-03-09 06:56:25 +01:00
|
|
|
VerilogNetSeq *ports,
|
|
|
|
|
VerilogStmtSeq *stmts,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
|
|
|
|
const string &filename,
|
2024-03-09 06:56:25 +01:00
|
|
|
int line,
|
|
|
|
|
VerilogReader *reader) :
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogStmt(line),
|
2025-01-22 02:35:21 +01:00
|
|
|
name_(name),
|
2018-09-28 17:54:21 +02:00
|
|
|
filename_(filename),
|
|
|
|
|
ports_(ports),
|
2022-07-11 17:49:12 +02:00
|
|
|
stmts_(stmts),
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts_(attr_stmts)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
parseStmts(reader);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogModule::~VerilogModule()
|
|
|
|
|
{
|
|
|
|
|
ports_->deleteContents();
|
|
|
|
|
delete ports_;
|
|
|
|
|
stmts_->deleteContents();
|
|
|
|
|
delete stmts_;
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts_->deleteContents();
|
|
|
|
|
delete attr_stmts_;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogModule::parseStmts(VerilogReader *reader)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
StdStringSet inst_names;
|
2020-02-02 02:13:41 +01:00
|
|
|
for (VerilogStmt *stmt : *stmts_) {
|
2018-09-28 17:54:21 +02:00
|
|
|
if (stmt->isDeclaration())
|
|
|
|
|
parseDcl(dynamic_cast<VerilogDcl*>(stmt), reader);
|
|
|
|
|
else if (stmt->isInstance())
|
|
|
|
|
checkInstanceName(dynamic_cast<VerilogInst*>(stmt), inst_names,
|
|
|
|
|
reader);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogModule::parseDcl(VerilogDcl *dcl,
|
|
|
|
|
VerilogReader *reader)
|
|
|
|
|
{
|
2020-02-02 02:13:41 +01:00
|
|
|
for (VerilogDclArg *arg : *dcl->args()) {
|
2025-01-22 02:35:21 +01:00
|
|
|
if (arg->isNamed()) {
|
|
|
|
|
const string &net_name = arg->netName();
|
|
|
|
|
VerilogDcl *existing_dcl = dcl_map_[net_name.c_str()];
|
2022-01-15 20:51:05 +01:00
|
|
|
if (existing_dcl) {
|
|
|
|
|
PortDirection *existing_dir = existing_dcl->direction();
|
|
|
|
|
if (existing_dir->isInternal())
|
|
|
|
|
// wire dcl can be used as modifier for input/inout dcls.
|
|
|
|
|
// Ignore the wire dcl.
|
2025-01-22 02:35:21 +01:00
|
|
|
dcl_map_[net_name.c_str()] = dcl;
|
2022-01-15 20:51:05 +01:00
|
|
|
else if (dcl->direction()->isTristate()) {
|
|
|
|
|
if (existing_dir->isOutput())
|
|
|
|
|
// tri dcl can be used as modifier for input/output/inout dcls.
|
|
|
|
|
// Keep the tristate dcl for outputs because it is more specific
|
|
|
|
|
// but ignore it for inputs and bidirs.
|
2025-01-22 02:35:21 +01:00
|
|
|
dcl_map_[net_name.c_str()] = dcl;
|
2022-01-15 20:51:05 +01:00
|
|
|
}
|
|
|
|
|
else if (dcl->direction()->isPowerGround()
|
|
|
|
|
&& (existing_dir->isOutput()
|
|
|
|
|
|| existing_dir->isInput()
|
|
|
|
|
|| existing_dir->isBidirect()))
|
|
|
|
|
// supply0/supply1 dcl can be used as modifier for
|
|
|
|
|
// input/output/inout dcls.
|
2025-01-22 02:35:21 +01:00
|
|
|
dcl_map_[net_name.c_str()] = dcl;
|
2023-03-26 15:34:36 +02:00
|
|
|
else if (!dcl->direction()->isInternal()) {
|
2025-01-22 02:35:21 +01:00
|
|
|
string net_vname = netVerilogName(net_name.c_str());
|
2024-12-29 00:48:18 +01:00
|
|
|
reader->warn(1395, filename_.c_str(), dcl->line(),
|
2022-01-15 20:51:05 +01:00
|
|
|
"signal %s previously declared on line %d.",
|
2023-03-26 15:34:36 +02:00
|
|
|
net_vname.c_str(),
|
2022-01-15 20:51:05 +01:00
|
|
|
existing_dcl->line());
|
2023-03-26 15:34:36 +02:00
|
|
|
}
|
2020-05-05 02:13:48 +02:00
|
|
|
}
|
2022-01-15 20:51:05 +01:00
|
|
|
else
|
2025-01-22 02:35:21 +01:00
|
|
|
dcl_map_[net_name.c_str()] = dcl;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for duplicate instance names during parse rather than during
|
|
|
|
|
// expansion so errors are only reported once.
|
|
|
|
|
void
|
|
|
|
|
VerilogModule::checkInstanceName(VerilogInst *inst,
|
2025-01-22 02:35:21 +01:00
|
|
|
StdStringSet &inst_names,
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogReader *reader)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
string inst_name = inst->instanceName();
|
|
|
|
|
if (inst_names.find(inst_name) != inst_names.end()) {
|
2024-03-30 00:16:46 +01:00
|
|
|
int i = 1;
|
2025-01-22 02:35:21 +01:00
|
|
|
string replacement_name;
|
2018-09-28 17:54:21 +02:00
|
|
|
do {
|
2025-01-22 02:35:21 +01:00
|
|
|
replacement_name = stdstrPrint("%s_%d", inst_name.c_str(), i++);
|
|
|
|
|
} while (inst_names.find(replacement_name) != inst_names.end());
|
|
|
|
|
string inst_vname = instanceVerilogName(inst_name.c_str());
|
2024-12-29 00:48:18 +01:00
|
|
|
reader->warn(1396, filename_.c_str(), inst->line(),
|
2020-12-14 02:21:35 +01:00
|
|
|
"instance name %s duplicated - renamed to %s.",
|
2023-03-26 15:34:36 +02:00
|
|
|
inst_vname.c_str(),
|
2025-01-22 02:35:21 +01:00
|
|
|
replacement_name.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
inst_name = replacement_name;
|
|
|
|
|
inst->setInstanceName(inst_name);
|
|
|
|
|
}
|
|
|
|
|
inst_names.insert(inst_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDcl *
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogModule::declaration(const string &net_name)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
return dcl_map_.findKey(net_name.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
VerilogStmt::VerilogStmt(int line) :
|
|
|
|
|
line_(line)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogInst::VerilogInst(const string &inst_name,
|
|
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2023-02-19 01:20:40 +01:00
|
|
|
const int line) :
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogStmt(line),
|
2025-01-22 02:35:21 +01:00
|
|
|
inst_name_(inst_name),
|
|
|
|
|
attr_stmts_(attr_stmts)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogInst::~VerilogInst()
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts_->deleteContents();
|
|
|
|
|
delete attr_stmts_;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogInst::setInstanceName(const string &inst_name)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
inst_name_ = inst_name;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogModuleInst::VerilogModuleInst(const string &module_name,
|
|
|
|
|
const string &inst_name,
|
2024-03-09 06:56:25 +01:00
|
|
|
VerilogNetSeq *pins,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2024-03-09 06:56:25 +01:00
|
|
|
int line) :
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogInst(inst_name, attr_stmts, line),
|
|
|
|
|
module_name_(module_name),
|
2018-09-28 17:54:21 +02:00
|
|
|
pins_(pins)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogModuleInst::~VerilogModuleInst()
|
|
|
|
|
{
|
|
|
|
|
if (pins_) {
|
|
|
|
|
pins_->deleteContents();
|
|
|
|
|
delete pins_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogModuleInst::hasPins()
|
|
|
|
|
{
|
|
|
|
|
return pins_
|
|
|
|
|
&& pins_->size() > 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogModuleInst::namedPins()
|
|
|
|
|
{
|
2018-10-24 01:24:22 +02:00
|
|
|
return pins_
|
|
|
|
|
&& pins_->size() > 0
|
2018-09-28 17:54:21 +02:00
|
|
|
&& (*pins_)[0]->isNamedPortRef();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogLibertyInst::VerilogLibertyInst(LibertyCell *cell,
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &inst_name,
|
|
|
|
|
const StdStringSeq &net_names,
|
|
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2024-03-09 06:56:25 +01:00
|
|
|
const int line) :
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogInst(inst_name, attr_stmts, line),
|
2018-09-28 17:54:21 +02:00
|
|
|
cell_(cell),
|
|
|
|
|
net_names_(net_names)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDcl::VerilogDcl(PortDirection *dir,
|
2024-03-09 06:56:25 +01:00
|
|
|
VerilogDclArgSeq *args,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2024-03-09 06:56:25 +01:00
|
|
|
int line) :
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogStmt(line),
|
|
|
|
|
dir_(dir),
|
2022-07-11 17:49:12 +02:00
|
|
|
args_(args),
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts_(attr_stmts)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDcl::VerilogDcl(PortDirection *dir,
|
2024-03-09 06:56:25 +01:00
|
|
|
VerilogDclArg *arg,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2024-03-09 06:56:25 +01:00
|
|
|
int line) :
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogStmt(line),
|
|
|
|
|
dir_(dir)
|
|
|
|
|
{
|
|
|
|
|
args_ = new VerilogDclArgSeq;
|
|
|
|
|
args_->push_back(arg);
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts_ = attr_stmts;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDcl::~VerilogDcl()
|
|
|
|
|
{
|
|
|
|
|
args_->deleteContents();
|
|
|
|
|
delete args_;
|
2025-01-22 02:35:21 +01:00
|
|
|
attr_stmts_->deleteContents();
|
|
|
|
|
delete attr_stmts_;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogDcl::appendArg(VerilogDclArg *arg)
|
|
|
|
|
{
|
|
|
|
|
args_->push_back(arg);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogDcl::portName()
|
|
|
|
|
{
|
|
|
|
|
return (*args_)[0]->netName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDclBus::VerilogDclBus(PortDirection *dir,
|
2024-03-09 06:56:25 +01:00
|
|
|
int from_index,
|
|
|
|
|
int to_index,
|
|
|
|
|
VerilogDclArgSeq *args,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2024-03-09 06:56:25 +01:00
|
|
|
int line) :
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogDcl(dir, args, attr_stmts, line),
|
2018-09-28 17:54:21 +02:00
|
|
|
from_index_(from_index),
|
|
|
|
|
to_index_(to_index)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDclBus::VerilogDclBus(PortDirection *dir,
|
2024-03-09 06:56:25 +01:00
|
|
|
int from_index,
|
|
|
|
|
int to_index,
|
|
|
|
|
VerilogDclArg *arg,
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts,
|
2024-03-09 06:56:25 +01:00
|
|
|
int line) :
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogDcl(dir, arg, attr_stmts, line),
|
2018-09-28 17:54:21 +02:00
|
|
|
from_index_(from_index),
|
|
|
|
|
to_index_(to_index)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
VerilogDclBus::size() const
|
|
|
|
|
{
|
|
|
|
|
return abs(to_index_ - from_index_) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogDclArg::VerilogDclArg(const string &net_name) :
|
|
|
|
|
net_name_(net_name),
|
2019-03-13 01:25:53 +01:00
|
|
|
assign_(nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDclArg::VerilogDclArg(VerilogAssign *assign) :
|
|
|
|
|
assign_(assign)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogDclArg::~VerilogDclArg()
|
|
|
|
|
{
|
|
|
|
|
delete assign_;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogDclArg::netName()
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
if (assign_)
|
|
|
|
|
return assign_->lhs()->name();
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2025-01-22 02:35:21 +01:00
|
|
|
return net_name_;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogAssign::VerilogAssign(VerilogNet *lhs,
|
|
|
|
|
VerilogNet *rhs,
|
|
|
|
|
int line) :
|
|
|
|
|
VerilogStmt(line),
|
|
|
|
|
lhs_(lhs),
|
|
|
|
|
rhs_(rhs)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogAssign::~VerilogAssign()
|
|
|
|
|
{
|
|
|
|
|
delete lhs_;
|
|
|
|
|
delete rhs_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
class VerilogNullNetNameIterator : public VerilogNetNameIterator
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual bool hasNext() { return false; }
|
2025-01-22 02:35:21 +01:00
|
|
|
virtual const string &next();
|
2018-09-28 17:54:21 +02:00
|
|
|
};
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &
|
|
|
|
|
VerilogNullNetNameIterator::next()
|
|
|
|
|
{
|
|
|
|
|
static const string null;
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
class VerilogOneNetNameIterator : public VerilogNetNameIterator
|
|
|
|
|
{
|
|
|
|
|
public:
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogOneNetNameIterator(const string &name);
|
2018-09-28 17:54:21 +02:00
|
|
|
virtual bool hasNext();
|
2025-01-22 02:35:21 +01:00
|
|
|
virtual const string &next();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
protected:
|
2025-01-22 02:35:21 +01:00
|
|
|
string name_;
|
|
|
|
|
bool has_next_;
|
2018-09-28 17:54:21 +02:00
|
|
|
};
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogOneNetNameIterator::VerilogOneNetNameIterator(const string &name) :
|
|
|
|
|
name_(name),
|
|
|
|
|
has_next_(true)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogOneNetNameIterator::hasNext()
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
return has_next_;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogOneNetNameIterator::next()
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
has_next_ = false;
|
|
|
|
|
return name_;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class VerilogBusNetNameIterator : public VerilogNetNameIterator
|
|
|
|
|
{
|
|
|
|
|
public:
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogBusNetNameIterator(const string bus_name,
|
2018-09-28 17:54:21 +02:00
|
|
|
int from_index,
|
|
|
|
|
int to_index);
|
|
|
|
|
virtual bool hasNext();
|
2025-01-22 02:35:21 +01:00
|
|
|
virtual const string &next();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
protected:
|
2025-01-22 02:35:21 +01:00
|
|
|
const string bus_name_;
|
2018-09-28 17:54:21 +02:00
|
|
|
int from_index_;
|
|
|
|
|
int to_index_;
|
|
|
|
|
int index_;
|
2023-03-26 15:34:36 +02:00
|
|
|
string bit_name_;
|
2018-09-28 17:54:21 +02:00
|
|
|
};
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogBusNetNameIterator::VerilogBusNetNameIterator(const string bus_name,
|
2018-09-28 17:54:21 +02:00
|
|
|
int from_index,
|
|
|
|
|
int to_index) :
|
|
|
|
|
bus_name_(bus_name),
|
|
|
|
|
from_index_(from_index),
|
|
|
|
|
to_index_(to_index),
|
|
|
|
|
index_(from_index)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogBusNetNameIterator::hasNext()
|
|
|
|
|
{
|
|
|
|
|
return (to_index_ > from_index_
|
|
|
|
|
&& index_ <= to_index_)
|
|
|
|
|
|| (to_index_ <= from_index_
|
|
|
|
|
&& index_ >= to_index_);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogBusNetNameIterator::next()
|
|
|
|
|
{
|
2023-03-26 15:34:36 +02:00
|
|
|
bit_name_ = verilogBusBitName(bus_name_, index_);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (to_index_ > from_index_)
|
|
|
|
|
index_++;
|
|
|
|
|
else
|
|
|
|
|
index_--;
|
2025-01-22 02:35:21 +01:00
|
|
|
return bit_name_;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-26 15:34:36 +02:00
|
|
|
static string
|
2025-01-22 02:35:21 +01:00
|
|
|
verilogBusBitName(const string &bus_name,
|
2023-03-26 15:34:36 +02:00
|
|
|
int index)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
return stdstrPrint("%s[%d]", bus_name.c_str(), index);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class VerilogConstantNetNameIterator : public VerilogNetNameIterator
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
VerilogConstantNetNameIterator(VerilogConstantValue *value,
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &zero,
|
|
|
|
|
const string &one);
|
2018-09-28 17:54:21 +02:00
|
|
|
virtual bool hasNext();
|
2025-01-22 02:35:21 +01:00
|
|
|
virtual const string &next();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
VerilogConstantValue *value_;
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &zero_;
|
|
|
|
|
const string &one_;
|
2018-09-28 17:54:21 +02:00
|
|
|
int bit_index_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
VerilogConstantNetNameIterator::
|
|
|
|
|
VerilogConstantNetNameIterator(VerilogConstantValue *value,
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &zero,
|
|
|
|
|
const string &one) :
|
2018-09-28 17:54:21 +02:00
|
|
|
value_(value),
|
|
|
|
|
zero_(zero),
|
|
|
|
|
one_(one),
|
|
|
|
|
bit_index_(value->size() - 1)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogConstantNetNameIterator::hasNext()
|
|
|
|
|
{
|
|
|
|
|
return bit_index_ >= 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogConstantNetNameIterator::next()
|
|
|
|
|
{
|
|
|
|
|
return (*value_)[bit_index_--] ? one_ : zero_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class VerilogNetConcatNameIterator : public VerilogNetNameIterator
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
VerilogNetConcatNameIterator(VerilogNetSeq *nets,
|
|
|
|
|
VerilogModule *module,
|
|
|
|
|
VerilogReader *reader);
|
|
|
|
|
virtual ~VerilogNetConcatNameIterator();
|
|
|
|
|
virtual bool hasNext();
|
2025-01-22 02:35:21 +01:00
|
|
|
virtual const string &next();
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
VerilogModule *module_;
|
|
|
|
|
VerilogReader *reader_;
|
|
|
|
|
VerilogNetSeq::Iterator net_iter_;
|
|
|
|
|
VerilogNetNameIterator *net_name_iter_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
VerilogNetConcatNameIterator::
|
|
|
|
|
VerilogNetConcatNameIterator(VerilogNetSeq *nets,
|
|
|
|
|
VerilogModule *module,
|
|
|
|
|
VerilogReader *reader) :
|
|
|
|
|
module_(module),
|
|
|
|
|
reader_(reader),
|
|
|
|
|
net_iter_(nets),
|
2019-03-13 01:25:53 +01:00
|
|
|
net_name_iter_(nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
if (net_iter_.hasNext())
|
|
|
|
|
net_name_iter_ = net_iter_.next()->nameIterator(module, reader);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetConcatNameIterator::~VerilogNetConcatNameIterator()
|
|
|
|
|
{
|
|
|
|
|
delete net_name_iter_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogNetConcatNameIterator::hasNext()
|
|
|
|
|
{
|
|
|
|
|
return (net_name_iter_ && net_name_iter_->hasNext())
|
|
|
|
|
|| net_iter_.hasNext();
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNetConcatNameIterator::next()
|
|
|
|
|
{
|
|
|
|
|
if (net_name_iter_ && net_name_iter_->hasNext())
|
|
|
|
|
return net_name_iter_->next();
|
|
|
|
|
else {
|
|
|
|
|
if (net_iter_.hasNext()) {
|
|
|
|
|
VerilogNet *net = net_iter_.next();
|
|
|
|
|
delete net_name_iter_;
|
|
|
|
|
net_name_iter_ = net->nameIterator(module_, reader_);
|
|
|
|
|
if (net_name_iter_ && net_name_iter_->hasNext())
|
|
|
|
|
return net_name_iter_->next();
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
static const string null;
|
|
|
|
|
return null;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-03-26 15:34:36 +02:00
|
|
|
const string VerilogNetUnnamed::null_;
|
|
|
|
|
|
|
|
|
|
VerilogNetNamed::VerilogNetNamed(const string &name) :
|
|
|
|
|
VerilogNet(),
|
|
|
|
|
name_(name)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetNamed::~VerilogNetNamed()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetScalar::VerilogNetScalar(const string &name) :
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNetNamed(name)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
verilogNetScalarSize(const char *name,
|
|
|
|
|
VerilogModule *module)
|
|
|
|
|
{
|
|
|
|
|
VerilogDcl *dcl = module->declaration(name);
|
|
|
|
|
if (dcl)
|
|
|
|
|
return dcl->size();
|
|
|
|
|
else
|
|
|
|
|
// undeclared signals are size 1
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
VerilogNetScalar::size(VerilogModule *module)
|
|
|
|
|
{
|
2023-03-26 15:34:36 +02:00
|
|
|
return verilogNetScalarSize(name_.c_str(), module);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static VerilogNetNameIterator *
|
2025-01-22 02:35:21 +01:00
|
|
|
verilogNetScalarNameIterator(const string &name,
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogModule *module)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
if (!name.empty()) {
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogDcl *dcl = module->declaration(name);
|
|
|
|
|
if (dcl && dcl->isBus()) {
|
|
|
|
|
VerilogDclBus *dcl_bus = dynamic_cast<VerilogDclBus *>(dcl);
|
|
|
|
|
return new VerilogBusNetNameIterator(name, dcl_bus->fromIndex(),
|
|
|
|
|
dcl_bus->toIndex());
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
return new VerilogOneNetNameIterator(name);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetNameIterator *
|
|
|
|
|
VerilogNetScalar::nameIterator(VerilogModule *module,
|
|
|
|
|
VerilogReader *)
|
|
|
|
|
{
|
2023-03-26 15:34:36 +02:00
|
|
|
return verilogNetScalarNameIterator(name_.c_str(), module);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetBitSelect::VerilogNetBitSelect(const string &name,
|
2018-09-28 17:54:21 +02:00
|
|
|
int index) :
|
2023-03-26 15:34:36 +02:00
|
|
|
VerilogNetNamed(verilogBusBitName(name, index)),
|
2018-09-28 17:54:21 +02:00
|
|
|
index_(index)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
VerilogNetBitSelect::size(VerilogModule *)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetNameIterator *
|
|
|
|
|
VerilogNetBitSelect::nameIterator(VerilogModule *,
|
|
|
|
|
VerilogReader *)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
return new VerilogOneNetNameIterator(name_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetPartSelect::VerilogNetPartSelect(const string &name,
|
2018-09-28 17:54:21 +02:00
|
|
|
int from_index,
|
|
|
|
|
int to_index):
|
|
|
|
|
VerilogNetNamed(name),
|
|
|
|
|
from_index_(from_index),
|
|
|
|
|
to_index_(to_index)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
VerilogNetPartSelect::size(VerilogModule *)
|
|
|
|
|
{
|
|
|
|
|
if (to_index_ > from_index_)
|
|
|
|
|
return to_index_ - from_index_ + 1;
|
|
|
|
|
else
|
|
|
|
|
return from_index_ - to_index_ + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetNameIterator *
|
|
|
|
|
VerilogNetPartSelect::nameIterator(VerilogModule *,
|
|
|
|
|
VerilogReader *)
|
|
|
|
|
{
|
2023-03-26 15:34:36 +02:00
|
|
|
return new VerilogBusNetNameIterator(name_.c_str(), from_index_, to_index_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetConstant::VerilogNetConstant(const string *constant,
|
|
|
|
|
VerilogReader *reader,
|
|
|
|
|
int line)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
parseConstant(constant, reader, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetConstant::parseConstant(const string *constant,
|
|
|
|
|
VerilogReader *reader,
|
|
|
|
|
int line)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
// Find constant size.
|
|
|
|
|
size_t csize_end = constant->find('\'');
|
|
|
|
|
string csize = constant->substr(0, csize_end);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
// Read the constant size.
|
2025-01-22 02:35:21 +01:00
|
|
|
size_t size = std::stol(csize);
|
2018-09-28 17:54:21 +02:00
|
|
|
value_ = new VerilogConstantValue(size);
|
|
|
|
|
|
|
|
|
|
// Read the constant base.
|
2025-01-22 02:35:21 +01:00
|
|
|
size_t base_idx = csize_end + 1;
|
|
|
|
|
char base = constant->at(base_idx);
|
|
|
|
|
switch (base) {
|
2018-09-28 17:54:21 +02:00
|
|
|
case 'b':
|
|
|
|
|
case 'B':
|
2025-01-22 02:35:21 +01:00
|
|
|
parseConstant(constant, base_idx, 2, 1);
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'O':
|
2025-01-22 02:35:21 +01:00
|
|
|
parseConstant(constant, base_idx, 8, 3);
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
|
|
|
|
case 'h':
|
|
|
|
|
case 'H':
|
2025-01-22 02:35:21 +01:00
|
|
|
parseConstant(constant, base_idx, 16, 4);
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'D':
|
2025-01-22 02:35:21 +01:00
|
|
|
parseConstant10(constant, base_idx, reader, line);
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
case '\0':
|
2025-01-22 02:35:21 +01:00
|
|
|
reader->report()->fileWarn(1861, reader->filename(), line,
|
|
|
|
|
"unknown constant base.");
|
2018-09-28 17:54:21 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
delete constant;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetConstant::parseConstant(const string *constant,
|
|
|
|
|
size_t base_idx,
|
2018-09-28 17:54:21 +02:00
|
|
|
int base,
|
|
|
|
|
int digit_bit_count)
|
|
|
|
|
{
|
|
|
|
|
// Scan the constant from LSD to MSD.
|
|
|
|
|
size_t size = value_->size();
|
|
|
|
|
char value_digit_str[2];
|
|
|
|
|
char *end;
|
|
|
|
|
value_digit_str[1] = '\0';
|
|
|
|
|
size_t bit = 0;
|
2025-01-22 02:35:21 +01:00
|
|
|
size_t idx = constant->size() - 1;
|
2018-09-28 17:54:21 +02:00
|
|
|
while (bit < size) {
|
2025-01-22 02:35:21 +01:00
|
|
|
char ch = (idx > base_idx) ? constant->at(idx--) : '0';
|
2018-09-28 17:54:21 +02:00
|
|
|
// Skip underscores.
|
|
|
|
|
if (ch != '_') {
|
|
|
|
|
value_digit_str[0] = ch;
|
|
|
|
|
unsigned value_digit = strtoul(value_digit_str, &end, base);
|
|
|
|
|
unsigned mask = 1;
|
|
|
|
|
for (int b = 0; b < digit_bit_count && bit < size; b++) {
|
|
|
|
|
bool value_bit = (value_digit & mask) != 0;
|
|
|
|
|
(*value_)[bit++] = value_bit;
|
|
|
|
|
mask = mask << 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetConstant::parseConstant10(const string *constant,
|
|
|
|
|
size_t base_idx,
|
|
|
|
|
VerilogReader *reader,
|
|
|
|
|
int line)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
// Copy the constant skipping underscores.
|
2025-01-22 02:35:21 +01:00
|
|
|
string tmp;
|
|
|
|
|
for (size_t i = base_idx + 1; i < constant->size(); i++) {
|
|
|
|
|
char ch = constant->at(i);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (ch != '_')
|
2025-01-22 02:35:21 +01:00
|
|
|
tmp += ch;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t size = value_->size();
|
2025-01-22 02:35:21 +01:00
|
|
|
size_t length = tmp.size();
|
|
|
|
|
const string &constant10_max = reader->constant10Max();
|
|
|
|
|
size_t max_length = constant10_max.size();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (length > max_length
|
|
|
|
|
|| (length == max_length
|
2025-01-22 02:35:21 +01:00
|
|
|
&& tmp > constant10_max))
|
|
|
|
|
reader->warn(1397, reader->filename(), line,
|
2020-12-14 02:21:35 +01:00
|
|
|
"base 10 constant greater than %s not supported.",
|
2025-01-22 02:35:21 +01:00
|
|
|
constant10_max.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
2025-01-22 02:35:21 +01:00
|
|
|
size_t *end = nullptr;
|
|
|
|
|
VerilogConstant10 value = std::stoull(tmp, end, 10);
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogConstant10 mask = 1;
|
|
|
|
|
for (size_t bit = 0; bit < size; bit++) {
|
|
|
|
|
(*value_)[bit] = (value & mask) != 0;
|
|
|
|
|
mask = mask << 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetConstant::~VerilogNetConstant()
|
|
|
|
|
{
|
|
|
|
|
delete value_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetNameIterator *
|
|
|
|
|
VerilogNetConstant::nameIterator(VerilogModule *,
|
|
|
|
|
VerilogReader *reader)
|
|
|
|
|
{
|
|
|
|
|
return new VerilogConstantNetNameIterator(value_,
|
|
|
|
|
reader->zeroNetName(),
|
|
|
|
|
reader->oneNetName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
VerilogNetConstant::size(VerilogModule *)
|
|
|
|
|
{
|
|
|
|
|
return value_->size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VerilogNetConcat::VerilogNetConcat(VerilogNetSeq *nets) :
|
|
|
|
|
nets_(nets)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetConcat::~VerilogNetConcat()
|
|
|
|
|
{
|
|
|
|
|
nets_->deleteContents();
|
|
|
|
|
delete nets_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
VerilogNetConcat::size(VerilogModule *module)
|
|
|
|
|
{
|
|
|
|
|
VerilogNetSeq::Iterator net_iter(nets_);
|
|
|
|
|
int sz = 0;
|
|
|
|
|
while (net_iter.hasNext()) {
|
|
|
|
|
VerilogNet *net = net_iter.next();
|
|
|
|
|
sz += net->size(module);
|
|
|
|
|
}
|
|
|
|
|
return sz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetNameIterator *
|
|
|
|
|
VerilogNetConcat::nameIterator(VerilogModule *module,
|
|
|
|
|
VerilogReader *reader)
|
|
|
|
|
{
|
|
|
|
|
return new VerilogNetConcatNameIterator(nets_, module, reader);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetPortRef::VerilogNetPortRef(const string &name) :
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNetScalar(name)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetPortRefScalarNet::VerilogNetPortRefScalarNet(const string &name) :
|
|
|
|
|
VerilogNetPortRef(name)
|
2023-03-26 15:34:36 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetPortRefScalarNet::VerilogNetPortRefScalarNet(const string &name,
|
|
|
|
|
const string &net_name) :
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNetPortRef(name),
|
2025-01-22 02:35:21 +01:00
|
|
|
net_name_(net_name)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
VerilogNetPortRefScalarNet::size(VerilogModule *module)
|
|
|
|
|
{
|
|
|
|
|
// VerilogNetScalar::size
|
2019-03-13 01:25:53 +01:00
|
|
|
VerilogDcl *dcl = nullptr;
|
2025-01-22 02:35:21 +01:00
|
|
|
if (!net_name_.empty())
|
2018-09-28 17:54:21 +02:00
|
|
|
dcl = module->declaration(net_name_);
|
|
|
|
|
if (dcl)
|
|
|
|
|
return dcl->size();
|
|
|
|
|
else
|
|
|
|
|
// undeclared signals are size 1
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetNameIterator *
|
|
|
|
|
VerilogNetPortRefScalarNet::nameIterator(VerilogModule *module,
|
|
|
|
|
VerilogReader *)
|
|
|
|
|
{
|
|
|
|
|
return verilogNetScalarNameIterator(net_name_, module);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetPortRefScalar::VerilogNetPortRefScalar(const string &name,
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNet *net) :
|
|
|
|
|
VerilogNetPortRef(name),
|
|
|
|
|
net_(net)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetPortRefScalar::~VerilogNetPortRefScalar()
|
|
|
|
|
{
|
|
|
|
|
delete net_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
VerilogNetPortRefScalar::size(VerilogModule *module)
|
|
|
|
|
{
|
|
|
|
|
if (net_)
|
|
|
|
|
return net_->size(module);
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerilogNetNameIterator *
|
|
|
|
|
VerilogNetPortRefScalar::nameIterator(VerilogModule *module,
|
|
|
|
|
VerilogReader *reader)
|
|
|
|
|
{
|
|
|
|
|
if (net_)
|
|
|
|
|
return net_->nameIterator(module, reader);
|
|
|
|
|
else
|
|
|
|
|
return new VerilogNullNetNameIterator();
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetPortRefBit::VerilogNetPortRefBit(const string &name,
|
2018-09-28 17:54:21 +02:00
|
|
|
int index,
|
|
|
|
|
VerilogNet *net) :
|
|
|
|
|
VerilogNetPortRefScalar(name, net),
|
2023-03-26 15:34:36 +02:00
|
|
|
bit_name_(verilogBusBitName(name, index))
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogNetPortRefPart::VerilogNetPortRefPart(const string &name,
|
2018-09-28 17:54:21 +02:00
|
|
|
int from_index,
|
|
|
|
|
int to_index,
|
|
|
|
|
VerilogNet *net) :
|
|
|
|
|
VerilogNetPortRefBit(name, from_index, net),
|
|
|
|
|
to_index_(to_index)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-26 15:34:36 +02:00
|
|
|
const string &
|
|
|
|
|
VerilogNetPortRefPart::name() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
return name_;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrEntry::VerilogAttrEntry(const string &key,
|
|
|
|
|
const string &value) :
|
2022-07-11 17:49:12 +02:00
|
|
|
key_(key),
|
|
|
|
|
value_(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 22:56:58 +01:00
|
|
|
std::string
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrEntry::key()
|
2022-07-11 17:49:12 +02:00
|
|
|
{
|
|
|
|
|
return key_;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 22:56:58 +01:00
|
|
|
std::string
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrEntry::value()
|
2022-07-11 17:49:12 +02:00
|
|
|
{
|
|
|
|
|
return value_;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmt::VerilogAttrStmt(VerilogAttrEntrySeq *attrs):
|
|
|
|
|
attrs_(attrs)
|
2022-07-11 17:49:12 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmt::~VerilogAttrStmt()
|
2022-07-11 17:49:12 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
attrs_->deleteContents();
|
|
|
|
|
delete attrs_;
|
2022-07-11 17:49:12 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrEntrySeq*
|
|
|
|
|
VerilogAttrStmt::attrs()
|
2022-07-11 17:49:12 +02:00
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
return attrs_;
|
2022-07-11 17:49:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Link verilog network
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Verilog net name to network net map.
|
|
|
|
|
typedef Map<const char*, Net*, CharPtrLess> BindingMap;
|
|
|
|
|
|
|
|
|
|
class VerilogBindingTbl
|
|
|
|
|
{
|
|
|
|
|
public:
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogBindingTbl(const string &zero_net_name_,
|
|
|
|
|
const string &one_net_name_);
|
2018-09-28 17:54:21 +02:00
|
|
|
Net *ensureNetBinding(const char *net_name,
|
|
|
|
|
Instance *inst,
|
|
|
|
|
NetworkReader *network);
|
|
|
|
|
Net *find(const char *name,
|
|
|
|
|
NetworkReader *network);
|
|
|
|
|
void bind(const char *name,
|
|
|
|
|
Net *net);
|
|
|
|
|
|
|
|
|
|
private:
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &zero_net_name_;
|
|
|
|
|
const string &one_net_name_;
|
2018-09-28 17:54:21 +02:00
|
|
|
BindingMap map_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Instance *
|
2019-06-27 01:01:58 +02:00
|
|
|
VerilogReader::linkNetwork(const char *top_cell_name,
|
2025-01-22 02:35:21 +01:00
|
|
|
bool make_black_boxes)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2019-07-04 06:18:38 +02:00
|
|
|
if (library_) {
|
|
|
|
|
Cell *top_cell = network_->findCell(library_, top_cell_name);
|
|
|
|
|
VerilogModule *module = this->module(top_cell);
|
|
|
|
|
if (module) {
|
|
|
|
|
// Seed the recursion for expansion with the top level instance.
|
2025-01-16 01:22:22 +01:00
|
|
|
Instance *top_instance = network_->makeInstance(top_cell, top_cell_name, nullptr);
|
2019-07-04 06:18:38 +02:00
|
|
|
VerilogBindingTbl bindings(zero_net_name_, one_net_name_);
|
|
|
|
|
VerilogNetSeq::Iterator port_iter(module->ports());
|
|
|
|
|
while (port_iter.hasNext()) {
|
|
|
|
|
VerilogNet *mod_port = port_iter.next();
|
|
|
|
|
VerilogNetNameIterator *net_name_iter = mod_port->nameIterator(module,
|
|
|
|
|
this);
|
|
|
|
|
while (net_name_iter->hasNext()) {
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &net_name = net_name_iter->next();
|
|
|
|
|
Port *port = network_->findPort(top_cell, net_name.c_str());
|
|
|
|
|
Net *net = bindings.ensureNetBinding(net_name.c_str(), top_instance, network_);
|
2019-07-04 06:18:38 +02:00
|
|
|
// Guard against repeated port name.
|
|
|
|
|
if (network_->findPin(top_instance, port) == nullptr) {
|
|
|
|
|
Pin *pin = network_->makePin(top_instance, port, nullptr);
|
|
|
|
|
network_->makeTerm(pin, net);
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-07-04 06:18:38 +02:00
|
|
|
delete net_name_iter;
|
|
|
|
|
}
|
|
|
|
|
makeModuleInstBody(module, top_instance, &bindings, make_black_boxes);
|
2025-01-22 02:35:21 +01:00
|
|
|
bool errors = reportLinkErrors();
|
2019-07-04 06:18:38 +02:00
|
|
|
deleteModules();
|
|
|
|
|
if (errors) {
|
|
|
|
|
network_->deleteInstance(top_instance);
|
|
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-07-04 06:18:38 +02:00
|
|
|
else
|
|
|
|
|
return top_instance;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-07-04 06:18:38 +02:00
|
|
|
else {
|
2025-01-22 02:35:21 +01:00
|
|
|
report_->error(1398, "%s is not a verilog module.", top_cell_name);
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2025-01-22 02:35:21 +01:00
|
|
|
report_->error(1399, "%s is not a verilog module.", top_cell_name);
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeModuleInstBody(VerilogModule *module,
|
|
|
|
|
Instance *inst,
|
|
|
|
|
VerilogBindingTbl *bindings,
|
|
|
|
|
bool make_black_boxes)
|
|
|
|
|
{
|
|
|
|
|
VerilogStmtSeq::Iterator stmt_iter(module->stmts());
|
|
|
|
|
while (stmt_iter.hasNext()) {
|
|
|
|
|
VerilogStmt *stmt = stmt_iter.next();
|
|
|
|
|
if (stmt->isModuleInst())
|
|
|
|
|
makeModuleInstNetwork(dynamic_cast<VerilogModuleInst*>(stmt),
|
|
|
|
|
inst, module, bindings, make_black_boxes);
|
|
|
|
|
else if (stmt->isLibertyInst())
|
|
|
|
|
makeLibertyInst(dynamic_cast<VerilogLibertyInst*>(stmt),
|
|
|
|
|
inst, module, bindings);
|
|
|
|
|
else if (stmt->isDeclaration()) {
|
|
|
|
|
VerilogDcl *dcl = dynamic_cast<VerilogDcl*>(stmt);
|
|
|
|
|
PortDirection *dir = dcl->direction();
|
|
|
|
|
VerilogDclArgSeq::Iterator arg_iter(dcl->args());
|
|
|
|
|
while (arg_iter.hasNext()) {
|
|
|
|
|
VerilogDclArg *arg = arg_iter.next();
|
|
|
|
|
VerilogAssign *assign = arg->assign();
|
|
|
|
|
if (assign)
|
|
|
|
|
mergeAssignNet(assign, module, inst, bindings);
|
|
|
|
|
if (dir->isGround()) {
|
2025-01-22 02:35:21 +01:00
|
|
|
Net *net = bindings->ensureNetBinding(arg->netName().c_str(),inst,network_);
|
2019-03-13 01:25:53 +01:00
|
|
|
network_->addConstantNet(net, LogicValue::zero);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if (dir->isPower()) {
|
2025-01-22 02:35:21 +01:00
|
|
|
Net *net = bindings->ensureNetBinding(arg->netName().c_str(),inst,network_);
|
2019-03-13 01:25:53 +01:00
|
|
|
network_->addConstantNet(net, LogicValue::one);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (stmt->isAssign())
|
|
|
|
|
mergeAssignNet(dynamic_cast<VerilogAssign*>(stmt), module, inst,
|
|
|
|
|
bindings);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeModuleInstNetwork(VerilogModuleInst *mod_inst,
|
|
|
|
|
Instance *parent,
|
|
|
|
|
VerilogModule *parent_module,
|
|
|
|
|
VerilogBindingTbl *parent_bindings,
|
|
|
|
|
bool make_black_boxes)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &module_name = mod_inst->moduleName();
|
|
|
|
|
Cell *cell = network_->findAnyCell(module_name.c_str());
|
2019-03-13 01:25:53 +01:00
|
|
|
if (cell == nullptr) {
|
2025-01-22 02:35:21 +01:00
|
|
|
string inst_vname = instanceVerilogName(mod_inst->instanceName().c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
if (make_black_boxes) {
|
|
|
|
|
cell = makeBlackBox(mod_inst, parent_module);
|
2023-03-07 01:34:20 +01:00
|
|
|
linkWarn(198, parent_module->filename(), mod_inst->line(),
|
2021-07-09 20:25:05 +02:00
|
|
|
"module %s not found. Creating black box for %s.",
|
2025-01-22 02:35:21 +01:00
|
|
|
mod_inst->moduleName().c_str(),
|
2023-03-26 15:34:36 +02:00
|
|
|
inst_vname.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
else
|
2023-03-07 01:34:20 +01:00
|
|
|
linkError(199, parent_module->filename(), mod_inst->line(),
|
2020-12-14 02:21:35 +01:00
|
|
|
"module %s not found for instance %s.",
|
2025-01-22 02:35:21 +01:00
|
|
|
mod_inst->moduleName().c_str(),
|
2023-03-26 15:34:36 +02:00
|
|
|
inst_vname.c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if (cell) {
|
2020-02-01 18:55:27 +01:00
|
|
|
LibertyCell *lib_cell = network_->libertyCell(cell);
|
|
|
|
|
if (lib_cell)
|
|
|
|
|
cell = network_->cell(lib_cell);
|
2025-01-22 02:35:21 +01:00
|
|
|
Instance *inst = network_->makeInstance(cell, mod_inst->instanceName().c_str(),
|
2018-09-28 17:54:21 +02:00
|
|
|
parent);
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts = mod_inst->attrStmts();
|
|
|
|
|
for (VerilogAttrStmt *stmt : *attr_stmts) {
|
|
|
|
|
for (VerilogAttrEntry *entry : *stmt->attrs()) {
|
2022-07-11 17:49:12 +02:00
|
|
|
network_->setAttribute(inst, entry->key(), entry->value());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-01 18:55:27 +01:00
|
|
|
if (lib_cell) {
|
|
|
|
|
// Make all pins so timing arcs are built.
|
|
|
|
|
LibertyCellPortBitIterator port_iter(lib_cell);
|
|
|
|
|
while (port_iter.hasNext()) {
|
|
|
|
|
LibertyPort *port = port_iter.next();
|
|
|
|
|
network_->makePin(inst, reinterpret_cast<Port*>(port), nullptr);
|
2019-01-20 18:44:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-02-01 18:55:27 +01:00
|
|
|
bool is_leaf = network_->isLeaf(cell);
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogBindingTbl bindings(zero_net_name_, one_net_name_);
|
|
|
|
|
if (mod_inst->hasPins()) {
|
|
|
|
|
if (mod_inst->namedPins())
|
|
|
|
|
makeNamedInstPins(cell, inst, mod_inst, &bindings, parent,
|
|
|
|
|
parent_module, parent_bindings, is_leaf);
|
|
|
|
|
else
|
|
|
|
|
makeOrderedInstPins(cell, inst, mod_inst, &bindings, parent,
|
|
|
|
|
parent_module, parent_bindings, is_leaf);
|
|
|
|
|
}
|
|
|
|
|
if (!is_leaf) {
|
2019-07-04 06:18:38 +02:00
|
|
|
VerilogModule *module = this->module(cell);
|
2022-01-15 20:51:05 +01:00
|
|
|
if (module)
|
|
|
|
|
makeModuleInstBody(module, inst, &bindings, make_black_boxes);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeNamedInstPins(Cell *cell,
|
|
|
|
|
Instance *inst,
|
|
|
|
|
VerilogModuleInst *mod_inst,
|
|
|
|
|
VerilogBindingTbl *bindings,
|
|
|
|
|
Instance *parent,
|
|
|
|
|
VerilogModule *parent_module,
|
|
|
|
|
VerilogBindingTbl *parent_bindings,
|
|
|
|
|
bool is_leaf)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
string inst_vname = instanceVerilogName(mod_inst->instanceName().c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogNetSeq::Iterator pin_iter(mod_inst->pins());
|
|
|
|
|
while (pin_iter.hasNext()) {
|
|
|
|
|
VerilogNetPortRef *vpin = dynamic_cast<VerilogNetPortRef*>(pin_iter.next());
|
2023-03-26 15:34:36 +02:00
|
|
|
const char *port_name = vpin->name().c_str();
|
2018-09-28 17:54:21 +02:00
|
|
|
Port *port = network_->findPort(cell, port_name);
|
|
|
|
|
if (port) {
|
|
|
|
|
if (vpin->hasNet()
|
2023-03-26 15:34:36 +02:00
|
|
|
&& network_->size(port) != vpin->size(parent_module)) {
|
2020-12-14 02:21:35 +01:00
|
|
|
linkWarn(200, parent_module->filename(), mod_inst->line(),
|
|
|
|
|
"instance %s port %s size %d does not match net size %d.",
|
2023-03-26 15:34:36 +02:00
|
|
|
inst_vname.c_str(),
|
2018-09-28 17:54:21 +02:00
|
|
|
network_->name(port),
|
|
|
|
|
network_->size(port),
|
|
|
|
|
vpin->size(parent_module));
|
2023-03-26 15:34:36 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
|
|
|
|
VerilogNetNameIterator *net_name_iter =
|
|
|
|
|
vpin->nameIterator(parent_module, this);
|
|
|
|
|
if (network_->hasMembers(port)) {
|
|
|
|
|
PortMemberIterator *port_iter = network_->memberIterator(port);
|
|
|
|
|
while (port_iter->hasNext()) {
|
|
|
|
|
Port *port = port_iter->next();
|
|
|
|
|
makeInstPin(inst, port, net_name_iter, bindings,
|
|
|
|
|
parent, parent_bindings, is_leaf);
|
|
|
|
|
}
|
|
|
|
|
delete port_iter;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
makeInstPin(inst, port, net_name_iter, bindings,
|
|
|
|
|
parent, parent_bindings, is_leaf);
|
|
|
|
|
}
|
|
|
|
|
delete net_name_iter;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-19 00:52:12 +02:00
|
|
|
else {
|
2021-07-08 01:57:34 +02:00
|
|
|
LibertyPgPort *pg_port = nullptr;
|
|
|
|
|
LibertyCell *lib_cell = network_->libertyCell(cell);
|
|
|
|
|
if (lib_cell)
|
|
|
|
|
pg_port = lib_cell->findPgPort(port_name);
|
|
|
|
|
// Do not warn about connections to pg ports (which are ignored).
|
2023-03-26 15:34:36 +02:00
|
|
|
if (pg_port == nullptr) {
|
2021-07-08 01:57:34 +02:00
|
|
|
linkWarn(201, parent_module->filename(), mod_inst->line(),
|
|
|
|
|
"instance %s port %s not found.",
|
2023-03-26 15:34:36 +02:00
|
|
|
inst_vname.c_str(),
|
2021-07-08 01:57:34 +02:00
|
|
|
port_name);
|
2023-03-26 15:34:36 +02:00
|
|
|
}
|
2019-06-19 00:52:12 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeOrderedInstPins(Cell *cell,
|
|
|
|
|
Instance *inst,
|
|
|
|
|
VerilogModuleInst *mod_inst,
|
|
|
|
|
VerilogBindingTbl *bindings,
|
|
|
|
|
Instance *parent,
|
|
|
|
|
VerilogModule *parent_module,
|
|
|
|
|
VerilogBindingTbl *parent_bindings,
|
|
|
|
|
bool is_leaf)
|
|
|
|
|
{
|
|
|
|
|
CellPortIterator *port_iter = network_->portIterator(cell);
|
|
|
|
|
VerilogNetSeq::Iterator pin_iter(mod_inst->pins());
|
|
|
|
|
while (pin_iter.hasNext() && port_iter->hasNext()) {
|
|
|
|
|
VerilogNet *net = pin_iter.next();
|
|
|
|
|
Port *port = port_iter->next();
|
2023-03-26 15:34:36 +02:00
|
|
|
if (network_->size(port) != net->size(parent_module)) {
|
2025-01-22 02:35:21 +01:00
|
|
|
string inst_vname = instanceVerilogName(mod_inst->instanceName().c_str());
|
2020-12-14 02:21:35 +01:00
|
|
|
linkWarn(202, parent_module->filename(), mod_inst->line(),
|
|
|
|
|
"instance %s port %s size %d does not match net size %d.",
|
2023-03-26 15:34:36 +02:00
|
|
|
inst_vname.c_str(),
|
2018-09-28 17:54:21 +02:00
|
|
|
network_->name(port),
|
|
|
|
|
network_->size(port),
|
|
|
|
|
net->size(parent_module));
|
2023-03-26 15:34:36 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
else {
|
|
|
|
|
VerilogNetNameIterator *net_name_iter=net->nameIterator(parent_module,
|
|
|
|
|
this);
|
|
|
|
|
if (network_->isBus(port)) {
|
|
|
|
|
PortMemberIterator *member_iter = network_->memberIterator(port);
|
|
|
|
|
while (member_iter->hasNext() && net_name_iter->hasNext()) {
|
|
|
|
|
Port *port = member_iter->next();
|
|
|
|
|
makeInstPin(inst, port, net_name_iter, bindings,
|
|
|
|
|
parent, parent_bindings, is_leaf);
|
|
|
|
|
}
|
|
|
|
|
delete member_iter;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
makeInstPin(inst, port, net_name_iter, bindings,
|
|
|
|
|
parent, parent_bindings, is_leaf);
|
|
|
|
|
delete net_name_iter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete port_iter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeInstPin(Instance *inst,
|
|
|
|
|
Port *port,
|
|
|
|
|
VerilogNetNameIterator *net_name_iter,
|
|
|
|
|
VerilogBindingTbl *bindings,
|
|
|
|
|
Instance *parent,
|
|
|
|
|
VerilogBindingTbl *parent_bindings,
|
|
|
|
|
bool is_leaf)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
string net_name;
|
2018-09-28 17:54:21 +02:00
|
|
|
if (net_name_iter->hasNext())
|
|
|
|
|
net_name = net_name_iter->next();
|
|
|
|
|
makeInstPin(inst, port, net_name, bindings, parent, parent_bindings,
|
|
|
|
|
is_leaf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeInstPin(Instance *inst,
|
|
|
|
|
Port *port,
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &net_name,
|
2018-09-28 17:54:21 +02:00
|
|
|
VerilogBindingTbl *bindings,
|
|
|
|
|
Instance *parent,
|
|
|
|
|
VerilogBindingTbl *parent_bindings,
|
|
|
|
|
bool is_leaf)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
Net *net = nullptr;
|
2025-01-22 02:35:21 +01:00
|
|
|
if (!net_name.empty())
|
|
|
|
|
net = parent_bindings->ensureNetBinding(net_name.c_str(), parent, network_);
|
2019-01-20 18:44:24 +01:00
|
|
|
if (is_leaf) {
|
|
|
|
|
// Connect leaf pin to net.
|
|
|
|
|
if (net)
|
|
|
|
|
network_->connect(inst, port, net);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2018-09-28 17:54:21 +02:00
|
|
|
Pin *pin = network_->makePin(inst, port, net);
|
|
|
|
|
if (!is_leaf && net) {
|
|
|
|
|
const char *port_name = network_->name(port);
|
|
|
|
|
Net *child_net = bindings->ensureNetBinding(port_name, inst, network_);
|
|
|
|
|
network_->makeTerm(pin, child_net);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeLibertyInst(VerilogLibertyInst *lib_inst,
|
|
|
|
|
Instance *parent,
|
|
|
|
|
VerilogModule *parent_module,
|
|
|
|
|
VerilogBindingTbl *parent_bindings)
|
|
|
|
|
{
|
|
|
|
|
LibertyCell *lib_cell = lib_inst->cell();
|
|
|
|
|
Cell *cell = reinterpret_cast<Cell*>(lib_cell);
|
2025-01-22 02:35:21 +01:00
|
|
|
Instance *inst = network_->makeInstance(cell, lib_inst->instanceName().c_str(),
|
2018-09-28 17:54:21 +02:00
|
|
|
parent);
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogAttrStmtSeq *attr_stmts = lib_inst->attrStmts();
|
|
|
|
|
for (VerilogAttrStmt *stmt : *attr_stmts) {
|
|
|
|
|
for (VerilogAttrEntry *entry : *stmt->attrs()) {
|
2022-07-11 17:49:12 +02:00
|
|
|
network_->setAttribute(inst, entry->key(), entry->value());
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
const StdStringSeq &net_names = lib_inst->netNames();
|
2018-12-05 23:18:41 +01:00
|
|
|
LibertyCellPortBitIterator port_iter(lib_cell);
|
|
|
|
|
while (port_iter.hasNext()) {
|
|
|
|
|
LibertyPort *port = port_iter.next();
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &net_name = net_names[port->pinIndex()];
|
2018-09-28 17:54:21 +02:00
|
|
|
// net_name may be the name of a single bit bus.
|
2025-01-22 02:35:21 +01:00
|
|
|
if (!net_name.empty()) {
|
2019-03-13 01:25:53 +01:00
|
|
|
Net *net = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
// If the pin is unconnected (ie, .A()) make the pin but not the net.
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogDcl *dcl = parent_module->declaration(net_name);
|
|
|
|
|
// Check for single bit bus reference .A(BUS) -> .A(BUS[LSB]).
|
|
|
|
|
if (dcl && dcl->isBus()) {
|
|
|
|
|
VerilogDclBus *dcl_bus = dynamic_cast<VerilogDclBus *>(dcl);
|
|
|
|
|
// Bus is only 1 bit wide.
|
|
|
|
|
string bus_name = verilogBusBitName(net_name, dcl_bus->fromIndex());
|
|
|
|
|
net = parent_bindings->ensureNetBinding(bus_name.c_str(), parent, network_);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
else
|
|
|
|
|
net = parent_bindings->ensureNetBinding(net_name.c_str(), parent, network_);
|
2018-09-28 17:54:21 +02:00
|
|
|
network_->makePin(inst, reinterpret_cast<Port*>(port), net);
|
|
|
|
|
}
|
2019-01-20 18:44:24 +01:00
|
|
|
else
|
|
|
|
|
// Make unconnected pin.
|
2019-03-13 01:25:53 +01:00
|
|
|
network_->makePin(inst, reinterpret_cast<Port*>(port), nullptr);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
Cell *
|
|
|
|
|
VerilogReader::makeBlackBox(VerilogModuleInst *mod_inst,
|
|
|
|
|
VerilogModule *parent_module)
|
|
|
|
|
{
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &module_name = mod_inst->moduleName();
|
|
|
|
|
Cell *cell = network_->makeCell(library_, module_name.c_str(), true,
|
2018-09-28 17:54:21 +02:00
|
|
|
parent_module->filename());
|
|
|
|
|
if (mod_inst->namedPins())
|
|
|
|
|
makeBlackBoxNamedPorts(cell, mod_inst, parent_module);
|
|
|
|
|
else
|
|
|
|
|
makeBlackBoxOrderedPorts(cell, mod_inst, parent_module);
|
|
|
|
|
return cell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeBlackBoxNamedPorts(Cell *cell,
|
|
|
|
|
VerilogModuleInst *mod_inst,
|
|
|
|
|
VerilogModule *parent_module)
|
|
|
|
|
{
|
|
|
|
|
VerilogNetSeq::Iterator pin_iter(mod_inst->pins());
|
|
|
|
|
while (pin_iter.hasNext()) {
|
|
|
|
|
VerilogNetNamed *vpin = dynamic_cast<VerilogNetNamed*>(pin_iter.next());
|
2023-03-26 15:34:36 +02:00
|
|
|
const char *port_name = vpin->name().c_str();
|
2018-09-28 17:54:21 +02:00
|
|
|
size_t size = vpin->size(parent_module);
|
|
|
|
|
Port *port = (size == 1)
|
|
|
|
|
? network_->makePort(cell, port_name)
|
|
|
|
|
: network_->makeBusPort(cell, port_name, 0, size - 1);
|
2021-09-17 17:35:45 +02:00
|
|
|
network_->setDirection(port, PortDirection::unknown());
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::makeBlackBoxOrderedPorts(Cell *cell,
|
|
|
|
|
VerilogModuleInst *mod_inst,
|
|
|
|
|
VerilogModule *parent_module)
|
|
|
|
|
{
|
|
|
|
|
int port_index = 0;
|
|
|
|
|
VerilogNetSeq::Iterator pin_iter(mod_inst->pins());
|
|
|
|
|
while (pin_iter.hasNext()) {
|
|
|
|
|
VerilogNet *net = pin_iter.next();
|
|
|
|
|
size_t size = net->size(parent_module);
|
2019-01-17 00:37:31 +01:00
|
|
|
char *port_name = stringPrint("p_%d", port_index);
|
2018-09-28 17:54:21 +02:00
|
|
|
Port *port = (size == 1)
|
|
|
|
|
? network_->makePort(cell, port_name)
|
|
|
|
|
: network_->makeBusPort(cell, port_name, size - 1, 0);
|
2019-01-17 00:37:31 +01:00
|
|
|
stringDelete(port_name);
|
2021-09-17 17:35:45 +02:00
|
|
|
network_->setDirection(port, PortDirection::unknown());
|
2018-09-28 17:54:21 +02:00
|
|
|
port_index++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VerilogReader::isBlackBox(Cell *cell)
|
|
|
|
|
{
|
|
|
|
|
return network_->library(cell) == library_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VerilogReader::mergeAssignNet(VerilogAssign *assign,
|
|
|
|
|
VerilogModule *module,
|
|
|
|
|
Instance *inst,
|
|
|
|
|
VerilogBindingTbl *bindings)
|
|
|
|
|
{
|
|
|
|
|
VerilogNet *lhs = assign->lhs();
|
|
|
|
|
VerilogNet *rhs = assign->rhs();
|
|
|
|
|
if (lhs->size(module) == rhs->size(module)) {
|
|
|
|
|
VerilogNetNameIterator *lhs_iter = lhs->nameIterator(module, this);
|
|
|
|
|
VerilogNetNameIterator *rhs_iter = rhs->nameIterator(module, this);
|
|
|
|
|
while (lhs_iter->hasNext() && rhs_iter->hasNext()) {
|
2025-01-22 02:35:21 +01:00
|
|
|
const string &lhs_name = lhs_iter->next();
|
|
|
|
|
const string &rhs_name = rhs_iter->next();
|
|
|
|
|
Net *lhs_net = bindings->ensureNetBinding(lhs_name.c_str(), inst, network_);
|
|
|
|
|
Net *rhs_net = bindings->ensureNetBinding(rhs_name.c_str(), inst, network_);
|
2018-09-28 17:54:21 +02:00
|
|
|
// Merge lower level net into higher level net so that deleting
|
|
|
|
|
// instances from the bottom up does not reference deleted nets
|
|
|
|
|
// by referencing the mergedInto field.
|
|
|
|
|
if (hierarchyLevel(lhs_net,network_) >= hierarchyLevel(rhs_net,network_))
|
|
|
|
|
network_->mergeInto(lhs_net, rhs_net);
|
|
|
|
|
else
|
|
|
|
|
network_->mergeInto(rhs_net, lhs_net);
|
|
|
|
|
// No need to update binding tables because the VerilogBindingTbl::find
|
|
|
|
|
// finds the net that survives the merge.
|
|
|
|
|
}
|
|
|
|
|
delete lhs_iter;
|
|
|
|
|
delete rhs_iter;
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-12-14 02:21:35 +01:00
|
|
|
linkWarn(203, module->filename(), assign->line(),
|
|
|
|
|
"assign left hand side size %d not equal right hand size %d.",
|
2018-09-28 17:54:21 +02:00
|
|
|
lhs->size(module),
|
|
|
|
|
rhs->size(module));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
hierarchyLevel(Net *net,
|
|
|
|
|
Network *network)
|
|
|
|
|
{
|
|
|
|
|
Instance *parent = network->instance(net);
|
|
|
|
|
int level = 0;
|
|
|
|
|
while (parent) {
|
|
|
|
|
parent = network->parent(parent);
|
|
|
|
|
level++;
|
|
|
|
|
}
|
|
|
|
|
return level;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogBindingTbl::VerilogBindingTbl(const string &zero_net_name,
|
|
|
|
|
const string &one_net_name) :
|
2018-09-28 17:54:21 +02:00
|
|
|
zero_net_name_(zero_net_name),
|
|
|
|
|
one_net_name_(one_net_name)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Follow the merged_into pointers rather than update the
|
|
|
|
|
// binding tables up the call tree when nodes are merged
|
|
|
|
|
// because the name changes up the hierarchy.
|
|
|
|
|
Net *
|
|
|
|
|
VerilogBindingTbl::find(const char *name, NetworkReader *network)
|
|
|
|
|
{
|
|
|
|
|
Net *net = map_.findKey(name);
|
|
|
|
|
while (net && network->mergedInto(net))
|
|
|
|
|
net = network->mergedInto(net);
|
|
|
|
|
return net;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2022-07-11 17:49:12 +02:00
|
|
|
VerilogBindingTbl::bind(const char *name,
|
2018-09-28 17:54:21 +02:00
|
|
|
Net *net)
|
|
|
|
|
{
|
|
|
|
|
map_[name] = net;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Net *
|
|
|
|
|
VerilogBindingTbl::ensureNetBinding(const char *net_name,
|
|
|
|
|
Instance *inst,
|
|
|
|
|
NetworkReader *network)
|
|
|
|
|
{
|
|
|
|
|
Net *net = find(net_name, network);
|
2019-03-13 01:25:53 +01:00
|
|
|
if (net == nullptr) {
|
2018-09-28 17:54:21 +02:00
|
|
|
net = network->makeNet(net_name, inst);
|
|
|
|
|
map_[network->name(net)] = net;
|
2025-01-22 02:35:21 +01:00
|
|
|
if (net_name == zero_net_name_)
|
2019-03-13 01:25:53 +01:00
|
|
|
network->addConstantNet(net, LogicValue::zero);
|
2025-01-22 02:35:21 +01:00
|
|
|
if (net_name == one_net_name_)
|
2019-03-13 01:25:53 +01:00
|
|
|
network->addConstantNet(net, LogicValue::one);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
return net;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
2020-12-14 02:21:35 +01:00
|
|
|
VerilogReader::linkWarn(int id,
|
|
|
|
|
const char *filename,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line,
|
|
|
|
|
const char *msg, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, msg);
|
2019-01-17 00:37:31 +01:00
|
|
|
char *msg_str = stringPrintArgs(msg, args);
|
2020-12-14 02:21:35 +01:00
|
|
|
VerilogError *error = new VerilogError(id, filename, line, msg_str, true);
|
2018-09-28 17:54:21 +02:00
|
|
|
link_errors_.push_back(error);
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-12-14 02:21:35 +01:00
|
|
|
VerilogReader::linkError(int id,
|
|
|
|
|
const char *filename,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line,
|
|
|
|
|
const char *msg, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, msg);
|
2019-01-17 00:37:31 +01:00
|
|
|
char *msg_str = stringPrintArgs(msg, args);
|
2020-12-14 02:21:35 +01:00
|
|
|
VerilogError *error = new VerilogError(id, filename, line, msg_str, false);
|
2018-09-28 17:54:21 +02:00
|
|
|
link_errors_.push_back(error);
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogReader::reportLinkErrors()
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
// Sort errors so they are in line number order rather than the order
|
|
|
|
|
// they are discovered.
|
|
|
|
|
sort(link_errors_, VerilogErrorCmp());
|
|
|
|
|
bool errors = false;
|
|
|
|
|
VerilogErrorSeq::Iterator error_iter(link_errors_);
|
|
|
|
|
while (error_iter.hasNext()) {
|
|
|
|
|
VerilogError *error = error_iter.next();
|
2021-02-07 18:22:59 +01:00
|
|
|
// Report as warnings to avoid throwing.
|
2025-01-22 02:35:21 +01:00
|
|
|
report_->fileWarn(error->id(), error->filename(), error->line(), "%s", error->msg());
|
2018-09-28 17:54:21 +02:00
|
|
|
errors |= !error->warn();
|
|
|
|
|
delete error;
|
|
|
|
|
}
|
|
|
|
|
link_errors_.clear();
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
VerilogScanner::VerilogScanner(std::istream *stream,
|
|
|
|
|
const char *filename,
|
|
|
|
|
Report *report) :
|
|
|
|
|
yyFlexLexer(stream),
|
|
|
|
|
filename_(filename),
|
|
|
|
|
report_(report)
|
|
|
|
|
{
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2025-01-22 02:35:21 +01:00
|
|
|
void
|
|
|
|
|
VerilogScanner::error(const char *msg)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-01-25 19:21:40 +01:00
|
|
|
report_->fileError(1866, filename_, lineno(), "%s", msg);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-01-22 02:35:21 +01:00
|
|
|
|
|
|
|
|
} // namespace
|