write_path_spice handle subckt calls in library subckts

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2023-03-21 21:03:08 -07:00
parent 054b5045d3
commit 458a7cf0d1
1 changed files with 75 additions and 16 deletions

View File

@ -48,6 +48,8 @@ namespace sta {
using std::string; using std::string;
using std::ofstream; using std::ofstream;
using std::ifstream; using std::ifstream;
using std::max;
using std::set;
typedef Map<string, StringVector*> CellSpicePortNames; typedef Map<string, StringVector*> CellSpicePortNames;
typedef int Stage; typedef int Stage;
@ -98,8 +100,8 @@ private:
DcalcAPIndex dcalc_ap_index); DcalcAPIndex dcalc_ap_index);
void writeStageParasitics(Stage stage); void writeStageParasitics(Stage stage);
void writeSubckts(); void writeSubckts();
void findPathCellnames(// Return values. set<string> findPathCellnames();
StringSet &path_cell_names); void findPathCellSubckts(set<string> &path_cell_names);
void recordSpicePortNames(const char *cell_name, void recordSpicePortNames(const char *cell_name,
StringVector &tokens); StringVector &tokens);
float maxTime(); float maxTime();
@ -332,6 +334,18 @@ WritePathSpice::writeSpice()
throw FileNotWritable(spice_filename_); 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 void
WritePathSpice::writeHeader() WritePathSpice::writeHeader()
{ {
@ -348,7 +362,8 @@ WritePathSpice::writeHeader()
float temp = pvt->temperature(); float temp = pvt->temperature();
streamPrint(spice_stream_, ".temp %.1f\n", temp); streamPrint(spice_stream_, ".temp %.1f\n", temp);
streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_); 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 max_time = maxTime();
float time_step = max_time / 1e+3; float time_step = max_time / 1e+3;
@ -373,9 +388,8 @@ WritePathSpice::maxTime()
} }
else { else {
float end_slew = findSlew(path_); float end_slew = findSlew(path_);
float max_time = delayAsFloat(input_slew float arrival = delayAsFloat(path_->arrival(this));
+ path_->arrival(this) float max_time = input_slew / 2.0 + arrival + end_slew;
+ end_slew * 2) * 1.5;
return max_time; return max_time;
} }
} }
@ -1342,8 +1356,8 @@ WritePathSpice::nodeName(ParasiticNode *node)
void void
WritePathSpice::writeSubckts() WritePathSpice::writeSubckts()
{ {
StringSet path_cell_names; set<string> path_cell_names = findPathCellnames();
findPathCellnames(path_cell_names); findPathCellSubckts(path_cell_names);
ifstream lib_subckts_stream(lib_subckt_filename_); ifstream lib_subckts_stream(lib_subckt_filename_);
if (lib_subckts_stream.is_open()) { if (lib_subckts_stream.is_open()) {
@ -1357,7 +1371,7 @@ WritePathSpice::writeSubckts()
if (tokens.size() >= 2 if (tokens.size() >= 2
&& stringEqual(tokens[0].c_str(), ".subckt")) { && stringEqual(tokens[0].c_str(), ".subckt")) {
const char *cell_name = tokens[1].c_str(); 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"; subckts_stream << line << "\n";
bool found_ends = false; bool found_ends = false;
while (getline(lib_subckts_stream, line)) { while (getline(lib_subckts_stream, line)) {
@ -1379,10 +1393,14 @@ WritePathSpice::writeSubckts()
lib_subckts_stream.close(); lib_subckts_stream.close();
if (!path_cell_names.empty()) { if (!path_cell_names.empty()) {
report_->error(28, "The following subkcts are missing from %s", string missing_cells;
lib_subckt_filename_); for (const string &cell_name : path_cell_names) {
for (const char *cell_name : path_cell_names) missing_cells += "\n";
report_->reportLine(" %s", cell_name); missing_cells += cell_name;
}
report_->error(28, "The subkct file %s is missing definitions for %s",
lib_subckt_filename_,
missing_cells.c_str());
} }
} }
else { else {
@ -1394,10 +1412,10 @@ WritePathSpice::writeSubckts()
throw FileNotReadable(lib_subckt_filename_); throw FileNotReadable(lib_subckt_filename_);
} }
void set<string>
WritePathSpice::findPathCellnames(// Return values. WritePathSpice::findPathCellnames()
StringSet &path_cell_names)
{ {
set<string> path_cell_names;
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
TimingArc *arc = stageGateArc(stage); TimingArc *arc = stageGateArc(stage);
if (arc) { if (arc) {
@ -1420,6 +1438,47 @@ WritePathSpice::findPathCellnames(// Return values.
delete pin_iter; delete pin_iter;
} }
} }
return path_cell_names;
}
// Subckts can call subckts (asap7).
void
WritePathSpice::findPathCellSubckts(set<string> &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 <cell_name> [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 void