// OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // 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. #include "VerilogReader.hh" #include #include #include #include "ContainerHelpers.hh" #include "Zlib.hh" #include "Debug.hh" #include "Report.hh" #include "Error.hh" #include "Stats.hh" #include "Liberty.hh" #include "PortDirection.hh" #include "Network.hh" #include "VerilogNamespace.hh" #include "StringUtil.hh" #include "verilog/VerilogReaderPvt.hh" #include "verilog/VerilogScanner.hh" namespace sta { using VerilogConstant10 = unsigned long long; static std::string verilogBusBitName(const std::string &bus_name, int index); static int hierarchyLevel(Net *net, Network *network); VerilogReader * makeVerilogReader(NetworkReader *network) { return new VerilogReader(network); } bool readVerilogFile(std::string_view filename, VerilogReader *verilog_reader) { return verilog_reader->read(filename); } void deleteVerilogReader(VerilogReader *verilog_reader) { delete verilog_reader; } //////////////////////////////////////////////////////////////// VerilogError::VerilogError(int id, std::string_view filename, int line, std::string_view msg, bool warn) : id_(id), filename_(filename), line_(line), msg_(msg), warn_(warn) { } class VerilogErrorCmp { public: bool operator()(const VerilogError *error1, const VerilogError *error2) const { int file_cmp = error1->filename_.compare(error2->filename_); if (file_cmp == 0) { if (error1->line_ == error2->line_) return error1->msg_ < error2->msg_; else return error1->line_ < error2->line_; } else return file_cmp < 0; } }; //////////////////////////////////////////////////////////////// VerilogReader::VerilogReader(NetworkReader *network) : report_(network->report()), debug_(network->debug()), network_(network), library_(nullptr), black_box_index_(0), zero_net_name_("zero_"), one_net_name_("one_") { network->setLinkFunc([this](std::string_view top_cell_name, bool make_black_boxes) -> Instance * { return linkNetwork(top_cell_name, make_black_boxes, true); }); constant10_max_ = std::to_string(std::numeric_limits::max()); } VerilogReader::~VerilogReader() { deleteModules(); } void VerilogReader::deleteModules() { deleteContents(module_map_); } bool VerilogReader::read(std::string_view filename) { gzstream::igzstream stream(std::string(filename).c_str()); if (stream.is_open()) { Stats stats(debug_, report_); VerilogScanner scanner(&stream, filename, report_); VerilogParse parser(&scanner, this); init(filename); bool success = (parser.parse() == 0); stats.report("Read verilog"); return success; } else throw FileNotReadable(filename); } void VerilogReader::init(std::string_view filename) { filename_ = filename; library_ = network_->findLibrary("verilog"); if (library_ == nullptr) library_ = network_->makeLibrary("verilog", ""); } VerilogModule * VerilogReader::module(Cell *cell) { return findKey(module_map_, cell); } void VerilogReader::makeModule(std::string &&module_vname, VerilogNetSeq *ports, VerilogStmtSeq *stmts, VerilogAttrStmtSeq *attr_stmts, int line) { const std::string module_name = moduleVerilogToSta(std::move(module_vname)); Cell *cell = network_->findCell(library_, module_name); if (cell) { VerilogModule *module = module_map_[cell]; delete module; module_map_.erase(cell); network_->deleteCell(cell); } VerilogModule *module = new VerilogModule(module_name, ports, stmts, attr_stmts, filename_, line, this); cell = network_->makeCell(library_, module_name, false, filename_); if (attr_stmts) { for (VerilogAttrStmt *stmt : *attr_stmts) { for (VerilogAttrEntry *entry : *stmt->attrs()) network_->setAttribute(cell, entry->key(), entry->value()); } } module_map_[cell] = module; makeCellPorts(cell, module, ports); } void VerilogReader::makeModule(std::string &&module_vname, VerilogStmtSeq *port_dcls, VerilogStmtSeq *stmts, VerilogAttrStmtSeq *attr_stmts, int line) { VerilogNetSeq *ports = new VerilogNetSeq; // Pull the port names out of the port declarations. for (VerilogStmt *dcl : *port_dcls) { if (dcl->isDeclaration()) { VerilogDcl *dcl1 = dynamic_cast(dcl); for (VerilogDclArg *arg : *dcl1->args()) { VerilogNetNamed *port = new VerilogNetScalar(arg->netName()); ports->push_back(port); } // Add the port declarations to the statements. stmts->push_back(dcl); } } delete port_dcls; makeModule(std::move(module_vname), ports, stmts, attr_stmts, line); } void VerilogReader::makeCellPorts(Cell *cell, VerilogModule *module, VerilogNetSeq *ports) { StringSet port_names; for (VerilogNet *mod_port : *ports) { const std::string &port_name = mod_port->name(); if (!port_names.contains(port_name)) { port_names.insert(port_name); if (mod_port->isNamed()) { if (mod_port->isNamedPortRef()) makeNamedPortRefCellPorts(cell, module, mod_port, port_names); else makeCellPort(cell, module, mod_port->name()); } } else warn(165, module->filename(), module->line(), "module {} repeated port name {}.", module->name(), port_name); } checkModuleDcls(module, port_names); } Port * VerilogReader::makeCellPort(Cell *cell, VerilogModule *module, const std::string &port_name) { VerilogDcl *dcl = module->declaration(port_name); if (dcl) { PortDirection *dir = dcl->direction(); VerilogDclBus *dcl_bus = dynamic_cast(dcl); Port *port = dcl->isBus() ? network_->makeBusPort(cell, port_name, dcl_bus->fromIndex(), dcl_bus->toIndex()) : network_->makePort(cell, port_name); network_->setDirection(port, dir); return port; } else { warn(166, module->filename(), module->line(), "module {} missing declaration for port {}.", module->name(), port_name); return network_->makePort(cell, port_name); } } void VerilogReader::makeNamedPortRefCellPorts(Cell *cell, VerilogModule *module, VerilogNet *mod_port, StringSet &port_names) { PortSeq *member_ports = new PortSeq; VerilogNetNameIterator *net_name_iter = mod_port->nameIterator(module, this); while (net_name_iter->hasNext()) { const std::string &net_name = net_name_iter->next(); port_names.insert(net_name); 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. network_->makeBundlePort(cell, mod_port->name(), member_ports); } // Make sure each declaration appears in the module port list. void VerilogReader::checkModuleDcls(VerilogModule *module, std::set &port_names) { for (auto const &[port_name, dcl] : *module->declarationMap()) { PortDirection *dir = dcl->direction(); if (dir->isInput() || dir->isOutput() || dir->isBidirect()) { if (!port_names.contains(port_name)) linkWarn(197, module->filename(), module->line(), "module {} declared signal {} is not in the port list.", module->name(), port_name); } } } VerilogDcl * VerilogReader::makeDcl(PortDirection *dir, VerilogDclArgSeq *args, VerilogAttrStmtSeq *attr_stmts, int line) { if (dir->isInternal()) { // Prune wire declarations without assigns because they just eat memory. VerilogDclArgSeq *assign_args = nullptr; for (VerilogDclArg *arg : *args) { if (arg->assign()) { if (assign_args == nullptr) assign_args = new VerilogDclArgSeq; assign_args->push_back(arg); } else { delete arg; } } delete args; if (assign_args) { return new VerilogDcl(dir, assign_args, attr_stmts, line); } else { deleteContents(attr_stmts); delete attr_stmts; return nullptr; } } else { return new VerilogDcl(dir, args, attr_stmts, line); } } VerilogDcl * VerilogReader::makeDcl(PortDirection *dir, VerilogDclArg *arg, VerilogAttrStmtSeq *attr_stmts, int line) { return new VerilogDcl(dir, arg, attr_stmts, line); } VerilogDclBus * VerilogReader::makeDclBus(PortDirection *dir, int from_index, int to_index, VerilogDclArg *arg, VerilogAttrStmtSeq *attr_stmts, int line) { return new VerilogDclBus(dir, from_index, to_index, arg, attr_stmts, line); } VerilogDclBus * VerilogReader::makeDclBus(PortDirection *dir, int from_index, int to_index, VerilogDclArgSeq *args, VerilogAttrStmtSeq *attr_stmts, int line) { return new VerilogDclBus(dir, from_index, to_index, args, attr_stmts, line); } VerilogDclArg * VerilogReader::makeDclArg(std::string &&net_vname) { const std::string net_name = netVerilogToSta(std::move(net_vname)); VerilogDclArg *dcl = new VerilogDclArg(net_name); return dcl; } VerilogDclArg * VerilogReader::makeDclArg(VerilogAssign *assign) { return new VerilogDclArg(assign); } VerilogNetPartSelect * VerilogReader::makeNetPartSelect(std::string &&net_vname, int from_index, int to_index) { const std::string net_name = netVerilogToSta(std::move(net_vname)); VerilogNetPartSelect *select = new VerilogNetPartSelect(net_name, from_index, to_index); return select; } VerilogNetConstant * VerilogReader::makeNetConstant(std::string &&constant, int line) { return new VerilogNetConstant(std::move(constant), this, line); } VerilogNetScalar * VerilogReader::makeNetScalar(std::string &&net_vname) { const std::string net_name = netVerilogToSta(std::move(net_vname)); VerilogNetScalar *scalar = new VerilogNetScalar(net_name); return scalar; } VerilogNetBitSelect * VerilogReader::makeNetBitSelect(std::string &&net_vname, int index) { const std::string net_name = netVerilogToSta(std::move(net_vname)); VerilogNetBitSelect *select = new VerilogNetBitSelect(net_name, index); return select; } VerilogAssign * VerilogReader::makeAssign(VerilogNet *lhs, VerilogNet *rhs, int line) { return new VerilogAssign(lhs, rhs, line); } VerilogInst * VerilogReader::makeModuleInst(std::string &&module_vname, std::string &&inst_vname, VerilogNetSeq *pins, VerilogAttrStmtSeq *attr_stmts, const int line) { const std::string module_name = moduleVerilogToSta(std::move(module_vname)); const std::string inst_name = instanceVerilogToSta(std::move(inst_vname)); Cell *cell = network_->findAnyCell(module_name); LibertyCell *liberty_cell = nullptr; if (cell) liberty_cell = network_->libertyCell(cell); // 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)) { const int port_count = liberty_cell->portBitCount(); StringSeq net_names(port_count); for (VerilogNet *vnet : *pins) { VerilogNetPortRefScalarNet *vpin = dynamic_cast(vnet); std::string_view port_name = vpin->name(); std::string_view net_name = vpin->netName(); Port *port = network_->findPort(cell, port_name); LibertyPort *lport = network_->libertyPort(port); if (lport->isBus()) { LibertyPortMemberIterator member_iter(lport); lport = member_iter.next(); } int pin_index = lport->pinIndex(); net_names[pin_index] = net_name; delete vpin; } VerilogInst *inst = new VerilogLibertyInst(liberty_cell, inst_name, net_names, attr_stmts, line); delete pins; return inst; } else { VerilogInst *inst = new VerilogModuleInst(module_name, inst_name, pins, attr_stmts, line); return inst; } } bool VerilogReader::hasScalarNamedPortRefs(LibertyCell *liberty_cell, VerilogNetSeq *pins) { if (pins && pins->size() > 0 && (*pins)[0]->isNamedPortRef()) { for (VerilogNet *vpin : *pins) { std::string_view port_name = vpin->name(); 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; } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefScalarNet(std::string &&port_vname) { const std::string port_name = portVerilogToSta(std::move(port_vname)); VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name); return ref; } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefScalarNet(std::string &&port_vname, std::string &&net_vname) { const std::string port_name = portVerilogToSta(std::move(port_vname)); const std::string net_name = netVerilogToSta(std::move(net_vname)); VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name, net_name); return ref; } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefBitSelect(std::string &&port_vname, std::string &&bus_vname, int index) { const std::string bus_name = portVerilogToSta(std::move(bus_vname)); const std::string net_name = verilogBusBitName(bus_name, index); const std::string port_name = portVerilogToSta(std::move(port_vname)); VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name, net_name); return ref; } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefScalar(std::string &&port_vname, VerilogNet *net) { const std::string port_name = portVerilogToSta(std::move(port_vname)); VerilogNetPortRef *ref = new VerilogNetPortRefScalar(port_name, net); return ref; } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefBit(std::string &&port_vname, int index, VerilogNet *net) { const std::string port_name = portVerilogToSta(std::move(port_vname)); VerilogNetPortRef *ref = new VerilogNetPortRefBit(port_name, index, net); return ref; } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefPart(std::string &&port_vname, int from_index, int to_index, VerilogNet *net) { const std::string port_name = portVerilogToSta(std::move(port_vname)); VerilogNetPortRef *ref = new VerilogNetPortRefPart(port_name, from_index, to_index, net); return ref; } VerilogNetConcat * VerilogReader::makeNetConcat(VerilogNetSeq *nets) { return new VerilogNetConcat(nets); } //////////////////////////////////////////////////////////////// VerilogModule::VerilogModule(const std::string &name, VerilogNetSeq *ports, VerilogStmtSeq *stmts, VerilogAttrStmtSeq *attr_stmts, const std::string &filename, int line, VerilogReader *reader) : VerilogStmt(line), name_(name), filename_(filename), ports_(ports), stmts_(stmts), attr_stmts_(attr_stmts) { parseStmts(reader); } VerilogModule::~VerilogModule() { deleteContents(ports_); delete ports_; deleteContents(stmts_); delete stmts_; deleteContents(attr_stmts_); delete attr_stmts_; } void VerilogModule::parseStmts(VerilogReader *reader) { StringSet inst_names; for (VerilogStmt *stmt : *stmts_) { if (stmt->isDeclaration()) parseDcl(dynamic_cast(stmt), reader); else if (stmt->isInstance()) checkInstanceName(dynamic_cast(stmt), inst_names, reader); } } void VerilogModule::parseDcl(VerilogDcl *dcl, VerilogReader *reader) { for (VerilogDclArg *arg : *dcl->args()) { if (arg->isNamed()) { const std::string &net_name = arg->netName(); VerilogDcl *existing_dcl = dcl_map_[net_name]; 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. dcl_map_[net_name] = dcl; 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. dcl_map_[net_name] = dcl; } 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. dcl_map_[net_name] = dcl; else if (!dcl->direction()->isInternal()) { std::string net_vname = netVerilogName(net_name); reader->warn(1395, filename_, dcl->line(), "signal {} previously declared on line {}.", net_vname, existing_dcl->line()); } } else dcl_map_[net_name] = dcl; } } } // Check for duplicate instance names during parse rather than during // expansion so errors are only reported once. void VerilogModule::checkInstanceName(VerilogInst *inst, StringSet &inst_names, VerilogReader *reader) { std::string inst_name = inst->instanceName(); if (inst_names.contains(inst_name)) { int i = 1; std::string replacement_name; do { replacement_name = sta::format("{}_{}", inst_name, i++); } while (inst_names.contains(replacement_name)); std::string inst_vname = instanceVerilogName(inst_name); reader->warn(1396, filename_, inst->line(), "instance name {} duplicated - renamed to {}.", inst_vname, replacement_name); inst_name = replacement_name; inst->setInstanceName(inst_name); } inst_names.insert(inst_name); } VerilogDcl * VerilogModule::declaration(std::string_view net_name) { return findStringKey(dcl_map_, net_name); } //////////////////////////////////////////////////////////////// VerilogStmt::VerilogStmt(int line) : line_(line) { } VerilogInst::VerilogInst(const std::string &inst_name, VerilogAttrStmtSeq *attr_stmts, const int line) : VerilogStmt(line), inst_name_(inst_name), attr_stmts_(attr_stmts) { } VerilogInst::~VerilogInst() { deleteContents(attr_stmts_); delete attr_stmts_; } void VerilogInst::setInstanceName(const std::string &inst_name) { inst_name_ = inst_name; } VerilogModuleInst::VerilogModuleInst(const std::string &module_name, const std::string &inst_name, VerilogNetSeq *pins, VerilogAttrStmtSeq *attr_stmts, int line) : VerilogInst(inst_name, attr_stmts, line), module_name_(module_name), pins_(pins) { } VerilogModuleInst::~VerilogModuleInst() { if (pins_) { deleteContents(pins_); delete pins_; } } bool VerilogModuleInst::hasPins() { return pins_ && pins_->size() > 0; } bool VerilogModuleInst::namedPins() { return pins_ && pins_->size() > 0 && (*pins_)[0]->isNamedPortRef(); } VerilogLibertyInst::VerilogLibertyInst(LibertyCell *cell, const std::string &inst_name, const StringSeq &net_names, VerilogAttrStmtSeq *attr_stmts, const int line) : VerilogInst(inst_name, attr_stmts, line), cell_(cell), net_names_(net_names) { } VerilogDcl::VerilogDcl(PortDirection *dir, VerilogDclArgSeq *args, VerilogAttrStmtSeq *attr_stmts, int line) : VerilogStmt(line), dir_(dir), args_(args), attr_stmts_(attr_stmts) { } VerilogDcl::VerilogDcl(PortDirection *dir, VerilogDclArg *arg, VerilogAttrStmtSeq *attr_stmts, int line) : VerilogStmt(line), dir_(dir) { args_ = new VerilogDclArgSeq; args_->push_back(arg); attr_stmts_ = attr_stmts; } VerilogDcl::~VerilogDcl() { deleteContents(args_); delete args_; deleteContents(attr_stmts_); delete attr_stmts_; } void VerilogDcl::appendArg(VerilogDclArg *arg) { args_->push_back(arg); } const std::string & VerilogDcl::portName() { return (*args_)[0]->netName(); } VerilogDclBus::VerilogDclBus(PortDirection *dir, int from_index, int to_index, VerilogDclArgSeq *args, VerilogAttrStmtSeq *attr_stmts, int line) : VerilogDcl(dir, args, attr_stmts, line), from_index_(from_index), to_index_(to_index) { } VerilogDclBus::VerilogDclBus(PortDirection *dir, int from_index, int to_index, VerilogDclArg *arg, VerilogAttrStmtSeq *attr_stmts, int line) : VerilogDcl(dir, arg, attr_stmts, line), from_index_(from_index), to_index_(to_index) { } int VerilogDclBus::size() const { return std::abs(to_index_ - from_index_) + 1; } VerilogDclArg::VerilogDclArg(const std::string &net_name) : net_name_(net_name), assign_(nullptr) { } VerilogDclArg::VerilogDclArg(VerilogAssign *assign) : assign_(assign) { } VerilogDclArg::~VerilogDclArg() { delete assign_; } const std::string & VerilogDclArg::netName() { if (assign_) return assign_->lhs()->name(); else return net_name_; } 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: bool hasNext() override { return false; } const std::string &next() override; }; const std::string & VerilogNullNetNameIterator::next() { static const std::string null; return null; } class VerilogOneNetNameIterator : public VerilogNetNameIterator { public: VerilogOneNetNameIterator(const std::string &name); bool hasNext() override; const std::string &next() override; protected: std::string name_; bool has_next_; }; VerilogOneNetNameIterator::VerilogOneNetNameIterator(const std::string &name) : name_(name), has_next_(true) { } bool VerilogOneNetNameIterator::hasNext() { return has_next_; } const std::string & VerilogOneNetNameIterator::next() { has_next_ = false; return name_; } class VerilogBusNetNameIterator : public VerilogNetNameIterator { public: VerilogBusNetNameIterator(const std::string bus_name, int from_index, int to_index); bool hasNext() override; const std::string &next() override; protected: const std::string bus_name_; int from_index_; int to_index_; int index_; std::string bit_name_; }; VerilogBusNetNameIterator::VerilogBusNetNameIterator(const std::string bus_name, 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_); } const std::string & VerilogBusNetNameIterator::next() { bit_name_ = verilogBusBitName(bus_name_, index_); if (to_index_ > from_index_) index_++; else index_--; return bit_name_; } static std::string verilogBusBitName(const std::string &bus_name, int index) { return sta::format("{}[{}]", bus_name, index); } class VerilogConstantNetNameIterator : public VerilogNetNameIterator { public: VerilogConstantNetNameIterator(VerilogConstantValue *value, const std::string &zero, const std::string &one); bool hasNext() override; const std::string &next() override; private: VerilogConstantValue *value_; const std::string &zero_; const std::string &one_; int bit_index_; }; VerilogConstantNetNameIterator::VerilogConstantNetNameIterator( VerilogConstantValue *value, const std::string &zero, const std::string &one) : value_(value), zero_(zero), one_(one), bit_index_(value->size() - 1) { } bool VerilogConstantNetNameIterator::hasNext() { return bit_index_ >= 0; } const std::string & VerilogConstantNetNameIterator::next() { return (*value_)[bit_index_--] ? one_ : zero_; } class VerilogNetConcatNameIterator : public VerilogNetNameIterator { public: VerilogNetConcatNameIterator(VerilogNetSeq *nets, VerilogModule *module, VerilogReader *reader); ~VerilogNetConcatNameIterator() override; bool hasNext() override; const std::string &next() override; private: VerilogModule *module_; VerilogReader *reader_; VerilogNetSeq *nets_; VerilogNetSeq::iterator net_iter_; VerilogNetNameIterator *net_name_iter_; }; VerilogNetConcatNameIterator::VerilogNetConcatNameIterator(VerilogNetSeq *nets, VerilogModule *module, VerilogReader *reader) : module_(module), reader_(reader), nets_(nets), net_iter_(nets->begin()), net_name_iter_(nullptr) { if (net_iter_ != nets_->end()) { VerilogNet *net = *net_iter_++; net_name_iter_ = net->nameIterator(module, reader); } } VerilogNetConcatNameIterator::~VerilogNetConcatNameIterator() { delete net_name_iter_; } bool VerilogNetConcatNameIterator::hasNext() { return (net_name_iter_ && net_name_iter_->hasNext()) || net_iter_ != nets_->end(); } const std::string & VerilogNetConcatNameIterator::next() { if (net_name_iter_ && net_name_iter_->hasNext()) return net_name_iter_->next(); else { if (net_iter_ != nets_->end()) { VerilogNet *net = *net_iter_++; delete net_name_iter_; net_name_iter_ = net->nameIterator(module_, reader_); if (net_name_iter_ && net_name_iter_->hasNext()) return net_name_iter_->next(); } } static const std::string null; return null; } //////////////////////////////////////////////////////////////// const std::string VerilogNetUnnamed::null_; VerilogNetNamed::VerilogNetNamed(const std::string &name) : VerilogNet(), name_(name) { } VerilogNetNamed::~VerilogNetNamed() {} VerilogNetScalar::VerilogNetScalar(const std::string &name) : VerilogNetNamed(name) { } static int verilogNetScalarSize(std::string_view 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) { return verilogNetScalarSize(name_, module); } static VerilogNetNameIterator * verilogNetScalarNameIterator(const std::string &name, VerilogModule *module) { if (!name.empty()) { VerilogDcl *dcl = module->declaration(name); if (dcl && dcl->isBus()) { VerilogDclBus *dcl_bus = dynamic_cast(dcl); return new VerilogBusNetNameIterator(name, dcl_bus->fromIndex(), dcl_bus->toIndex()); } } return new VerilogOneNetNameIterator(name); } VerilogNetNameIterator * VerilogNetScalar::nameIterator(VerilogModule *module, VerilogReader *) { return verilogNetScalarNameIterator(name_, module); } VerilogNetBitSelect::VerilogNetBitSelect(const std::string &name, int index) : VerilogNetNamed(verilogBusBitName(name, index)), index_(index) { } int VerilogNetBitSelect::size(VerilogModule *) { return 1; } VerilogNetNameIterator * VerilogNetBitSelect::nameIterator(VerilogModule *, VerilogReader *) { return new VerilogOneNetNameIterator(name_); } VerilogNetPartSelect::VerilogNetPartSelect(const std::string &name, 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 *) { return new VerilogBusNetNameIterator(name_, from_index_, to_index_); } VerilogNetConstant::VerilogNetConstant(std::string constant, VerilogReader *reader, int line) { parseConstant(constant, reader, line); } void VerilogNetConstant::parseConstant(const std::string &constant, VerilogReader *reader, int line) { // Find constant size. size_t csize_end = constant.find('\''); std::string csize = constant.substr(0, csize_end); // Read the constant size. size_t size = std::stol(csize); value_ = new VerilogConstantValue(size); // Read the constant base. size_t base_idx = csize_end + 1; char base = constant.at(base_idx); switch (base) { case 'b': case 'B': parseConstant(constant, base_idx, 2, 1); break; case 'o': case 'O': parseConstant(constant, base_idx, 8, 3); break; case 'h': case 'H': parseConstant(constant, base_idx, 16, 4); break; case 'd': case 'D': parseConstant10(constant, base_idx, reader, line); break; default: case '\0': reader->report()->fileWarn(1861, reader->filename(), line, "unknown constant base."); break; } } void VerilogNetConstant::parseConstant(const std::string &constant, size_t base_idx, 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; size_t idx = constant.size() - 1; while (bit < size) { char ch = (idx > base_idx) ? constant.at(idx--) : '0'; // 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 VerilogNetConstant::parseConstant10(const std::string &constant, size_t base_idx, VerilogReader *reader, int line) { // Copy the constant skipping underscores. std::string tmp; for (size_t i = base_idx + 1; i < constant.size(); i++) { char ch = constant.at(i); if (ch != '_') tmp += ch; } size_t size = value_->size(); size_t length = tmp.size(); const std::string &constant10_max = reader->constant10Max(); size_t max_length = constant10_max.size(); if (length > max_length || (length == max_length && tmp > constant10_max)) reader->warn(1397, reader->filename(), line, "base 10 constant greater than {} not supported.", constant10_max); else { size_t *end = nullptr; VerilogConstant10 value = std::stoull(tmp, end, 10); 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() { deleteContents(nets_); delete nets_; } int VerilogNetConcat::size(VerilogModule *module) { int sz = 0; for (VerilogNet *net : *nets_) sz += net->size(module); return sz; } VerilogNetNameIterator * VerilogNetConcat::nameIterator(VerilogModule *module, VerilogReader *reader) { return new VerilogNetConcatNameIterator(nets_, module, reader); } VerilogNetPortRef::VerilogNetPortRef(const std::string &name) : VerilogNetScalar(name) { } VerilogNetPortRefScalarNet::VerilogNetPortRefScalarNet(const std::string &name) : VerilogNetPortRef(name) { } VerilogNetPortRefScalarNet::VerilogNetPortRefScalarNet(const std::string &name, const std::string &net_name) : VerilogNetPortRef(name), net_name_(net_name) { } int VerilogNetPortRefScalarNet::size(VerilogModule *module) { // VerilogNetScalar::size VerilogDcl *dcl = nullptr; if (!net_name_.empty()) 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); } VerilogNetPortRefScalar::VerilogNetPortRefScalar(const std::string &name, 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(); } VerilogNetPortRefBit::VerilogNetPortRefBit(const std::string &name, int index, VerilogNet *net) : VerilogNetPortRefScalar(name, net), bit_name_(verilogBusBitName(name, index)) { } VerilogNetPortRefPart::VerilogNetPortRefPart(const std::string &name, int from_index, int to_index, VerilogNet *net) : VerilogNetPortRefBit(name, from_index, net), to_index_(to_index) { } const std::string & VerilogNetPortRefPart::name() const { return name_; } VerilogAttrEntry::VerilogAttrEntry(const std::string &key, const std::string &value) : key_(key), value_(value) { } std::string VerilogAttrEntry::key() { return key_; } std::string VerilogAttrEntry::value() { return value_; } VerilogAttrStmt::VerilogAttrStmt(VerilogAttrEntrySeq *attrs) : attrs_(attrs) { } VerilogAttrStmt::~VerilogAttrStmt() { deleteContents(attrs_); delete attrs_; } VerilogAttrEntrySeq * VerilogAttrStmt::attrs() { return attrs_; } //////////////////////////////////////////////////////////////// // // Link verilog network // //////////////////////////////////////////////////////////////// // Verilog net name to network net map. using BindingMap = std::map>; class VerilogBindingTbl { public: VerilogBindingTbl(const std::string &zero_net_name_, const std::string &one_net_name_); Net *ensureNetBinding(std::string_view net_name, Instance *inst, NetworkReader *network); Net *find(std::string_view name, NetworkReader *network); void bind(std::string_view name, Net *net); private: const std::string &zero_net_name_; const std::string &one_net_name_; BindingMap net_map_; }; Instance * VerilogReader::linkNetwork(std::string_view top_cell_name, bool make_black_boxes, bool delete_modules) { if (library_) { const std::string top_cell_str(top_cell_name); Cell *top_cell = network_->findCell(library_, top_cell_str); VerilogModule *module = this->module(top_cell); if (module) { // Seed the recursion for expansion with the top level instance. Instance *top_instance = network_->makeInstance(top_cell, top_cell_str, nullptr); VerilogBindingTbl bindings(zero_net_name_, one_net_name_); for (VerilogNet *mod_port : *module->ports()) { VerilogNetNameIterator *net_name_iter = mod_port->nameIterator(module, this); while (net_name_iter->hasNext()) { const std::string &net_name = net_name_iter->next(); Port *port = network_->findPort(top_cell, net_name); Net *net = bindings.ensureNetBinding(net_name, top_instance, network_); // Guard against repeated port name. if (network_->findPin(top_instance, port) == nullptr) { Pin *pin = network_->makePin(top_instance, port, nullptr); network_->makeTerm(pin, net); } } delete net_name_iter; } makeModuleInstBody(module, top_instance, &bindings, make_black_boxes); bool errors = reportLinkErrors(); if (delete_modules) deleteModules(); if (errors) { network_->deleteInstance(top_instance); return nullptr; } else return top_instance; } else { report_->error(1398, "{} is not a verilog module.", top_cell_name); return nullptr; } } else { report_->error(1399, "{} is not a verilog module.", top_cell_name); return nullptr; } } void VerilogReader::makeModuleInstBody(VerilogModule *module, Instance *inst, VerilogBindingTbl *bindings, bool make_black_boxes) { for (VerilogStmt *stmt : *module->stmts()) { if (stmt->isModuleInst()) makeModuleInstNetwork(dynamic_cast(stmt), inst, module, bindings, make_black_boxes); else if (stmt->isLibertyInst()) makeLibertyInst(dynamic_cast(stmt), inst, module, bindings); else if (stmt->isDeclaration()) { VerilogDcl *dcl = dynamic_cast(stmt); PortDirection *dir = dcl->direction(); for (VerilogDclArg *arg : *dcl->args()) { VerilogAssign *assign = arg->assign(); if (assign) mergeAssignNet(assign, module, inst, bindings); if (dir->isGround()) { Net *net = bindings->ensureNetBinding(arg->netName(), inst, network_); network_->addConstantNet(net, LogicValue::zero); } if (dir->isPower()) { Net *net = bindings->ensureNetBinding(arg->netName(), inst, network_); network_->addConstantNet(net, LogicValue::one); } } } else if (stmt->isAssign()) mergeAssignNet(dynamic_cast(stmt), module, inst, bindings); } } void VerilogReader::makeModuleInstNetwork(VerilogModuleInst *mod_inst, Instance *parent, VerilogModule *parent_module, VerilogBindingTbl *parent_bindings, bool make_black_boxes) { const std::string &module_name = mod_inst->moduleName(); Cell *cell = network_->findAnyCell(module_name); if (cell == nullptr) { std::string inst_vname = instanceVerilogName(mod_inst->instanceName()); if (make_black_boxes) { cell = makeBlackBox(mod_inst, parent_module); linkWarn(198, parent_module->filename(), mod_inst->line(), "module {} not found. Creating black box for {}.", mod_inst->moduleName(), inst_vname); } else linkError(199, parent_module->filename(), mod_inst->line(), "module {} not found for instance {}.", mod_inst->moduleName(), inst_vname); } if (cell) { LibertyCell *lib_cell = network_->libertyCell(cell); if (lib_cell) cell = network_->cell(lib_cell); Instance *inst = network_->makeInstance(cell, mod_inst->instanceName(), parent); VerilogAttrStmtSeq *attr_stmts = mod_inst->attrStmts(); for (VerilogAttrStmt *stmt : *attr_stmts) { for (VerilogAttrEntry *entry : *stmt->attrs()) { network_->setAttribute(inst, entry->key(), entry->value()); } } // Make all pins so timing arcs are built and get_pins finds them. CellPortBitIterator *port_iter = network_->portBitIterator(cell); while (port_iter->hasNext()) { Port *port = port_iter->next(); network_->makePin(inst, port, nullptr); } delete port_iter; bool is_leaf = network_->isLeaf(cell); 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) { VerilogModule *module = this->module(cell); if (module) makeModuleInstBody(module, inst, &bindings, make_black_boxes); } } } void VerilogReader::makeNamedInstPins(Cell *cell, Instance *inst, VerilogModuleInst *mod_inst, VerilogBindingTbl *bindings, Instance *parent, VerilogModule *parent_module, VerilogBindingTbl *parent_bindings, bool is_leaf) { std::string inst_vname = instanceVerilogName(mod_inst->instanceName()); for (auto mpin : *mod_inst->pins()) { VerilogNetPortRef *vpin = dynamic_cast(mpin); const std::string &port_name = vpin->name(); Port *port = network_->findPort(cell, port_name); if (port) { if (vpin->hasNet() && network_->size(port) != vpin->size(parent_module)) { linkWarn(200, parent_module->filename(), mod_inst->line(), "instance {} port {} size {} does not match net size {}.", inst_vname, network_->name(port), network_->size(port), vpin->size(parent_module)); } 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; } } else linkWarn(201, parent_module->filename(), mod_inst->line(), "instance {} port {} not found.", inst_vname, port_name); } } 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 *mod_pins = mod_inst->pins(); VerilogNetSeq::iterator pin_iter = mod_pins->begin(); while (pin_iter != mod_pins->end() && port_iter->hasNext()) { VerilogNet *net = *pin_iter++; Port *port = port_iter->next(); if (network_->size(port) != net->size(parent_module)) { std::string inst_vname = instanceVerilogName(mod_inst->instanceName()); linkWarn(202, parent_module->filename(), mod_inst->line(), "instance {} port {} size {} does not match net size {}.", inst_vname, network_->name(port), network_->size(port), net->size(parent_module)); } 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) { std::string net_name; 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, const std::string &net_name, VerilogBindingTbl *bindings, Instance *parent, VerilogBindingTbl *parent_bindings, bool is_leaf) { Net *net = nullptr; if (!net_name.empty()) net = parent_bindings->ensureNetBinding(net_name, parent, network_); if (is_leaf) { // Connect leaf pin to net. if (net) network_->connect(inst, port, net); } else { // Pin should already exist by prior makePin, then connect to parent // net if present and create a term for the child-side net. Pin *pin = network_->findPin(inst, port); if (net) { network_->connect(inst, port, net); std::string 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(lib_cell); Instance *inst = network_->makeInstance(cell, lib_inst->instanceName(), parent); VerilogAttrStmtSeq *attr_stmts = lib_inst->attrStmts(); for (VerilogAttrStmt *stmt : *attr_stmts) { for (VerilogAttrEntry *entry : *stmt->attrs()) { network_->setAttribute(inst, entry->key(), entry->value()); } } const StringSeq &net_names = lib_inst->netNames(); LibertyCellPortBitIterator port_iter(lib_cell); while (port_iter.hasNext()) { LibertyPort *port = port_iter.next(); const std::string &net_name = net_names[port->pinIndex()]; // net_name may be the name of a single bit bus. if (!net_name.empty()) { Net *net = nullptr; // If the pin is unconnected (ie, .A()) make the pin but not the net. 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(dcl); // Bus is only 1 bit wide. std::string bus_name = verilogBusBitName(net_name, dcl_bus->fromIndex()); net = parent_bindings->ensureNetBinding(bus_name, parent, network_); } else net = parent_bindings->ensureNetBinding(net_name, parent, network_); network_->makePin(inst, reinterpret_cast(port), net); } else // Make unconnected pin. network_->makePin(inst, reinterpret_cast(port), nullptr); } } //////////////////////////////////////////////////////////////// Cell * VerilogReader::makeBlackBox(VerilogModuleInst *mod_inst, VerilogModule *parent_module) { const std::string &module_name = mod_inst->moduleName(); Cell *cell = network_->makeCell(library_, module_name, true, 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) { for (VerilogNet *mpin : *mod_inst->pins()) { VerilogNetNamed *vpin = dynamic_cast(mpin); const std::string &port_name = vpin->name(); size_t size = vpin->size(parent_module); Port *port = (size == 1) ? network_->makePort(cell, port_name) : network_->makeBusPort(cell, port_name, 0, size - 1); network_->setDirection(port, PortDirection::unknown()); } } void VerilogReader::makeBlackBoxOrderedPorts(Cell *cell, VerilogModuleInst *mod_inst, VerilogModule *parent_module) { int port_index = 0; VerilogNetSeq *nets = mod_inst->pins(); if (nets) { for (VerilogNet *net : *nets) { size_t size = net->size(parent_module); std::string port_name = format("p_{}", port_index); Port *port = (size == 1) ? network_->makePort(cell, port_name) : network_->makeBusPort(cell, port_name, size - 1, 0); network_->setDirection(port, PortDirection::unknown()); 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()) { const std::string &lhs_name = lhs_iter->next(); const std::string &rhs_name = rhs_iter->next(); Net *lhs_net = bindings->ensureNetBinding(lhs_name, inst, network_); Net *rhs_net = bindings->ensureNetBinding(rhs_name, inst, network_); // 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 linkWarn(203, module->filename(), assign->line(), "assign left hand side size {} not equal right hand size {}.", 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; } //////////////////////////////////////////////////////////////// VerilogBindingTbl::VerilogBindingTbl(const std::string &zero_net_name, const std::string &one_net_name) : 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(std::string_view name, NetworkReader *network) { Net *net = findStringKey(net_map_, name); while (net && network->mergedInto(net)) net = network->mergedInto(net); return net; } void VerilogBindingTbl::bind(std::string_view name, Net *net) { net_map_[std::string(name)] = net; } Net * VerilogBindingTbl::ensureNetBinding(std::string_view net_name, Instance *inst, NetworkReader *network) { Net *net = find(net_name, network); if (net == nullptr) { const std::string net_str(net_name); net = network->makeNet(net_str, inst); net_map_[std::string(network->name(net))] = net; if (net_str == zero_net_name_) network->addConstantNet(net, LogicValue::zero); if (net_str == one_net_name_) network->addConstantNet(net, LogicValue::one); } return net; } //////////////////////////////////////////////////////////////// bool VerilogReader::reportLinkErrors() { // Sort errors so they are in line number order rather than the order // they are discovered. sort(link_errors_, VerilogErrorCmp()); bool errors = false; for (VerilogError *error : link_errors_) { // Report as warnings to avoid throwing. report_->fileWarn(error->id(), error->filename(), error->line(), "{}", error->msg()); errors |= !error->warn(); delete error; } link_errors_.clear(); return errors; } //////////////////////////////////////////////////////////////// VerilogScanner::VerilogScanner(std::istream *stream, std::string_view filename, Report *report) : yyFlexLexer(stream), filename_(filename), report_(report) { } void VerilogScanner::error(std::string_view msg) { report_->fileError(1870, filename_, lineno(), "{}", msg); } } // namespace sta