852 lines
13 KiB
Plaintext
Executable File
852 lines
13 KiB
Plaintext
Executable File
// 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.
|
|
|
|
%{
|
|
#include <cstring>
|
|
|
|
#include "Report.hh"
|
|
#include "StringUtil.hh"
|
|
#include "StringSeq.hh"
|
|
#include "parasitics/SpefReaderPvt.hh"
|
|
#include "parasitics/SpefScanner.hh"
|
|
|
|
#undef yylex
|
|
#define yylex scanner->lex
|
|
|
|
// warning: variable 'yynerrs_' set but not used
|
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
|
|
|
void
|
|
sta::SpefParse::error(const location_type &loc,
|
|
const std::string &msg)
|
|
{
|
|
reader->report()->fileError(164,reader->filename(),
|
|
loc.begin.line,"%s",msg.c_str());
|
|
}
|
|
%}
|
|
|
|
%require "3.2"
|
|
%skeleton "lalr1.cc"
|
|
%debug
|
|
%define api.namespace {sta}
|
|
%locations
|
|
%define api.location.file "SpefLocation.hh"
|
|
%define parse.assert
|
|
%parse-param { SpefScanner *scanner }
|
|
%parse-param { SpefReader *reader }
|
|
%define api.parser.class {SpefParse}
|
|
|
|
%union {
|
|
char ch;
|
|
char *string;
|
|
int integer;
|
|
float number;
|
|
sta::StringSeq *string_seq;
|
|
sta::PortDirection *port_dir;
|
|
sta::SpefRspfPi *pi;
|
|
sta::SpefTriple *triple;
|
|
sta::Pin *pin;
|
|
sta::Net *net;
|
|
}
|
|
|
|
%token SPEF DESIGN DATE VENDOR PROGRAM DESIGN_FLOW
|
|
%token PVERSION DIVIDER DELIMITER
|
|
%token BUS_DELIMITER T_UNIT C_UNIT R_UNIT L_UNIT NAME_MAP
|
|
%token POWER_NETS GROUND_NETS KW_C KW_L KW_S KW_D KW_V
|
|
%token PORTS PHYSICAL_PORTS DEFINE PDEFINE
|
|
%token D_NET D_PNET R_NET R_PNET END
|
|
%token CONN CAP RES INDUC KW_P KW_I KW_N DRIVER CELL C2_R1_C1 LOADS
|
|
%token RC KW_Q KW_K
|
|
|
|
%token INTEGER FLOAT QSTRING INDEX IDENT NAME
|
|
|
|
%type <integer> INTEGER
|
|
%type <number> FLOAT
|
|
%type <string> QSTRING INDEX IDENT NAME
|
|
|
|
%type <integer> conf cap_id res_id induc_id cap_elem cap_elems
|
|
%type <integer> res_elem res_elems induc_elem induc_elems
|
|
%type <integer> pos_integer
|
|
|
|
%type <number> number pos_number threshold
|
|
%type <number> real_component imaginary_component pole poles
|
|
%type <number> residue residues complex_par_value cnumber
|
|
|
|
%type <string> name_or_index net_name net_names inst_name
|
|
%type <string> name_map_entries name_map_entry mapped_item
|
|
%type <string> physical_inst port_name pport_name port_entry pport_entry
|
|
%type <string> port_entries pport_entries pport
|
|
%type <string> entity external_connection
|
|
%type <string> cell_type
|
|
%type <string> driver_cell pnet_ref
|
|
%type <string> pexternal_connection internal_pdspf_node
|
|
%type <string> parasitic_node internal_parasitic_node
|
|
|
|
%type <ch> hchar suffix_bus_delim prefix_bus_delim
|
|
|
|
%type <string_seq> qstrings
|
|
%type<port_dir> direction
|
|
|
|
%type<triple> par_value total_cap
|
|
|
|
%type<pi> pi_model
|
|
|
|
%type<pin> pin_name driver_pair internal_connection
|
|
|
|
%type<net> net
|
|
|
|
%start file
|
|
|
|
%{
|
|
%}
|
|
|
|
%%
|
|
|
|
file:
|
|
header_def
|
|
name_map
|
|
power_def
|
|
external_def
|
|
define_def
|
|
internal_def
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
prefix_bus_delim:
|
|
'['
|
|
{ $$ = '['; }
|
|
| '{'
|
|
{ $$ = '}'; }
|
|
| '('
|
|
{ $$ = ')'; }
|
|
| '<'
|
|
{ $$ = '<'; }
|
|
;
|
|
|
|
suffix_bus_delim:
|
|
']'
|
|
{ $$ = ']'; }
|
|
| '}'
|
|
{ $$ = '}'; }
|
|
| ')'
|
|
{ $$ = ')'; }
|
|
| '>'
|
|
{ $$ = '>'; }
|
|
;
|
|
|
|
hchar:
|
|
'.'
|
|
{ $$ = '.'; }
|
|
| '/'
|
|
{ $$ = '/'; }
|
|
| '|'
|
|
{ $$ = '|'; }
|
|
| ':'
|
|
{ $$ = ':'; }
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
header_def:
|
|
spef_version
|
|
design_name
|
|
date
|
|
vendor
|
|
program_name
|
|
program_version
|
|
design_flow
|
|
hierarchy_div_def
|
|
pin_delim_def
|
|
bus_delim_def
|
|
unit_def
|
|
;
|
|
|
|
spef_version:
|
|
SPEF QSTRING
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
design_name:
|
|
DESIGN QSTRING
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
date:
|
|
DATE QSTRING
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
program_name:
|
|
PROGRAM QSTRING
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
program_version:
|
|
PVERSION QSTRING
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
vendor:
|
|
VENDOR QSTRING
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
design_flow:
|
|
DESIGN_FLOW qstrings
|
|
{ reader->setDesignFlow($2); }
|
|
;
|
|
|
|
qstrings:
|
|
QSTRING
|
|
{ $$ = new sta::StringSeq;
|
|
$$->push_back($1);
|
|
}
|
|
| qstrings QSTRING
|
|
{ $$->push_back($2); }
|
|
;
|
|
|
|
hierarchy_div_def:
|
|
DIVIDER hchar
|
|
{ reader->setDivider($2); }
|
|
;
|
|
|
|
pin_delim_def:
|
|
DELIMITER hchar
|
|
{ reader->setDelimiter($2); }
|
|
;
|
|
|
|
bus_delim_def:
|
|
BUS_DELIMITER prefix_bus_delim
|
|
{ reader->setBusBrackets($2, '\0'); }
|
|
| BUS_DELIMITER prefix_bus_delim suffix_bus_delim
|
|
{ reader->setBusBrackets($2, $3); }
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
unit_def:
|
|
time_scale
|
|
cap_scale
|
|
res_scale
|
|
induc_scale
|
|
;
|
|
|
|
time_scale:
|
|
T_UNIT pos_number IDENT
|
|
{ reader->setTimeScale($2, $3); }
|
|
;
|
|
|
|
cap_scale:
|
|
C_UNIT pos_number IDENT
|
|
{ reader->setCapScale($2, $3); }
|
|
;
|
|
|
|
res_scale:
|
|
R_UNIT pos_number IDENT
|
|
{ reader->setResScale($2, $3); }
|
|
;
|
|
|
|
induc_scale:
|
|
L_UNIT pos_number IDENT
|
|
{ reader->setInductScale($2, $3); }
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
name_map:
|
|
/* empty */
|
|
| NAME_MAP name_map_entries
|
|
;
|
|
|
|
name_map_entries:
|
|
name_map_entry
|
|
| name_map_entries name_map_entry
|
|
;
|
|
|
|
name_map_entry:
|
|
INDEX mapped_item
|
|
{ reader->makeNameMapEntry($1, $2); }
|
|
;
|
|
|
|
mapped_item:
|
|
IDENT
|
|
| NAME
|
|
| QSTRING
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
power_def:
|
|
/* empty */
|
|
| power_net_def
|
|
| ground_net_def
|
|
| power_net_def ground_net_def
|
|
;
|
|
|
|
power_net_def:
|
|
POWER_NETS net_names
|
|
;
|
|
|
|
ground_net_def:
|
|
GROUND_NETS net_names
|
|
;
|
|
|
|
net_names:
|
|
net_name
|
|
| net_names net_name
|
|
;
|
|
|
|
net_name:
|
|
name_or_index
|
|
{ sta::stringDelete($1); }
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
external_def:
|
|
/* empty */
|
|
| port_def
|
|
| physical_port_def
|
|
| port_def physical_port_def
|
|
;
|
|
|
|
port_def:
|
|
PORTS port_entries
|
|
;
|
|
|
|
port_entries:
|
|
port_entry
|
|
| port_entries port_entry
|
|
;
|
|
|
|
port_entry:
|
|
port_name direction conn_attrs
|
|
{ sta::stringDelete($1); }
|
|
;
|
|
|
|
direction:
|
|
IDENT
|
|
{ $$ = reader->portDirection($1);
|
|
sta::stringDelete($1);
|
|
}
|
|
;
|
|
|
|
port_name:
|
|
name_or_index
|
|
;
|
|
|
|
inst_name:
|
|
name_or_index
|
|
;
|
|
|
|
physical_port_def:
|
|
PHYSICAL_PORTS pport_entries
|
|
;
|
|
|
|
pport_entries:
|
|
pport_entry
|
|
| pport_entries pport_entry
|
|
;
|
|
|
|
pport_entry:
|
|
pport_name IDENT conn_attrs
|
|
;
|
|
|
|
pport_name:
|
|
name_or_index
|
|
{ sta::stringDelete($1); }
|
|
| physical_inst ':' pport
|
|
{ sta::stringDelete($1);
|
|
sta::stringDelete($3);
|
|
}
|
|
;
|
|
|
|
pport:
|
|
name_or_index
|
|
;
|
|
|
|
physical_inst:
|
|
name_or_index
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
conn_attrs:
|
|
/* empty */
|
|
| conn_attrs conn_attr
|
|
;
|
|
|
|
conn_attr:
|
|
coordinates
|
|
| cap_load
|
|
| slews
|
|
| driving_cell
|
|
;
|
|
|
|
coordinates:
|
|
KW_C number number
|
|
;
|
|
|
|
cap_load:
|
|
KW_L par_value
|
|
{ delete $2; }
|
|
;
|
|
|
|
par_value:
|
|
number
|
|
{ $$ = new sta::SpefTriple($1); }
|
|
| number ':' number ':' number
|
|
{ $$ = new sta::SpefTriple($1, $3, $5); }
|
|
;
|
|
|
|
slews:
|
|
KW_S par_value par_value
|
|
{ delete $2;
|
|
delete $3;
|
|
}
|
|
| KW_S par_value par_value threshold threshold
|
|
{ delete $2;
|
|
delete $3;
|
|
}
|
|
;
|
|
|
|
threshold:
|
|
pos_number
|
|
| pos_number ':' pos_number ':' pos_number
|
|
;
|
|
|
|
driving_cell:
|
|
KW_D cell_type
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
cell_type:
|
|
IDENT
|
|
| INDEX
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
define_def:
|
|
/* empty */
|
|
| define_def define_entry
|
|
;
|
|
|
|
define_entry:
|
|
DEFINE inst_name entity
|
|
{ sta::stringDelete($2);
|
|
sta::stringDelete($3);
|
|
}
|
|
| DEFINE inst_name inst_name entity
|
|
{ sta::stringDelete($2);
|
|
sta::stringDelete($3);
|
|
sta::stringDelete($4);
|
|
}
|
|
| PDEFINE physical_inst entity
|
|
{ sta::stringDelete($2);
|
|
sta::stringDelete($3);
|
|
}
|
|
;
|
|
|
|
entity:
|
|
QSTRING
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
internal_def:
|
|
nets
|
|
| internal_def nets
|
|
;
|
|
|
|
nets:
|
|
d_net
|
|
| r_net
|
|
| d_pnet
|
|
| r_pnet
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
d_net:
|
|
D_NET net total_cap
|
|
{ reader->dspfBegin($2, $3); }
|
|
routing_conf conn_sec cap_sec res_sec induc_sec END
|
|
{ reader->dspfFinish(); }
|
|
;
|
|
|
|
net:
|
|
name_or_index
|
|
{ $$ = reader->findNet($1);
|
|
sta::stringDelete($1);
|
|
}
|
|
;
|
|
|
|
total_cap:
|
|
par_value
|
|
;
|
|
|
|
routing_conf:
|
|
/* empty */
|
|
| KW_V conf
|
|
;
|
|
|
|
conf:
|
|
pos_integer
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
conn_sec:
|
|
/* empty */
|
|
| CONN conn_defs internal_node_coords
|
|
;
|
|
|
|
conn_defs:
|
|
conn_def
|
|
| conn_defs conn_def
|
|
;
|
|
|
|
conn_def:
|
|
KW_P external_connection direction conn_attrs
|
|
| KW_I internal_connection direction conn_attrs
|
|
;
|
|
|
|
external_connection:
|
|
name_or_index
|
|
{ sta::stringDelete($1); }
|
|
| physical_inst ':' pport
|
|
{ sta::stringDelete($1);
|
|
sta::stringDelete($3);
|
|
}
|
|
;
|
|
|
|
internal_connection:
|
|
pin_name
|
|
;
|
|
|
|
pin_name:
|
|
name_or_index
|
|
{ $$ = reader->findPin($1);
|
|
sta::stringDelete($1);
|
|
}
|
|
;
|
|
|
|
internal_node_coords:
|
|
/* empty */
|
|
| internal_node_coords internal_node_coord
|
|
;
|
|
|
|
internal_node_coord:
|
|
KW_N internal_parasitic_node coordinates
|
|
;
|
|
|
|
internal_parasitic_node:
|
|
name_or_index
|
|
{ sta::stringDelete($1); }
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
cap_sec:
|
|
/* empty */
|
|
| CAP cap_elems
|
|
;
|
|
|
|
cap_elems:
|
|
/* empty */
|
|
{ $$ = 0; }
|
|
| cap_elems cap_elem
|
|
;
|
|
|
|
cap_elem:
|
|
cap_id parasitic_node par_value
|
|
{ reader->makeCapacitor($1, $2, $3); }
|
|
| cap_id parasitic_node parasitic_node par_value
|
|
{ reader->makeCapacitor($1, $2, $3, $4); }
|
|
;
|
|
|
|
cap_id:
|
|
pos_integer
|
|
;
|
|
|
|
parasitic_node:
|
|
name_or_index
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
res_sec:
|
|
/* empty */
|
|
| RES res_elems
|
|
;
|
|
|
|
res_elems:
|
|
/* empty */
|
|
{ $$ = 0; }
|
|
| res_elems res_elem
|
|
;
|
|
|
|
res_elem:
|
|
res_id parasitic_node parasitic_node par_value
|
|
{ reader->makeResistor($1, $2, $3, $4); }
|
|
;
|
|
|
|
res_id:
|
|
pos_integer
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
induc_sec:
|
|
/* empty */
|
|
| INDUC induc_elems
|
|
;
|
|
|
|
induc_elems:
|
|
/* empty */
|
|
{ $$ = 0; }
|
|
| induc_elems induc_elem
|
|
;
|
|
|
|
induc_elem:
|
|
induc_id parasitic_node parasitic_node par_value
|
|
{ delete $4; }
|
|
;
|
|
|
|
induc_id:
|
|
pos_integer
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
r_net:
|
|
R_NET net total_cap
|
|
{ reader->rspfBegin($2, $3); }
|
|
routing_conf driver_reducs END
|
|
{ reader->rspfFinish(); }
|
|
;
|
|
|
|
driver_reducs:
|
|
/* empty */
|
|
| driver_reducs driver_reduc
|
|
;
|
|
|
|
driver_reduc:
|
|
driver_pair driver_cell pi_model
|
|
{ reader->rspfDrvrBegin($1, $3);
|
|
sta::stringDelete($2);
|
|
}
|
|
load_desc
|
|
{ reader->rspfDrvrFinish(); }
|
|
;
|
|
|
|
driver_pair:
|
|
DRIVER pin_name
|
|
{ $$ = $2; }
|
|
;
|
|
|
|
driver_cell:
|
|
CELL cell_type
|
|
{ $$ = $2; }
|
|
;
|
|
|
|
pi_model:
|
|
C2_R1_C1 par_value par_value par_value
|
|
{ $$ = new sta::SpefRspfPi($2, $3, $4); }
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
load_desc:
|
|
LOADS rc_descs
|
|
;
|
|
|
|
rc_descs:
|
|
rc_desc
|
|
| rc_descs rc_desc
|
|
;
|
|
|
|
rc_desc:
|
|
RC pin_name par_value
|
|
{ reader->rspfLoad($2, $3); }
|
|
| RC pin_name par_value pole_residue_desc
|
|
{ reader->rspfLoad($2, $3); }
|
|
;
|
|
|
|
pole_residue_desc:
|
|
pole_desc residue_desc
|
|
;
|
|
|
|
pole_desc:
|
|
KW_Q pos_integer poles
|
|
;
|
|
|
|
poles:
|
|
pole
|
|
| poles pole
|
|
;
|
|
|
|
pole:
|
|
complex_par_value
|
|
;
|
|
|
|
complex_par_value:
|
|
cnumber
|
|
| number
|
|
| cnumber ':' cnumber ':' cnumber
|
|
| number ':' number ':' number
|
|
;
|
|
|
|
cnumber:
|
|
'(' real_component imaginary_component ')'
|
|
{ $$ = $2; }
|
|
;
|
|
|
|
real_component:
|
|
number
|
|
;
|
|
|
|
imaginary_component:
|
|
number
|
|
;
|
|
|
|
residue_desc:
|
|
KW_K pos_integer residues
|
|
;
|
|
|
|
residues:
|
|
residue
|
|
| residues residue
|
|
;
|
|
|
|
residue:
|
|
complex_par_value
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
d_pnet:
|
|
D_PNET pnet_ref total_cap routing_conf pconn_sec cap_sec res_sec
|
|
induc_sec END
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
pnet_ref:
|
|
name_or_index
|
|
;
|
|
|
|
pconn_sec:
|
|
CONN pconn_defs internal_pnode_coords
|
|
;
|
|
|
|
pconn_defs:
|
|
pconn_def
|
|
| pconn_defs pconn_def
|
|
;
|
|
|
|
pconn_def:
|
|
KW_P pexternal_connection direction conn_attr
|
|
| KW_I internal_connection direction conn_attr
|
|
;
|
|
|
|
pexternal_connection:
|
|
pport_name
|
|
;
|
|
|
|
internal_pnode_coords:
|
|
/* empty */
|
|
| internal_pnode_coords internal_pnode_coord
|
|
;
|
|
|
|
internal_pnode_coord:
|
|
KW_N internal_pdspf_node coordinates
|
|
;
|
|
|
|
internal_pdspf_node:
|
|
name_or_index
|
|
{
|
|
sta::stringDelete($1);
|
|
$$ = 0;
|
|
}
|
|
;
|
|
|
|
name_or_index:
|
|
IDENT
|
|
| NAME
|
|
| INDEX
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
r_pnet:
|
|
R_PNET pnet_ref total_cap routing_conf END
|
|
{ sta::stringDelete($2); }
|
|
| R_PNET pnet_ref total_cap routing_conf pdriver_reduc END
|
|
{ sta::stringDelete($2); }
|
|
;
|
|
|
|
pdriver_reduc:
|
|
pdriver_pair driver_cell pi_model load_desc
|
|
;
|
|
|
|
pdriver_pair:
|
|
DRIVER internal_connection
|
|
;
|
|
|
|
/****************************************************************/
|
|
|
|
number:
|
|
INTEGER
|
|
{ $$ = static_cast<float>($1); }
|
|
| FLOAT
|
|
;
|
|
|
|
pos_integer:
|
|
INTEGER
|
|
{ int value = $1;
|
|
if (value < 0)
|
|
reader->warn(1525, "%d is not positive.", value);
|
|
$$ = value;
|
|
}
|
|
;
|
|
|
|
pos_number:
|
|
INTEGER
|
|
{ float value = static_cast<float>($1);
|
|
if (value < 0)
|
|
reader->warn(1526, "%.4f is not positive.", value);
|
|
$$ = value;
|
|
}
|
|
| FLOAT
|
|
{ float value = static_cast<float>($1);
|
|
if (value < 0)
|
|
reader->warn(1527, "%.4f is not positive.", value);
|
|
$$ = value;
|
|
}
|
|
;
|
|
|
|
%%
|