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::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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue