c++ sdf reader

commit da9f267cbb3ed711bff3d2e2c1470fa12f7de26c
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Jan 25 11:31:41 2025 -0700

    zlib optional

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit dfbe36202ef77f77e1a7c42163db9f6a5d9a8380
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 19:24:05 2025 -0700

    sdf use option for prefix

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit bd7fc399ddfa472e25606c92421c123a725181da
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 18:57:46 2025 -0700

    mv sdf error to reader

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 088d43b0e5c90b0bc24c64384164f1bcc50c5165
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 18:48:28 2025 -0700

    sdf lex use option for previs

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 6ccf8c33bd8c44fdd914d9a36fa703a7594353e2
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 17:10:07 2025 -0700

    sdf error

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 43794955a9f79a2900bb8e4cef030a907347627a
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 16:13:00 2025 -0700

    SdfParse reorg sections

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 666062124f5718a512092fcdd295827cfb2b6c51
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 16:07:51 2025 -0700

    sdf lex previs

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 83e9925e09817f39d60ae0292fd9eed5e6c40f43
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 16:05:11 2025 -0700

    sdf clenup directives

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit dd71619af605abdaaaa9feb0800eb78e225828d6
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 11:41:47 2025 -0700

    sdf parse valgrind pass

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit c068e6512824ac27a99fdaa6dcd9a908ee991857
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Jan 24 08:45:39 2025 -0700

    sdf parse

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 454602fbd464387442cd1e296f3f0e3b5c366e52
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Jan 23 21:50:24 2025 -0700

    sdf parse passes

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit a352451c163f95f82446f2a25d39706f68ae98d6
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Jan 23 19:15:09 2025 -0700

    sdf parse pass all but 1

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 87d537582134a767a13ec4596957b7d7a8e1edfd
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Jan 23 12:53:15 2025 -0700

    sdf parse report_checks4

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit c2ee81a51d4fba1281bf452055c9113af7a0de1f
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Jan 23 12:30:25 2025 -0700

    sdf link

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit d71e4b0c8f95256ab3ec9e53e26218baaa3c9f8c
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Jan 23 12:02:45 2025 -0700

    sdf parse compiles

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 6ca6800d5cd52640e275bf7eb77a8b1db85e2957
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Jan 22 18:19:27 2025 -0700

    sdf reader c++

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-01-25 11:34:04 -07:00
parent fafbcb216e
commit c9a8726707
6 changed files with 457 additions and 413 deletions

View File

@ -311,12 +311,12 @@ bison_target(VerilogParse ${STA_HOME}/verilog/VerilogParse.yy
add_flex_bison_dependency(VerilogLex VerilogParse) add_flex_bison_dependency(VerilogLex VerilogParse)
# Sdf scan/parse. # Sdf scan/parse.
flex_target(SdfLex ${STA_HOME}/sdf/SdfLex.ll ${CMAKE_CURRENT_BINARY_DIR}/SdfLex.cc flex_target(SdfLex ${STA_HOME}/sdf/SdfLex.ll
COMPILE_FLAGS --prefix=SdfLex_ ${CMAKE_CURRENT_BINARY_DIR}/SdfLex.cc)
) bison_target(SdfParse ${STA_HOME}/sdf/SdfParse.yy
bison_target(SdfParse ${STA_HOME}/sdf/SdfParse.yy ${CMAKE_CURRENT_BINARY_DIR}/SdfParse.cc ${CMAKE_CURRENT_BINARY_DIR}/SdfParse.cc
COMPILE_FLAGS --name-prefix=SdfParse_ # centos7 bison 3.0.4 < 3.3.0 uses parser_class_name instead of api.parsr.class
) COMPILE_FLAGS "-Wno-deprecated")
add_flex_bison_dependency(SdfLex SdfParse) add_flex_bison_dependency(SdfLex SdfParse)
# Saif scan/parse. # Saif scan/parse.

View File

@ -1,5 +1,4 @@
%{ %{
// OpenSTA, Static Timing Analyzer // OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc. // Copyright (c) 2025, Parallax Software, Inc.
// //
@ -27,23 +26,28 @@
#include "util/FlexDisableRegister.hh" #include "util/FlexDisableRegister.hh"
#include "sdf/SdfReaderPvt.hh" #include "sdf/SdfReaderPvt.hh"
#include "SdfParse.hh" #include "SdfParse.hh"
#include "sdf/SdfScanner.hh"
#define YY_NO_INPUT #undef YY_DECL
#define YY_DECL \
int \
sta::SdfScanner::lex(sta::SdfParse::semantic_type *const yylval, \
sta::SdfParse::location_type *loc)
static std::string sdf_token; // update location on matching
#define YY_USER_ACTION loc->step(); loc->columns(yyleng);
void
sdfFlushBuffer()
{
YY_FLUSH_BUFFER;
}
typedef sta::SdfParse::token token;
%} %}
/* %option debug */ %option c++
%option yyclass="sta::SdfScanner"
%option prefix="Sdf"
%option noyywrap %option noyywrap
%option nounput
%option never-interactive %option never-interactive
%option stack
%option yylineno
/* %option debug */
%x COMMENT %x COMMENT
%x QUOTE %x QUOTE
@ -62,140 +66,139 @@ EOL \r?\n
"*/" { BEGIN INITIAL; } "*/" { BEGIN INITIAL; }
. .
{EOL} { sta::sdf_reader->incrLine(); } {EOL} { loc->lines(); loc->step(); }
<<EOF>> { <<EOF>> {
SdfParse_error("unterminated comment"); error("unterminated comment");
BEGIN(INITIAL); BEGIN(INITIAL);
yyterminate(); yyterminate();
} }
} }
"\"" { BEGIN QUOTE; sdf_token.erase(); } "\"" { BEGIN QUOTE; token_.clear(); }
<QUOTE>{ <QUOTE>{
"\\". { sdf_token += yytext[1]; } "\\". { token_ += yytext[1]; }
"\"" { "\"" {
BEGIN INITIAL; BEGIN INITIAL;
SdfParse_lval.string = sta::stringCopy(sdf_token.c_str()); yylval->string = new string(token_);
return QSTRING; return token::QSTRING;
} }
. { sdf_token += yytext[0]; } . { token_ += yytext[0]; }
<<EOF>> { <<EOF>> {
SdfParse_error("unterminated quoted string"); error("unterminated quoted string");
BEGIN(INITIAL); BEGIN(INITIAL);
yyterminate(); yyterminate();
} }
} }
"//"[^\n]*{EOL} { sta::sdf_reader->incrLine(); } "//"[^\n]*{EOL} { loc->lines(); loc->step(); }
("-"|"+")?([0-9]*)("."[0-9]+)([eE]("-"|"+")?[0-9]+)? { ("-"|"+")?([0-9]*)("."[0-9]+)([eE]("-"|"+")?[0-9]+)? {
SdfParse_lval.number = static_cast<float>(atof(yytext)); yylval->number = atof(yytext);
return FNUMBER; return token::FNUMBER;
} }
"+"?[0-9]+ { "+"?[0-9]+ {
SdfParse_lval.integer = atoi(yytext); yylval->integer = atoi(yytext);
return DNUMBER; return token::DNUMBER;
} }
":"|"{"|"}"|"["|"]"|","|"*"|";"|"="|"-"|"+"|"|"|"("|")"|{HCHAR} { ":"|"{"|"}"|"["|"]"|","|"*"|";"|"="|"-"|"+"|"|"|"("|")"|{HCHAR} {
return ((int) yytext[0]); return ((int) yytext[0]);
} }
ABSOLUTE { return ABSOLUTE; } ABSOLUTE { return token::ABSOLUTE; }
CELL { return CELL; } CELL { return token::CELL; }
CELLTYPE { return CELLTYPE; } CELLTYPE { return token::CELLTYPE; }
DATE { return DATE; } DATE { return token::DATE; }
DELAY { return DELAY; } DELAY { return token::DELAY; }
DELAYFILE { return DELAYFILE; } DELAYFILE { return token::DELAYFILE; }
DESIGN { return DESIGN; } DESIGN { return token::DESIGN; }
DEVICE { return DEVICE; } DEVICE { return token::DEVICE; }
DIVIDER { return DIVIDER; } DIVIDER { return token::DIVIDER; }
HOLD { return HOLD; } HOLD { return token::HOLD; }
INCREMENTAL|INCREMENT { return INCREMENTAL; } INCREMENTAL|INCREMENT { return token::INCREMENTAL; }
INSTANCE { return INSTANCE; } INSTANCE { return token::INSTANCE; }
INTERCONNECT { return INTERCONNECT; } INTERCONNECT { return token::INTERCONNECT; }
IOPATH { return IOPATH; } IOPATH { return token::IOPATH; }
NOCHANGE { return NOCHANGE; } NOCHANGE { return token::NOCHANGE; }
PERIOD { return PERIOD; } PERIOD { return token::PERIOD; }
PORT { return PORT; } PORT { return token::PORT; }
PROCESS { return PROCESS; } PROCESS { return token::PROCESS; }
PROGRAM { return PROGRAM; } PROGRAM { return token::PROGRAM; }
RECOVERY { return RECOVERY; } RECOVERY { return token::RECOVERY; }
RECREM { return RECREM; } RECREM { return token::RECREM; }
REMOVAL { return REMOVAL; } REMOVAL { return token::REMOVAL; }
RETAIN { return RETAIN; } RETAIN { return token::RETAIN; }
SDFVERSION { return SDFVERSION; } SDFVERSION { return token::SDFVERSION; }
SETUP { return SETUP; } SETUP { return token::SETUP; }
SETUPHOLD { return SETUPHOLD; } SETUPHOLD { return token::SETUPHOLD; }
SKEW { return SKEW; } SKEW { return token::SKEW; }
TEMPERATURE { return TEMPERATURE; } TEMPERATURE { return token::TEMPERATURE; }
TIMESCALE { return TIMESCALE; } TIMESCALE { return token::TIMESCALE; }
TIMINGCHECK { return TIMINGCHECK; } TIMINGCHECK { return token::TIMINGCHECK; }
VENDOR { return VENDOR; } VENDOR { return token::VENDOR; }
VERSION { return PVERSION; } VERSION { return token::PVERSION; }
VOLTAGE { return VOLTAGE; } VOLTAGE { return token::VOLTAGE; }
WIDTH { return WIDTH; } WIDTH { return token::WIDTH; }
negedge { return NEGEDGE; } negedge { return token::NEGEDGE; }
posedge { return POSEDGE; } posedge { return token::POSEDGE; }
CONDELSE { return token::CONDELSE; }
CONDELSE { return CONDELSE; }
COND { COND {
BEGIN COND_EXPR; BEGIN COND_EXPR;
sdf_token.erase(); token_.clear();
return COND; return token::COND;
} }
<COND_EXPR>"("{BLANK}*IOPATH { <COND_EXPR>"("{BLANK}*IOPATH {
BEGIN INITIAL; BEGIN INITIAL;
SdfParse_lval.string = sta::stringCopy(sdf_token.c_str()); yylval->string = new string(token_);
return EXPR_OPEN_IOPATH; return token::EXPR_OPEN_IOPATH;
} }
<COND_EXPR>"(" { <COND_EXPR>"(" {
/* Timing check conditions don't allow parens, /* Timing check conditions don't allow parens,
* so use the paren as a marker for the end of the expr. * so use the paren as a marker for the end of the expr.
*/ */
if (sta::sdf_reader->inTimingCheck()) { if (reader_->inTimingCheck()) {
BEGIN INITIAL; BEGIN INITIAL;
SdfParse_lval.string= sta::stringCopy(sdf_token.c_str()); yylval->string = new string(token_);
return EXPR_OPEN; return token::EXPR_OPEN;
}
else
sdf_token += yytext[0];
} }
else
token_ += yytext[0];
}
<COND_EXPR>{BLANK}+{ID}{BLANK}*")" { <COND_EXPR>{BLANK}+{ID}{BLANK}*")" {
/* (COND expr port) */ /* (COND expr port) */
if (sta::sdf_reader->inTimingCheck()) { if (reader_->inTimingCheck()) {
BEGIN INITIAL; BEGIN INITIAL;
/* remove trailing ")" */ /* remove trailing ")" */
yytext[strlen(yytext)-1] = '\0'; string cond_id(token_);
sdf_token += yytext; cond_id += yytext;
SdfParse_lval.string= sta::stringCopy(sdf_token.c_str()); yylval->string = new string(cond_id.substr(0, cond_id.size() - 1));
/* No way to pass expr and id separately, so pass them together. */ /* No way to pass expr and id separately, so pass them together. */
return EXPR_ID_CLOSE; return token::EXPR_ID_CLOSE;
} }
else else
sdf_token += yytext; token_ += yytext[0];
} }
<COND_EXPR>{BLANK} {} <COND_EXPR>{BLANK} {}
<COND_EXPR>. { sdf_token += yytext[0]; } <COND_EXPR>. { token_ += yytext[0]; }
{ID} { {ID} {
SdfParse_lval.string = sta::stringCopy(yytext); yylval->string = new string(yytext);
return ID; return token::ID;
} }
{EOL} { sta::sdf_reader->incrLine(); } {EOL} { loc->lines(); loc->step(); }
{BLANK} { /* Ignore blanks. */ } {BLANK} { /* Ignore blanks. */ }

View File

@ -1,5 +1,3 @@
%{
// OpenSTA, Static Timing Analyzer // OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc. // Copyright (c) 2025, Parallax Software, Inc.
// //
@ -24,25 +22,41 @@
// //
// This notice may not be removed or altered from any source distribution. // This notice may not be removed or altered from any source distribution.
%{
#include <cctype> #include <cctype>
#include "sdf/SdfReaderPvt.hh" #include "sdf/SdfReaderPvt.hh"
#include "sdf/SdfScanner.hh"
int SdfLex_lex(); #undef yylex
#define SdfParse_lex SdfLex_lex #define yylex scanner->lex
// use yacc generated parser errors
#define YYERROR_VERBOSE
#define YYDEBUG 1 // warning: variable 'yynerrs_' set but not used
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#define loc_line(loc) loc.begin.line
%} %}
%require "3.0"
%skeleton "lalr1.cc"
%debug
%define api.namespace {sta}
%locations
%define parse.assert
%parse-param { SdfScanner *scanner }
%parse-param { SdfReader *reader }
// bison 3.0.4 for centos7
%define parser_class_name {SdfParse}
// bison 3.3.2
//%define api.parser.class {SdfParse}
// expected shift/reduce conflicts // expected shift/reduce conflicts
%expect 4 %expect 4
%union { %union {
char character; char character;
const char *string; std::string *string;
float number; float number;
float *number_ptr; float *number_ptr;
int integer; int integer;
@ -72,10 +86,10 @@ int SdfLex_lex();
%type <transition> port_transition %type <transition> port_transition
%type <character> hchar %type <character> hchar
%start file // Used by error recovery.
%destructor { delete $$; } QSTRING
%{ %start file
%}
%% %%
@ -90,23 +104,22 @@ header:
// technically the ordering of these statements is fixed by the spec // technically the ordering of these statements is fixed by the spec
header_stmt: header_stmt:
'(' SDFVERSION QSTRING ')' { sta::stringDelete($3); } '(' SDFVERSION QSTRING ')' { delete $3; }
| '(' DESIGN QSTRING ')' { sta::stringDelete($3); } | '(' DESIGN QSTRING ')' { delete $3; }
| '(' DATE QSTRING ')' { sta::stringDelete($3); } | '(' DATE QSTRING ')' { delete $3; }
| '(' VENDOR QSTRING ')' { sta::stringDelete($3); } | '(' VENDOR QSTRING ')' { delete $3; }
| '(' PROGRAM QSTRING ')' { sta::stringDelete($3); } | '(' PROGRAM QSTRING ')' { delete $3; }
| '(' PVERSION QSTRING ')' { sta::stringDelete($3); } | '(' PVERSION QSTRING ')' { delete $3; }
| '(' DIVIDER hchar ')' { sta::sdf_reader->setDivider($3); } | '(' DIVIDER hchar ')' { reader->setDivider($3); }
| '(' VOLTAGE triple ')' { sta::sdf_reader->deleteTriple($3); } | '(' VOLTAGE triple ')' { reader->deleteTriple($3); }
| '(' VOLTAGE NUMBER ')' | '(' VOLTAGE NUMBER ')'
| '(' VOLTAGE ')' // Illegal SDF (from OC). | '(' VOLTAGE ')' // Illegal SDF (from OC).
| '(' PROCESS QSTRING ')' { sta::stringDelete($3); } | '(' PROCESS QSTRING ')' { delete $3; }
| '(' PROCESS ')' // Illegal SDF (from OC). | '(' PROCESS ')' // Illegal SDF (from OC).
| '(' TEMPERATURE NUMBER ')' | '(' TEMPERATURE NUMBER ')'
| '(' TEMPERATURE triple ')' { sta::sdf_reader->deleteTriple($3); } | '(' TEMPERATURE triple ')' { reader->deleteTriple($3); }
| '(' TEMPERATURE ')' // Illegal SDF (from OC). | '(' TEMPERATURE ')' // Illegal SDF (from OC).
| '(' TIMESCALE NUMBER ID ')' | '(' TIMESCALE NUMBER ID ')' { reader->setTimescale($3, $4); }
{ sta::sdf_reader->setTimescale($3, $4); }
; ;
hchar: hchar:
@ -116,7 +129,7 @@ hchar:
{ $$ = '.'; } { $$ = '.'; }
; ;
number_opt: { $$ = NULL; } number_opt: { $$ = nullptr; }
| NUMBER { $$ = new float($1); } | NUMBER { $$ = new float($1); }
; ;
@ -127,21 +140,21 @@ cells:
cell: cell:
'(' CELL celltype cell_instance timing_specs ')' '(' CELL celltype cell_instance timing_specs ')'
{ sta::sdf_reader->cellFinish(); } { reader->cellFinish(); }
; ;
celltype: celltype:
'(' CELLTYPE QSTRING ')' '(' CELLTYPE QSTRING ')'
{ sta::sdf_reader->setCell($3); } { reader->setCell($3); }
; ;
cell_instance: cell_instance:
'(' INSTANCE ')' '(' INSTANCE ')'
{ sta::sdf_reader->setInstance(NULL); } { reader->setInstance(nullptr); }
| '(' INSTANCE '*' ')' | '(' INSTANCE '*' ')'
{ sta::sdf_reader->setInstanceWildcard(); } { reader->setInstanceWildcard(); }
| '(' INSTANCE path ')' | '(' INSTANCE path ')'
{ sta::sdf_reader->setInstance($3); } { reader->setInstance($3); }
; ;
timing_specs: timing_specs:
@ -160,10 +173,10 @@ deltypes:
deltype: deltype:
'(' ABSOLUTE '(' ABSOLUTE
{ sta::sdf_reader->setInIncremental(false); } { reader->setInIncremental(false); }
del_defs ')' del_defs ')'
| '(' INCREMENTAL | '(' INCREMENTAL
{ sta::sdf_reader->setInIncremental(true); } { reader->setInIncremental(true); }
del_defs ')' del_defs ')'
; ;
@ -173,28 +186,28 @@ del_defs:
path: path:
ID ID
{ $$ = sta::sdf_reader->unescaped($1); } { $$ = reader->unescaped($1); }
| path hchar ID | path hchar ID
{ $$ = sta::sdf_reader->makePath($1, sta::sdf_reader->unescaped($3)); } { $$ = reader->makePath($1, reader->unescaped($3)); }
; ;
del_def: del_def:
'(' IOPATH port_spec port_instance retains delval_list ')' '(' IOPATH port_spec port_instance retains delval_list ')'
{ sta::sdf_reader->iopath($3, $4, $6, NULL, false); } { reader->iopath($3, $4, $6, nullptr, false); }
| '(' CONDELSE '(' IOPATH port_spec port_instance | '(' CONDELSE '(' IOPATH port_spec port_instance
retains delval_list ')' ')' retains delval_list ')' ')'
{ sta::sdf_reader->iopath($5, $6, $8, NULL, true); } { reader->iopath($5, $6, $8, nullptr, true); }
| '(' COND EXPR_OPEN_IOPATH port_spec port_instance | '(' COND EXPR_OPEN_IOPATH port_spec port_instance
retains delval_list ')' ')' retains delval_list ')' ')'
{ sta::sdf_reader->iopath($4, $5, $7, $3, false); } { reader->iopath($4, $5, $7, $3, false); }
| '(' INTERCONNECT port_instance port_instance delval_list ')' | '(' INTERCONNECT port_instance port_instance delval_list ')'
{ sta::sdf_reader->interconnect($3, $4, $5); } { reader->interconnect($3, $4, $5); }
| '(' PORT port_instance delval_list ')' | '(' PORT port_instance delval_list ')'
{ sta::sdf_reader->port($3, $4); } { reader->port($3, $4); }
| '(' DEVICE delval_list ')' | '(' DEVICE delval_list ')'
{ sta::sdf_reader->device($3); } { reader->device($3); }
| '(' DEVICE port_instance delval_list ')' | '(' DEVICE port_instance delval_list ')'
{ sta::sdf_reader->device($3, $4); } { reader->device($3, $4); }
; ;
retains: retains:
@ -204,12 +217,12 @@ retains:
retain: retain:
'(' RETAIN delval_list ')' '(' RETAIN delval_list ')'
{ sta::sdf_reader->deleteTripleSeq($3); } { reader->deleteTripleSeq($3); }
; ;
delval_list: delval_list:
value value
{ $$ = sta::sdf_reader->makeTripleSeq(); $$->push_back($1); } { $$ = reader->makeTripleSeq(); $$->push_back($1); }
| delval_list value | delval_list value
{ $1->push_back($2); $$ = $1; } { $1->push_back($2); $$ = $1; }
; ;
@ -219,80 +232,77 @@ tchk_defs:
; ;
tchk_def: tchk_def:
'(' SETUP { sta::sdf_reader->setInTimingCheck(true); } '(' SETUP { reader->setInTimingCheck(true); }
port_tchk port_tchk value ')' port_tchk port_tchk value ')'
{ sta::sdf_reader->timingCheck(sta::TimingRole::setup(), $4, $5, $6); { reader->timingCheck(sta::TimingRole::setup(), $4, $5, $6);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' HOLD { sta::sdf_reader->setInTimingCheck(true); } | '(' HOLD { reader->setInTimingCheck(true); }
port_tchk port_tchk value ')' port_tchk port_tchk value ')'
{ sta::sdf_reader->timingCheck(sta::TimingRole::hold(), $4, $5, $6); { reader->timingCheck(sta::TimingRole::hold(), $4, $5, $6);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' SETUPHOLD { sta::sdf_reader->setInTimingCheck(true); } | '(' SETUPHOLD { reader->setInTimingCheck(true); }
port_tchk port_tchk value value ')' port_tchk port_tchk value value ')'
{ sta::sdf_reader->timingCheckSetupHold($4, $5, $6, $7); { reader->timingCheckSetupHold($4, $5, $6, $7);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' RECOVERY { sta::sdf_reader->setInTimingCheck(true); } | '(' RECOVERY { reader->setInTimingCheck(true); }
port_tchk port_tchk value ')' port_tchk port_tchk value ')'
{ sta::sdf_reader->timingCheck(sta::TimingRole::recovery(),$4,$5,$6); { reader->timingCheck(sta::TimingRole::recovery(),$4,$5,$6);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' REMOVAL { sta::sdf_reader->setInTimingCheck(true); } | '(' REMOVAL { reader->setInTimingCheck(true); }
port_tchk port_tchk value ')' port_tchk port_tchk value ')'
{ sta::sdf_reader->timingCheck(sta::TimingRole::removal(),$4,$5,$6); { reader->timingCheck(sta::TimingRole::removal(),$4,$5,$6);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' RECREM { sta::sdf_reader->setInTimingCheck(true); } | '(' RECREM { reader->setInTimingCheck(true); }
port_tchk port_tchk value value ')' port_tchk port_tchk value value ')'
{ sta::sdf_reader->timingCheckRecRem($4, $5, $6, $7); { reader->timingCheckRecRem($4, $5, $6, $7);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' SKEW { sta::sdf_reader->setInTimingCheck(true); } | '(' SKEW { reader->setInTimingCheck(true); }
port_tchk port_tchk value ')' port_tchk port_tchk value ')'
// Sdf skew clk/ref are reversed from liberty. // Sdf skew clk/ref are reversed from liberty.
{ sta::sdf_reader->timingCheck(sta::TimingRole::skew(),$5,$4,$6); { reader->timingCheck(sta::TimingRole::skew(),$5,$4,$6);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' WIDTH { sta::sdf_reader->setInTimingCheck(true); } | '(' WIDTH { reader->setInTimingCheck(true); }
port_tchk value ')' port_tchk value ')'
{ sta::sdf_reader->timingCheckWidth($4, $5); { reader->timingCheckWidth($4, $5);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' PERIOD { sta::sdf_reader->setInTimingCheck(true); } | '(' PERIOD { reader->setInTimingCheck(true); }
port_tchk value ')' port_tchk value ')'
{ sta::sdf_reader->timingCheckPeriod($4, $5); { reader->timingCheckPeriod($4, $5);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
| '(' NOCHANGE { sta::sdf_reader->setInTimingCheck(true); } | '(' NOCHANGE { reader->setInTimingCheck(true); }
port_tchk port_tchk value value ')' port_tchk port_tchk value value ')'
{ sta::sdf_reader->timingCheckNochange($4, $5, $6, $7); { reader->timingCheckNochange($4, $5, $6, $7);
sta::sdf_reader->setInTimingCheck(false); reader->setInTimingCheck(false);
} }
; ;
port: port:
ID ID
{ $$ = sta::sdf_reader->unescaped($1); } { $$ = reader->unescaped($1); }
| ID '[' DNUMBER ']' | ID '[' DNUMBER ']'
{ const char *bus_name = sta::sdf_reader->unescaped($1); { $$ = reader->makeBusName($1, $3); }
$$ = sta::stringPrint("%s[%d]", bus_name, $3);
sta::stringDelete(bus_name);
}
; ;
port_instance: port_instance:
port port
| path hchar port | path hchar port
{ $$ = sta::sdf_reader->makePath($1, $3); } { $$ = reader->makePath($1, $3); }
; ;
port_spec: port_spec:
port_instance port_instance
{ $$=sta::sdf_reader->makePortSpec(sta::Transition::riseFall(),$1,NULL); } { $$=reader->makePortSpec(sta::Transition::riseFall(),$1,nullptr); }
| '(' port_transition port_instance ')' | '(' port_transition port_instance ')'
{ $$ = sta::sdf_reader->makePortSpec($2, $3, NULL); } { $$ = reader->makePortSpec($2, $3, nullptr); }
; ;
port_transition: port_transition:
@ -303,19 +313,19 @@ port_transition:
port_tchk: port_tchk:
port_spec port_spec
| '(' COND EXPR_ID_CLOSE | '(' COND EXPR_ID_CLOSE
{ $$ = sta::sdf_reader->makeCondPortSpec($3); } { $$ = reader->makeCondPortSpec($3); }
| '(' COND EXPR_OPEN port_transition port_instance ')' ')' | '(' COND EXPR_OPEN port_transition port_instance ')' ')'
{ $$ = sta::sdf_reader->makePortSpec($4, $5, $3); } { $$ = reader->makePortSpec($4, $5, $3); }
; ;
value: value:
'(' ')' '(' ')'
{ {
$$ = sta::sdf_reader->makeTriple(); $$ = reader->makeTriple();
} }
| '(' NUMBER ')' | '(' NUMBER ')'
{ {
$$ = sta::sdf_reader->makeTriple($2); $$ = reader->makeTriple($2);
} }
| '(' triple ')' { $$ = $2; } | '(' triple ')' { $$ = $2; }
; ;
@ -324,17 +334,17 @@ triple:
NUMBER ':' number_opt ':' number_opt NUMBER ':' number_opt ':' number_opt
{ {
float *fp = new float($1); float *fp = new float($1);
$$ = sta::sdf_reader->makeTriple(fp, $3, $5); $$ = reader->makeTriple(fp, $3, $5);
} }
| number_opt ':' NUMBER ':' number_opt | number_opt ':' NUMBER ':' number_opt
{ {
float *fp = new float($3); float *fp = new float($3);
$$ = sta::sdf_reader->makeTriple($1, fp, $5); $$ = reader->makeTriple($1, fp, $5);
} }
| number_opt ':' number_opt ':' NUMBER | number_opt ':' number_opt ':' NUMBER
{ {
float *fp = new float($5); float *fp = new float($5);
$$ = sta::sdf_reader->makeTriple($1, $3, fp); $$ = reader->makeTriple($1, $3, fp);
} }
; ;

View File

@ -27,8 +27,10 @@
#include <cstdarg> #include <cstdarg>
#include <cctype> #include <cctype>
#include "Zlib.hh"
#include "Error.hh" #include "Error.hh"
#include "Debug.hh" #include "Debug.hh"
#include "Stats.hh"
#include "Report.hh" #include "Report.hh"
#include "MinMax.hh" #include "MinMax.hh"
#include "TimingArc.hh" #include "TimingArc.hh"
@ -39,13 +41,12 @@
#include "DcalcAnalysisPt.hh" #include "DcalcAnalysisPt.hh"
#include "Sdc.hh" #include "Sdc.hh"
#include "sdf/SdfReaderPvt.hh" #include "sdf/SdfReaderPvt.hh"
#include "sdf/SdfScanner.hh"
extern int
SdfParse_parse();
extern int SdfParse_debug;
namespace sta { namespace sta {
using std::to_string;
class SdfTriple class SdfTriple
{ {
public: public:
@ -63,22 +64,20 @@ private:
class SdfPortSpec class SdfPortSpec
{ {
public: public:
SdfPortSpec(Transition *tr, SdfPortSpec(const Transition *tr,
const char *port, const string *port,
const char *cond); const string *cond);
~SdfPortSpec(); ~SdfPortSpec();
const char *port() const { return port_; } const string *port() const { return port_; }
Transition *transition() const { return tr_; } const Transition *transition() const { return tr_; }
const char *cond() const { return cond_; } const string *cond() const { return cond_; }
private: private:
Transition *tr_; const Transition *tr_;
const char *port_; const string *port_;
const char *cond_; // timing checks only const string *cond_; // timing checks only
}; };
SdfReader *sdf_reader = nullptr;
bool bool
readSdf(const char *filename, readSdf(const char *filename,
const char *path, const char *path,
@ -95,9 +94,7 @@ readSdf(const char *filename,
sta->sdc()->analysisType(), sta->sdc()->analysisType(),
unescaped_dividers, incremental_only, unescaped_dividers, incremental_only,
cond_use, sta); cond_use, sta);
sdf_reader = &reader;
bool success = reader.read(); bool success = reader.read();
sdf_reader = nullptr;
return success; return success;
} }
@ -121,7 +118,6 @@ SdfReader::SdfReader(const char *filename,
unescaped_dividers_(unescaped_dividers), unescaped_dividers_(unescaped_dividers),
is_incremental_only_(is_incremental_only), is_incremental_only_(is_incremental_only),
cond_use_(cond_use), cond_use_(cond_use),
line_(1),
divider_('/'), divider_('/'),
escape_('\\'), escape_('\\'),
instance_(nullptr), instance_(nullptr),
@ -143,13 +139,14 @@ SdfReader::~SdfReader()
bool bool
SdfReader::read() SdfReader::read()
{ {
// Use zlib to uncompress gzip'd files automagically. gzstream::igzstream stream(filename_);
stream_ = gzopen(filename_, "rb"); if (stream.good()) {
//::SdfParse_debug = 1; Stats stats(debug_, report_);
if (stream_) { SdfScanner scanner(&stream, filename_, this, report_);
// yyparse returns 0 on success. scanner_ = &scanner;
bool success = (::SdfParse_parse() == 0); SdfParse parser(&scanner, this);
gzclose(stream_); bool success = (parser.parse() == 0);
stats.report("Read sdf");
return success; return success;
} }
else else
@ -164,28 +161,28 @@ SdfReader::setDivider(char divider)
void void
SdfReader::setTimescale(float multiplier, SdfReader::setTimescale(float multiplier,
const char *units) const string *units)
{ {
if (multiplier == 1.0 if (multiplier == 1.0
|| multiplier == 10.0 || multiplier == 10.0
|| multiplier == 100.0) { || multiplier == 100.0) {
if (stringEq(units, "us")) if (*units == "us")
timescale_ = multiplier * 1E-6F; timescale_ = multiplier * 1E-6F;
else if (stringEq(units, "ns")) else if (*units == "ns")
timescale_ = multiplier * 1E-9F; timescale_ = multiplier * 1E-9F;
else if (stringEq(units, "ps")) else if (*units == "ps")
timescale_ = multiplier * 1E-12F; timescale_ = multiplier * 1E-12F;
else else
sdfError(180, "TIMESCALE units not us, ns, or ps."); sdfError(180, "TIMESCALE units not us, ns, or ps.");
} }
else else
sdfError(181, "TIMESCALE multiplier not 1, 10, or 100."); sdfError(181, "TIMESCALE multiplier not 1, 10, or 100.");
stringDelete(units); delete units;
} }
void void
SdfReader::interconnect(const char *from_pin_name, SdfReader::interconnect(const string *from_pin_name,
const char *to_pin_name, const string *to_pin_name,
SdfTripleSeq *triples) SdfTripleSeq *triples)
{ {
// Ignore non-incremental annotations in incremental only mode. // Ignore non-incremental annotations in incremental only mode.
@ -202,38 +199,41 @@ SdfReader::interconnect(const char *from_pin_name,
bool to_is_hier = network_->isHierarchical(to_pin); bool to_is_hier = network_->isHierarchical(to_pin);
if (from_is_hier || to_is_hier) { if (from_is_hier || to_is_hier) {
if (from_is_hier) if (from_is_hier)
sdfError(182, "pin %s is a hierarchical pin.", from_pin_name); sdfError(182, "pin %s is a hierarchical pin.",
from_pin_name->c_str());
if (to_is_hier) if (to_is_hier)
sdfError(183, "pin %s is a hierarchical pin.", to_pin_name); sdfError(183, "pin %s is a hierarchical pin.",
to_pin_name->c_str());
} }
else else
sdfWarn(184, "INTERCONNECT from %s to %s not found.", sdfWarn(184, "INTERCONNECT from %s to %s not found.",
from_pin_name, to_pin_name); from_pin_name->c_str(),
to_pin_name->c_str());
} }
} }
else { else {
if (from_pin == nullptr) if (from_pin == nullptr)
sdfWarn(185, "pin %s not found.", from_pin_name); sdfWarn(185, "pin %s not found.", from_pin_name->c_str());
if (to_pin == nullptr) if (to_pin == nullptr)
sdfWarn(186, "pin %s not found.", to_pin_name); sdfWarn(186, "pin %s not found.", to_pin_name->c_str());
} }
} }
stringDelete(from_pin_name); delete from_pin_name;
stringDelete(to_pin_name); delete to_pin_name;
deleteTripleSeq(triples); deleteTripleSeq(triples);
} }
void void
SdfReader::port(const char *to_pin_name, SdfReader::port(const string *to_pin_name,
SdfTripleSeq *triples) SdfTripleSeq *triples)
{ {
// Ignore non-incremental annotations in incremental only mode. // Ignore non-incremental annotations in incremental only mode.
if (!(is_incremental_only_ && !in_incremental_)) { if (!(is_incremental_only_ && !in_incremental_)) {
Pin *to_pin = (instance_) Pin *to_pin = (instance_)
? network_->findPinRelative(instance_, to_pin_name) ? network_->findPinRelative(instance_, to_pin_name->c_str())
: network_->findPin(to_pin_name); : network_->findPin(to_pin_name->c_str());
if (to_pin == nullptr) if (to_pin == nullptr)
sdfWarn(187, "pin %s not found.", to_pin_name); sdfWarn(187, "pin %s not found.", to_pin_name->c_str());
else { else {
Vertex *vertex = graph_->pinLoadVertex(to_pin); Vertex *vertex = graph_->pinLoadVertex(to_pin);
VertexInEdgeIterator edge_iter(vertex, graph_); VertexInEdgeIterator edge_iter(vertex, graph_);
@ -244,7 +244,7 @@ SdfReader::port(const char *to_pin_name,
} }
} }
} }
stringDelete(to_pin_name); delete to_pin_name;
deleteTripleSeq(triples); deleteTripleSeq(triples);
} }
@ -295,16 +295,16 @@ SdfReader::setEdgeDelays(Edge *edge,
} }
void void
SdfReader::setCell(const char *cell_name) SdfReader::setCell(const string *cell_name)
{ {
cell_name_ = cell_name; cell_name_ = cell_name;
} }
void void
SdfReader::setInstance(const char *instance_name) SdfReader::setInstance(const string *instance_name)
{ {
if (instance_name) { if (instance_name) {
if (stringEq(instance_name, "*")) { if (*instance_name == "*") {
notSupported("INSTANCE wildcards"); notSupported("INSTANCE wildcards");
instance_ = nullptr; instance_ = nullptr;
} }
@ -313,17 +313,17 @@ SdfReader::setInstance(const char *instance_name)
if (instance_) { if (instance_) {
Cell *inst_cell = network_->cell(instance_); Cell *inst_cell = network_->cell(instance_);
const char *inst_cell_name = network_->name(inst_cell); const char *inst_cell_name = network_->name(inst_cell);
if (cell_name_ && !stringEqual(inst_cell_name, cell_name_)) if (cell_name_ && !stringEq(inst_cell_name, cell_name_->c_str()))
sdfWarn(190, "instance %s cell %s does not match enclosing cell %s.", sdfWarn(190, "instance %s cell %s does not match enclosing cell %s.",
instance_name, instance_name->c_str(),
inst_cell_name, inst_cell_name,
cell_name_); cell_name_->c_str());
} }
} }
} }
else else
instance_ = nullptr; instance_ = nullptr;
stringDelete(instance_name); delete instance_name;
} }
void void
@ -336,26 +336,26 @@ SdfReader::setInstanceWildcard()
void void
SdfReader::cellFinish() SdfReader::cellFinish()
{ {
stringDelete(cell_name_); delete cell_name_;
cell_name_ = nullptr; cell_name_ = nullptr;
instance_ = nullptr; instance_ = nullptr;
} }
void void
SdfReader::iopath(SdfPortSpec *from_edge, SdfReader::iopath(SdfPortSpec *from_edge,
const char *to_port_name, const string *to_port_name,
SdfTripleSeq *triples, SdfTripleSeq *triples,
const char *cond, const string *cond,
bool condelse) bool condelse)
{ {
if (instance_) { if (instance_) {
const char *from_port_name = from_edge->port(); const string *from_port_name = from_edge->port();
Cell *cell = network_->cell(instance_); Cell *cell = network_->cell(instance_);
Port *from_port = findPort(cell, from_port_name); Port *from_port = findPort(cell, from_port_name);
Port *to_port = findPort(cell, to_port_name); Port *to_port = findPort(cell, to_port_name);
if (from_port && to_port) { if (from_port && to_port) {
Pin *from_pin = network_->findPin(instance_, from_port_name); Pin *from_pin = network_->findPin(instance_, from_port);
Pin *to_pin = network_->findPin(instance_, to_port_name); Pin *to_pin = network_->findPin(instance_, to_port);
// Do not report an error if the pin is not found because the // Do not report an error if the pin is not found because the
// instance may not have the pin. // instance may not have the pin.
if (from_pin && to_pin) { if (from_pin && to_pin) {
@ -405,27 +405,27 @@ SdfReader::iopath(SdfPortSpec *from_edge,
if (!matched) if (!matched)
sdfWarn(191, "cell %s IOPATH %s -> %s not found.", sdfWarn(191, "cell %s IOPATH %s -> %s not found.",
network_->cellName(instance_), network_->cellName(instance_),
from_port_name, from_port_name->c_str(),
to_port_name); to_port_name->c_str());
} }
} }
} }
} }
stringDelete(to_port_name); delete to_port_name;
deletePortSpec(from_edge); delete from_edge;
deleteTripleSeq(triples); deleteTripleSeq(triples);
stringDelete(cond); delete cond;
} }
Port * Port *
SdfReader::findPort(const Cell *cell, SdfReader::findPort(const Cell *cell,
const char *port_name) const string *port_name)
{ {
Port *port = network_->findPort(cell, port_name); Port *port = network_->findPort(cell, port_name->c_str());
if (port == nullptr) if (port == nullptr)
sdfWarn(194, "instance %s port %s not found.", sdfWarn(194, "instance %s port %s not found.",
network_->pathName(instance_), network_->pathName(instance_),
port_name); port_name->c_str());
return port; return port;
} }
@ -436,16 +436,16 @@ SdfReader::timingCheck(TimingRole *role,
SdfTriple *triple) SdfTriple *triple)
{ {
if (instance_) { if (instance_) {
const char *data_port_name = data_edge->port(); const string *data_port_name = data_edge->port();
const char *clk_port_name = clk_edge->port(); const string *clk_port_name = clk_edge->port();
Cell *cell = network_->cell(instance_); Cell *cell = network_->cell(instance_);
Port *data_port = findPort(cell, data_port_name); Port *data_port = findPort(cell, data_port_name);
Port *clk_port = findPort(cell, clk_port_name); Port *clk_port = findPort(cell, clk_port_name);
if (data_port && clk_port) if (data_port && clk_port)
timingCheck1(role, data_port, data_edge, clk_port, clk_edge, triple); timingCheck1(role, data_port, data_edge, clk_port, clk_edge, triple);
} }
deletePortSpec(data_edge); delete data_edge;
deletePortSpec(clk_edge); delete clk_edge;
deleteTriple(triple); deleteTriple(triple);
} }
@ -514,8 +514,8 @@ SdfReader::annotateCheckEdges(Pin *data_pin,
bool match_generic) bool match_generic)
{ {
bool matched = false; bool matched = false;
const char *cond_start = data_edge->cond(); const string *cond_start = data_edge->cond();
const char *cond_end = clk_edge->cond(); const string *cond_end = clk_edge->cond();
// Timing check graph edges from clk to data. // Timing check graph edges from clk to data.
Vertex *to_vertex = graph_->pinLoadVertex(data_pin); Vertex *to_vertex = graph_->pinLoadVertex(data_pin);
// Fanin < fanout, so search for driver from load. // Fanin < fanout, so search for driver from load.
@ -556,11 +556,11 @@ SdfReader::timingCheckWidth(SdfPortSpec *edge,
// Ignore non-incremental annotations in incremental only mode. // Ignore non-incremental annotations in incremental only mode.
if (!(is_incremental_only_ && !in_incremental_) if (!(is_incremental_only_ && !in_incremental_)
&& instance_) { && instance_) {
const char *port_name = edge->port(); const string *port_name = edge->port();
Cell *cell = network_->cell(instance_); Cell *cell = network_->cell(instance_);
Port *port = findPort(cell, port_name); Port *port = findPort(cell, port_name);
if (port) { if (port) {
Pin *pin = network_->findPin(instance_, port_name); Pin *pin = network_->findPin(instance_, port_name->c_str());
if (pin) { if (pin) {
const RiseFall *rf = edge->transition()->asRiseFall(); const RiseFall *rf = edge->transition()->asRiseFall();
Edge *edge; Edge *edge;
@ -571,7 +571,7 @@ SdfReader::timingCheckWidth(SdfPortSpec *edge,
} }
} }
} }
deletePortSpec(edge); delete edge;
deleteTriple(triple); deleteTriple(triple);
} }
@ -603,8 +603,8 @@ SdfReader::timingCheckSetupHold1(SdfPortSpec *data_edge,
TimingRole *setup_role, TimingRole *setup_role,
TimingRole *hold_role) TimingRole *hold_role)
{ {
const char *data_port_name = data_edge->port(); const string *data_port_name = data_edge->port();
const char *clk_port_name = clk_edge->port(); const string *clk_port_name = clk_edge->port();
Cell *cell = network_->cell(instance_); Cell *cell = network_->cell(instance_);
Port *data_port = findPort(cell, data_port_name); Port *data_port = findPort(cell, data_port_name);
Port *clk_port = findPort(cell, clk_port_name); Port *clk_port = findPort(cell, clk_port_name);
@ -612,8 +612,8 @@ SdfReader::timingCheckSetupHold1(SdfPortSpec *data_edge,
timingCheck1(setup_role, data_port, data_edge, clk_port, clk_edge, setup_triple); timingCheck1(setup_role, data_port, data_edge, clk_port, clk_edge, setup_triple);
timingCheck1(hold_role, data_port, data_edge, clk_port, clk_edge, hold_triple); timingCheck1(hold_role, data_port, data_edge, clk_port, clk_edge, hold_triple);
} }
deletePortSpec(data_edge); delete data_edge;
deletePortSpec(clk_edge); delete clk_edge;
deleteTriple(setup_triple); deleteTriple(setup_triple);
deleteTriple(hold_triple); deleteTriple(hold_triple);
} }
@ -625,12 +625,12 @@ SdfReader::timingCheckPeriod(SdfPortSpec *edge,
// Ignore non-incremental annotations in incremental only mode. // Ignore non-incremental annotations in incremental only mode.
if (!(is_incremental_only_ && !in_incremental_) if (!(is_incremental_only_ && !in_incremental_)
&& instance_) { && instance_) {
const char *port_name = edge->port(); const string *port_name = edge->port();
Cell *cell = network_->cell(instance_); Cell *cell = network_->cell(instance_);
Port *port = findPort(cell, port_name); Port *port = findPort(cell, port_name);
if (port) { if (port) {
// Edge specifier is ignored for period checks. // Edge specifier is ignored for period checks.
Pin *pin = network_->findPin(instance_, port_name); Pin *pin = network_->findPin(instance_, port_name->c_str());
if (pin) { if (pin) {
float **values = triple->values(); float **values = triple->values();
float *value_ptr = values[triple_min_index_]; float *value_ptr = values[triple_min_index_];
@ -648,7 +648,7 @@ SdfReader::timingCheckPeriod(SdfPortSpec *edge,
} }
} }
} }
deletePortSpec(edge); delete edge;
deleteTriple(triple); deleteTriple(triple);
} }
@ -659,8 +659,8 @@ SdfReader::timingCheckNochange(SdfPortSpec *data_edge,
SdfTriple *after_triple) SdfTriple *after_triple)
{ {
notSupported("NOCHANGE"); notSupported("NOCHANGE");
deletePortSpec(data_edge); delete data_edge;
deletePortSpec(clk_edge); delete clk_edge;
deleteTriple(before_triple); deleteTriple(before_triple);
deleteTriple(after_triple); deleteTriple(after_triple);
} }
@ -682,7 +682,7 @@ SdfReader::device(SdfTripleSeq *triples)
} }
void void
SdfReader::device(const char *to_port_name, SdfReader::device(const string *to_port_name,
SdfTripleSeq *triples) SdfTripleSeq *triples)
{ {
// Ignore non-incremental annotations in incremental only mode. // Ignore non-incremental annotations in incremental only mode.
@ -691,11 +691,11 @@ SdfReader::device(const char *to_port_name,
Cell *cell = network_->cell(instance_); Cell *cell = network_->cell(instance_);
Port *to_port = findPort(cell, to_port_name); Port *to_port = findPort(cell, to_port_name);
if (to_port) { if (to_port) {
Pin *to_pin = network_->findPin(instance_, to_port_name); Pin *to_pin = network_->findPin(instance_, to_port_name->c_str());
setDevicePinDelays(to_pin, triples); setDevicePinDelays(to_pin, triples);
} }
} }
stringDelete(to_port_name); delete to_port_name;
deleteTripleSeq(triples); deleteTripleSeq(triples);
} }
@ -798,7 +798,7 @@ SdfReader::setEdgeArcDelaysCondUse(Edge *edge,
} }
bool bool
SdfReader::condMatch(const char *sdf_cond, SdfReader::condMatch(const string *sdf_cond,
const char *lib_cond) const char *lib_cond)
{ {
// If the sdf is not conditional it matches any library condition. // If the sdf is not conditional it matches any library condition.
@ -806,7 +806,7 @@ SdfReader::condMatch(const char *sdf_cond,
return true; return true;
else if (sdf_cond && lib_cond) { else if (sdf_cond && lib_cond) {
// Match sdf_cond and lib_cond ignoring blanks. // Match sdf_cond and lib_cond ignoring blanks.
const char *c1 = sdf_cond; const char *c1 = sdf_cond->c_str();
const char *c2 = lib_cond; const char *c2 = lib_cond;
char ch1, ch2; char ch1, ch2;
do { do {
@ -827,44 +827,35 @@ SdfReader::condMatch(const char *sdf_cond,
SdfPortSpec * SdfPortSpec *
SdfReader::makePortSpec(Transition *tr, SdfReader::makePortSpec(Transition *tr,
const char *port, const string *port,
const char *cond) const string *cond)
{ {
SdfPortSpec *port_spec = new SdfPortSpec(tr, port, cond); return new SdfPortSpec(tr, port, cond);
stringDelete(port);
stringDelete(cond);
return port_spec;
} }
SdfPortSpec * SdfPortSpec *
SdfReader::makeCondPortSpec(const char *cond_port) SdfReader::makeCondPortSpec(const string *cond_port)
{ {
// Search from end to find port name because condition may contain spaces. // Search from end to find port name because condition may contain spaces.
string cond_port1(cond_port); string cond_port1(*cond_port);
trimRight(cond_port1); trimRight(cond_port1);
auto port_idx = cond_port1.find_last_of(" "); auto port_idx = cond_port1.find_last_of(" ");
if (port_idx != cond_port1.npos) { if (port_idx != cond_port1.npos) {
string port1 = cond_port1.substr(port_idx + 1); string *port1 = new string(cond_port1.substr(port_idx + 1));
auto cond_end = cond_port1.find_last_not_of(" ", port_idx); auto cond_end = cond_port1.find_last_not_of(" ", port_idx);
if (cond_end != cond_port1.npos) { if (cond_end != cond_port1.npos) {
string cond1 = cond_port1.substr(0, cond_end + 1); string *cond1 = new string(cond_port1.substr(0, cond_end + 1));
SdfPortSpec *port_spec = new SdfPortSpec(Transition::riseFall(), SdfPortSpec *port_spec = new SdfPortSpec(Transition::riseFall(),
port1.c_str(), port1,
cond1.c_str()); cond1);
stringDelete(cond_port); delete cond_port;
return port_spec; return port_spec;
} }
} }
stringDelete(cond_port); delete cond_port;
return nullptr; return nullptr;
} }
void
SdfReader::deletePortSpec(SdfPortSpec *edge)
{
delete edge;
}
SdfTripleSeq * SdfTripleSeq *
SdfReader::makeTripleSeq() SdfReader::makeTripleSeq()
{ {
@ -925,91 +916,70 @@ SdfReader::setInIncremental(bool incr)
in_incremental_ = incr; in_incremental_ = incr;
} }
const char * string *
SdfReader::unescaped(const char *token) SdfReader::unescaped(const string *token)
{ {
char path_escape = network_->pathEscape(); char path_escape = network_->pathEscape();
char path_divider = network_->pathDivider(); char path_divider = network_->pathDivider();
char *unescaped = new char[strlen(token) + 1]; size_t token_length = token->size();
char *u = unescaped; string *unescaped = new string;
size_t token_length = strlen(token);
for (size_t i = 0; i < token_length; i++) { for (size_t i = 0; i < token_length; i++) {
char ch = token[i]; char ch = (*token)[i];
if (ch == escape_) { if (ch == escape_) {
char next_ch = token[i + 1]; char next_ch = (*token)[i + 1];
if (next_ch == divider_) { if (next_ch == divider_) {
// Escaped divider. // Escaped divider.
// Translate sdf escape to network escape. // Translate sdf escape to network escape.
*u++ = path_escape; *unescaped += path_escape;
// Translate sdf divider to network divider. // Translate sdf divider to network divider.
*u++ = path_divider; *unescaped += path_divider;
} }
else if (next_ch == '[' else if (next_ch == '['
|| next_ch == ']' || next_ch == ']'
|| next_ch == escape_) { || next_ch == escape_) {
// Escaped bus bracket or escape. // Escaped bus bracket or escape.
// Translate sdf escape to network escape. // Translate sdf escape to network escape.
*u++ = path_escape; *unescaped += path_escape;
*u++ = next_ch; *unescaped += next_ch;
} }
else else
// Escaped non-divider character. // Escaped non-divider character.
*u++ = next_ch; *unescaped += next_ch;
i++; i++;
} }
else else
// Just the normal noises. // Just the normal noises.
*u++ = ch; *unescaped += ch;
} }
*u = '\0'; debugPrint(debug_, "sdf_name", 1, "unescape %s -> %s",
debugPrint(debug_, "sdf_name", 1, "token %s -> %s", token, unescaped); token->c_str(),
stringDelete(token); unescaped->c_str());
delete token;
return unescaped; return unescaped;
} }
// Translate sdf divider to network divider. string *
char * SdfReader::makePath(const string *head,
SdfReader::makePath(const char *head, const string *tail)
const char *tail)
{ {
char *path = stringPrint("%s%c%s", string *path = new string(*head);
head, *path += network_->pathDivider();
network_->pathDivider(), *path += *tail;
tail); delete head;
sta::stringDelete(head); delete tail;
sta::stringDelete(tail);
return path; return path;
} }
void string *
SdfReader::incrLine() SdfReader::makeBusName(string *base_name,
int index)
{ {
line_++; string *bus_name = unescaped(base_name);
} *bus_name += '[';
*bus_name += to_string(index);
void *bus_name += ']';
SdfReader::getChars(char *buf, delete base_name;
size_t &result, return bus_name;
size_t max_size)
{
char *status = gzgets(stream_, buf, max_size);
if (status == Z_NULL)
result = 0; // YY_nullptr
else
result = strlen(buf);
}
void
SdfReader::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 void
@ -1024,7 +994,7 @@ SdfReader::sdfWarn(int id,
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
report_->vfileWarn(id, filename_, line_, fmt, args); report_->vfileWarn(id, filename_, scanner_->lineno(), fmt, args);
va_end(args); va_end(args);
} }
@ -1034,35 +1004,35 @@ SdfReader::sdfError(int id,
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
report_->vfileError(id, filename_, line_, fmt, args); report_->vfileError(id, filename_, scanner_->lineno(), fmt, args);
va_end(args); va_end(args);
} }
Pin * Pin *
SdfReader::findPin(const char *name) SdfReader::findPin(const string *name)
{ {
if (path_) { if (path_) {
string path_name = path_; string path_name(path_);
path_name += divider_; path_name += divider_;
path_name += name; path_name += *name;
Pin *pin = network_->findPin(path_name.c_str()); Pin *pin = network_->findPin(path_name.c_str());
return pin; return pin;
} }
else else
return network_->findPin(name); return network_->findPin(name->c_str());
} }
Instance * Instance *
SdfReader::findInstance(const char *name) SdfReader::findInstance(const string *name)
{ {
string inst_name; string inst_name;
if (path_) { if (path_) {
inst_name = path_; inst_name = path_;
inst_name += divider_; inst_name += divider_;
inst_name += name; inst_name += *name;
} }
else else
inst_name = name; inst_name = *name;
Instance *inst = network_->findInstance(inst_name.c_str()); Instance *inst = network_->findInstance(inst_name.c_str());
if (inst == nullptr) if (inst == nullptr)
sdfWarn(195, "instance %s not found.", inst_name.c_str()); sdfWarn(195, "instance %s not found.", inst_name.c_str());
@ -1071,19 +1041,19 @@ SdfReader::findInstance(const char *name)
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
SdfPortSpec::SdfPortSpec(Transition *tr, SdfPortSpec::SdfPortSpec(const Transition *tr,
const char *port, const string *port,
const char *cond) : const string *cond) :
tr_(tr), tr_(tr),
port_(stringCopy(port)), port_(port),
cond_(stringCopy(cond)) cond_(cond)
{ {
} }
SdfPortSpec::~SdfPortSpec() SdfPortSpec::~SdfPortSpec()
{ {
stringDelete(port_); delete port_;
stringDelete(cond_); delete cond_;
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -1114,16 +1084,32 @@ SdfTriple::hasValue() const
return values_[0] || values_[1] || values_[2]; return values_[0] || values_[1] || values_[2];
} }
} // namespace ////////////////////////////////////////////////////////////////
// Global namespace SdfScanner::SdfScanner(std::istream *stream,
const char *filename,
void sdfFlushBuffer(); SdfReader *reader,
Report *report) :
int yyFlexLexer(stream),
SdfParse_error(const char *msg) filename_(filename),
reader_(reader),
report_(report)
{ {
sdfFlushBuffer();
sta::sdf_reader->sdfError(196, "%s.\n", msg);
return 0;
} }
void
SdfScanner::error(const char *msg)
{
report_->fileError(1866, filename_, lineno(), "%s", msg);
}
////////////////////////////////////////////////////////////////
void
SdfParse::error(const location_type &loc,
const string &msg)
{
reader->report()->fileError(164,reader->filename(),loc.begin.line,"%s",msg.c_str());
}
} // namespace

View File

@ -24,7 +24,6 @@
#pragma once #pragma once
#include "Zlib.hh"
#include "Vector.hh" #include "Vector.hh"
#include "TimingRole.hh" #include "TimingRole.hh"
#include "Transition.hh" #include "Transition.hh"
@ -34,20 +33,12 @@
#include "SdcClass.hh" #include "SdcClass.hh"
#include "StaState.hh" #include "StaState.hh"
// Header for SdfReader.cc to communicate with SdfLex.cc, SdfParse.cc
// global namespace
#define YY_INPUT(buf,result,max_size) \
sta::sdf_reader->getChars(buf, result, max_size)
int
SdfParse_error(const char *msg);
namespace sta { namespace sta {
class Report; class Report;
class SdfTriple; class SdfTriple;
class SdfPortSpec; class SdfPortSpec;
class SdfScanner;
typedef Vector<SdfTriple*> SdfTripleSeq; typedef Vector<SdfTriple*> SdfTripleSeq;
@ -67,7 +58,8 @@ public:
bool read(); bool read();
void setDivider(char divider); void setDivider(char divider);
void setTimescale(float multiplier, const char *units); void setTimescale(float multiplier,
const string *units);
void setPortDeviceDelay(Edge *edge, void setPortDeviceDelay(Edge *edge,
SdfTripleSeq *triples, SdfTripleSeq *triples,
bool from_trans); bool from_trans);
@ -88,17 +80,17 @@ public:
int triple_index, int triple_index,
int arc_delay_index, int arc_delay_index,
const MinMax *min_max); const MinMax *min_max);
void setInstance(const char *instance_name); void setInstance(const string *instance_name);
void setInstanceWildcard(); void setInstanceWildcard();
void cellFinish(); void cellFinish();
void setCell(const char *cell_name); void setCell(const string *cell_name);
void interconnect(const char *from_pin_name, void interconnect(const string *from_pin_name,
const char *to_pin_name, const string *to_pin_name,
SdfTripleSeq *triples); SdfTripleSeq *triples);
void iopath(SdfPortSpec *from_edge, void iopath(SdfPortSpec *from_edge,
const char *to_port_name, const string *to_port_name,
SdfTripleSeq *triples, SdfTripleSeq *triples,
const char *cond, const string *cond,
bool condelse); bool condelse);
void timingCheck(TimingRole *role, void timingCheck(TimingRole *role,
SdfPortSpec *data_edge, SdfPortSpec *data_edge,
@ -126,10 +118,10 @@ public:
SdfPortSpec *clk_edge, SdfPortSpec *clk_edge,
SdfTriple *before_triple, SdfTriple *before_triple,
SdfTriple *after_triple); SdfTriple *after_triple);
void port(const char *to_pin_name, void port(const string *to_pin_name,
SdfTripleSeq *triples); SdfTripleSeq *triples);
void device(SdfTripleSeq *triples); void device(SdfTripleSeq *triples);
void device(const char *to_pin_name, void device(const string *to_pin_name,
SdfTripleSeq *triples); SdfTripleSeq *triples);
SdfTriple *makeTriple(); SdfTriple *makeTriple();
@ -141,29 +133,20 @@ public:
SdfTripleSeq *makeTripleSeq(); SdfTripleSeq *makeTripleSeq();
void deleteTripleSeq(SdfTripleSeq *triples); void deleteTripleSeq(SdfTripleSeq *triples);
SdfPortSpec *makePortSpec(Transition *tr, SdfPortSpec *makePortSpec(Transition *tr,
const char *port, const string *port,
const char *cond); const string *cond);
SdfPortSpec *makeCondPortSpec(const char *cond_port); SdfPortSpec *makeCondPortSpec(const string *cond_port);
const char *unescaped(const char *token); string *unescaped(const string *token);
char *makePath(const char *head, string *makePath(const string *head,
const char *tail); const string *tail);
// Parser state used to control lexer for COND handling. // Parser state used to control lexer for COND handling.
bool inTimingCheck() { return in_timing_check_; } bool inTimingCheck() { return in_timing_check_; }
void setInTimingCheck(bool in); void setInTimingCheck(bool in);
bool inIncremental() const { return in_incremental_; } bool inIncremental() const { return in_incremental_; }
void setInIncremental(bool incr); void setInIncremental(bool incr);
string *makeBusName(string *bus_name,
// flex YY_INPUT yy_n_chars arg changed definition from int to size_t, int index);
// 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_; } const char *filename() { return filename_; }
int line() { return line_; }
void sdfWarn(int id, void sdfWarn(int id,
const char *fmt, ...); const char *fmt, ...);
void sdfError(int id, void sdfError(int id,
@ -178,11 +161,11 @@ private:
Edge *findCheckEdge(Pin *from_pin, Edge *findCheckEdge(Pin *from_pin,
Pin *to_pin, Pin *to_pin,
TimingRole *sdf_role, TimingRole *sdf_role,
const char *cond_start, const string *cond_start,
const char *cond_end); const string *cond_end);
Edge *findWireEdge(Pin *from_pin, Edge *findWireEdge(Pin *from_pin,
Pin *to_pin); Pin *to_pin);
bool condMatch(const char *sdf_cond, bool condMatch(const string *sdf_cond,
const char *lib_cond); const char *lib_cond);
void timingCheck1(TimingRole *role, void timingCheck1(TimingRole *role,
Port *data_port, Port *data_port,
@ -197,18 +180,18 @@ private:
TimingRole *sdf_role, TimingRole *sdf_role,
SdfTriple *triple, SdfTriple *triple,
bool match_generic); bool match_generic);
void deletePortSpec(SdfPortSpec *edge); Pin *findPin(const string *name);
Pin *findPin(const char *name); Instance *findInstance(const string *name);
Instance *findInstance(const char *name);
void setEdgeDelays(Edge *edge, void setEdgeDelays(Edge *edge,
SdfTripleSeq *triples, SdfTripleSeq *triples,
const char *sdf_cmd); const char *sdf_cmd);
void setDevicePinDelays(Pin *to_pin, void setDevicePinDelays(Pin *to_pin,
SdfTripleSeq *triples); SdfTripleSeq *triples);
Port *findPort(const Cell *cell, Port *findPort(const Cell *cell,
const char *port_name); const string *port_name);
const char *filename_; const char *filename_;
SdfScanner *scanner_;
const char *path_; const char *path_;
// Which values to pull out of the sdf triples. // Which values to pull out of the sdf triples.
int triple_min_index_; int triple_min_index_;
@ -221,12 +204,10 @@ private:
bool is_incremental_only_; bool is_incremental_only_;
MinMaxAll *cond_use_; MinMaxAll *cond_use_;
int line_;
gzFile stream_;
char divider_; char divider_;
char escape_; char escape_;
Instance *instance_; Instance *instance_;
const char *cell_name_; const string *cell_name_;
bool in_timing_check_; bool in_timing_check_;
bool in_incremental_; bool in_incremental_;
float timescale_; float timescale_;
@ -234,6 +215,4 @@ private:
static const int null_index_ = -1; static const int null_index_ = -1;
}; };
extern SdfReader *sdf_reader;
} // namespace } // namespace

66
sdf/SdfScanner.hh Normal file
View File

@ -0,0 +1,66 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#ifndef __FLEX_LEXER_H
#undef yyFlexLexer
#define yyFlexLexer SdfFlexLexer
#include <FlexLexer.h>
#endif
#include "location.hh"
#include "SdfParse.hh"
namespace sta {
class Report;
class SdfScanner : public SdfFlexLexer
{
public:
SdfScanner(std::istream *stream,
const char *filename,
SdfReader *reader,
Report *report);
virtual ~SdfScanner() {}
virtual int lex(SdfParse::semantic_type *const yylval,
SdfParse::location_type *yylloc);
// YY_DECL defined in SdfLex.ll
// Method body created by flex in SdfLex.cc
void error(const char *msg);
// Get rid of override virtual function warning.
using FlexLexer::yylex;
private:
string token_;
const char *filename_;
SdfReader *reader_;
Report *report_;
};
} // namespace