182 lines
5.1 KiB
C++
182 lines
5.1 KiB
C++
// OpenSTA, Static Timing Analyzer
|
|
// Copyright (c) 2019, Parallax Software, Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "Machine.hh"
|
|
#include "Zlib.hh"
|
|
#include "Error.hh"
|
|
#include "Report.hh"
|
|
#include "StringUtil.hh"
|
|
#include "Parasitics.hh"
|
|
#include "SpfReader.hh"
|
|
#include "SpefReader.hh"
|
|
#include "ReadParasitics.hh"
|
|
|
|
namespace sta {
|
|
|
|
typedef enum {
|
|
parasitics_file_dspf,
|
|
parasitics_file_rspf,
|
|
parasitics_file_spef,
|
|
parasitics_file_unknown
|
|
} ParasiticsFileType;
|
|
|
|
static void
|
|
parsiticsFileType(gzFile stream,
|
|
Report *report,
|
|
ParasiticsFileType &file_type,
|
|
int &line_num);
|
|
static bool
|
|
isSpfComment(const char *line,
|
|
bool &in_multi_line_comment,
|
|
bool &in_single_line_comment);
|
|
|
|
bool
|
|
readParasiticsFile(const char *filename,
|
|
Instance *instance,
|
|
ParasiticAnalysisPt *ap,
|
|
bool increment,
|
|
bool pin_cap_included,
|
|
bool keep_coupling_caps,
|
|
float coupling_cap_factor,
|
|
ReduceParasiticsTo reduce_to,
|
|
bool delete_after_reduce,
|
|
const OperatingConditions *op_cond,
|
|
const Corner *corner,
|
|
const MinMax *cnst_min_max,
|
|
bool save, bool quiet,
|
|
Report *report,
|
|
Network *network,
|
|
Parasitics *parasitics)
|
|
{
|
|
bool success = false;
|
|
// Use zlib to uncompress gzip'd files automagically.
|
|
gzFile stream = gzopen(filename, "rb");
|
|
if (stream) {
|
|
ParasiticsFileType file_type;
|
|
int line_num;
|
|
parsiticsFileType(stream, report, file_type, line_num);
|
|
switch (file_type) {
|
|
case parasitics_file_spef:
|
|
success = readSpefFile(filename, stream, line_num,
|
|
instance, ap, increment, pin_cap_included,
|
|
keep_coupling_caps, coupling_cap_factor,
|
|
reduce_to, delete_after_reduce,
|
|
op_cond, corner, cnst_min_max,
|
|
save, quiet, report, network, parasitics);
|
|
|
|
break;
|
|
case parasitics_file_rspf:
|
|
success = readSpfFile(filename, stream, line_num, true, instance, ap,
|
|
increment, pin_cap_included,
|
|
keep_coupling_caps, coupling_cap_factor,
|
|
reduce_to, delete_after_reduce,
|
|
op_cond, corner, cnst_min_max,
|
|
save, quiet, report, network, parasitics);
|
|
break;
|
|
case parasitics_file_dspf:
|
|
success = readSpfFile(filename, stream, line_num, false, instance, ap,
|
|
increment, pin_cap_included,
|
|
keep_coupling_caps, coupling_cap_factor,
|
|
reduce_to, delete_after_reduce,
|
|
op_cond, corner, cnst_min_max,
|
|
save, quiet, report,
|
|
network, parasitics);
|
|
break;
|
|
case parasitics_file_unknown:
|
|
report->error("unknown parasitics file type.\n");
|
|
break;
|
|
}
|
|
gzclose(stream);
|
|
}
|
|
else
|
|
throw FileNotReadable(filename);
|
|
return success;
|
|
}
|
|
|
|
// Read the first line of a parasitics file to find its type.
|
|
static void
|
|
parsiticsFileType(gzFile stream,
|
|
Report *report,
|
|
ParasiticsFileType &file_type,
|
|
int &line_num)
|
|
{
|
|
file_type = parasitics_file_unknown;
|
|
line_num = 1;
|
|
const int line_len = 100;
|
|
char line[line_len];
|
|
char *err;
|
|
bool in_multi_line_comment = false;
|
|
bool in_single_line_comment = false;
|
|
// Skip comment lines before looking for file type.
|
|
do {
|
|
err = gzgets(stream, line, line_len);
|
|
if (err == Z_NULL) {
|
|
report->error("SPEF/RSPF/DSPF header not found.\n");
|
|
file_type = parasitics_file_unknown;
|
|
}
|
|
if (line[strlen(line) - 1] == '\n')
|
|
line_num++;
|
|
} while (isSpfComment(line, in_multi_line_comment, in_single_line_comment)
|
|
|| in_multi_line_comment
|
|
|| in_single_line_comment);
|
|
|
|
if (stringEq(line, "*SPEF", 5))
|
|
file_type = parasitics_file_spef;
|
|
else if (stringEq(line, "*|RSPF", 6))
|
|
file_type = parasitics_file_rspf;
|
|
else if (stringEq(line, "*|DSPF", 6))
|
|
file_type = parasitics_file_dspf;
|
|
}
|
|
|
|
static bool
|
|
isSpfComment(const char *line,
|
|
bool &in_multi_line_comment,
|
|
bool &in_single_line_comment)
|
|
{
|
|
const char *s = line;
|
|
while (isspace(*s) && *s)
|
|
s++;
|
|
if (in_multi_line_comment) {
|
|
in_multi_line_comment = (strstr(s, "*/") == NULL);
|
|
return true;
|
|
}
|
|
else if (in_single_line_comment) {
|
|
in_single_line_comment = (line[strlen(line) - 1] != '\n');
|
|
return true;
|
|
}
|
|
else if (*s && stringEq(s, "/*", 2)) {
|
|
in_multi_line_comment = strstr(s, "*/") == NULL;
|
|
return true;
|
|
}
|
|
else if (*s && stringEq(s, "//", 2)) {
|
|
in_single_line_comment = (line[strlen(line) - 1] != '\n');
|
|
return true;
|
|
}
|
|
else if (*s && stringEq(s, "*", 1)
|
|
&& !stringEq(s, "*|", 2)
|
|
&& !stringEq(s, "*SPEF", 5)) {
|
|
in_single_line_comment = false;
|
|
// DSPF or RSPF comment.
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
} // namespace
|