Merge branch 'parallaxsw:master' into master
This commit is contained in:
commit
0c534d862b
|
|
@ -200,6 +200,7 @@ set(STA_SOURCE
|
|||
|
||||
power/Power.cc
|
||||
power/ReadVcdActivities.cc
|
||||
power/SaifReader.cc
|
||||
power/Vcd.cc
|
||||
power/VcdReader.cc
|
||||
|
||||
|
|
@ -308,6 +309,15 @@ bison_target(SdfParser ${STA_HOME}/sdf/SdfParse.yy ${CMAKE_CURRENT_BINARY_DIR}/S
|
|||
add_flex_bison_dependency(SdfLex SdfParser)
|
||||
|
||||
|
||||
# Saif scan/parse.
|
||||
flex_target(SaifLex ${STA_HOME}/power/SaifLex.ll ${CMAKE_CURRENT_BINARY_DIR}/SaifLex.cc
|
||||
COMPILE_FLAGS --prefix=SaifLex_
|
||||
)
|
||||
bison_target(SaifParser ${STA_HOME}/power/SaifParse.yy ${CMAKE_CURRENT_BINARY_DIR}/SaifParse.cc
|
||||
COMPILE_FLAGS --name-prefix=SaifParse_
|
||||
)
|
||||
add_flex_bison_dependency(SaifLex SaifParser)
|
||||
|
||||
################################################################
|
||||
|
||||
set(STA_TCL_INIT ${CMAKE_CURRENT_BINARY_DIR}/StaTclInitVar.cc)
|
||||
|
|
@ -513,6 +523,9 @@ target_sources(OpenSTA
|
|||
|
||||
${FLEX_VerilogLex_OUTPUTS}
|
||||
${BISON_VerilogParser_OUTPUTS}
|
||||
|
||||
${FLEX_SaifLex_OUTPUTS}
|
||||
${BISON_SaifParser_OUTPUTS}
|
||||
)
|
||||
|
||||
target_link_libraries(OpenSTA
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -8,5 +8,5 @@ read_spef gcd_sky130hd.spef
|
|||
# Generate vcd file
|
||||
# iverilog -o gcd_tb gcd_tb.v
|
||||
# vvp gcd_tb
|
||||
read_power_activities -scope gcd_tb/gcd1 -vcd gcd_sky130hd.vcd
|
||||
read_vcd -scope gcd_tb/gcd1 gcd_sky130hd.vcd
|
||||
report_power
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ enum class PwrActivityOrigin
|
|||
input,
|
||||
user,
|
||||
vcd,
|
||||
saif,
|
||||
propagated,
|
||||
clock,
|
||||
constant,
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ static EnumNameMap<PwrActivityOrigin> pwr_activity_origin_map =
|
|||
{PwrActivityOrigin::input, "input"},
|
||||
{PwrActivityOrigin::user, "user"},
|
||||
{PwrActivityOrigin::vcd, "vcd"},
|
||||
{PwrActivityOrigin::saif, "saif"},
|
||||
{PwrActivityOrigin::propagated, "propagated"},
|
||||
{PwrActivityOrigin::clock, "clock"},
|
||||
{PwrActivityOrigin::constant, "constant"},
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "power/Power.hh"
|
||||
#include "power/VcdReader.hh"
|
||||
#include "power/ReadVcdActivities.hh"
|
||||
#include "power/SaifReader.hh"
|
||||
|
||||
using namespace sta;
|
||||
|
||||
|
|
@ -103,9 +104,11 @@ set_power_pin_activity(const Pin *pin,
|
|||
return power->setUserActivity(pin, activity, duty, PwrActivityOrigin::user);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
read_vcd_activities(const char *filename,
|
||||
const char *scope)
|
||||
read_vcd_file(const char *filename,
|
||||
const char *scope)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
cmdLinkedNetwork();
|
||||
|
|
@ -128,4 +131,15 @@ report_vcd_var_values(const char *filename,
|
|||
reportVcdVarValues(filename, var_name, sta);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
read_saif_file(const char *filename,
|
||||
const char *scope)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
cmdLinkedNetwork();
|
||||
return readSaif(filename, scope, sta);
|
||||
}
|
||||
|
||||
%} // inline
|
||||
|
|
|
|||
|
|
@ -283,7 +283,41 @@ proc read_power_activities { args } {
|
|||
if { [info exists keys(-scope)] } {
|
||||
set scope $keys(-scope)
|
||||
}
|
||||
read_vcd_activities $filename $scope
|
||||
sta_warn 304 "read_power_activities is deprecated. Use read_vcd."
|
||||
read_vcd_file $filename $scope
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
define_cmd_args "read_vcd" { [-scope scope] filename }
|
||||
|
||||
proc read_vcd { args } {
|
||||
parse_key_args "read_vcd" args \
|
||||
keys {-scope} flags {}
|
||||
|
||||
check_argc_eq1 "read_vcd" $args
|
||||
set filename [file nativename [lindex $args 0]]
|
||||
set scope ""
|
||||
if { [info exists keys(-scope)] } {
|
||||
set scope $keys(-scope)
|
||||
}
|
||||
read_vcd_file $filename $scope
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
define_cmd_args "read_saif" { [-scope scope] filename }
|
||||
|
||||
proc read_saif { args } {
|
||||
parse_key_args "read_saif" args keys {-scope} flags {}
|
||||
|
||||
check_argc_eq1 "read_saif" $args
|
||||
set filename [file nativename [lindex $args 0]]
|
||||
set scope ""
|
||||
if { [info exists keys(-scope)] } {
|
||||
set scope $keys(-scope)
|
||||
}
|
||||
read_saif_file $filename $scope
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "ReadVcdActivities.hh"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <set>
|
||||
|
||||
#include "VcdReader.hh"
|
||||
#include "Debug.hh"
|
||||
|
|
@ -33,8 +34,6 @@ using std::abs;
|
|||
using std::min;
|
||||
using std::to_string;
|
||||
|
||||
typedef Set<const Pin*> ConstPinSet;
|
||||
|
||||
class ReadVcdActivities : public StaState
|
||||
{
|
||||
public:
|
||||
|
|
@ -66,7 +65,7 @@ private:
|
|||
double clk_period_;
|
||||
Sta *sta_;
|
||||
Power *power_;
|
||||
ConstPinSet annotated_pins_;
|
||||
std::set<const Pin*> annotated_pins_;
|
||||
|
||||
static constexpr double sim_clk_period_tolerance_ = .1;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
%{
|
||||
|
||||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2024, 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 <cstdint>
|
||||
|
||||
#include "util/FlexDisableRegister.hh"
|
||||
#include "StringUtil.hh"
|
||||
#include "power/SaifReaderPvt.hh"
|
||||
#include "SaifParse.hh"
|
||||
|
||||
#define YY_NO_INPUT
|
||||
|
||||
static std::string saif_token;
|
||||
|
||||
void
|
||||
saifFlushBuffer()
|
||||
{
|
||||
YY_FLUSH_BUFFER;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
/* %option debug */
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
%option never-interactive
|
||||
|
||||
%x COMMENT
|
||||
%x QUOTE
|
||||
%x COND_EXPR
|
||||
|
||||
ID ([A-Za-z_])([A-Za-z0-9_$\[\]\\.])*
|
||||
HCHAR "."|"/"
|
||||
BLANK [ \n\t\r\b]
|
||||
EOL \r?\n
|
||||
|
||||
%%
|
||||
|
||||
"/*" { BEGIN COMMENT; }
|
||||
<COMMENT>{
|
||||
|
||||
"*/" { BEGIN INITIAL; }
|
||||
|
||||
.
|
||||
{EOL} { sta::saif_reader->incrLine(); }
|
||||
|
||||
<<EOF>> {
|
||||
SaifParse_error("unterminated comment");
|
||||
BEGIN(INITIAL);
|
||||
yyterminate();
|
||||
}
|
||||
}
|
||||
|
||||
"\"" { BEGIN QUOTE; saif_token.erase(); }
|
||||
<QUOTE>{
|
||||
|
||||
"\\". { saif_token += yytext[1]; }
|
||||
|
||||
"\"" {
|
||||
BEGIN INITIAL;
|
||||
SaifParse_lval.string = sta::stringCopy(saif_token.c_str());
|
||||
return QSTRING;
|
||||
}
|
||||
|
||||
. { saif_token += yytext[0]; }
|
||||
|
||||
<<EOF>> {
|
||||
SaifParse_error("unterminated quoted string");
|
||||
BEGIN(INITIAL);
|
||||
yyterminate();
|
||||
}
|
||||
}
|
||||
|
||||
"//"[^\n]*{EOL} { sta::saif_reader->incrLine(); }
|
||||
|
||||
[0-9]+ {
|
||||
SaifParse_lval.uint = atoll(yytext);
|
||||
return UINT;
|
||||
}
|
||||
|
||||
":"|"{"|"}"|"["|"]"|","|"*"|";"|"="|"-"|"+"|"|"|"("|")"|{HCHAR} {
|
||||
return ((int) yytext[0]);
|
||||
}
|
||||
|
||||
SAIFILE { return SAIFILE; }
|
||||
SAIFVERSION { return SAIFVERSION; }
|
||||
DIRECTION { return DIRECTION; }
|
||||
DESIGN { return DESIGN; }
|
||||
DATE { return DATE; }
|
||||
VENDOR { return VENDOR; }
|
||||
PROGRAM_NAME { return PROGRAM_NAME; }
|
||||
VERSION { return VERSION; }
|
||||
DIVIDER { return DIVIDER; }
|
||||
TIMESCALE { return TIMESCALE; }
|
||||
DURATION { return DURATION; }
|
||||
INSTANCE { return INSTANCE; }
|
||||
NET { return NET; }
|
||||
PORT { return PORT; }
|
||||
T0 { return T0; }
|
||||
T1 { return T1; }
|
||||
TX { return TX; }
|
||||
TZ { return TZ; }
|
||||
TB { return TB; }
|
||||
TC { return TC; }
|
||||
IG { return IG; }
|
||||
|
||||
{ID} {
|
||||
SaifParse_lval.string = sta::stringCopy(yytext);
|
||||
return ID;
|
||||
}
|
||||
|
||||
{EOL} { sta::saif_reader->incrLine(); }
|
||||
|
||||
{BLANK} { /* Ignore blanks. */ }
|
||||
|
||||
/* Send out of bound characters to parser. */
|
||||
. { return ((int) yytext[0]); }
|
||||
|
||||
%%
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
%{
|
||||
|
||||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2024, 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 <cctype>
|
||||
|
||||
#include "StringUtil.hh"
|
||||
#include "power/SaifReaderPvt.hh"
|
||||
|
||||
int SaifLex_lex();
|
||||
#define SaifParse_lex SaifLex_lex
|
||||
// use yacc generated parser errors
|
||||
#define YYERROR_VERBOSE
|
||||
|
||||
#define YYDEBUG 1
|
||||
|
||||
%}
|
||||
|
||||
// expected shift/reduce conflicts
|
||||
%expect 2
|
||||
|
||||
%union {
|
||||
char character;
|
||||
const char *string;
|
||||
uint64_t uint;
|
||||
sta::SaifState state;
|
||||
sta::SaifStateDurations state_durations;
|
||||
}
|
||||
|
||||
%token SAIFILE SAIFVERSION DIRECTION DESIGN DATE VENDOR PROGRAM_NAME VERSION
|
||||
%token DIVIDER TIMESCALE DURATION
|
||||
%token INSTANCE NET PORT
|
||||
%token T0 T1 TX TZ TB TC IG
|
||||
%token QSTRING ID FNUMBER DNUMBER UINT
|
||||
|
||||
%type <uint> UINT
|
||||
%type <string> QSTRING ID
|
||||
%type <character> hchar
|
||||
%type <state> state
|
||||
%type <state_durations> state_durations
|
||||
|
||||
%start file
|
||||
|
||||
%{
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
file:
|
||||
'(' SAIFILE header instance ')' {}
|
||||
;
|
||||
|
||||
header:
|
||||
header_stmt
|
||||
| header header_stmt
|
||||
;
|
||||
|
||||
header_stmt:
|
||||
'(' SAIFVERSION QSTRING ')' { sta::stringDelete($3); }
|
||||
| '(' DIRECTION QSTRING ')' { sta::stringDelete($3); }
|
||||
| '(' DESIGN QSTRING ')' { sta::stringDelete($3); }
|
||||
| '(' DESIGN ')' { }
|
||||
| '(' DATE QSTRING ')' { sta::stringDelete($3); }
|
||||
| '(' VENDOR QSTRING ')' { sta::stringDelete($3); }
|
||||
| '(' PROGRAM_NAME QSTRING ')' { sta::stringDelete($3); }
|
||||
| '(' VERSION QSTRING ')' { sta::stringDelete($3); }
|
||||
| '(' DIVIDER hchar ')' { sta::saif_reader->setDivider($3); }
|
||||
| '(' TIMESCALE UINT ID ')' { sta::saif_reader->setTimescale($3, $4); }
|
||||
| '(' DURATION UINT ')' { sta::saif_reader->setDuration($3); }
|
||||
;
|
||||
|
||||
hchar:
|
||||
'/'
|
||||
{ $$ = '/'; }
|
||||
| '.'
|
||||
{ $$ = '.'; }
|
||||
;
|
||||
|
||||
instance:
|
||||
'(' INSTANCE ID
|
||||
{ sta::saif_reader->instancePush($3); }
|
||||
instance_contents ')'
|
||||
{ sta::saif_reader->instancePop(); }
|
||||
| '(' INSTANCE QSTRING ID
|
||||
{ sta::saif_reader->instancePush($3); }
|
||||
instance_contents ')'
|
||||
{ sta::saif_reader->instancePop(); }
|
||||
;
|
||||
|
||||
instance_contents:
|
||||
/* empty */
|
||||
| instance_content
|
||||
| instance_contents instance_content
|
||||
;
|
||||
|
||||
instance_content:
|
||||
'(' PORT ports ')'
|
||||
| '(' NET nets ')'
|
||||
| instance
|
||||
;
|
||||
|
||||
nets:
|
||||
net
|
||||
| nets net
|
||||
;
|
||||
|
||||
net:
|
||||
'(' ID state_durations ')'
|
||||
{ sta::saif_reader->setNetDurations($2, $3); }
|
||||
;
|
||||
|
||||
ports:
|
||||
port
|
||||
| ports port
|
||||
;
|
||||
|
||||
port:
|
||||
'(' ID state_durations ')'
|
||||
;
|
||||
|
||||
state_durations:
|
||||
'(' state UINT ')'
|
||||
{ $$[static_cast<int>($2)] = $3; }
|
||||
| state_durations '(' state UINT ')'
|
||||
{ $$[static_cast<int>($3)] = $4; }
|
||||
;
|
||||
|
||||
state:
|
||||
T0
|
||||
{ $$ = sta::SaifState::T0; }
|
||||
| T1
|
||||
{ $$ = sta::SaifState::T1; }
|
||||
| TX
|
||||
{ $$ = sta::SaifState::TX; }
|
||||
| TZ
|
||||
{ $$ = sta::SaifState::TZ; }
|
||||
| TB
|
||||
{ $$ = sta::SaifState::TB; }
|
||||
| TC
|
||||
{ $$ = sta::SaifState::TC; }
|
||||
| IG
|
||||
{ $$ = sta::SaifState::IG; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2024, 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 "power/SaifReader.hh"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Error.hh"
|
||||
#include "Debug.hh"
|
||||
#include "Report.hh"
|
||||
#include "Network.hh"
|
||||
#include "Sdc.hh"
|
||||
#include "Power.hh"
|
||||
#include "power/SaifReaderPvt.hh"
|
||||
#include "Sta.hh"
|
||||
|
||||
extern int
|
||||
SaifParse_parse();
|
||||
extern int SaifParse_debug;
|
||||
|
||||
namespace sta {
|
||||
|
||||
using std::min;
|
||||
|
||||
SaifReader *saif_reader = nullptr;
|
||||
|
||||
bool
|
||||
readSaif(const char *filename,
|
||||
const char *scope,
|
||||
Sta *sta)
|
||||
{
|
||||
SaifReader reader(filename, scope, sta);
|
||||
saif_reader = &reader;
|
||||
bool success = reader.read();
|
||||
saif_reader = nullptr;
|
||||
return success;
|
||||
}
|
||||
|
||||
SaifReader::SaifReader(const char *filename,
|
||||
const char *scope,
|
||||
Sta *sta) :
|
||||
StaState(sta),
|
||||
filename_(filename),
|
||||
scope_(scope),
|
||||
stream_(nullptr),
|
||||
line_(1),
|
||||
divider_('/'),
|
||||
escape_('\\'),
|
||||
timescale_(1.0E-9F), // default units of ns
|
||||
duration_(0.0),
|
||||
clk_period_(0.0),
|
||||
in_scope_level_(0),
|
||||
power_(sta->power())
|
||||
{
|
||||
}
|
||||
|
||||
SaifReader::~SaifReader()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
SaifReader::read()
|
||||
{
|
||||
// Use zlib to uncompress gzip'd files automagically.
|
||||
stream_ = gzopen(filename_, "rb");
|
||||
if (stream_) {
|
||||
clk_period_ = INF;
|
||||
for (Clock *clk : *sdc_->clocks())
|
||||
clk_period_ = min(static_cast<double>(clk->period()), clk_period_);
|
||||
|
||||
saif_scope_.clear();
|
||||
in_scope_level_ = 0;
|
||||
annotated_pins_.clear();
|
||||
//::SaifParse_debug = 1;
|
||||
// yyparse returns 0 on success.
|
||||
bool success = (::SaifParse_parse() == 0);
|
||||
gzclose(stream_);
|
||||
return success;
|
||||
}
|
||||
else
|
||||
throw FileNotReadable(filename_);
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::setDivider(char divider)
|
||||
{
|
||||
divider_ = divider;
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::setTimescale(uint64_t multiplier,
|
||||
const char *units)
|
||||
{
|
||||
if (multiplier == 1
|
||||
|| multiplier == 10
|
||||
|| multiplier == 100) {
|
||||
if (stringEq(units, "us"))
|
||||
timescale_ = multiplier * 1E-6;
|
||||
else if (stringEq(units, "ns"))
|
||||
timescale_ = multiplier * 1E-9;
|
||||
else if (stringEq(units, "ps"))
|
||||
timescale_ = multiplier * 1E-12;
|
||||
else if (stringEq(units, "fs"))
|
||||
timescale_ = multiplier * 1E-15;
|
||||
else
|
||||
saifError(180, "TIMESCALE units not us, ns, or ps.");
|
||||
}
|
||||
else
|
||||
saifError(181, "TIMESCALE multiplier not 1, 10, or 100.");
|
||||
stringDelete(units);
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::setDuration(uint64_t duration)
|
||||
{
|
||||
duration_ = duration;
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::instancePush(const char *instance_name)
|
||||
{
|
||||
if (in_scope_level_ == 0) {
|
||||
// Check for a match to the annotation scope.
|
||||
saif_scope_.push_back(instance_name);
|
||||
|
||||
string saif_scope;
|
||||
bool first = true;
|
||||
for (string &inst : saif_scope_) {
|
||||
if (!first)
|
||||
saif_scope += network_->pathDivider();
|
||||
saif_scope += inst;
|
||||
first = false;
|
||||
}
|
||||
if (stringEq(saif_scope.c_str(), scope_))
|
||||
in_scope_level_ = saif_scope_.size();
|
||||
}
|
||||
else {
|
||||
// Inside annotation scope.
|
||||
Instance *parent = path_.empty() ? network_->topInstance() : path_.back();
|
||||
Instance *child = network_->findChild(parent, instance_name);
|
||||
path_.push_back(child);
|
||||
}
|
||||
stringDelete(instance_name);
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::instancePop()
|
||||
{
|
||||
if (in_scope_level_ == 0)
|
||||
saif_scope_.pop_back();
|
||||
if (!path_.empty())
|
||||
path_.pop_back();
|
||||
if (saif_scope_.size() < in_scope_level_)
|
||||
in_scope_level_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::setNetDurations(const char *net_name,
|
||||
SaifStateDurations &durations)
|
||||
{
|
||||
if (in_scope_level_ > 0) {
|
||||
Instance *parent = path_.empty() ? network_->topInstance() : path_.back();
|
||||
if (parent) {
|
||||
const char *net_name1 = unescaped(net_name);
|
||||
const Pin *pin = sdc_network_->findPin(parent, net_name1);
|
||||
if (pin) {
|
||||
double t1 = durations[static_cast<int>(SaifState::T1)];
|
||||
float duty = t1 / duration_;
|
||||
double tc = durations[static_cast<int>(SaifState::TC)];
|
||||
float activity = tc / (duration_ * timescale_ / clk_period_);
|
||||
debugPrint(debug_, "read_saif", 2,
|
||||
"%s duty %.0f / %llu = %.2f tc %.0f activity %.2f",
|
||||
sdc_network_->pathName(pin),
|
||||
t1,
|
||||
duration_,
|
||||
duty,
|
||||
tc,
|
||||
activity);
|
||||
power_->setUserActivity(pin, activity, duty, PwrActivityOrigin::saif);
|
||||
annotated_pins_.insert(pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
SaifReader::unescaped(const char *token)
|
||||
{
|
||||
char *unescaped = new char[strlen(token) + 1];
|
||||
char *u = unescaped;
|
||||
size_t token_length = strlen(token);
|
||||
|
||||
for (size_t i = 0; i < token_length; i++) {
|
||||
char ch = token[i];
|
||||
if (ch == escape_) {
|
||||
char next_ch = token[i + 1];
|
||||
*u++ = next_ch;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
// Just the normal noises.
|
||||
*u++ = ch;
|
||||
}
|
||||
*u = '\0';
|
||||
debugPrint(debug_, "saif_name", 1, "token %s -> %s", token, unescaped);
|
||||
return unescaped;
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::incrLine()
|
||||
{
|
||||
line_++;
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::getChars(char *buf,
|
||||
size_t &result,
|
||||
size_t max_size)
|
||||
{
|
||||
char *status = gzgets(stream_, buf, max_size);
|
||||
if (status == Z_NULL)
|
||||
result = 0; // YY_nullptr
|
||||
else
|
||||
result = strlen(buf);
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::getChars(char *buf,
|
||||
int &result,
|
||||
size_t max_size)
|
||||
{
|
||||
char *status = gzgets(stream_, buf, max_size);
|
||||
if (status == Z_NULL)
|
||||
result = 0; // YY_nullptr
|
||||
else
|
||||
result = strlen(buf);
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::notSupported(const char *feature)
|
||||
{
|
||||
saifError(193, "%s not supported.", feature);
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::saifWarn(int id,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
report_->vfileWarn(id, filename_, line_, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
SaifReader::saifError(int id,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
report_->vfileError(id, filename_, line_, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Global namespace
|
||||
|
||||
void saifFlushBuffer();
|
||||
|
||||
int
|
||||
SaifParse_error(const char *msg)
|
||||
{
|
||||
saifFlushBuffer();
|
||||
sta::saif_reader->saifError(196, "%s.\n", msg);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2024, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace sta {
|
||||
|
||||
class Sta;
|
||||
|
||||
bool
|
||||
readSaif(const char *filename,
|
||||
const char *scope,
|
||||
Sta *sta);
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2024, 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include "Zlib.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "StaState.hh"
|
||||
|
||||
// Header for SaifReader.cc to communicate with SaifLex.cc, SaifParse.cc
|
||||
|
||||
// global namespace
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
sta::saif_reader->getChars(buf, result, max_size)
|
||||
int
|
||||
SaifParse_error(const char *msg);
|
||||
|
||||
namespace sta {
|
||||
|
||||
class Sta;
|
||||
class Power;
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
enum class SaifState { T0, T1, TX, TZ, TB, TC, IG };
|
||||
|
||||
typedef std::array<uint64_t, static_cast<int>(SaifState::IG)+1> SaifStateDurations;
|
||||
|
||||
class SaifReader : public StaState
|
||||
{
|
||||
public:
|
||||
SaifReader(const char *filename,
|
||||
const char *scope,
|
||||
Sta *sta);
|
||||
~SaifReader();
|
||||
bool read();
|
||||
|
||||
void setDivider(char divider);
|
||||
void setTimescale(uint64_t multiplier,
|
||||
const char *units);
|
||||
void setDuration(uint64_t duration);
|
||||
void instancePush(const char *instance_name);
|
||||
void instancePop();
|
||||
void setNetDurations(const char *net_name,
|
||||
SaifStateDurations &durations);
|
||||
|
||||
// flex YY_INPUT yy_n_chars arg changed definition from int to size_t,
|
||||
// so provide both forms.
|
||||
void getChars(char *buf,
|
||||
size_t &result,
|
||||
size_t max_size);
|
||||
void getChars(char *buf,
|
||||
int &result,
|
||||
size_t max_size);
|
||||
void incrLine();
|
||||
const char *filename() { return filename_; }
|
||||
int line() { return line_; }
|
||||
void saifWarn(int id,
|
||||
const char *fmt, ...);
|
||||
void saifError(int id,
|
||||
const char *fmt,
|
||||
...);
|
||||
void notSupported(const char *feature);
|
||||
|
||||
private:
|
||||
const char *unescaped(const char *token);
|
||||
|
||||
const char *filename_;
|
||||
const char *scope_; // Divider delimited scope to begin annotation.
|
||||
|
||||
gzFile stream_;
|
||||
int line_;
|
||||
char divider_;
|
||||
char escape_;
|
||||
double timescale_;
|
||||
int64_t duration_;
|
||||
double clk_period_;
|
||||
|
||||
vector<string> saif_scope_; // Scope during parsing.
|
||||
size_t in_scope_level_;
|
||||
vector<Instance*> path_; // Path within scope.
|
||||
std::set<const Pin*> annotated_pins_;
|
||||
Power *power_;
|
||||
};
|
||||
|
||||
extern SaifReader *saif_reader;
|
||||
|
||||
} // namespace
|
||||
|
|
@ -16,14 +16,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "SdcClass.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class Report;
|
||||
class MinMax;
|
||||
class Network;
|
||||
class Graph;
|
||||
class MinMaxAll;
|
||||
class Corner;
|
||||
class StaState;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#include "SdcClass.hh"
|
||||
#include "StaState.hh"
|
||||
|
||||
// Header for ReadSdf.cc to communicate with SdfLex.cc, SdfParse.cc
|
||||
// Header for SdfReader.cc to communicate with SdfLex.cc, SdfParse.cc
|
||||
|
||||
// global namespace
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue