diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index a8eff2ee..c11796c2 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -2473,9 +2473,9 @@ LibertyReader::visitClockGatingIntegratedCell(LibertyAttr *attr) if (cell_) { const char *clock_gate_type = getAttrString(attr); if (clock_gate_type) { - if (stringBeginEq(clock_gate_type, "latch_posedge")) + if (stringBeginEqual(clock_gate_type, "latch_posedge")) cell_->setClockGateType(ClockGateType::latch_posedge); - else if (stringBeginEq(clock_gate_type, "latch_negedge")) + else if (stringBeginEqual(clock_gate_type, "latch_negedge")) cell_->setClockGateType(ClockGateType::latch_negedge); else cell_->setClockGateType(ClockGateType::other); diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index 04ff978d..bab55865 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -108,9 +108,6 @@ private: StringSet &path_cell_names); void recordSpicePortNames(const char *cell_name, StringVector &tokens); - float pgPortVoltage(const char *pg_port_name, - LibertyCell *cell); - float pgPortVoltage(LibertyPgPort *pg_port); float maxTime(); const char *nodeName(ParasiticNode *node); void initNodeMap(const char *net_name); @@ -159,12 +156,18 @@ private: TimingArc *next_arc, DcalcAPIndex dcalc_ap_index); LibertyPort *onePort(FuncExpr *expr); + void writeVoltageSource(const char *inst_name, + const char *port_name, + float voltage, + int &volt_index); void writeVoltageSource(LibertyCell *cell, const char *inst_name, const char *subckt_port_name, const char *pg_port_name, + float voltage, int &volt_index); float slewAxisMinValue(TimingArc *arc); + float pgPortVoltage(LibertyPgPort *pg_port); // Stage "accessors". // @@ -296,11 +299,16 @@ WritePathSpice::WritePathSpice(Path *path, { bool exists; default_library_->supplyVoltage(power_name_, power_voltage_, exists); - if (!exists) - report_->error("supply %s voltage not found,\n", power_name_); + if (!exists) { + auto dcalc_ap = path_->dcalcAnalysisPt(this); + auto op_cond = dcalc_ap->operatingConditions(); + if (op_cond == nullptr) + op_cond = network_->defaultLibertyLibrary()->defaultOperatingConditions(); + power_voltage_ = op_cond->voltage(); + } default_library_->supplyVoltage(gnd_name_, gnd_voltage_, exists); if (!exists) - report_->error("supply %s voltage not found,\n", gnd_name_); + gnd_voltage_ = 0.0; } WritePathSpice::~WritePathSpice() @@ -403,26 +411,31 @@ WritePathSpice::writeStageInstances() streamPrint(spice_stream_, "\n"); } -float -WritePathSpice::pgPortVoltage(const char *pg_port_name, - LibertyCell *cell) -{ - auto pg_port = cell->findPgPort(pg_port_name); - return pgPortVoltage(pg_port); -} - float WritePathSpice::pgPortVoltage(LibertyPgPort *pg_port) { - auto cell = pg_port->cell(); - auto voltage_name = pg_port->voltageName(); - auto lib = cell->libertyLibrary(); - float voltage; + LibertyLibrary *liberty = pg_port->cell()->libertyLibrary(); + float voltage = 0.0; bool exists; - lib->supplyVoltage(voltage_name, voltage, exists); - if (!exists) - report_->error("pg_port %s voltage %s not found,\n", - pg_port->name(), voltage_name); + auto voltage_name = pg_port->voltageName(); + if (voltage_name) { + liberty->supplyVoltage(voltage_name, voltage, exists); + if (!exists) { + if (stringEqual(voltage_name, power_name_)) + voltage = power_voltage_; + else if (stringEqual(voltage_name, gnd_name_)) + voltage = gnd_voltage_; + else + report_->error("pg_pin %s/%s voltage %s not found,\n", + pg_port->cell()->name(), + pg_port->name(), + voltage_name); + } + } + else + report_->error("Liberty pg_port %s/%s missing voltage_name attribute,\n", + pg_port->cell()->name(), + pg_port->name()); return voltage; } @@ -818,6 +831,9 @@ WritePathSpice::writeSubcktInst(const Pin *input_pin) } else if (pg_port) streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_cname); + else if (stringEq(subckt_port_cname, power_name_) + || stringEq(subckt_port_cname, gnd_name_)) + streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_cname); } streamPrint(spice_stream_, " %s\n", cell_name); } @@ -851,14 +867,16 @@ WritePathSpice::writeSubcktInstVoltSrcs(Stage stage, debugPrint2(debug_, "write_spice", 2, " port %s%s\n", subckt_port_name, pg_port ? " pwr/gnd" : ""); - if (pg_port) { - auto voltage = pgPortVoltage(pg_port); - streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n", - volt_index, - inst_name, subckt_port_name, - voltage); - volt_index++; - } else if (!(stringEq(subckt_port_name, input_port_name) + if (pg_port) + writeVoltageSource(inst_name, subckt_port_name, + pgPortVoltage(pg_port), volt_index); + else if (stringEq(subckt_port_name, power_name_)) + writeVoltageSource(inst_name, subckt_port_name, + power_voltage_, volt_index); + else if (stringEq(subckt_port_name, gnd_name_)) + writeVoltageSource(inst_name, subckt_port_name, + gnd_voltage_, volt_index); + else if (!(stringEq(subckt_port_name, input_port_name) || stringEq(subckt_port_name, drvr_port_name))) { // Input voltage to sensitize path from gate input to output. auto port = cell->findLibertyPort(subckt_port_name); @@ -879,11 +897,13 @@ WritePathSpice::writeSubcktInstVoltSrcs(Stage stage, case LogicValue::unknown: writeVoltageSource(cell, inst_name, subckt_port_name, port->relatedGroundPin(), + gnd_voltage_, volt_index); break; case LogicValue::one: writeVoltageSource(cell, inst_name, subckt_port_name, port->relatedPowerPin(), + power_voltage_, volt_index); break; case LogicValue::rise: @@ -914,39 +934,38 @@ WritePathSpice::writeClkedStepSource(const Pin *pin, writeStepVoltSource(pin, tr, slew, time, volt_index); } +void +WritePathSpice::writeVoltageSource(const char *inst_name, + const char *port_name, + float voltage, + int &volt_index) +{ + streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n", + volt_index, + inst_name, port_name, + voltage); + volt_index++; +} + void WritePathSpice::writeVoltageSource(LibertyCell *cell, const char *inst_name, const char *subckt_port_name, const char *pg_port_name, + float voltage, int &volt_index) { - auto pg_port = cell->findPgPort(pg_port_name); - if (pg_port) { - auto voltage_name = pg_port->voltageName(); - if (voltage_name) { - float voltage; - bool exists; - cell->libertyLibrary()->supplyVoltage(voltage_name, voltage, exists); - if (!exists) - report_->error("pg_port %s voltage %s not found,\n", - pg_port_name, voltage_name); - streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n", - volt_index, - inst_name, subckt_port_name, - voltage); - volt_index++; - } + if (pg_port_name) { + auto pg_port = cell->findPgPort(pg_port_name); + if (pg_port) + voltage = pgPortVoltage(pg_port); else - report_->error("port %s %s voltage %s not found,\n", - subckt_port_name, - pg_port_name, - voltage_name); + report_->error("%s pg_port %s not found,\n", + cell->name(), + pg_port_name); + } - else - report_->error("port %s %s not found,\n", - subckt_port_name, - pg_port_name); + writeVoltageSource(inst_name, subckt_port_name, voltage, volt_index); } void @@ -1345,7 +1364,7 @@ WritePathSpice::writeSubckts() bool found_ends = false; while (getline(lib_subckts_stream, line)) { subckts_stream << line << "\n"; - if (stringEqual(line.c_str(), ".ends")) { + if (stringBeginEqual(line.c_str(), ".ends")) { subckts_stream << "\n"; found_ends = true; break; @@ -1416,8 +1435,11 @@ WritePathSpice::recordSpicePortNames(const char *cell_name, auto port_name = tokens[i].c_str(); auto port = cell->findLibertyPort(port_name); auto pg_port = cell->findPgPort(port_name); - if (port == nullptr && pg_port == nullptr) - report_->error("subckt %s port %s has no corresponding liberty port or pg_port.\n", + if (port == nullptr + && pg_port == nullptr + && !stringEqual(port_name, power_name_) + && !stringEqual(port_name, gnd_name_)) + report_->error("subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground.\n", cell_name, port_name); spice_port_names->push_back(port_name); } diff --git a/tcl/Cmds.tcl b/tcl/Cmds.tcl index 932b8ae3..d71f971a 100644 --- a/tcl/Cmds.tcl +++ b/tcl/Cmds.tcl @@ -1942,18 +1942,12 @@ proc write_path_spice { args } { if { [info exists keys(-power)] } { set power $keys(-power) - if { ![liberty_supply_exists $power] } { - sta_error "liberty $power not found.\n" - } } else { sta_error "No -power specified.\n" } if { [info exists keys(-ground)] } { set ground $keys(-ground) - if { ![liberty_supply_exists $ground] } { - sta_error "liberty $ground not found.\n" - } } else { sta_error "No -ground specified.\n" } diff --git a/util/StringUtil.hh b/util/StringUtil.hh index e79c486f..be7556ad 100644 --- a/util/StringUtil.hh +++ b/util/StringUtil.hh @@ -49,12 +49,12 @@ stringEqIf(const char *str1, || (str1 && str2 && strcmp(str1, str2) == 0); } -// Compare the beginning of str1 to str2. +// Case insensitive compare the beginning of str1 to str2. inline bool -stringBeginEq(const char *str1, - const char *str2) +stringBeginEqual(const char *str1, + const char *str2) { - return strncasecmp(str1, str2, strlen(str2)) == 9; + return strncasecmp(str1, str2, strlen(str2)) == 0; } // Case insensitive compare.