// OpenSTA, Static Timing Analyzer // Copyright (c) 2021, Parallax Software, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include "VerilogReader.hh" #include #include "DisallowCopyAssign.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 "verilog/VerilogReaderPvt.hh" extern int VerilogParse_parse(); namespace sta { VerilogReader *verilog_reader; static const char *unconnected_net_name = reinterpret_cast(1); static const char * verilogBusBitName(const char *bus_name, int index); static const char * verilogBusBitNameTmp(const char *bus_name, int index); static int hierarchyLevel(Net *net, Network *network); // Return top level instance. Instance * linkVerilogNetwork(const char *top_cell_name, bool make_black_boxes, Report *report, NetworkReader *network); bool readVerilogFile(const char *filename, NetworkReader *network) { if (verilog_reader == nullptr) verilog_reader = new VerilogReader(network); return verilog_reader->read(filename); } void deleteVerilogReader() { delete verilog_reader; verilog_reader = nullptr; } //////////////////////////////////////////////////////////////// class VerilogError { public: VerilogError(int id, const char *filename, int line, const char *msg, bool warn); ~VerilogError(); const char *msg() const { return msg_; } const char *filename() const { return filename_; } int id() const { return id_; } int line() const { return line_; } bool warn() const { return warn_; } private: DISALLOW_COPY_AND_ASSIGN(VerilogError); int id_; const char *filename_; int line_; const char *msg_; bool warn_; friend class VerilogErrorCmp; }; VerilogError::VerilogError(int id, const char *filename, int line, const char *msg, bool warn) : id_(id), 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; } }; //////////////////////////////////////////////////////////////// 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(linkVerilogNetwork); VerilogConstant10 constant10_max = 0; constant10_max_ = stringPrint("%llu", ~constant10_max); constant10_max_length_ = strlen(constant10_max_); } VerilogReader::~VerilogReader() { deleteModules(); stringDelete(constant10_max_); } void VerilogReader::deleteModules() { StringSet filenames; for (auto module_iter : module_map_) { VerilogModule *module = module_iter.second; filenames.insert(module->filename()); delete module; } deleteContents(&filenames); module_map_.clear(); } bool VerilogReader::read(const char *filename) { // Use zlib to uncompress gzip'd files automagically. stream_ = gzopen(filename, "rb"); if (stream_) { Stats stats(debug_, report_); init(filename); bool success = (::VerilogParse_parse() == 0); gzclose(stream_); reportStmtCounts(); stats.report("Read verilog"); return success; } else throw FileNotReadable(filename); } void VerilogReader::init(const char *filename) { // Statements point to verilog_filename, so copy it. filename_ = stringCopy(filename); line_ = 1; library_ = network_->findLibrary("verilog"); if (library_ == nullptr) library_ = network_->makeLibrary("verilog", nullptr); report_stmt_stats_ = debug_->check("verilog", 1); 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; } void VerilogReader::getChars(char *buf, size_t &result, size_t max_size) { char *status = gzgets(stream_, buf, max_size); if (status == Z_NULL) result = 0; // YY_nullptr else result = strlen(buf); } void VerilogReader::getChars(char *buf, int &result, size_t max_size) { char *status = gzgets(stream_, buf, max_size); if (status == Z_NULL) result = 0; // YY_nullptr else result = strlen(buf); } VerilogModule * VerilogReader::module(Cell *cell) { return module_map_.findKey(cell); } void VerilogReader::makeModule(const char *name, VerilogNetSeq *ports, VerilogStmtSeq *stmts, int line) { Cell *cell = network_->findCell(library_, name); if (cell) { VerilogModule *module = module_map_[cell]; delete module; module_map_.erase(cell); network_->deleteCell(cell); } VerilogModule *module = new VerilogModule(name, ports, stmts, filename_, line, this); cell = network_->makeCell(library_, name, false, filename_); module_map_[cell] = module; makeCellPorts(cell, module, ports); module_count_++; } void VerilogReader::makeModule(const char *name, VerilogStmtSeq *port_dcls, VerilogStmtSeq *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()) { const char *port_name = stringCopy(arg->netName()); VerilogNetNamed *port = new VerilogNetScalar(port_name); ports->push_back(port); } // Add the port declarations to the statements. stmts->push_back(dcl); } } delete port_dcls; makeModule(name, ports, stmts, line); } void VerilogReader::makeCellPorts(Cell *cell, VerilogModule *module, VerilogNetSeq *ports) { StringSet port_names; for (VerilogNet *mod_port : *ports) { const char *port_name = mod_port->name(); if (port_names.findKey(port_name) == nullptr) { port_names.insert(stringCopy(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 %s repeated port name %s.", module->name(), port_name); } checkModuleDcls(module, port_names); deleteContents(&port_names); } Port * VerilogReader::makeCellPort(Cell *cell, VerilogModule *module, const char *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 %s missing declaration for port %s.", 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 char *net_name = net_name_iter->next(); port_names.insert(stringCopy(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, StringSet &port_names) { VerilogDclMap::ConstIterator dcl_iter(module->declarationMap()); while (dcl_iter.hasNext()) { VerilogDcl *dcl; const char *port_name; dcl_iter.next(port_name, dcl); PortDirection *dir = dcl->direction(); if (dir->isInput() || dir->isOutput() || dir->isBidirect()) { if (port_names.findKey(port_name) == nullptr) linkWarn(197, module->filename(), module->line(), "module %s declared signal %s is not in the port list.", module->name(), port_name); } } } VerilogDcl * VerilogReader::makeDcl(PortDirection *dir, VerilogDclArgSeq *args, 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; dcl_arg_count_--; } } delete args; if (assign_args) { dcl_count_++; return new VerilogDcl(dir, assign_args, line); } else return nullptr; } else { dcl_count_++; return new VerilogDcl(dir, args, line); } } VerilogDcl * VerilogReader::makeDcl(PortDirection *dir, VerilogDclArg *arg, int line) { dcl_count_++; return new VerilogDcl(dir, arg, line); } VerilogDclBus * VerilogReader::makeDclBus(PortDirection *dir, int from_index, int to_index, VerilogDclArg *arg, int line) { dcl_bus_count_++; return new VerilogDclBus(dir, from_index, to_index, arg, line); } VerilogDclBus * VerilogReader::makeDclBus(PortDirection *dir, int from_index, int to_index, VerilogDclArgSeq *args, int line) { dcl_bus_count_++; return new VerilogDclBus(dir, from_index, to_index, args, line); } VerilogDclArg * VerilogReader::makeDclArg(const char *net_name) { dcl_arg_count_++; return new VerilogDclArg(net_name); } VerilogDclArg * VerilogReader::makeDclArg(VerilogAssign *assign) { dcl_arg_count_++; return new VerilogDclArg(assign); } VerilogNetPartSelect * VerilogReader::makeNetPartSelect(const char *name, int from_index, int to_index) { net_part_select_count_++; if (report_stmt_stats_) net_bus_names_ += strlen(name) + 1; return new VerilogNetPartSelect(name, from_index, to_index); } VerilogNetConstant * VerilogReader::makeNetConstant(const char *constant) { net_constant_count_++; return new VerilogNetConstant(constant, this); } VerilogNetScalar * VerilogReader::makeNetScalar(const char *name) { net_scalar_count_++; if (report_stmt_stats_) net_scalar_names_ += strlen(name) + 1; return new VerilogNetScalar(name); } VerilogNetBitSelect * VerilogReader::makeNetBitSelect(const char *name, int index) { net_bit_select_count_++; if (report_stmt_stats_) net_bus_names_ += strlen(name) + 1; return new VerilogNetBitSelect(name, index); } VerilogAssign * VerilogReader::makeAssign(VerilogNet *lhs, VerilogNet *rhs, int line) { assign_count_++; return new VerilogAssign(lhs, rhs, line); } VerilogInst * VerilogReader::makeModuleInst(const char *module_name, const char *inst_name, VerilogNetSeq *pins, const int line) { 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)) { int port_count = network_->portBitCount(cell); const char **net_names = new const char *[port_count]; for (int i = 0; i < port_count; i++) net_names[i] = nullptr; for (VerilogNet *vnet : *pins) { VerilogNetPortRefScalarNet *vpin = dynamic_cast(vnet); const char *port_name = vpin->name(); const char *net_name = vpin->netName(); // Steal the net name string. vpin->setNetName(nullptr); 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(); const char *prev_net_name = net_names[pin_index]; if (prev_net_name && prev_net_name !=unconnected_net_name) // Repeated port reference. stringDelete(prev_net_name); net_names[pin_index]=(net_name == nullptr) ? unconnected_net_name : net_name; delete vpin; net_port_ref_scalar_net_count_--; } VerilogInst *inst = new VerilogLibertyInst(liberty_cell, inst_name, net_names, line); stringDelete(module_name); delete pins; if (report_stmt_stats_) { inst_names_ += strlen(inst_name) + 1; inst_lib_count_++; inst_lib_net_arrays_ += port_count; } return inst; } else { VerilogInst *inst = new VerilogModuleInst(module_name, inst_name, pins, line); if (report_stmt_stats_) { inst_module_names_ += strlen(module_name) + 1; inst_names_ += strlen(inst_name) + 1; inst_mod_count_++; } return inst; } } bool VerilogReader::hasScalarNamedPortRefs(LibertyCell *liberty_cell, VerilogNetSeq *pins) { if (pins && pins->size() > 0 && (*pins)[0]->isNamedPortRef()) { for (VerilogNet *vpin : *pins) { const char *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(const char *port_name, const char *net_name) { net_port_ref_scalar_net_count_++; if (report_stmt_stats_) { if (net_name) net_scalar_names_ += strlen(net_name) + 1; port_names_ += strlen(port_name) + 1; } return new VerilogNetPortRefScalarNet(port_name, net_name); } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefBitSelect(const char *port_name, const char *bus_name, int index) { net_port_ref_scalar_net_count_++; const char *net_name = verilogBusBitName(bus_name, index); if (report_stmt_stats_) { net_scalar_names_ += strlen(net_name) + 1; port_names_ += strlen(port_name) + 1; } stringDelete(bus_name); return new VerilogNetPortRefScalarNet(port_name, net_name); } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefScalar(const char *port_name, VerilogNet *net) { net_port_ref_scalar_count_++; if (report_stmt_stats_) port_names_ += strlen(port_name) + 1; return new VerilogNetPortRefScalar(port_name, net); } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefBit(const char *port_name, int index, VerilogNet *net) { net_port_ref_bit_count_++; return new VerilogNetPortRefBit(port_name, index, net); } VerilogNetPortRef * VerilogReader::makeNetNamedPortRefPart(const char *port_name, int from_index, int to_index, VerilogNet *net) { net_port_ref_part_count_++; return new VerilogNetPortRefPart(port_name, from_index, to_index, net); } VerilogNetConcat * VerilogReader::makeNetConcat(VerilogNetSeq *nets) { concat_count_++; return new VerilogNetConcat(nets); } void VerilogReader::incrLine() { line_++; } #define printClassMemory(name, class_name, count) \ report_->reportLine(" %-20s %9d * %3d = %6.1fMb\n", \ name, \ count, \ static_cast(sizeof(class_name)), \ (count * sizeof(class_name) * 1e-6)) #define printStringMemory(name, count) \ report_->reportLine(" %-20s %6.1fMb", name, count * 1e-6) void VerilogReader::reportStmtCounts() { if (debug_->check("verilog", 1)) { report_->reportLine("Verilog stats"); 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 VerilogReader::error(int id, const char *filename, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); report()->vfileError(id, filename, line, fmt, args); va_end(args); } void VerilogReader::warn(int id, const char *filename, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); report()->vfileWarn(id, filename, line, fmt, args); va_end(args); } const char * VerilogReader::verilogName(VerilogModuleInst *mod_inst) { return sta::instanceVerilogName(mod_inst->instanceName(), network_->pathEscape()); } const char * VerilogReader::instanceVerilogName(const char *inst_name) { return sta::netVerilogName(inst_name, network_->pathEscape()); } const char * VerilogReader::netVerilogName(const char *net_name) { return sta::netVerilogName(net_name, network_->pathEscape()); } //////////////////////////////////////////////////////////////// VerilogModule::VerilogModule(const char *name, VerilogNetSeq *ports, VerilogStmtSeq *stmts, const char *filename, int line, VerilogReader *reader) : VerilogStmt(line), name_(name), filename_(filename), ports_(ports), stmts_(stmts) { parseStmts(reader); } VerilogModule::~VerilogModule() { ports_->deleteContents(); delete ports_; stmts_->deleteContents(); delete stmts_; stringDelete(name_); } 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()) { const char *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()) reader->warn(18, filename_, dcl->line(), "signal %s previously declared on line %d.", reader->netVerilogName(net_name), 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) { const char *inst_name = inst->instanceName(); if (inst_names.findKey(inst_name)) { int i = 1; const char *replacement_name = nullptr; do { if (replacement_name) stringDelete(replacement_name); replacement_name = stringPrint("%s_%d", inst_name, i); } while (inst_names.findKey(replacement_name)); reader->warn(19, filename_, inst->line(), "instance name %s duplicated - renamed to %s.", reader->instanceVerilogName(inst_name), replacement_name); inst_name = replacement_name; inst->setInstanceName(inst_name); } inst_names.insert(inst_name); } VerilogDcl * VerilogModule::declaration(const char *net_name) { return dcl_map_.findKey(net_name); } //////////////////////////////////////////////////////////////// VerilogStmt::VerilogStmt(int line) : line_(line) { } VerilogInst::VerilogInst(const char *inst_name, const int line) : VerilogStmt(line), inst_name_(inst_name) { } VerilogInst::~VerilogInst() { stringDelete(inst_name_); } void VerilogInst::setInstanceName(const char *inst_name) { stringDelete(inst_name_); inst_name_ = inst_name; } VerilogModuleInst::VerilogModuleInst(const char *module_name, const char *inst_name, VerilogNetSeq *pins, int line) : VerilogInst(inst_name, line), module_name_(module_name), pins_(pins) { } VerilogModuleInst::~VerilogModuleInst() { if (pins_) { pins_->deleteContents(); delete pins_; } stringDelete(module_name_); } bool VerilogModuleInst::hasPins() { return pins_ && pins_->size() > 0; } bool VerilogModuleInst::namedPins() { return pins_ && pins_->size() > 0 && (*pins_)[0]->isNamedPortRef(); } VerilogLibertyInst::VerilogLibertyInst(LibertyCell *cell, const char *inst_name, const char **net_names, const int line) : VerilogInst(inst_name, line), cell_(cell), net_names_(net_names) { } VerilogLibertyInst::~VerilogLibertyInst() { int port_count = cell_->portBitCount(); for (int i = 0; i < port_count; i++) { const char *net_name = net_names_[i]; if (net_name && net_name != unconnected_net_name) stringDelete(net_name); } delete [] net_names_; } VerilogDcl::VerilogDcl(PortDirection *dir, VerilogDclArgSeq *args, int line) : VerilogStmt(line), dir_(dir), args_(args) { } VerilogDcl::VerilogDcl(PortDirection *dir, VerilogDclArg *arg, int line) : VerilogStmt(line), dir_(dir) { args_ = new VerilogDclArgSeq; args_->push_back(arg); } VerilogDcl::~VerilogDcl() { args_->deleteContents(); delete args_; } void VerilogDcl::appendArg(VerilogDclArg *arg) { args_->push_back(arg); } const char * VerilogDcl::portName() { return (*args_)[0]->netName(); } VerilogDclBus::VerilogDclBus(PortDirection *dir, int from_index, int to_index, VerilogDclArgSeq *args, int line) : VerilogDcl(dir, args, line), from_index_(from_index), to_index_(to_index) { } VerilogDclBus::VerilogDclBus(PortDirection *dir, int from_index, int to_index, VerilogDclArg *arg, int line) : VerilogDcl(dir, arg, line), from_index_(from_index), to_index_(to_index) { } int VerilogDclBus::size() const { return abs(to_index_ - from_index_) + 1; } VerilogDclArg::VerilogDclArg(const char *net_name) : net_name_(net_name), assign_(nullptr) { } VerilogDclArg::VerilogDclArg(VerilogAssign *assign) : net_name_(nullptr), assign_(assign) { } VerilogDclArg::~VerilogDclArg() { stringDelete(net_name_); delete assign_; } const char * VerilogDclArg::netName() { if (net_name_) return net_name_; else if (assign_) return assign_->lhs()->name(); else return nullptr; } 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: VerilogNullNetNameIterator() {} virtual bool hasNext() { return false; } virtual const char *next() { return nullptr; } private: DISALLOW_COPY_AND_ASSIGN(VerilogNullNetNameIterator); }; class VerilogOneNetNameIterator : public VerilogNetNameIterator { public: explicit VerilogOneNetNameIterator(const char *name); virtual bool hasNext(); virtual const char *next(); protected: const char *name_; private: DISALLOW_COPY_AND_ASSIGN(VerilogOneNetNameIterator); }; VerilogOneNetNameIterator::VerilogOneNetNameIterator(const char *name) : name_(name) { } bool VerilogOneNetNameIterator::hasNext() { return name_ != nullptr; } const char * VerilogOneNetNameIterator::next() { const char *name = name_; name_ = nullptr; return name; } class VerilogBusNetNameIterator : public VerilogNetNameIterator { public: VerilogBusNetNameIterator(const char *bus_name, int from_index, int to_index); virtual bool hasNext(); virtual const char *next(); protected: const char *bus_name_; int from_index_; int to_index_; int index_; private: DISALLOW_COPY_AND_ASSIGN(VerilogBusNetNameIterator); }; VerilogBusNetNameIterator::VerilogBusNetNameIterator(const char *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 char * VerilogBusNetNameIterator::next() { const char *bit_name = verilogBusBitNameTmp(bus_name_, index_); if (to_index_ > from_index_) index_++; else index_--; return bit_name; } static const char * verilogBusBitNameTmp(const char *bus_name, int index) { return stringPrintTmp("%s[%d]", bus_name, index); } static const char * verilogBusBitName(const char *bus_name, int index) { return stringPrint("%s[%d]", bus_name, index); } class VerilogConstantNetNameIterator : public VerilogNetNameIterator { public: VerilogConstantNetNameIterator(VerilogConstantValue *value, const char *zero, const char *one); virtual bool hasNext(); virtual const char *next(); private: DISALLOW_COPY_AND_ASSIGN(VerilogConstantNetNameIterator); VerilogConstantValue *value_; const char *zero_; const char *one_; int bit_index_; }; VerilogConstantNetNameIterator:: VerilogConstantNetNameIterator(VerilogConstantValue *value, const char *zero, const char *one) : value_(value), zero_(zero), one_(one), bit_index_(value->size() - 1) { } bool VerilogConstantNetNameIterator::hasNext() { return bit_index_ >= 0; } const char * 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(); virtual const char *next(); private: DISALLOW_COPY_AND_ASSIGN(VerilogNetConcatNameIterator); 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), net_name_iter_(nullptr) { 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(); } const char * 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(); } } return nullptr; } //////////////////////////////////////////////////////////////// VerilogNetNamed::VerilogNetNamed(const char *name) : VerilogNet(), name_(name) { } VerilogNetNamed::~VerilogNetNamed() { stringDelete(name_); } void VerilogNetNamed::setName(const char *name) { name_ = name; } VerilogNetScalar::VerilogNetScalar(const char *name) : 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) { return verilogNetScalarSize(name_, module); } static VerilogNetNameIterator * verilogNetScalarNameIterator(const char *name, VerilogModule *module) { if (name) { 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()); } else return new VerilogOneNetNameIterator(name); } else return new VerilogOneNetNameIterator(nullptr); } VerilogNetNameIterator * VerilogNetScalar::nameIterator(VerilogModule *module, VerilogReader *) { return verilogNetScalarNameIterator(name_, module); } VerilogNetBitSelect::VerilogNetBitSelect(const char *name, int index) : VerilogNetNamed(name), index_(index) { } const char * VerilogNetBitSelect::name() { return verilogBusBitNameTmp(name_, index_); } int VerilogNetBitSelect::size(VerilogModule *) { return 1; } VerilogNetNameIterator * VerilogNetBitSelect::nameIterator(VerilogModule *, VerilogReader *) { return new VerilogOneNetNameIterator(verilogBusBitNameTmp(name_, index_)); } VerilogNetPartSelect::VerilogNetPartSelect(const char *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(const char *constant, VerilogReader *reader) { parseConstant(constant, reader); } void VerilogNetConstant::parseConstant(const char *constant, VerilogReader *reader) { size_t constant_length = strlen(constant); char *tmp = new char[constant_length + 1]; char *t = tmp; const char *c = constant; // Copy the constant size to tmp. while (*c && *c != '\'') *t++ = *c++; *t = '\0'; // Read the constant size. size_t size = atol(tmp); value_ = new VerilogConstantValue(size); // Read the constant base. const char *base_ptr = c + 1; char base_ch = *base_ptr; switch (base_ch) { case 'b': case 'B': parseConstant(constant, constant_length, base_ptr, 2, 1); break; case 'o': case 'O': parseConstant(constant, constant_length, base_ptr, 8, 3); break; case 'h': case 'H': parseConstant(constant, constant_length, base_ptr, 16, 4); break; case 'd': case 'D': parseConstant10(base_ptr + 1, tmp, reader); break; default: case '\0': VerilogParse_error("unknown constant base.\n"); break; } stringDelete(tmp); stringDelete(constant); } void VerilogNetConstant::parseConstant(const char *constant, size_t constant_length, const char *base_ptr, 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'; const char *c = &constant[constant_length - 1]; size_t bit = 0; while (bit < size) { char ch = (c > base_ptr) ? *c-- : '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 char *constant_str, char *tmp, VerilogReader *reader) { // Copy the constant skipping underscores. char *t = tmp; for (const char *c = constant_str; *c; c++) { char ch = *c; if (ch != '_') *t++ = ch; } *t = '\0'; size_t size = value_->size(); size_t length = strlen(tmp); size_t max_length = reader->constant10MaxLength(); if (length > max_length || (length == max_length && strcmp(tmp, reader->constant10Max()) > 0)) reader->warn(20, reader->filename(), reader->line(), "base 10 constant greater than %s not supported.", reader->constant10Max()); else { char *end; VerilogConstant10 value = strtoull(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() { 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); } VerilogNetPortRef::VerilogNetPortRef(const char *name) : VerilogNetScalar(name) { } VerilogNetPortRefScalarNet:: VerilogNetPortRefScalarNet(const char *name, const char *net_name) : VerilogNetPortRef(name), net_name_(net_name) { } VerilogNetPortRefScalarNet::~VerilogNetPortRefScalarNet() { stringDelete(net_name_); } int VerilogNetPortRefScalarNet::size(VerilogModule *module) { // VerilogNetScalar::size VerilogDcl *dcl = nullptr; if (net_name_) 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 char *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 char *name, int index, VerilogNet *net) : VerilogNetPortRefScalar(name, net), index_(index) { } const char * VerilogNetPortRefBit::name() { return verilogBusBitNameTmp(name_, index_); } VerilogNetPortRefPart::VerilogNetPortRefPart(const char *name, int from_index, int to_index, VerilogNet *net) : VerilogNetPortRefBit(name, from_index, net), to_index_(to_index) { } const char * VerilogNetPortRefPart::name() { return name_; } //////////////////////////////////////////////////////////////// // // Link verilog network // //////////////////////////////////////////////////////////////// Instance * linkVerilogNetwork(const char *top_cell_name, bool make_black_boxes, Report *report, NetworkReader *) { return verilog_reader->linkNetwork(top_cell_name, make_black_boxes, report); } // Verilog net name to network net map. typedef Map BindingMap; class VerilogBindingTbl { public: VerilogBindingTbl(const char *zero_net_name_, const char *one_net_name_); 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: DISALLOW_COPY_AND_ASSIGN(VerilogBindingTbl); const char *zero_net_name_; const char *one_net_name_; BindingMap map_; }; Instance * VerilogReader::linkNetwork(const char *top_cell_name, bool make_black_boxes, Report *report) { 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. Instance *top_instance = network_->makeInstance(top_cell, "", nullptr); 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()) { const char *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(report); deleteModules(); if (errors) { network_->deleteInstance(top_instance); return nullptr; } else return top_instance; } else { report->error(162, "%s is not a verilog module.", top_cell_name); return nullptr; } } else { report->error(163, "%s is not a verilog module.", top_cell_name); return nullptr; } } 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(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(); 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()) { 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 char *module_name = mod_inst->moduleName(); Cell *cell = network_->findAnyCell(module_name); if (cell == nullptr) { if (make_black_boxes) { cell = makeBlackBox(mod_inst, parent_module); linkWarn(198, filename_, mod_inst->line(), "module %s not found. Creating black box for %s.", mod_inst->moduleName(), verilogName(mod_inst)); } else linkError(199, filename_, mod_inst->line(), "module %s not found for instance %s.", mod_inst->moduleName(), verilogName(mod_inst)); } 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); 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), nullptr); } } 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); 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) { VerilogNetSeq::Iterator pin_iter(mod_inst->pins()); while (pin_iter.hasNext()) { VerilogNetPortRef *vpin = dynamic_cast(pin_iter.next()); const char *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 %s port %s size %d does not match net size %d.", verilogName(mod_inst), 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 { 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). if (pg_port == nullptr) linkWarn(201, parent_module->filename(), mod_inst->line(), "instance %s port %s not found.", verilogName(mod_inst), 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::Iterator pin_iter(mod_inst->pins()); while (pin_iter.hasNext() && port_iter->hasNext()) { VerilogNet *net = pin_iter.next(); Port *port = port_iter->next(); if (network_->size(port) != net->size(parent_module)) linkWarn(202, parent_module->filename(), mod_inst->line(), "instance %s port %s size %d does not match net size %d.", verilogName(mod_inst), 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) { const char *net_name = nullptr; 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 char *net_name, VerilogBindingTbl *bindings, Instance *parent, VerilogBindingTbl *parent_bindings, bool is_leaf) { Net *net = nullptr; if (net_name) 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 *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(lib_cell); Instance *inst = network_->makeInstance(cell, lib_inst->instanceName(), parent); const char **net_names = lib_inst->netNames(); LibertyCellPortBitIterator port_iter(lib_cell); while (port_iter.hasNext()) { LibertyPort *port = port_iter.next(); const char *net_name = net_names[port->pinIndex()]; // net_name may be the name of a single bit bus. if (net_name) { Net *net = nullptr; // If the pin is unconnected (ie, .A()) make the pin but not the net. if (net_name != unconnected_net_name) { 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. const char *bus_name = verilogBusBitNameTmp(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 char *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) { VerilogNetSeq::Iterator pin_iter(mod_inst->pins()); while (pin_iter.hasNext()) { VerilogNetNamed *vpin = dynamic_cast(pin_iter.next()); const char *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::Iterator pin_iter(mod_inst->pins()); while (pin_iter.hasNext()) { VerilogNet *net = pin_iter.next(); size_t size = net->size(parent_module); char *port_name = stringPrint("p_%d", port_index); Port *port = (size == 1) ? network_->makePort(cell, port_name) : network_->makeBusPort(cell, port_name, size - 1, 0); stringDelete(port_name); 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 char *lhs_name = lhs_iter->next(); const char *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 %d not equal right hand size %d.", 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 char *zero_net_name, const char *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(const char *name, NetworkReader *network) { Net *net = map_.findKey(name); while (net && network->mergedInto(net)) net = network->mergedInto(net); return net; } void VerilogBindingTbl::bind(const char *name, Net *net) { map_[name] = net; } Net * VerilogBindingTbl::ensureNetBinding(const char *net_name, Instance *inst, NetworkReader *network) { Net *net = find(net_name, network); if (net == nullptr) { net = network->makeNet(net_name, inst); map_[network->name(net)] = net; if (stringEq(net_name, zero_net_name_)) network->addConstantNet(net, LogicValue::zero); if (stringEq(net_name, one_net_name_)) network->addConstantNet(net, LogicValue::one); } return net; } //////////////////////////////////////////////////////////////// void VerilogReader::linkWarn(int id, const char *filename, int line, const char *msg, ...) { va_list args; va_start(args, msg); char *msg_str = stringPrintArgs(msg, args); VerilogError *error = new VerilogError(id, filename, line, msg_str, true); link_errors_.push_back(error); va_end(args); } void VerilogReader::linkError(int id, const char *filename, int line, const char *msg, ...) { va_list args; va_start(args, msg); char *msg_str = stringPrintArgs(msg, args); VerilogError *error = new VerilogError(id, filename, line, msg_str, false); link_errors_.push_back(error); va_end(args); } bool VerilogReader::reportLinkErrors(Report *report) { // 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(); // Report as warnings to avoid throwing. report->fileWarn(error->id(), error->filename(), error->line(), "%s", error->msg()); errors |= !error->warn(); delete error; } link_errors_.clear(); return errors; } } // namespace //////////////////////////////////////////////////////////////// // Global namespace void verilogFlushBuffer(); int VerilogParse_error(const char *msg) { sta::verilog_reader->report()->fileError(164, sta::verilog_reader->filename(), sta::verilog_reader->line(), "%s", msg); verilogFlushBuffer(); return 0; }