diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index c445ecd0..bf8029c0 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf index f69ea92a..ed8ec03e 100644 Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ diff --git a/include/sta/PathExpanded.hh b/include/sta/PathExpanded.hh index f62b302a..d943e7c9 100644 --- a/include/sta/PathExpanded.hh +++ b/include/sta/PathExpanded.hh @@ -40,7 +40,7 @@ public: size_t size() const { return paths_.size(); } // path(0) is the startpoint. // path(size()-1) is the endpoint. - PathRef *path(size_t index); + const PathRef *path(size_t index) const; TimingArc *prevArc(size_t index); // Returns the path start point. // Register/Latch Q pin diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 52c2ef2d..fa735883 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -905,9 +905,9 @@ public: // Previous path end is used to detect path group changes // so headers are reported by group. void reportPathEnd(PathEnd *end, - PathEnd *prev_end); + PathEnd *prev_end, + bool last); void reportPathEnd(PathEnd *end); - void reportPathEnds(PathEndSeq *ends); ReportPath *reportPath() { return report_path_; } void reportPath(Path *path); diff --git a/include/sta/StringUtil.hh b/include/sta/StringUtil.hh index c2a117a5..3b2f6cee 100644 --- a/include/sta/StringUtil.hh +++ b/include/sta/StringUtil.hh @@ -169,6 +169,11 @@ void stringPrint(string &str, const char *fmt, ...) __attribute__((format (printf, 2, 3))); +// Formated append to std::string. +void +stringAppend(string &str, + const char *fmt, + ...) __attribute__((format (printf, 2, 3))); // Print to a temporary string. char * diff --git a/search/PathExpanded.cc b/search/PathExpanded.cc index 972e3bfa..8c63e5b2 100644 --- a/search/PathExpanded.cc +++ b/search/PathExpanded.cc @@ -146,8 +146,8 @@ PathExpanded::startIndex() const return pathsIndex(start_index_); } -PathRef * -PathExpanded::path(size_t index) +const PathRef * +PathExpanded::path(size_t index) const { if (index < paths_.size()) return &paths_[pathsIndex(index)]; diff --git a/search/Property.cc b/search/Property.cc index 01491905..568ec68c 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -1260,7 +1260,7 @@ getProperty(PathEnd *end, PathExpanded expanded(end->path(), sta); PathRefSeq paths; for (auto i = expanded.startIndex(); i < expanded.size(); i++) { - PathRef *path = expanded.path(i); + const PathRef *path = expanded.path(i); paths.push_back(*path); } return PropertyValue(&paths); diff --git a/search/ReportPath.cc b/search/ReportPath.cc index f19f2e9e..3770bd05 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -269,58 +269,16 @@ ReportPath::setReportSigmas(bool report) //////////////////////////////////////////////////////////////// -void -ReportPath::reportPathEndHeader() -{ - switch (format_) { - case ReportPathFormat::full: - case ReportPathFormat::full_clock: - case ReportPathFormat::full_clock_expanded: - case ReportPathFormat::shorter: - case ReportPathFormat::endpoint: - break; - case ReportPathFormat::summary: - reportSummaryHeader(); - break; - case ReportPathFormat::slack_only: - reportSlackOnlyHeader(); - break; - default: - report_->critical(1470, "unsupported path type"); - break; - } -} - -void -ReportPath::reportPathEndFooter() -{ - string header; - switch (format_) { - case ReportPathFormat::full: - case ReportPathFormat::full_clock: - case ReportPathFormat::full_clock_expanded: - case ReportPathFormat::shorter: - break; - case ReportPathFormat::endpoint: - case ReportPathFormat::summary: - case ReportPathFormat::slack_only: - reportBlankLine(); - break; - default: - report_->critical(1471, "unsupported path type"); - break; - } -} - void ReportPath::reportPathEnd(PathEnd *end) { - reportPathEnd(end, nullptr); + reportPathEnd(end, nullptr, true); } void ReportPath::reportPathEnd(PathEnd *end, - PathEnd *prev_end) + PathEnd *prev_end, + bool last) { switch (format_) { case ReportPathFormat::full: @@ -345,8 +303,8 @@ ReportPath::reportPathEnd(PathEnd *end, case ReportPathFormat::slack_only: reportSlackOnly(end); break; - default: - report_->critical(1473, "unsupported path type"); + case ReportPathFormat::json: + reportJson(end, last); break; } } @@ -367,6 +325,49 @@ ReportPath::reportPathEnds(PathEndSeq *ends) reportPathEndFooter(); } +void +ReportPath::reportPathEndHeader() +{ + switch (format_) { + case ReportPathFormat::full: + case ReportPathFormat::full_clock: + case ReportPathFormat::full_clock_expanded: + case ReportPathFormat::shorter: + case ReportPathFormat::endpoint: + break; + case ReportPathFormat::summary: + reportSummaryHeader(); + break; + case ReportPathFormat::slack_only: + reportSlackOnlyHeader(); + break; + case ReportPathFormat::json: + reportJsonHeader(); + break; + } +} + +void +ReportPath::reportPathEndFooter() +{ + string header; + switch (format_) { + case ReportPathFormat::full: + case ReportPathFormat::full_clock: + case ReportPathFormat::full_clock_expanded: + case ReportPathFormat::shorter: + break; + case ReportPathFormat::endpoint: + case ReportPathFormat::summary: + case ReportPathFormat::slack_only: + reportBlankLine(); + break; + case ReportPathFormat::json: + reportJsonFooter(); + break; + } +} + void ReportPath::reportEndpointHeader(PathEnd *end, PathEnd *prev_end) @@ -1043,6 +1044,146 @@ ReportPath::pathEndpoint(PathEnd *end) //////////////////////////////////////////////////////////////// +void +ReportPath::reportJsonHeader() +{ + report_->reportLine("{\"checks\": ["); +} + +void +ReportPath::reportJsonFooter() +{ + report_->reportLine("]"); + report_->reportLine("}"); +} + +void +ReportPath::reportJson(const PathEnd *end, + bool last) +{ + string result; + result += "{\n"; + stringAppend(result, " \"type\": \"%s\",\n", end->typeName()); + stringAppend(result, " \"path_group\": \"%s\",\n", + search_->pathGroup(end)->name()); + stringAppend(result, " \"path_type\": \"%s\",\n", + end->minMax(this)->asString()); + + PathExpanded expanded(end->path(), this); + const Pin *startpoint = expanded.startPath()->vertex(this)->pin(); + const Pin *endpoint = expanded.endPath()->vertex(this)->pin(); + stringAppend(result, " \"startpoint\": \"%s\",\n", + network_->pathName(startpoint)); + stringAppend(result, " \"endpoint\": \"%s\",\n", + network_->pathName(endpoint)); + + const ClockEdge *src_clk_edge = end->sourceClkEdge(this); + const PathVertex *tgt_clk_path = end->targetClkPath(); + if (src_clk_edge) { + stringAppend(result, " \"source_clock\": \"%s\",\n", + src_clk_edge->clock()->name()); + stringAppend(result, " \"source_clock_edge\": \"%s\",\n", + src_clk_edge->transition()->name()); + } + reportJson(expanded, "source_path", 2, !end->isUnconstrained(), result); + + const ClockEdge *tgt_clk_edge = end->targetClkEdge(this); + if (tgt_clk_edge) { + stringAppend(result, " \"target_clock\": \"%s\",\n", + tgt_clk_edge->clock()->name()); + stringAppend(result, " \"target_clock_edge\": \"%s\",\n", + tgt_clk_edge->transition()->name()); + } + if (tgt_clk_path) + reportJson(end->targetClkPath(), "target_clock_path", 2, true, result); + + if (end->checkRole(this)) { + stringAppend(result, " \"data_arrival_time\": %.3e,\n", + end->dataArrivalTimeOffset(this)); + + const MultiCyclePath *mcp = end->multiCyclePath(); + if (mcp) + stringAppend(result, " \"multi_cycle_path\": %d,\n", + mcp->pathMultiplier()); + + PathDelay *path_delay = end->pathDelay(); + if (path_delay) + stringAppend(result, " \"path_delay\": %.3e,\n", + path_delay->delay()); + + stringAppend(result, " \"crpr\": %.3e,\n", end->checkCrpr(this)); + stringAppend(result, " \"margin\": %.3e,\n", end->margin(this)); + stringAppend(result, " \"required_time\": %.3e,\n", + end->requiredTimeOffset(this)); + stringAppend(result, " \"slack\": %.3e\n", end->slack(this)); + } + result += "}"; + if (!last) + result += ","; + report_->reportLineString(result); +} + +void +ReportPath::reportJson(const Path *path) +{ + string result; + result += "{\n"; + reportJson(path, "path", 0, false, result); + result += "}\n"; + report_->reportLineString(result); +} + +void +ReportPath::reportJson(const Path *path, + const char *path_name, + int indent, + bool trailing_comma, + string &result) +{ + PathExpanded expanded(path, this); + reportJson(expanded, path_name, indent, trailing_comma, result); +} + +void +ReportPath::reportJson(const PathExpanded &expanded, + const char *path_name, + int indent, + bool trailing_comma, + string &result) +{ + stringAppend(result, "%*s\"%s\": [\n", indent, "", path_name); + for (size_t i = 0; i < expanded.size(); i++) { + const PathRef *path = expanded.path(i); + const Pin *pin = path->vertex(this)->pin(); + stringAppend(result, "%*s {\n", indent, ""); + stringAppend(result, "%*s \"pin\": \"%s\",\n", + indent, "", + network_->pathName(pin)); + double x, y; + bool exists; + network_->location(pin, x, y, exists); + if (exists) { + stringAppend(result, "%*s \"x\": %.9f,\n", indent, "", x); + stringAppend(result, "%*s \"y\": %.9f,\n", indent, "", y); + } + + stringAppend(result, "%*s \"arrival\": %.3e,\n", + indent, "", + delayAsFloat(path->arrival(this))); + stringAppend(result, "%*s \"slew\": %.3e\n", + indent, "", + delayAsFloat(path->slew(this))); + stringAppend(result, "%*s }%s\n", + indent, "", + (i < expanded.size() - 1) ? "," : ""); + } + stringAppend(result, "%*s]%s\n", + indent, "", + trailing_comma ? "," : ""); +} + +//////////////////////////////////////////////////////////////// + void ReportPath::reportSlackOnlyHeader() { @@ -2365,12 +2506,13 @@ ReportPath::reportPath(const Path *path) reportPathFull(path); break; case ReportPathFormat::json: - reportPathJson(path); + reportJson(path); break; + case ReportPathFormat::shorter: + case ReportPathFormat::endpoint: case ReportPathFormat::summary: case ReportPathFormat::slack_only: - default: - report_->critical(1474, "unsupported path type"); + report_->reportLine("Format not supported."); break; } } @@ -2383,54 +2525,7 @@ ReportPath::reportPathFull(const Path *path) reportSrcClkAndPath(path, expanded, 0.0, delay_zero, delay_zero, false); } -void -ReportPath::reportPathJson(const Path *path) -{ - report_->reportLine("{ \"path\": ["); - PathExpanded expanded(path, this); - for (auto i = expanded.startIndex(); i < expanded.size(); i++) { - string line; - PathRef *path = expanded.path(i); - const Pin *pin = path->vertex(this)->pin(); - report_->reportLine(" {"); - line = " \"pin\": \""; - line += network_->pathName(pin); - line += "\","; - report_->reportLineString(line); - - double x, y; - bool exists; - string tmp; - network_->location(pin, x, y, exists); - if (exists) { - line = " \"x\": "; - stringPrint(tmp, "%.9f", x); - line += tmp + ",\n"; - line += " \"y\": "; - stringPrint(tmp, "%.9f", y); - line += tmp + ","; - report_->reportLineString(line); - } - - line = " \"arrival\": "; - stringPrint(tmp, "%.3e", delayAsFloat(path->arrival(this))); - line += tmp; - line += ","; - report_->reportLineString(line); - - line = " \"slew\": "; - stringPrint(tmp, "%.3e", delayAsFloat(path->slew(this))); - line += tmp; - report_->reportLineString(line); - - line = " }"; - if (i < expanded.size() - 1) - line += ","; - report_->reportLineString(line); - } - report_->reportLine(" ]"); - report_->reportLine("}"); -} +//////////////////////////////////////////////////////////////// void ReportPath::reportPath1(const Path *path, @@ -2517,7 +2612,7 @@ ReportPath::reportPath4(const Path *path, Arrival prev_time(0.0); if (skip_first_path) { path_first_index = 1; - PathRef *start = expanded.path(0); + const PathRef *start = expanded.path(0); prev_time = start->arrival(this) + time_offset; } size_t path_last_index = expanded.size() - 1; @@ -2551,7 +2646,7 @@ ReportPath::reportPath5(const Path *path, expanded.clkPath(clk_path); Vertex *clk_start = clk_path.vertex(this); for (size_t i = path_first_index; i <= path_last_index; i++) { - PathRef *path1 = expanded.path(i); + const PathRef *path1 = expanded.path(i); TimingArc *prev_arc = expanded.prevArc(i); Vertex *vertex = path1->vertex(this); Pin *pin = vertex->pin(); diff --git a/search/ReportPath.hh b/search/ReportPath.hh index 75778cc0..f2017a14 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -61,7 +61,8 @@ public: // Previous path end is used to detect path group changes // so headers are reported by group. void reportPathEnd(PathEnd *end, - PathEnd *prev_end); + PathEnd *prev_end, + bool last); void reportPathEnds(PathEndSeq *ends); void reportPath(const Path *path); @@ -81,6 +82,22 @@ public: void reportFull(const PathEndGatedClock *end); void reportFull(const PathEndDataCheck *end); + void reportJsonHeader(); + void reportJsonFooter(); + void reportJson(const PathEnd *end, + bool last); + void reportJson(const Path *path); + void reportJson(const Path *path, + const char *path_name, + int indent, + bool trailing_comma, + string &result); + void reportJson(const PathExpanded &expanded, + const char *path_name, + int indent, + bool trailing_comma, + string &result); + void reportEndHeader(); void reportEndLine(PathEnd *end); @@ -264,7 +281,6 @@ protected: void reportPath(const PathEnd *end, PathExpanded &expanded); void reportPathFull(const Path *path); - void reportPathJson(const Path *path); void reportPathHeader(); void reportPath1(const Path *path, PathExpanded &expanded, diff --git a/search/Search.i b/search/Search.i index da07b521..e90f03a8 100644 --- a/search/Search.i +++ b/search/Search.i @@ -480,9 +480,10 @@ report_path_end(PathEnd *end) void report_path_end2(PathEnd *end, - PathEnd *prev_end) + PathEnd *prev_end, + bool last) { - Sta::sta()->reportPathEnd(end, prev_end); + Sta::sta()->reportPathEnd(end, prev_end, last); } void diff --git a/search/Search.tcl b/search/Search.tcl index f6e5af90..76689129 100644 --- a/search/Search.tcl +++ b/search/Search.tcl @@ -1069,9 +1069,12 @@ proc parse_path_group_arg { group_names } { proc report_path_ends { path_ends } { report_path_end_header set prev_end "NULL" + set end_count [llength $path_ends] + set i 0 foreach path_end $path_ends { - report_path_end2 $path_end $prev_end + report_path_end2 $path_end $prev_end [expr $i == ($end_count - 1)] set prev_end $path_end + incr i } report_path_end_footer } diff --git a/search/Sta.cc b/search/Sta.cc index 1416edd6..175d1215 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2518,12 +2518,6 @@ Sta::setReportPathSigmas(bool report_sigmas) report_path_->setReportSigmas(report_sigmas); } -void -Sta::reportPathEnds(PathEndSeq *ends) -{ - report_path_->reportPathEnds(ends); -} - void Sta::reportPathEndHeader() { @@ -2544,9 +2538,10 @@ Sta::reportPathEnd(PathEnd *end) void Sta::reportPathEnd(PathEnd *end, - PathEnd *prev_end) + PathEnd *prev_end, + bool last) { - report_path_->reportPathEnd(end, prev_end); + report_path_->reportPathEnd(end, prev_end, last); } void diff --git a/spice/WritePathSpice.cc b/spice/WritePathSpice.cc index ab6509fe..50607b5b 100644 --- a/spice/WritePathSpice.cc +++ b/spice/WritePathSpice.cc @@ -84,10 +84,10 @@ private: float maxTime(); float pathMaxTime(); void writeMeasureDelayStmt(Stage stage, - Path *from_path, - Path *to_path); + const Path *from_path, + const Path *to_path); void writeMeasureSlewStmt(Stage stage, - Path *path); + const Path *path); void writeInputWaveform(); void writeClkWaveform(); @@ -110,9 +110,9 @@ private: int stageGateInputPathIndex(Stage stage); int stageDrvrPathIndex(Stage stage); int stageLoadPathIndex(Stage stage); - PathRef *stageGateInputPath(Stage stage); - PathRef *stageDrvrPath(Stage stage); - PathRef *stageLoadPath(Stage stage); + const PathRef *stageGateInputPath(Stage stage); + const PathRef *stageDrvrPath(Stage stage); + const PathRef *stageLoadPath(Stage stage); TimingArc *stageGateArc(Stage stage); TimingArc *stageWireArc(Stage stage); Edge *stageGateEdge(Stage stage); @@ -128,8 +128,8 @@ private: LibertyCell *stageLibertyCell(Stage stage); Instance *stageInstance(Stage stage); - float findSlew(Path *path); - float findSlew(Path *path, + float findSlew(const Path *path); + float findSlew(const Path *path, const RiseFall *rf, TimingArc *next_arc); Path *path_; @@ -240,7 +240,7 @@ float WritePathSpice::maxTime() { Stage input_stage = stageFirst(); - PathRef *input_path = stageDrvrPath(input_stage); + const PathRef *input_path = stageDrvrPath(input_stage); if (input_path->isClock(this)) { const Clock *clk = input_path->clock(this); float period = clk->period(); @@ -258,7 +258,7 @@ WritePathSpice::pathMaxTime() { float max_time = 0.0; for (size_t i = 0; i < path_expanded_.size(); i++) { - PathRef *path = path_expanded_.path(i); + const PathRef *path = path_expanded_.path(i); const RiseFall *rf = path->transition(this); Vertex *vertex = path->vertex(this); float path_max_slew = railToRailSlew(findSlew(vertex,rf,nullptr), rf); @@ -315,7 +315,7 @@ WritePathSpice::writeInputSource() streamPrint(spice_stream_, "**************\n\n"); Stage input_stage = stageFirst(); - PathRef *input_path = stageDrvrPath(input_stage); + const PathRef *input_path = stageDrvrPath(input_stage); if (input_path->isClock(this)) writeClkWaveform(); else @@ -327,7 +327,7 @@ void WritePathSpice::writeInputWaveform() { Stage input_stage = stageFirst(); - PathRef *input_path = stageDrvrPath(input_stage); + const PathRef *input_path = stageDrvrPath(input_stage); const RiseFall *rf = input_path->transition(this); TimingArc *next_arc = stageGateArc(input_stage + 1); float slew0 = findSlew(input_path, rf, next_arc); @@ -352,7 +352,7 @@ void WritePathSpice::writeClkWaveform() { Stage input_stage = stageFirst(); - PathRef *input_path = stageDrvrPath(input_stage); + const PathRef *input_path = stageDrvrPath(input_stage); TimingArc *next_arc = stageGateArc(input_stage + 1); const ClockEdge *clk_edge = input_path->clkEdge(this); @@ -387,7 +387,7 @@ WritePathSpice::writeClkWaveform() } float -WritePathSpice::findSlew(Path *path) +WritePathSpice::findSlew(const Path *path) { Vertex *vertex = path->vertex(this); const RiseFall *rf = path->transition(this); @@ -395,9 +395,9 @@ WritePathSpice::findSlew(Path *path) } float -WritePathSpice::findSlew(Path *path, - const RiseFall *rf, - TimingArc *next_arc) +WritePathSpice::findSlew(const Path *path, + const RiseFall *rf, + TimingArc *next_arc) { Vertex *vertex = path->vertex(this); return findSlew(vertex, rf, next_arc); @@ -413,9 +413,9 @@ WritePathSpice::writeMeasureStmts() streamPrint(spice_stream_, "********************\n\n"); for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { - PathRef *gate_input_path = stageGateInputPath(stage); - PathRef *drvr_path = stageDrvrPath(stage); - PathRef *load_path = stageLoadPath(stage); + const PathRef *gate_input_path = stageGateInputPath(stage); + const PathRef *drvr_path = stageDrvrPath(stage); + const PathRef *load_path = stageLoadPath(stage); if (gate_input_path) { // gate input -> gate output writeMeasureSlewStmt(stage, gate_input_path); @@ -432,8 +432,8 @@ WritePathSpice::writeMeasureStmts() void WritePathSpice::writeMeasureDelayStmt(Stage stage, - Path *from_path, - Path *to_path) + const Path *from_path, + const Path *to_path) { writeMeasureDelayStmt(from_path->pin(this), from_path->transition(this), to_path->pin(this), to_path->transition(this), @@ -442,7 +442,7 @@ WritePathSpice::writeMeasureDelayStmt(Stage stage, void WritePathSpice::writeMeasureSlewStmt(Stage stage, - Path *path) + const Path *path) { const Pin *pin = path->pin(this); const RiseFall *rf = path->transition(this); @@ -514,7 +514,7 @@ WritePathSpice::writeGateStage(Stage stage) drvr_port->name()); writeSubcktInst(inst); - PathRef *drvr_path = stageDrvrPath(stage); + const PathRef *drvr_path = stageDrvrPath(stage); const RiseFall *drvr_rf = drvr_path->transition(this); Edge *gate_edge = stageGateEdge(stage); @@ -544,7 +544,7 @@ WritePathSpice::writeGateStage(Stage stage) void WritePathSpice::writeStageParasitics(Stage stage) { - PathRef *drvr_path = stageDrvrPath(stage); + const PathRef *drvr_path = stageDrvrPath(stage); DcalcAnalysisPt *dcalc_ap = drvr_path->dcalcAnalysisPt(this); ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); const Pin *drvr_pin = stageDrvrPin(stage); @@ -637,21 +637,21 @@ WritePathSpice::stageLoadPathIndex(Stage stage) return stage * 2 - 1; } -PathRef * +const PathRef * WritePathSpice::stageGateInputPath(Stage stage) { int path_index = stageGateInputPathIndex(stage); return path_expanded_.path(path_index); } -PathRef * +const PathRef * WritePathSpice::stageDrvrPath(Stage stage) { int path_index = stageDrvrPathIndex(stage); return path_expanded_.path(path_index); } -PathRef * +const PathRef * WritePathSpice::stageLoadPath(Stage stage) { int path_index = stageLoadPathIndex(stage); @@ -678,7 +678,7 @@ WritePathSpice::stageWireArc(Stage stage) Edge * WritePathSpice::stageGateEdge(Stage stage) { - PathRef *path = stageDrvrPath(stage); + const PathRef *path = stageDrvrPath(stage); TimingArc *arc = stageGateArc(stage); return path->prevEdge(arc, this); } @@ -686,7 +686,7 @@ WritePathSpice::stageGateEdge(Stage stage) Edge * WritePathSpice::stageWireEdge(Stage stage) { - PathRef *path = stageLoadPath(stage); + const PathRef *path = stageLoadPath(stage); TimingArc *arc = stageWireArc(stage); return path->prevEdge(arc, this); } @@ -694,7 +694,7 @@ WritePathSpice::stageWireEdge(Stage stage) Pin * WritePathSpice::stageGateInputPin(Stage stage) { - PathRef *path = stageGateInputPath(stage); + const PathRef *path = stageGateInputPath(stage); return path->pin(this); } @@ -708,7 +708,7 @@ WritePathSpice::stageGateInputPort(Stage stage) Pin * WritePathSpice::stageDrvrPin(Stage stage) { - PathRef *path = stageDrvrPath(stage); + const PathRef *path = stageDrvrPath(stage); return path->pin(this); } @@ -722,7 +722,7 @@ WritePathSpice::stageDrvrPort(Stage stage) Pin * WritePathSpice::stageLoadPin(Stage stage) { - PathRef *path = stageLoadPath(stage); + const PathRef *path = stageLoadPath(stage); return path->pin(this); } diff --git a/tcl/Util.tcl b/tcl/Util.tcl index 23b3ba00..f233bf47 100644 --- a/tcl/Util.tcl +++ b/tcl/Util.tcl @@ -341,21 +341,20 @@ proc sta_unknown { args } { } if { $ret != 0 } { return -code $ret -errorcode $errorCode \ - "error in unknown while checking if \"$name\" is a unique command abbreviation: $msg" + "Error in unknown while checking if \"$name\" is a unique command abbreviation: $msg." } if { [llength $cmds] == 1 } { return [uplevel 1 [lreplace $args 0 0 $cmds]] } if { [llength $cmds] > 1 } { if {[string equal $name ""]} { - return -code error "empty command name \"\"" + return -code error "Empty command name \"\"" } else { return -code error \ - "ambiguous command name \"$name\": [lsort $cmds]" + "Ambiguous command name \"$name\": [lsort $cmds]." } } - - ::unknown {*}$args + return [uplevel 1 [::unknown {*}$args]] } proc is_bus_subscript { subscript } { diff --git a/util/StringUtil.cc b/util/StringUtil.cc index 659c06a4..02c5edfc 100644 --- a/util/StringUtil.cc +++ b/util/StringUtil.cc @@ -76,6 +76,20 @@ stringPrint(string &str, str = tmp; } +void +stringAppend(string &str, + const char *fmt, + ...) +{ + va_list args; + va_start(args, fmt); + char *tmp; + size_t tmp_length; + stringPrintTmp(fmt, args, tmp, tmp_length); + va_end(args); + str += tmp; +} + string stdstrPrint(const char *fmt, ...)