From 458a7cf0d1015b2ea51bcbd294ab24c8cb1e35ed Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 21 Mar 2023 21:03:08 -0700 Subject: [PATCH] write_path_spice handle subckt calls in library subckts Signed-off-by: James Cherry --- search/WritePathSpice.cc | 91 +++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 16 deletions(-) diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index bba79426..4fe8e625 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -48,6 +48,8 @@ namespace sta { using std::string; using std::ofstream; using std::ifstream; +using std::max; +using std::set; typedef Map CellSpicePortNames; typedef int Stage; @@ -98,8 +100,8 @@ private: DcalcAPIndex dcalc_ap_index); void writeStageParasitics(Stage stage); void writeSubckts(); - void findPathCellnames(// Return values. - StringSet &path_cell_names); + set findPathCellnames(); + void findPathCellSubckts(set &path_cell_names); void recordSpicePortNames(const char *cell_name, StringVector &tokens); float maxTime(); @@ -332,6 +334,18 @@ WritePathSpice::writeSpice() throw FileNotWritable(spice_filename_); } +// Use c++17 fs::path(filename).stem() +static string +filenameStem(const char *filename) +{ + string filename1 = filename; + const size_t last_slash_idx = filename1.find_last_of("\\/"); + if (last_slash_idx != std::string::npos) + return filename1.substr(last_slash_idx + 1); + else + return filename1; +} + void WritePathSpice::writeHeader() { @@ -348,7 +362,8 @@ WritePathSpice::writeHeader() float temp = pvt->temperature(); streamPrint(spice_stream_, ".temp %.1f\n", temp); streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_); - streamPrint(spice_stream_, ".include \"%s\"\n", subckt_filename_); + string subckt_filename_stem = filenameStem(subckt_filename_); + streamPrint(spice_stream_, ".include \"%s\"\n", subckt_filename_stem.c_str()); float max_time = maxTime(); float time_step = max_time / 1e+3; @@ -373,9 +388,8 @@ WritePathSpice::maxTime() } else { float end_slew = findSlew(path_); - float max_time = delayAsFloat(input_slew - + path_->arrival(this) - + end_slew * 2) * 1.5; + float arrival = delayAsFloat(path_->arrival(this)); + float max_time = input_slew / 2.0 + arrival + end_slew; return max_time; } } @@ -1342,8 +1356,8 @@ WritePathSpice::nodeName(ParasiticNode *node) void WritePathSpice::writeSubckts() { - StringSet path_cell_names; - findPathCellnames(path_cell_names); + set path_cell_names = findPathCellnames(); + findPathCellSubckts(path_cell_names); ifstream lib_subckts_stream(lib_subckt_filename_); if (lib_subckts_stream.is_open()) { @@ -1357,7 +1371,7 @@ WritePathSpice::writeSubckts() if (tokens.size() >= 2 && stringEqual(tokens[0].c_str(), ".subckt")) { const char *cell_name = tokens[1].c_str(); - if (path_cell_names.hasKey(cell_name)) { + if (path_cell_names.find(cell_name) != path_cell_names.end()) { subckts_stream << line << "\n"; bool found_ends = false; while (getline(lib_subckts_stream, line)) { @@ -1379,10 +1393,14 @@ WritePathSpice::writeSubckts() lib_subckts_stream.close(); if (!path_cell_names.empty()) { - report_->error(28, "The following subkcts are missing from %s", - lib_subckt_filename_); - for (const char *cell_name : path_cell_names) - report_->reportLine(" %s", cell_name); + string missing_cells; + for (const string &cell_name : path_cell_names) { + missing_cells += "\n"; + missing_cells += cell_name; + } + report_->error(28, "The subkct file %s is missing definitions for %s", + lib_subckt_filename_, + missing_cells.c_str()); } } else { @@ -1394,10 +1412,10 @@ WritePathSpice::writeSubckts() throw FileNotReadable(lib_subckt_filename_); } -void -WritePathSpice::findPathCellnames(// Return values. - StringSet &path_cell_names) +set +WritePathSpice::findPathCellnames() { + set path_cell_names; for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { TimingArc *arc = stageGateArc(stage); if (arc) { @@ -1420,6 +1438,47 @@ WritePathSpice::findPathCellnames(// Return values. delete pin_iter; } } + return path_cell_names; +} + +// Subckts can call subckts (asap7). +void +WritePathSpice::findPathCellSubckts(set &path_cell_names) +{ + ifstream lib_subckts_stream(lib_subckt_filename_); + if (lib_subckts_stream.is_open()) { + string line; + while (getline(lib_subckts_stream, line)) { + // .subckt [args..] + StringVector tokens; + split(line, " \t", tokens); + if (tokens.size() >= 2 + && stringEqual(tokens[0].c_str(), ".subckt")) { + const char *cell_name = tokens[1].c_str(); + if (path_cell_names.find(cell_name) != path_cell_names.end()) { + // Scan the subckt definition for subckt calls. + string stmt; + while (getline(lib_subckts_stream, line)) { + if (line[0] == '+') + stmt += line.substr(1); + else { + // Process previous statement. + if (tolower(stmt[0]) == 'x') { + split(stmt, " \t", tokens); + string &subckt_cell = tokens[tokens.size() - 1]; + path_cell_names.insert(subckt_cell); + } + stmt = line; + } + if (stringBeginEqual(line.c_str(), ".ends")) + break; + } + } + } + } + } + else + throw FileNotReadable(lib_subckt_filename_); } void