write_path_spice handle subckt calls in library subckts
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
054b5045d3
commit
458a7cf0d1
|
|
@ -48,6 +48,8 @@ namespace sta {
|
|||
using std::string;
|
||||
using std::ofstream;
|
||||
using std::ifstream;
|
||||
using std::max;
|
||||
using std::set;
|
||||
|
||||
typedef Map<string, StringVector*> 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<string> findPathCellnames();
|
||||
void findPathCellSubckts(set<string> &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<string> 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<string>
|
||||
WritePathSpice::findPathCellnames()
|
||||
{
|
||||
set<string> 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<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
|
||||
|
|
|
|||
Loading…
Reference in New Issue