2017-02-12 13:21:08 +01:00
/*
KLayout Layout Viewer
2023-01-01 22:27:09 +01:00
Copyright ( C ) 2006 - 2023 Matthias Koefferlein
2017-02-12 13:21:08 +01:00
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 2 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 , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2018-06-13 23:59:39 +02:00
# include "dbLEFDEFImporter.h"
2020-04-19 16:54:41 +02:00
# include "dbLayoutUtils.h"
2020-06-13 15:39:41 +02:00
# include "dbTechnology.h"
2023-10-06 11:41:16 +02:00
# include "dbShapeProcessor.h"
2017-02-12 13:21:08 +01:00
# include "tlStream.h"
# include "tlProgress.h"
2020-04-19 16:54:41 +02:00
# include "tlFileUtils.h"
2017-02-12 13:21:08 +01:00
# include <cctype>
2018-06-13 23:59:39 +02:00
namespace db
2017-02-12 13:21:08 +01:00
{
2020-06-13 15:39:41 +02:00
// -----------------------------------------------------------------------------------
// Path resolution utility
2023-08-03 23:27:31 +02:00
std : : string correct_path ( const std : : string & fn_in , const db : : Layout & layout , const std : : string & base_path )
2020-06-13 15:39:41 +02:00
{
2023-08-03 23:27:31 +02:00
const db : : Technology * tech = layout . technology ( ) ;
// Allow LEF reference through expressions, i.e.
// $(base_path) - path of the main file
// $(tech_dir) - the location of the .lyt file if a technology is specified
// $(tech_name) - the name of the technology if one is specified
// In addition expressions are interpolated, e.g. "$(env('HOME'))".
tl : : Eval expr ;
expr . set_var ( " base_path " , base_path ) ;
if ( tech ) {
expr . set_var ( " tech_dir " , tech - > base_path ( ) ) ;
expr . set_var ( " tech_name " , tech - > name ( ) ) ;
}
std : : string fn = expr . interpolate ( fn_in ) ;
2020-06-13 15:39:41 +02:00
if ( ! tl : : is_absolute ( fn ) ) {
// if a technology is given and the file can be found in the technology's base path, take it
// from there.
if ( tech & & ! tech - > base_path ( ) . empty ( ) ) {
std : : string new_fn = tl : : combine_path ( tech - > base_path ( ) , fn ) ;
if ( tl : : file_exists ( new_fn ) ) {
return new_fn ;
}
}
if ( ! base_path . empty ( ) ) {
return tl : : combine_path ( base_path , fn ) ;
} else {
return fn ;
}
} else {
return fn ;
}
}
2020-07-25 22:15:09 +02:00
// -----------------------------------------------------------------------------------
// Utilities
static bool is_hex_digit ( char c )
{
char cup = toupper ( c ) ;
return ( cup > = ' A ' & & cup < = ' F ' ) | | ( c > = ' 0 ' & & c < = ' 9 ' ) ;
}
2020-08-22 21:15:39 +02:00
static unsigned int hex_value ( char c )
2020-07-25 22:15:09 +02:00
{
char cup = toupper ( c ) ;
if ( cup > = ' A ' & & cup < = ' F ' ) {
return ( cup - ' A ' ) + 10 ;
} else if ( c > = ' 0 ' & & c < = ' 9 ' ) {
return c - ' 0 ' ;
} else {
return 0 ;
}
}
2020-08-23 00:40:28 +02:00
std : : vector < unsigned int > string2masks ( const std : : string & s )
2020-08-22 21:15:39 +02:00
{
std : : vector < unsigned int > res ;
res . reserve ( s . size ( ) ) ;
for ( const char * cp = s . c_str ( ) ; * cp ; + + cp ) {
if ( ! is_hex_digit ( * cp ) ) {
throw tl : : Exception ( " Not a hex string: " + s ) ;
}
res . push_back ( hex_value ( * cp ) ) ;
}
2020-08-23 00:40:28 +02:00
std : : reverse ( res . begin ( ) , res . end ( ) ) ;
2020-08-22 21:15:39 +02:00
return res ;
}
static unsigned int mask ( const std : : vector < unsigned int > & masks , unsigned int index )
{
if ( index < ( unsigned int ) masks . size ( ) ) {
return masks [ index ] ;
} else {
return 0 ;
}
}
2021-02-21 21:00:55 +01:00
static std : : string purpose_to_name ( LayerPurpose purpose )
{
switch ( purpose ) {
case Outline :
return " OUTLINE " ;
case Regions :
return " REGION " ;
2022-04-23 22:26:37 +02:00
case RegionsGuide :
return " REGIONGUIDE " ;
case RegionsFence :
return " REGIONFENCE " ;
case RegionsNone :
return " REGIONNONE " ;
2021-02-21 21:00:55 +01:00
case PlacementBlockage :
return " BLOCKAGE " ;
case Routing :
return " NET " ;
case SpecialRouting :
return " SPNET " ;
case ViaGeometry :
return " VIA " ;
case Label :
return " LABEL " ;
2021-06-08 22:16:10 +02:00
case LEFLabel :
return " LEFLABEL " ;
2021-02-21 21:00:55 +01:00
case Pins :
return " PIN " ;
case Fills :
return " FILL " ;
case FillsOPC :
return " FILLOPC " ;
case LEFPins :
return " LEFPIN " ;
case Obstructions :
return " LEFOBS " ;
case Blockage :
return " BLK " ;
case All :
return " ALL " ;
2022-04-23 22:26:37 +02:00
default :
return std : : string ( ) ;
2021-02-21 21:00:55 +01:00
}
}
static std : : string
layer_spec_to_name ( const std : : string & layer_name , LayerPurpose purpose , unsigned int mask , const db : : DVector & via_size )
{
std : : string ps = purpose_to_name ( purpose ) ;
std : : string n = layer_name ;
if ( ! n . empty ( ) ) {
n + = " . " ;
}
n + = ps ;
if ( mask > 0 ) {
n + = " : " ;
n + = tl : : to_string ( mask ) ;
}
if ( via_size ! = db : : DVector ( ) ) {
n + = " :SIZE " ;
n + = tl : : sprintf ( " %.12gX%.12g " , via_size . x ( ) , via_size . y ( ) ) ;
}
return n ;
}
2020-07-25 22:15:09 +02:00
// -----------------------------------------------------------------------------------
// RuleBasedViaGenerator implementation
RuleBasedViaGenerator : : RuleBasedViaGenerator ( )
2020-08-22 21:15:39 +02:00
: LEFDEFLayoutGenerator ( ) , m_bottom_mask ( 0 ) , m_cut_mask ( 0 ) , m_top_mask ( 0 ) , m_rows ( 1 ) , m_columns ( 1 )
2020-07-25 22:15:09 +02:00
{ }
void
2020-08-23 18:58:52 +02:00
RuleBasedViaGenerator : : create_cell ( LEFDEFReaderState & reader , Layout & layout , db : : Cell & cell , const std : : vector < std : : string > * maskshift_layers , const std : : vector < unsigned int > & masks , const LEFDEFNumberOfMasks * nm )
2020-07-25 22:15:09 +02:00
{
2020-08-23 18:58:52 +02:00
// will not be used with an external maskshift layer stack
tl_assert ( maskshift_layers = = 0 ) ;
2020-08-22 21:15:39 +02:00
unsigned int mask_bottom = mask ( masks , 0 ) , mask_cut = mask ( masks , 1 ) , mask_top = mask ( masks , 2 ) ;
2020-07-25 22:15:09 +02:00
if ( mask_bottom = = 0 ) {
mask_bottom = m_bottom_mask ;
}
if ( mask_cut = = 0 ) {
mask_cut = m_cut_mask ;
}
if ( mask_top = = 0 ) {
mask_top = m_top_mask ;
}
unsigned int num_cut_masks = nm ? nm - > number_of_masks ( m_cut_layer ) : 1 ;
// NOTE: missing cuts due to pattern holes don't change mask assignment
db : : Vector vs ( ( m_cutsize . x ( ) * m_columns + m_cutspacing . x ( ) * ( m_columns - 1 ) ) / 2 , ( m_cutsize . y ( ) * m_rows + m_cutspacing . y ( ) * ( m_rows - 1 ) ) / 2 ) ;
db : : Box via_box ( m_offset - vs , m_offset + vs ) ;
2020-12-19 19:42:40 +01:00
std : : set < unsigned int > dl ;
2020-07-25 22:15:09 +02:00
2023-10-19 22:02:22 +02:00
dl = reader . open_layer ( layout , m_bottom_layer , ViaGeometry , mask_bottom ) ;
2020-12-19 19:42:40 +01:00
for ( std : : set < unsigned int > : : const_iterator l = dl . begin ( ) ; l ! = dl . end ( ) ; + + l ) {
cell . shapes ( * l ) . insert ( db : : Polygon ( via_box . enlarged ( m_be ) . moved ( m_bo ) ) ) ;
2020-07-25 22:15:09 +02:00
}
2023-10-19 22:02:22 +02:00
dl = reader . open_layer ( layout , m_top_layer , ViaGeometry , mask_top ) ;
2020-12-19 19:42:40 +01:00
for ( std : : set < unsigned int > : : const_iterator l = dl . begin ( ) ; l ! = dl . end ( ) ; + + l ) {
2022-04-23 22:26:37 +02:00
cell . shapes ( * l ) . insert ( db : : Polygon ( via_box . enlarged ( m_te ) . moved ( m_to ) ) ) ;
2020-07-25 22:15:09 +02:00
}
const char * p = m_pattern . c_str ( ) ;
int rp = m_pattern . empty ( ) ? - 1 : 0 ;
const char * p0 = p , * p1 = p ;
for ( int r = 0 ; r < m_rows ; + + r ) {
if ( rp = = 0 ) {
if ( * p ) {
// read a new row specification
rp = 0 ;
while ( * p & & is_hex_digit ( * p ) ) {
rp = ( rp * 16 ) + hex_value ( * p + + ) ;
}
if ( * p = = ' _ ' ) {
+ + p ;
}
p0 = p ;
if ( * p ) {
while ( * p & & ( is_hex_digit ( * p ) | | toupper ( * p ) = = ' R ' ) ) {
+ + p ;
}
}
p1 = p ;
if ( * p = = ' _ ' ) {
+ + p ;
}
}
}
if ( rp ! = 0 ) {
if ( rp > 0 ) {
- - rp ;
}
const char * pp = p0 ;
unsigned int d = 0 ;
int cp = ( p = = p0 ? - 1 : 0 ) ;
int bit = 0 ;
for ( int c = 0 ; c < m_columns ; + + c ) {
if ( cp = = 0 ) {
d = 0 ;
cp = 4 ;
bit = 0 ;
if ( * pp & & pp < p1 & & toupper ( * pp ) = = ' R ' ) {
+ + pp ;
if ( * pp & & pp < p1 ) {
cp = 4 * hex_value ( * pp + + ) ;
if ( * pp & & pp < p1 ) {
d = ( unsigned int ) hex_value ( * pp + + ) ;
}
}
} else if ( * pp & & pp < p1 ) {
d = ( unsigned int ) hex_value ( * pp + + ) ;
}
if ( cp > 0 ) {
- - cp ;
}
} else if ( cp > 0 ) {
- - cp ;
} else {
d = 0xf ;
}
if ( ( d & ( 0x8 > > ( bit + + % 4 ) ) ) ! = 0 ) {
db : : Vector vbl ( ( m_cutsize + m_cutspacing ) . x ( ) * c , ( m_cutsize + m_cutspacing ) . y ( ) * r ) ;
db : : Box vb ( via_box . lower_left ( ) + vbl , via_box . lower_left ( ) + vbl + m_cutsize ) ;
unsigned int cm = 0 ;
if ( mask_cut > 0 ) {
// This is the core algorithm for mask assignment in patterned vias
cm = ( mask_cut + r + c - 1 ) % num_cut_masks + 1 ;
}
2021-02-21 21:00:55 +01:00
dl = reader . open_layer ( layout , m_cut_layer , ViaGeometry , cm , vb ) ;
2020-12-19 19:42:40 +01:00
for ( std : : set < unsigned int > : : const_iterator l = dl . begin ( ) ; l ! = dl . end ( ) ; + + l ) {
cell . shapes ( * l ) . insert ( db : : Polygon ( vb ) ) ;
2020-07-25 22:15:09 +02:00
}
}
}
}
}
}
// -----------------------------------------------------------------------------------
// GeometryBasedViaGenerator implementation
2020-08-22 21:15:39 +02:00
GeometryBasedLayoutGenerator : : GeometryBasedLayoutGenerator ( )
2020-08-23 18:58:52 +02:00
: LEFDEFLayoutGenerator ( ) , m_fixedmask ( false )
{
// .. nothing yet ..
}
2020-07-25 22:15:09 +02:00
2020-07-27 23:13:15 +02:00
unsigned int
2020-08-23 18:58:52 +02:00
GeometryBasedLayoutGenerator : : get_maskshift ( const std : : string & ln , const std : : vector < std : : string > * msl , const std : : vector < unsigned int > & masks )
2020-07-27 23:13:15 +02:00
{
2020-08-23 18:58:52 +02:00
if ( ! msl ) {
msl = & m_maskshift_layers ;
}
2020-08-18 23:02:01 +02:00
2020-08-23 18:58:52 +02:00
for ( std : : vector < std : : string > : : const_iterator l = msl - > begin ( ) ; l ! = msl - > end ( ) ; + + l ) {
2020-08-23 00:40:28 +02:00
if ( ! l - > empty ( ) & & * l = = ln ) {
2020-08-23 18:58:52 +02:00
return mask ( masks , ( unsigned int ) ( l - msl - > begin ( ) ) ) ;
2020-08-18 23:02:01 +02:00
}
2020-08-23 18:58:52 +02:00
}
2020-08-18 23:02:01 +02:00
2020-08-23 18:58:52 +02:00
return 0 ;
}
unsigned int
GeometryBasedLayoutGenerator : : mask_for ( const std : : string & ln , unsigned int m , unsigned int mshift , const LEFDEFNumberOfMasks * nm ) const
{
// for FIXEDMASK we don't do any mask shifting
2020-08-23 19:20:53 +02:00
if ( m_fixedmask | | mshift = = 0 ) {
2020-08-23 18:58:52 +02:00
return m ;
2020-08-23 19:20:53 +02:00
} else if ( m = = 0 ) {
return mshift ;
2020-08-23 18:58:52 +02:00
} else {
return ( m + mshift - 2 ) % nm - > number_of_masks ( ln ) + 1 ;
2020-07-27 23:13:15 +02:00
}
2020-08-23 18:58:52 +02:00
}
2020-07-27 23:13:15 +02:00
2020-08-23 18:58:52 +02:00
unsigned int
GeometryBasedLayoutGenerator : : combine_maskshifts ( const std : : string & ln , unsigned int mshift1 , unsigned int mshift2 , const LEFDEFNumberOfMasks * nm ) const
{
if ( mshift1 = = 0 | | mshift2 = = 0 ) {
return mshift1 + mshift2 ;
} else {
return ( mshift1 + mshift2 - 2 ) % nm - > number_of_masks ( ln ) + 1 ;
}
2020-07-27 23:13:15 +02:00
}
2020-07-25 22:15:09 +02:00
void
2020-08-23 18:58:52 +02:00
GeometryBasedLayoutGenerator : : create_cell ( LEFDEFReaderState & reader , Layout & layout , db : : Cell & cell , const std : : vector < std : : string > * ext_msl , const std : : vector < unsigned int > & masks , const LEFDEFNumberOfMasks * nm )
2020-07-25 22:15:09 +02:00
{
2021-02-21 21:00:55 +01:00
for ( std : : map < std : : pair < std : : string , LayerDetailsKey > , db : : Shapes > : : const_iterator g = m_shapes . begin ( ) ; g ! = m_shapes . end ( ) ; + + g ) {
2020-08-23 18:58:52 +02:00
unsigned int mshift = get_maskshift ( g - > first . first , ext_msl , masks ) ;
2021-02-21 21:00:55 +01:00
unsigned int mask = mask_for ( g - > first . first , g - > first . second . mask , mshift , nm ) ;
2020-08-23 18:58:52 +02:00
2021-02-21 21:00:55 +01:00
std : : set < unsigned int > dl = reader . open_layer ( layout , g - > first . first , g - > first . second . purpose , mask , g - > first . second . via_size ) ;
2020-12-19 19:42:40 +01:00
for ( std : : set < unsigned int > : : const_iterator l = dl . begin ( ) ; l ! = dl . end ( ) ; + + l ) {
cell . shapes ( * l ) . insert ( g - > second ) ;
2020-07-25 22:15:09 +02:00
}
2020-08-23 18:58:52 +02:00
2020-07-25 22:15:09 +02:00
}
2020-07-25 22:54:25 +02:00
2020-08-23 00:40:28 +02:00
for ( std : : list < Via > : : const_iterator v = m_vias . begin ( ) ; v ! = m_vias . end ( ) ; + + v ) {
2022-04-23 22:26:37 +02:00
LEFDEFLayoutGenerator * g = reader . via_generator ( v - > name , v - > nondefaultrule ) ;
2020-08-23 00:40:28 +02:00
if ( ! g ) {
continue ;
2020-07-25 22:54:25 +02:00
}
2020-08-23 00:40:28 +02:00
std : : vector < std : : string > msl = g - > maskshift_layers ( ) ;
msl . resize ( 3 , std : : string ( ) ) ;
2020-08-23 18:58:52 +02:00
unsigned mshift_bottom = get_maskshift ( msl [ 0 ] , ext_msl , masks ) ;
unsigned mshift_cut = get_maskshift ( msl [ 1 ] , ext_msl , masks ) ;
unsigned mshift_top = get_maskshift ( msl [ 2 ] , ext_msl , masks ) ;
2022-04-23 22:26:37 +02:00
db : : Cell * vc = reader . via_cell ( v - > name , v - > nondefaultrule , layout ,
2020-08-23 18:58:52 +02:00
combine_maskshifts ( msl [ 0 ] , v - > bottom_mask , mshift_bottom , nm ) ,
combine_maskshifts ( msl [ 1 ] , v - > cut_mask , mshift_cut , nm ) ,
combine_maskshifts ( msl [ 2 ] , v - > top_mask , mshift_top , nm ) ,
2020-08-23 00:40:28 +02:00
nm ) ;
if ( vc ) {
cell . insert ( db : : CellInstArray ( db : : CellInst ( vc - > cell_index ( ) ) , v - > trans ) ) ;
}
}
}
template < class Shape >
static db : : Shape insert_shape ( db : : Shapes & shapes , const Shape & shape , db : : properties_id_type prop_id )
{
if ( prop_id = = 0 ) {
return shapes . insert ( shape ) ;
} else {
return shapes . insert ( db : : object_with_properties < Shape > ( shape , prop_id ) ) ;
2020-07-25 22:54:25 +02:00
}
2020-07-25 22:15:09 +02:00
}
void
2021-02-21 21:00:55 +01:00
GeometryBasedLayoutGenerator : : add_polygon ( const std : : string & ln , LayerPurpose purpose , const db : : Polygon & poly , unsigned int mask , db : : properties_id_type prop_id , const db : : DVector & via_size )
2020-07-25 22:15:09 +02:00
{
2021-02-21 21:00:55 +01:00
insert_shape ( m_shapes [ std : : make_pair ( ln , LayerDetailsKey ( purpose , mask , via_size ) ) ] , poly , prop_id ) ;
2020-07-25 22:54:25 +02:00
}
void
2021-02-21 21:00:55 +01:00
GeometryBasedLayoutGenerator : : add_box ( const std : : string & ln , LayerPurpose purpose , const db : : Box & box , unsigned int mask , db : : properties_id_type prop_id , const db : : DVector & via_size )
2020-07-25 22:54:25 +02:00
{
2021-02-21 21:00:55 +01:00
insert_shape ( m_shapes [ std : : make_pair ( ln , LayerDetailsKey ( purpose , mask , via_size ) ) ] , box , prop_id ) ;
2020-08-23 00:40:28 +02:00
}
void
2021-02-21 21:00:55 +01:00
GeometryBasedLayoutGenerator : : add_path ( const std : : string & ln , LayerPurpose purpose , const db : : Path & path , unsigned int mask , db : : properties_id_type prop_id , const db : : DVector & via_size )
2020-08-23 00:40:28 +02:00
{
2021-02-21 21:00:55 +01:00
insert_shape ( m_shapes [ std : : make_pair ( ln , LayerDetailsKey ( purpose , mask , via_size ) ) ] , path , prop_id ) ;
2020-08-23 00:40:28 +02:00
}
void
GeometryBasedLayoutGenerator : : add_text ( const std : : string & ln , LayerPurpose purpose , const db : : Text & text , unsigned int mask , db : : properties_id_type prop_id )
{
2021-02-21 21:00:55 +01:00
insert_shape ( m_shapes [ std : : make_pair ( ln , LayerDetailsKey ( purpose , mask ) ) ] , text , prop_id ) ;
2020-08-23 00:40:28 +02:00
}
void
GeometryBasedLayoutGenerator : : add_via ( const std : : string & vn , const db : : Trans & trans , unsigned int bottom_mask , unsigned int cut_mask , unsigned int top_mask )
{
m_vias . push_back ( Via ( ) ) ;
m_vias . back ( ) . name = vn ;
m_vias . back ( ) . trans = trans ;
m_vias . back ( ) . bottom_mask = bottom_mask ;
m_vias . back ( ) . cut_mask = cut_mask ;
m_vias . back ( ) . top_mask = top_mask ;
2020-07-25 22:15:09 +02:00
}
2023-10-06 11:41:16 +02:00
void
GeometryBasedLayoutGenerator : : subtract_overlap_from_outline ( const std : : set < std : : string > & overlap_layers )
{
db : : Shapes all_overlaps ;
std : : vector < std : : map < std : : pair < std : : string , LayerDetailsKey > , db : : Shapes > : : iterator > to_remove ;
for ( auto s = m_shapes . begin ( ) ; s ! = m_shapes . end ( ) ; + + s ) {
if ( overlap_layers . find ( s - > first . first ) ! = overlap_layers . end ( ) ) {
all_overlaps . insert ( s - > second ) ;
to_remove . push_back ( s ) ;
}
}
for ( auto i = to_remove . begin ( ) ; i ! = to_remove . end ( ) ; + + i ) {
m_shapes . erase ( * i ) ;
}
if ( all_overlaps . empty ( ) ) {
return ;
}
for ( auto s = m_shapes . begin ( ) ; s ! = m_shapes . end ( ) ; + + s ) {
if ( s - > first . second . purpose ! = Outline ) {
continue ;
}
db : : ShapeProcessor proc ;
size_t pn = 0 ;
for ( auto sh = s - > second . begin ( db : : ShapeIterator : : All ) ; ! sh . at_end ( ) ; + + sh ) {
proc . insert ( * sh , pn ) ;
pn + = 2 ;
}
pn = 1 ;
for ( auto sh = all_overlaps . begin ( db : : ShapeIterator : : All ) ; ! sh . at_end ( ) ; + + sh ) {
proc . insert ( * sh , pn ) ;
pn + = 2 ;
}
2023-10-17 20:49:37 +02:00
db : : BooleanOp op ( db : : BooleanOp : : And ) ;
2023-10-06 11:41:16 +02:00
db : : ShapeGenerator sg ( s - > second , true /*clear shapes*/ ) ;
db : : PolygonGenerator out ( sg , true , true ) ;
proc . process ( out , op ) ;
}
}
2017-02-12 13:21:08 +01:00
// -----------------------------------------------------------------------------------
// LEFDEFTechnologyComponent implementation
LEFDEFReaderOptions : : LEFDEFReaderOptions ( )
: m_read_all_layers ( true ) ,
m_dbu ( 0.001 ) ,
m_produce_net_names ( true ) ,
m_net_property_name ( 1 ) ,
2017-09-04 23:05:46 +02:00
m_produce_inst_names ( true ) ,
m_inst_property_name ( 1 ) ,
2020-02-23 00:29:12 +01:00
m_produce_pin_names ( false ) ,
m_pin_property_name ( 1 ) ,
2017-02-12 13:21:08 +01:00
m_produce_cell_outlines ( true ) ,
m_cell_outline_layer ( " OUTLINE " ) ,
m_produce_placement_blockages ( true ) ,
m_placement_blockage_layer ( " PLACEMENT_BLK " ) ,
2017-09-04 23:05:46 +02:00
m_produce_regions ( true ) ,
m_region_layer ( " REGIONS " ) ,
2017-02-12 13:21:08 +01:00
m_produce_via_geometry ( true ) ,
m_via_geometry_suffix ( " " ) ,
m_via_geometry_datatype ( 0 ) ,
2020-04-18 17:58:50 +02:00
m_via_cellname_prefix ( " VIA_ " ) ,
2017-02-12 13:21:08 +01:00
m_produce_pins ( true ) ,
m_pins_suffix ( " .PIN " ) ,
m_pins_datatype ( 2 ) ,
2020-04-19 14:38:14 +02:00
m_produce_lef_pins ( true ) ,
m_lef_pins_suffix ( " .PIN " ) ,
m_lef_pins_datatype ( 2 ) ,
2021-02-21 17:28:58 +01:00
m_produce_fills ( true ) ,
m_fills_suffix ( " .FILL " ) ,
m_fills_datatype ( 5 ) ,
2017-02-12 13:21:08 +01:00
m_produce_obstructions ( true ) ,
m_obstructions_suffix ( " .OBS " ) ,
m_obstructions_datatype ( 3 ) ,
m_produce_blockages ( true ) ,
m_blockages_suffix ( " .BLK " ) ,
m_blockages_datatype ( 4 ) ,
m_produce_labels ( true ) ,
m_labels_suffix ( " .LABEL " ) ,
m_labels_datatype ( 1 ) ,
2021-06-08 22:16:10 +02:00
m_produce_lef_labels ( true ) ,
m_lef_labels_suffix ( " .LABEL " ) ,
m_lef_labels_datatype ( 1 ) ,
2017-02-12 13:21:08 +01:00
m_produce_routing ( true ) ,
m_routing_suffix ( " " ) ,
2020-04-18 17:58:50 +02:00
m_routing_datatype ( 0 ) ,
2020-04-19 14:38:14 +02:00
m_produce_special_routing ( true ) ,
m_special_routing_suffix ( " " ) ,
m_special_routing_datatype ( 0 ) ,
2020-04-19 16:54:41 +02:00
m_separate_groups ( false ) ,
2023-04-30 14:47:52 +02:00
m_joined_paths ( false ) ,
2020-05-02 00:14:06 +02:00
m_map_file ( ) ,
2022-03-05 14:57:09 +01:00
m_macro_resolution_mode ( 0 ) ,
m_read_lef_with_def ( true ) ,
m_paths_relative_to_cwd ( false )
2017-02-12 13:21:08 +01:00
{
// .. nothing yet ..
}
LEFDEFReaderOptions : : LEFDEFReaderOptions ( const LEFDEFReaderOptions & d )
2020-05-31 21:50:10 +02:00
: db : : FormatSpecificReaderOptions ( )
2017-02-12 13:21:08 +01:00
{
2020-05-31 21:50:10 +02:00
operator = ( d ) ;
}
LEFDEFReaderOptions & LEFDEFReaderOptions : : operator = ( const LEFDEFReaderOptions & d )
{
if ( this ! = & d ) {
db : : FormatSpecificReaderOptions : : operator = ( d ) ;
m_read_all_layers = d . m_read_all_layers ;
m_layer_map = d . m_layer_map ;
m_dbu = d . m_dbu ;
m_produce_net_names = d . m_produce_net_names ;
m_net_property_name = d . m_net_property_name ;
m_produce_inst_names = d . m_produce_inst_names ;
m_inst_property_name = d . m_inst_property_name ;
m_produce_pin_names = d . m_produce_pin_names ;
m_pin_property_name = d . m_pin_property_name ;
m_produce_cell_outlines = d . m_produce_cell_outlines ;
m_cell_outline_layer = d . m_cell_outline_layer ;
m_produce_placement_blockages = d . m_produce_placement_blockages ;
m_placement_blockage_layer = d . m_placement_blockage_layer ;
m_produce_regions = d . m_produce_regions ;
m_region_layer = d . m_region_layer ;
m_produce_via_geometry = d . m_produce_via_geometry ;
m_via_geometry_suffix = d . m_via_geometry_suffix ;
2020-07-18 22:28:14 +02:00
m_via_geometry_suffixes = d . m_via_geometry_suffixes ;
2020-05-31 21:50:10 +02:00
m_via_geometry_datatype = d . m_via_geometry_datatype ;
2020-07-18 22:28:14 +02:00
m_via_geometry_datatypes = d . m_via_geometry_datatypes ;
2020-06-01 13:37:45 +02:00
m_via_cellname_prefix = d . m_via_cellname_prefix ;
2020-05-31 21:50:10 +02:00
m_produce_pins = d . m_produce_pins ;
m_pins_suffix = d . m_pins_suffix ;
2020-07-18 22:28:14 +02:00
m_pins_suffixes = d . m_pins_suffixes ;
2020-05-31 21:50:10 +02:00
m_pins_datatype = d . m_pins_datatype ;
2020-07-18 22:28:14 +02:00
m_pins_datatypes = d . m_pins_datatypes ;
2020-06-01 13:37:45 +02:00
m_produce_lef_pins = d . m_produce_lef_pins ;
m_lef_pins_suffix = d . m_lef_pins_suffix ;
2020-07-18 22:28:14 +02:00
m_lef_pins_suffixes = d . m_lef_pins_suffixes ;
2020-06-01 13:37:45 +02:00
m_lef_pins_datatype = d . m_lef_pins_datatype ;
2020-07-18 22:28:14 +02:00
m_lef_pins_datatypes = d . m_lef_pins_datatypes ;
2021-02-21 17:28:58 +01:00
m_produce_fills = d . m_produce_fills ;
m_fills_suffix = d . m_fills_suffix ;
m_fills_suffixes = d . m_fills_suffixes ;
m_fills_datatype = d . m_fills_datatype ;
m_fills_datatypes = d . m_fills_datatypes ;
2020-05-31 21:50:10 +02:00
m_produce_obstructions = d . m_produce_obstructions ;
m_obstructions_suffix = d . m_obstructions_suffix ;
m_obstructions_datatype = d . m_obstructions_datatype ;
m_produce_blockages = d . m_produce_blockages ;
m_blockages_suffix = d . m_blockages_suffix ;
m_blockages_datatype = d . m_blockages_datatype ;
m_produce_labels = d . m_produce_labels ;
m_labels_suffix = d . m_labels_suffix ;
m_labels_datatype = d . m_labels_datatype ;
2021-06-08 22:16:10 +02:00
m_produce_lef_labels = d . m_produce_lef_labels ;
m_lef_labels_suffix = d . m_lef_labels_suffix ;
m_lef_labels_datatype = d . m_lef_labels_datatype ;
2020-05-31 21:50:10 +02:00
m_produce_routing = d . m_produce_routing ;
m_routing_suffix = d . m_routing_suffix ;
2020-07-18 22:28:14 +02:00
m_routing_suffixes = d . m_routing_suffixes ;
2020-05-31 21:50:10 +02:00
m_routing_datatype = d . m_routing_datatype ;
2020-07-18 22:28:14 +02:00
m_routing_datatypes = d . m_routing_datatypes ;
2020-06-01 13:37:45 +02:00
m_produce_special_routing = d . m_produce_special_routing ;
m_special_routing_suffix = d . m_special_routing_suffix ;
2020-07-18 22:28:14 +02:00
m_special_routing_suffixes = d . m_special_routing_suffixes ;
2020-06-01 13:37:45 +02:00
m_special_routing_datatype = d . m_special_routing_datatype ;
2020-07-18 22:28:14 +02:00
m_special_routing_datatypes = d . m_special_routing_datatypes ;
2020-06-01 13:37:45 +02:00
m_separate_groups = d . m_separate_groups ;
2023-04-30 14:47:52 +02:00
m_joined_paths = d . m_joined_paths ;
2020-06-01 13:37:45 +02:00
m_map_file = d . m_map_file ;
m_macro_resolution_mode = d . m_macro_resolution_mode ;
2020-05-31 21:50:10 +02:00
m_lef_files = d . m_lef_files ;
2021-05-04 22:56:03 +02:00
m_macro_layout_files = d . m_macro_layout_files ;
2020-08-19 23:06:46 +02:00
m_read_lef_with_def = d . m_read_lef_with_def ;
2022-03-05 14:57:09 +01:00
m_paths_relative_to_cwd = d . m_paths_relative_to_cwd ;
2020-08-30 01:37:14 +02:00
set_macro_layouts ( d . macro_layouts ( ) ) ;
2020-05-31 21:50:10 +02:00
}
return * this ;
2017-02-12 13:21:08 +01:00
}
db : : FormatSpecificReaderOptions *
LEFDEFReaderOptions : : clone ( ) const
{
return new LEFDEFReaderOptions ( * this ) ;
}
const std : : string &
LEFDEFReaderOptions : : format_name ( ) const
{
static const std : : string n ( " LEFDEF " ) ;
return n ;
}
2020-07-18 22:28:14 +02:00
static void set_datatypes ( db : : LEFDEFReaderOptions * data , void ( db : : LEFDEFReaderOptions : : * clear ) ( ) , void ( db : : LEFDEFReaderOptions : : * set_datatype ) ( int datatype ) , void ( db : : LEFDEFReaderOptions : : * set_datatype_per_mask ) ( unsigned int mask , int datatype ) , const std : : string & s )
{
( data - > * clear ) ( ) ;
2022-02-28 20:30:08 +01:00
( data - > * set_datatype ) ( - 1 ) ;
2020-07-18 22:28:14 +02:00
tl : : Extractor ex ( s . c_str ( ) ) ;
while ( ! ex . at_end ( ) ) {
tl : : Extractor ex_saved = ex ;
unsigned int mask = 0 ;
if ( ex . try_read ( mask ) & & ex . test ( " : " ) ) {
int dt = 0 ;
ex . read ( dt ) ;
2020-07-27 23:13:15 +02:00
( data - > * set_datatype_per_mask ) ( std : : max ( ( unsigned int ) 1 , mask ) , dt ) ;
2020-07-18 22:28:14 +02:00
} else {
ex = ex_saved ;
int dt = 0 ;
ex . read ( dt ) ;
( data - > * set_datatype ) ( dt ) ;
}
if ( ex . at_end ( ) ) {
break ;
} else {
ex . expect ( " , " ) ;
}
}
}
static void set_suffixes ( db : : LEFDEFReaderOptions * data , void ( db : : LEFDEFReaderOptions : : * clear ) ( ) , void ( db : : LEFDEFReaderOptions : : * set_suffix ) ( const std : : string & suffix ) , void ( db : : LEFDEFReaderOptions : : * set_suffix_per_mask ) ( unsigned int mask , const std : : string & suffix ) , const std : : string & s )
{
( data - > * clear ) ( ) ;
2022-02-28 20:30:08 +01:00
( data - > * set_suffix ) ( std : : string ( ) ) ;
2020-07-18 22:28:14 +02:00
tl : : Extractor ex ( s . c_str ( ) ) ;
while ( ! ex . at_end ( ) ) {
tl : : Extractor ex_saved = ex ;
unsigned int mask = 0 ;
if ( ex . try_read ( mask ) & & ex . test ( " : " ) ) {
std : : string sfx ;
ex . read_word_or_quoted ( sfx ) ;
2020-07-27 23:13:15 +02:00
( data - > * set_suffix_per_mask ) ( std : : max ( ( unsigned int ) 1 , mask ) , sfx ) ;
2020-07-18 22:28:14 +02:00
} else {
ex = ex_saved ;
std : : string sfx ;
ex . read_word_or_quoted ( sfx ) ;
( data - > * set_suffix ) ( sfx ) ;
}
if ( ex . at_end ( ) ) {
break ;
} else {
ex . expect ( " , " ) ;
}
}
}
static std : : string get_datatypes ( const db : : LEFDEFReaderOptions * data , int ( db : : LEFDEFReaderOptions : : * get_datatype ) ( ) const , int ( db : : LEFDEFReaderOptions : : * get_datatype_per_mask ) ( unsigned int mask ) const , unsigned int max_mask )
{
std : : string res ;
int dt0 = ( data - > * get_datatype ) ( ) ;
if ( dt0 > = 0 ) {
res + = tl : : to_string ( dt0 ) ;
}
for ( unsigned int i = 0 ; i < = max_mask ; + + i ) {
int dt = ( data - > * get_datatype_per_mask ) ( i ) ;
if ( dt > = 0 & & dt ! = dt0 ) {
if ( ! res . empty ( ) ) {
res + = " , " ;
}
2020-07-27 23:13:15 +02:00
res + = tl : : to_string ( i ) ;
2020-07-18 22:28:14 +02:00
res + = " : " ;
res + = tl : : to_string ( dt ) ;
}
}
return res ;
}
static std : : string get_suffixes ( const db : : LEFDEFReaderOptions * data , const std : : string & ( db : : LEFDEFReaderOptions : : * get_suffix ) ( ) const , const std : : string & ( db : : LEFDEFReaderOptions : : * get_suffix_per_mask ) ( unsigned int mask ) const , unsigned int max_mask )
{
std : : string res ;
std : : string sfx0 = ( data - > * get_suffix ) ( ) ;
if ( ! sfx0 . empty ( ) ) {
res + = tl : : to_word_or_quoted_string ( sfx0 ) ;
}
for ( unsigned int i = 0 ; i < = max_mask ; + + i ) {
std : : string sfx = ( data - > * get_suffix_per_mask ) ( i ) ;
if ( ! sfx . empty ( ) & & sfx ! = sfx0 ) {
if ( ! res . empty ( ) ) {
res + = " , " ;
}
2020-07-27 23:13:15 +02:00
res + = tl : : to_string ( i ) ;
2020-07-18 22:28:14 +02:00
res + = " : " ;
res + = tl : : to_word_or_quoted_string ( sfx ) ;
}
}
return res ;
}
void
LEFDEFReaderOptions : : set_via_geometry_suffix_str ( const std : : string & s )
{
set_suffixes ( this , & LEFDEFReaderOptions : : clear_via_geometry_suffixes_per_mask , & LEFDEFReaderOptions : : set_via_geometry_suffix , & LEFDEFReaderOptions : : set_via_geometry_suffix_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : via_geometry_suffix_str ( ) const
{
return get_suffixes ( this , & LEFDEFReaderOptions : : via_geometry_suffix , & LEFDEFReaderOptions : : via_geometry_suffix_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_via_geometry_datatype_str ( const std : : string & s )
{
set_datatypes ( this , & LEFDEFReaderOptions : : clear_via_geometry_datatypes_per_mask , & LEFDEFReaderOptions : : set_via_geometry_datatype , & LEFDEFReaderOptions : : set_via_geometry_datatype_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : via_geometry_datatype_str ( ) const
{
return get_datatypes ( this , & LEFDEFReaderOptions : : via_geometry_datatype , & LEFDEFReaderOptions : : via_geometry_datatype_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_pins_suffix_str ( const std : : string & s )
{
set_suffixes ( this , & LEFDEFReaderOptions : : clear_pins_suffixes_per_mask , & LEFDEFReaderOptions : : set_pins_suffix , & LEFDEFReaderOptions : : set_pins_suffix_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : pins_suffix_str ( ) const
{
return get_suffixes ( this , & LEFDEFReaderOptions : : pins_suffix , & LEFDEFReaderOptions : : pins_suffix_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_pins_datatype_str ( const std : : string & s )
{
set_datatypes ( this , & LEFDEFReaderOptions : : clear_pins_datatypes_per_mask , & LEFDEFReaderOptions : : set_pins_datatype , & LEFDEFReaderOptions : : set_pins_datatype_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : pins_datatype_str ( ) const
{
return get_datatypes ( this , & LEFDEFReaderOptions : : pins_datatype , & LEFDEFReaderOptions : : pins_datatype_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_lef_pins_suffix_str ( const std : : string & s )
{
set_suffixes ( this , & LEFDEFReaderOptions : : clear_lef_pins_suffixes_per_mask , & LEFDEFReaderOptions : : set_lef_pins_suffix , & LEFDEFReaderOptions : : set_lef_pins_suffix_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : lef_pins_suffix_str ( ) const
{
return get_suffixes ( this , & LEFDEFReaderOptions : : lef_pins_suffix , & LEFDEFReaderOptions : : lef_pins_suffix_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_lef_pins_datatype_str ( const std : : string & s )
{
set_datatypes ( this , & LEFDEFReaderOptions : : clear_lef_pins_datatypes_per_mask , & LEFDEFReaderOptions : : set_lef_pins_datatype , & LEFDEFReaderOptions : : set_lef_pins_datatype_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : lef_pins_datatype_str ( ) const
{
return get_datatypes ( this , & LEFDEFReaderOptions : : lef_pins_datatype , & LEFDEFReaderOptions : : lef_pins_datatype_per_mask , max_mask_number ( ) ) ;
}
2021-02-21 17:28:58 +01:00
void
LEFDEFReaderOptions : : set_fills_suffix_str ( const std : : string & s )
{
set_suffixes ( this , & LEFDEFReaderOptions : : clear_fills_suffixes_per_mask , & LEFDEFReaderOptions : : set_fills_suffix , & LEFDEFReaderOptions : : set_fills_suffix_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : fills_suffix_str ( ) const
{
return get_suffixes ( this , & LEFDEFReaderOptions : : fills_suffix , & LEFDEFReaderOptions : : fills_suffix_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_fills_datatype_str ( const std : : string & s )
{
set_datatypes ( this , & LEFDEFReaderOptions : : clear_fills_datatypes_per_mask , & LEFDEFReaderOptions : : set_fills_datatype , & LEFDEFReaderOptions : : set_fills_datatype_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : fills_datatype_str ( ) const
{
return get_datatypes ( this , & LEFDEFReaderOptions : : fills_datatype , & LEFDEFReaderOptions : : fills_datatype_per_mask , max_mask_number ( ) ) ;
}
2020-07-18 22:28:14 +02:00
void
LEFDEFReaderOptions : : set_routing_suffix_str ( const std : : string & s )
{
set_suffixes ( this , & LEFDEFReaderOptions : : clear_routing_suffixes_per_mask , & LEFDEFReaderOptions : : set_routing_suffix , & LEFDEFReaderOptions : : set_routing_suffix_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : routing_suffix_str ( ) const
{
return get_suffixes ( this , & LEFDEFReaderOptions : : routing_suffix , & LEFDEFReaderOptions : : routing_suffix_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_routing_datatype_str ( const std : : string & s )
{
set_datatypes ( this , & LEFDEFReaderOptions : : clear_routing_datatypes_per_mask , & LEFDEFReaderOptions : : set_routing_datatype , & LEFDEFReaderOptions : : set_routing_datatype_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : routing_datatype_str ( ) const
{
return get_datatypes ( this , & LEFDEFReaderOptions : : routing_datatype , & LEFDEFReaderOptions : : routing_datatype_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_special_routing_suffix_str ( const std : : string & s )
{
set_suffixes ( this , & LEFDEFReaderOptions : : clear_special_routing_suffixes_per_mask , & LEFDEFReaderOptions : : set_special_routing_suffix , & LEFDEFReaderOptions : : set_special_routing_suffix_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : special_routing_suffix_str ( ) const
{
return get_suffixes ( this , & LEFDEFReaderOptions : : special_routing_suffix , & LEFDEFReaderOptions : : special_routing_suffix_per_mask , max_mask_number ( ) ) ;
}
void
LEFDEFReaderOptions : : set_special_routing_datatype_str ( const std : : string & s )
{
set_datatypes ( this , & LEFDEFReaderOptions : : clear_special_routing_datatypes_per_mask , & LEFDEFReaderOptions : : set_special_routing_datatype , & LEFDEFReaderOptions : : set_special_routing_datatype_per_mask , s ) ;
}
std : : string
LEFDEFReaderOptions : : special_routing_datatype_str ( ) const
{
return get_datatypes ( this , & LEFDEFReaderOptions : : special_routing_datatype , & LEFDEFReaderOptions : : special_routing_datatype_per_mask , max_mask_number ( ) ) ;
}
2017-02-12 13:21:08 +01:00
// -----------------------------------------------------------------------------------
// LEFDEFLayerDelegate implementation
2020-06-13 15:39:41 +02:00
LEFDEFReaderState : : LEFDEFReaderState ( const LEFDEFReaderOptions * tc , db : : Layout & layout , const std : : string & base_path )
2022-04-23 22:26:37 +02:00
: mp_importer ( 0 ) , m_create_layers ( true ) , m_has_explicit_layer_mapping ( false ) , m_laynum ( 1 ) , mp_tech_comp ( tc )
2017-02-12 13:21:08 +01:00
{
2023-08-05 00:58:16 +02:00
if ( ! tc ) {
// use default options
} else if ( ! tc - > map_file ( ) . empty ( ) ) {
2020-06-13 15:39:41 +02:00
2022-04-23 22:26:37 +02:00
read_map_file ( tc - > map_file ( ) , layout , base_path ) ;
2020-04-19 20:14:12 +02:00
2020-06-13 15:39:41 +02:00
} else {
2023-08-05 00:58:16 +02:00
m_layer_map = tc - > layer_map ( ) ;
m_create_layers = tc - > read_all_layers ( ) ;
2020-06-13 15:39:41 +02:00
}
2017-02-12 13:21:08 +01:00
}
2020-07-25 22:15:09 +02:00
LEFDEFReaderState : : ~ LEFDEFReaderState ( )
{
2022-04-23 22:26:37 +02:00
for ( std : : map < std : : pair < std : : string , std : : string > , LEFDEFLayoutGenerator * > : : const_iterator i = m_via_generators . begin ( ) ; i ! = m_via_generators . end ( ) ; + + i ) {
2020-07-25 22:15:09 +02:00
delete i - > second ;
}
m_via_generators . clear ( ) ;
2020-08-23 00:40:28 +02:00
for ( std : : map < std : : string , LEFDEFLayoutGenerator * > : : const_iterator i = m_macro_generators . begin ( ) ; i ! = m_macro_generators . end ( ) ; + + i ) {
delete i - > second ;
}
m_macro_generators . clear ( ) ;
2020-07-25 22:15:09 +02:00
}
2022-04-23 22:26:37 +02:00
void
LEFDEFReaderState : : common_reader_error ( const std : : string & msg )
{
if ( mp_importer ) {
mp_importer - > error ( msg ) ;
}
}
void
2022-08-13 22:15:07 +02:00
LEFDEFReaderState : : common_reader_warn ( const std : : string & msg , int warn_level )
2022-04-23 22:26:37 +02:00
{
if ( mp_importer ) {
2022-08-13 22:15:07 +02:00
mp_importer - > warn ( msg , warn_level ) ;
2022-04-23 22:26:37 +02:00
}
}
2017-02-12 13:21:08 +01:00
void
2020-04-18 17:58:50 +02:00
LEFDEFReaderState : : register_layer ( const std : : string & ln )
2017-02-12 13:21:08 +01:00
{
m_default_number . insert ( std : : make_pair ( ln , m_laynum ) ) ;
+ + m_laynum ;
}
2020-11-21 00:38:25 +01:00
static bool try_read_layers ( tl : : Extractor & ex , std : : vector < int > & layers )
2020-04-19 16:54:41 +02:00
{
2020-11-21 00:38:25 +01:00
int l = 0 ;
if ( ! ex . try_read ( l ) ) {
return false ;
}
layers . push_back ( l ) ;
if ( ex . test ( " , " ) ) {
do {
if ( ! ex . try_read ( l ) ) {
return false ;
}
layers . push_back ( l ) ;
} while ( ex . test ( " , " ) ) ;
}
return true ;
2020-04-19 16:54:41 +02:00
}
2022-04-23 22:26:37 +02:00
static std : : string : : size_type find_file_sep ( const std : : string & s , std : : string : : size_type from )
{
std : : string : : size_type p1 = s . find ( " + " , from ) ;
std : : string : : size_type p2 = s . find ( " , " , from ) ;
if ( p1 = = std : : string : : npos ) {
return p2 ;
} else if ( p2 = = std : : string : : npos ) {
return p1 ;
} else {
return p1 < p2 ? p1 : p2 ;
}
}
static std : : vector < std : : string > split_file_list ( const std : : string & infile )
{
std : : vector < std : : string > files ;
size_t p = 0 ;
for ( size_t pp = 0 ; ( pp = find_file_sep ( infile , p ) ) ! = std : : string : : npos ; p = pp + 1 ) {
files . push_back ( std : : string ( infile , p , pp - p ) ) ;
}
files . push_back ( std : : string ( infile , p ) ) ;
return files ;
}
2020-04-19 16:54:41 +02:00
void
2022-04-23 22:26:37 +02:00
LEFDEFReaderState : : read_map_file ( const std : : string & filename , db : : Layout & layout , const std : : string & base_path )
2017-02-12 13:21:08 +01:00
{
2020-07-25 23:28:38 +02:00
m_has_explicit_layer_mapping = true ;
2020-06-13 15:39:41 +02:00
2022-04-23 22:26:37 +02:00
std : : vector < std : : string > paths = split_file_list ( filename ) ;
std : : map < std : : pair < std : : string , LayerDetailsKey > , std : : vector < db : : LayerProperties > > layer_map ;
for ( std : : vector < std : : string > : : const_iterator p = paths . begin ( ) ; p ! = paths . end ( ) ; + + p ) {
read_single_map_file ( correct_path ( * p , layout , base_path ) , layer_map ) ;
}
2020-04-19 16:54:41 +02:00
2022-04-23 22:26:37 +02:00
// build an explicit layer mapping now.
m_layers . clear ( ) ;
m_layer_map . clear ( ) ;
db : : DirectLayerMapping lm ( & layout ) ;
for ( std : : map < std : : pair < std : : string , LayerDetailsKey > , std : : vector < db : : LayerProperties > > : : const_iterator i = layer_map . begin ( ) ; i ! = layer_map . end ( ) ; + + i ) {
for ( std : : vector < db : : LayerProperties > : : const_iterator j = i - > second . begin ( ) ; j ! = i - > second . end ( ) ; + + j ) {
unsigned int layer = lm . map_layer ( * j ) . second ;
m_layers [ i - > first ] . insert ( layer ) ;
m_layer_map . mmap ( * j , layer ) ;
}
}
}
void
LEFDEFReaderState : : read_single_map_file ( const std : : string & path , std : : map < std : : pair < std : : string , LayerDetailsKey > , std : : vector < db : : LayerProperties > > & layer_map )
{
2020-04-19 16:54:41 +02:00
tl : : InputFile file ( path ) ;
tl : : InputStream file_stream ( file ) ;
tl : : TextInputStream ts ( file_stream ) ;
2022-04-23 22:26:37 +02:00
tl : : log < < tl : : to_string ( tr ( " Reading LEF/DEF map file " ) ) < < " " < < file_stream . absolute_path ( ) ;
2023-08-05 00:58:16 +02:00
// Purpose name to purpose code
2020-04-19 16:54:41 +02:00
std : : map < std : : string , LayerPurpose > purpose_translation ;
purpose_translation [ " LEFPIN " ] = LEFPins ;
purpose_translation [ " PIN " ] = Pins ;
2023-08-05 00:58:16 +02:00
purpose_translation [ " LEFPINNAME " ] = LEFLabel ;
purpose_translation [ " PINNAME " ] = Label ;
2021-02-21 17:28:58 +01:00
purpose_translation [ " FILL " ] = Fills ;
purpose_translation [ " FILLOPC " ] = FillsOPC ;
2020-04-19 16:54:41 +02:00
purpose_translation [ " LEFOBS " ] = Obstructions ;
purpose_translation [ " SPNET " ] = SpecialRouting ;
purpose_translation [ " NET " ] = Routing ;
purpose_translation [ " VIA " ] = ViaGeometry ;
purpose_translation [ " BLOCKAGE " ] = Blockage ;
2020-11-21 00:38:25 +01:00
purpose_translation [ " ALL " ] = All ;
2020-04-19 16:54:41 +02:00
2023-08-05 00:58:16 +02:00
// List of purposes corresponding to ALL
LayerPurpose all_purposes [ ] = {
LEFPins , Pins , Fills , FillsOPC , Obstructions , SpecialRouting , Routing , ViaGeometry
} ;
2020-04-19 16:54:41 +02:00
while ( ! ts . at_end ( ) ) {
const std : : string & l = ts . get_line ( ) ;
tl : : Extractor ex ( l . c_str ( ) ) ;
if ( ex . at_end ( ) | | ex . test ( " # " ) ) {
// ignore empty of comment lines
} else {
std : : string w1 , w2 ;
2020-12-19 22:11:23 +01:00
std : : vector < int > layers , datatypes ;
2021-02-21 21:00:55 +01:00
size_t max_purpose_str = 15 ;
2020-04-19 16:54:41 +02:00
2020-12-19 22:11:23 +01:00
if ( ! ex . try_read_word ( w1 ) | | ! ex . try_read_word ( w2 , " ._$,/: " ) | | ! try_read_layers ( ex , layers ) | | ! try_read_layers ( ex , datatypes ) ) {
2020-11-21 00:38:25 +01:00
tl : : warn < < tl : : sprintf ( tl : : to_string ( tr ( " Reading layer map file %s, line %d not understood - skipped " ) ) , path , ts . line_number ( ) ) ;
continue ;
}
2020-04-19 16:54:41 +02:00
2020-11-21 00:38:25 +01:00
if ( w1 = = " DIEAREA " ) {
2020-04-19 20:14:12 +02:00
2020-12-19 22:11:23 +01:00
for ( std : : vector < int > : : const_iterator l = layers . begin ( ) ; l ! = layers . end ( ) ; + + l ) {
for ( std : : vector < int > : : const_iterator d = datatypes . begin ( ) ; d ! = datatypes . end ( ) ; + + d ) {
2021-02-21 21:00:55 +01:00
layer_map [ std : : make_pair ( std : : string ( ) , LayerDetailsKey ( Outline ) ) ] . push_back ( db : : LayerProperties ( * l , * d , " OUTLINE " ) ) ;
2020-12-19 22:11:23 +01:00
}
}
2020-04-19 20:14:12 +02:00
2022-04-23 22:26:37 +02:00
} else if ( w1 = = " REGION " ) {
std : : string name = " REGIONS " ;
LayerPurpose lp = Regions ;
if ( w2 = = " FENCE " ) {
name = " REGIONS_FENCE " ;
lp = RegionsFence ;
} else if ( w2 = = " GUIDE " ) {
name = " REGIONS_GUIDE " ;
lp = RegionsGuide ;
} else if ( w2 = = " NONE " ) {
name = " REGIONS_NONE " ;
lp = RegionsNone ;
} else if ( w2 ! = " ALL " ) {
tl : : warn < < tl : : sprintf ( tl : : to_string ( tr ( " Reading layer map file %s, line %d - ignoring unknowns REGION purpose %s (use FENCE, GUIDE or ALL) " ) ) , path , ts . line_number ( ) , w2 ) ;
}
2020-04-19 20:14:12 +02:00
2020-12-19 22:11:23 +01:00
for ( std : : vector < int > : : const_iterator l = layers . begin ( ) ; l ! = layers . end ( ) ; + + l ) {
for ( std : : vector < int > : : const_iterator d = datatypes . begin ( ) ; d ! = datatypes . end ( ) ; + + d ) {
2022-04-23 22:26:37 +02:00
layer_map [ std : : make_pair ( std : : string ( ) , LayerDetailsKey ( lp ) ) ] . push_back ( db : : LayerProperties ( * l , * d , name ) ) ;
2020-12-19 22:11:23 +01:00
}
}
2020-04-19 20:14:12 +02:00
2020-11-21 00:38:25 +01:00
} else if ( w1 = = " BLOCKAGE " ) {
2020-04-19 16:54:41 +02:00
2020-12-19 22:11:23 +01:00
for ( std : : vector < int > : : const_iterator l = layers . begin ( ) ; l ! = layers . end ( ) ; + + l ) {
for ( std : : vector < int > : : const_iterator d = datatypes . begin ( ) ; d ! = datatypes . end ( ) ; + + d ) {
2021-02-21 21:00:55 +01:00
layer_map [ std : : make_pair ( std : : string ( ) , LayerDetailsKey ( PlacementBlockage ) ) ] . push_back ( db : : LayerProperties ( * l , * d , " PLACEMENT_BLK " ) ) ;
2020-12-19 22:11:23 +01:00
}
}
2020-04-19 16:54:41 +02:00
2020-11-21 00:38:25 +01:00
} else if ( w1 = = " NAME " ) {
2020-04-19 16:54:41 +02:00
2020-11-21 00:38:25 +01:00
// converts a line like
// "NAME M1/PINS,M2/PINS ..."
// into a canonical name mapping like
// "(M1/LABELS): M1.LABEL"
// "(M2/LABELS): M2.LABEL"
2021-06-08 22:49:22 +02:00
// supported purposes: PINS(->Label), LEFPINS(->LEFLabels)
2020-04-19 16:54:41 +02:00
2021-06-08 22:49:22 +02:00
std : : vector < std : : pair < std : : string , LayerPurpose > > layer_defs ;
2021-06-08 22:16:10 +02:00
2020-11-21 00:38:25 +01:00
std : : vector < std : : string > purposes = tl : : split ( w2 , " , " ) ;
for ( std : : vector < std : : string > : : const_iterator p = purposes . begin ( ) ; p ! = purposes . end ( ) ; + + p ) {
2021-06-08 22:49:22 +02:00
2020-11-21 00:38:25 +01:00
if ( * p = = " DIEAREA " | | * p = = " ALL " | | * p = = " COMP " ) {
2021-06-08 22:49:22 +02:00
2020-11-21 00:38:25 +01:00
tl : : warn < < tl : : sprintf ( tl : : to_string ( tr ( " Reading layer map file %s, line %d: NAME record ignored for entity: %s " ) ) , path , ts . line_number ( ) , * p ) ;
2021-06-08 22:49:22 +02:00
2020-11-21 00:38:25 +01:00
} else {
2021-06-08 22:49:22 +02:00
2021-06-08 22:16:10 +02:00
std : : vector < std : : string > lp = tl : : split ( * p , " / " ) ;
2021-06-08 22:49:22 +02:00
2021-06-08 22:16:10 +02:00
if ( lp . size ( ) > 1 ) {
2021-06-08 22:49:22 +02:00
LayerPurpose label_purpose = Pins ;
2021-06-08 22:16:10 +02:00
std : : map < std : : string , LayerPurpose > : : const_iterator i = purpose_translation . find ( lp [ 1 ] ) ;
if ( i ! = purpose_translation . end ( ) ) {
label_purpose = i - > second ;
}
2021-06-08 22:49:22 +02:00
if ( label_purpose = = Pins | | label_purpose = = LEFPins ) {
layer_defs . push_back ( std : : make_pair ( lp . front ( ) , label_purpose = = Pins ? Label : LEFLabel ) ) ;
} else {
tl : : warn < < tl : : sprintf ( tl : : to_string ( tr ( " Reading layer map file %s, line %d: NAME record ignored for purpose: %s " ) ) , path , ts . line_number ( ) , purpose_to_name ( label_purpose ) ) ;
}
} else {
layer_defs . push_back ( std : : make_pair ( lp . front ( ) , Label ) ) ;
layer_defs . push_back ( std : : make_pair ( lp . front ( ) , LEFLabel ) ) ;
2021-06-08 22:16:10 +02:00
}
2021-06-08 22:49:22 +02:00
2020-04-19 16:54:41 +02:00
}
2021-06-08 22:49:22 +02:00
}
2021-06-08 22:16:10 +02:00
2021-06-08 22:49:22 +02:00
std : : string final_name ;
for ( std : : vector < std : : pair < std : : string , LayerPurpose > > : : const_iterator i = layer_defs . begin ( ) ; i ! = layer_defs . end ( ) ; + + i ) {
if ( ! final_name . empty ( ) ) {
final_name + = " / " ;
}
final_name + = i - > first + " . " + purpose_to_name ( i - > second ) ;
}
2021-06-08 22:16:10 +02:00
2021-06-08 22:49:22 +02:00
for ( std : : vector < std : : pair < std : : string , LayerPurpose > > : : const_iterator i = layer_defs . begin ( ) ; i ! = layer_defs . end ( ) ; + + i ) {
for ( std : : vector < int > : : const_iterator l = layers . begin ( ) ; l ! = layers . end ( ) ; + + l ) {
for ( std : : vector < int > : : const_iterator d = datatypes . begin ( ) ; d ! = datatypes . end ( ) ; + + d ) {
layer_map [ std : : make_pair ( i - > first , LayerDetailsKey ( i - > second ) ) ] . push_back ( db : : LayerProperties ( * l , * d , final_name ) ) ;
2020-12-19 22:11:23 +01:00
}
2020-04-19 16:54:41 +02:00
}
2020-11-21 00:38:25 +01:00
}
2020-04-19 16:54:41 +02:00
2020-11-21 00:38:25 +01:00
} else if ( w1 = = " COMP " ) {
2020-08-29 08:57:10 +02:00
2020-11-21 00:38:25 +01:00
// ignore "COMP (ALL) ..."
tl : : warn < < tl : : sprintf ( tl : : to_string ( tr ( " Reading layer map file %s, line %d: COMP entry ignored " ) ) , path , ts . line_number ( ) ) ;
2020-08-29 08:57:10 +02:00
2020-11-21 00:38:25 +01:00
} else {
2020-04-19 16:54:41 +02:00
2020-11-21 00:38:25 +01:00
// converts a line like
// "M1 SPNET,NET,PINS,LEFPINS ..."
// into a canonical name mapping like
// "(M1,NET): M1.NET/PINS"
// "(M1,PINS): M1.NET/PINS"
// (separating, translating and recombing the purposes)
2020-04-19 16:54:41 +02:00
2021-02-21 21:00:55 +01:00
std : : set < LayerDetailsKey > translated_purposes ;
2020-04-19 16:54:41 +02:00
2020-11-21 00:38:25 +01:00
std : : vector < std : : string > purposes = tl : : split ( w2 , " , " ) ;
std : : reverse ( purposes . begin ( ) , purposes . end ( ) ) ;
2020-07-25 22:15:09 +02:00
2020-11-21 00:38:25 +01:00
unsigned int mask = 0 ;
2020-08-19 23:47:25 +02:00
2020-11-21 00:38:25 +01:00
for ( std : : vector < std : : string > : : const_iterator p = purposes . begin ( ) ; p ! = purposes . end ( ) ; + + p ) {
2020-08-19 23:47:25 +02:00
2020-11-21 00:38:25 +01:00
std : : string p_uc = tl : : to_upper_case ( * p ) ;
tl : : Extractor ex ( p_uc . c_str ( ) ) ;
2020-04-19 16:54:41 +02:00
2020-11-21 00:38:25 +01:00
std : : string ps ;
ex . read_word_or_quoted ( ps ) ;
2021-02-21 21:00:55 +01:00
db : : DVector via_size ;
2020-07-25 22:15:09 +02:00
2020-11-21 00:38:25 +01:00
std : : map < std : : string , LayerPurpose > : : const_iterator i = purpose_translation . find ( ps ) ;
if ( i ! = purpose_translation . end ( ) ) {
2020-07-25 22:15:09 +02:00
2020-11-21 00:38:25 +01:00
if ( i - > second = = Routing ) {
2020-08-02 12:01:28 +02:00
2020-11-21 00:38:25 +01:00
if ( ex . test ( " :VOLTAGE: " ) ) {
double f = 0.0 ;
ex . read ( f ) ;
tl : : warn < < tl : : sprintf ( tl : : to_string ( tr ( " Reading layer map file %s, line %d: NET voltage constraint ignored for layer %s " ) ) , path , ts . line_number ( ) , w1 ) ;
}
2020-08-02 12:01:28 +02:00
2020-11-21 00:38:25 +01:00
} else if ( i - > second = = ViaGeometry ) {
2020-08-02 12:01:28 +02:00
2020-11-21 00:38:25 +01:00
if ( ex . test ( " :SIZE: " ) ) {
2021-02-21 21:00:55 +01:00
double sx = 0.0 , sy = 0.0 ;
ex . read ( sx ) ;
ex . test ( " X " ) ;
ex . read ( sy ) ;
via_size = db : : DVector ( sx , sy ) ;
2020-07-25 22:15:09 +02:00
}
2020-08-19 23:47:25 +02:00
}
2020-04-19 16:54:41 +02:00
2020-08-19 23:47:25 +02:00
}
2020-08-02 12:01:28 +02:00
2020-11-21 01:00:28 +01:00
if ( ex . test ( " :MASK: " ) ) {
ex . read ( mask ) ;
}
2020-08-02 12:01:28 +02:00
2020-11-21 01:00:28 +01:00
if ( i = = purpose_translation . end ( ) ) {
2020-08-02 12:01:28 +02:00
2020-11-21 01:00:28 +01:00
tl : : warn < < tl : : sprintf ( tl : : to_string ( tr ( " Reading layer map file %s, line %d: purpose %s ignored for layer %s " ) ) , path , ts . line_number ( ) , ps , w1 ) ;
2020-08-02 12:01:28 +02:00
2020-11-21 01:00:28 +01:00
} else if ( i - > second = = All ) {
2020-07-25 22:15:09 +02:00
2023-08-05 00:58:16 +02:00
for ( LayerPurpose * p = all_purposes ; p ! = all_purposes + sizeof ( all_purposes ) / sizeof ( all_purposes [ 0 ] ) ; + + p ) {
translated_purposes . insert ( LayerDetailsKey ( * p , mask , via_size ) ) ;
2020-08-02 00:56:55 +02:00
}
2020-11-21 00:38:25 +01:00
} else {
2020-11-21 01:00:28 +01:00
2021-02-21 21:00:55 +01:00
translated_purposes . insert ( LayerDetailsKey ( i - > second , mask , via_size ) ) ;
2020-11-21 01:00:28 +01:00
2020-04-19 16:54:41 +02:00
}
2020-11-21 00:38:25 +01:00
}
2020-04-19 16:54:41 +02:00
2020-11-21 00:38:25 +01:00
// create a visual description string for the combined purposes
std : : string purpose_str ;
2021-02-21 21:00:55 +01:00
for ( std : : set < LayerDetailsKey > : : const_iterator p = translated_purposes . begin ( ) ; p ! = translated_purposes . end ( ) ; + + p ) {
2020-11-21 00:38:25 +01:00
if ( p ! = translated_purposes . begin ( ) ) {
purpose_str + = " / " ;
2020-04-19 16:54:41 +02:00
}
2021-02-21 21:00:55 +01:00
std : : string ps = layer_spec_to_name ( std : : string ( ) , p - > purpose , p - > mask , p - > via_size ) ;
2020-04-19 16:54:41 +02:00
2021-02-21 21:00:55 +01:00
if ( p ! = translated_purposes . begin ( ) & & ( purpose_str + ps ) . size ( ) > max_purpose_str ) {
2020-11-21 00:38:25 +01:00
purpose_str + = " ... " ;
break ;
} else {
purpose_str + = ps ;
2020-04-19 16:54:41 +02:00
}
}
2020-11-21 00:38:25 +01:00
std : : string final_name = w1 + " . " + purpose_str ;
2021-02-21 21:00:55 +01:00
for ( std : : set < LayerDetailsKey > : : const_iterator p = translated_purposes . begin ( ) ; p ! = translated_purposes . end ( ) ; + + p ) {
2020-12-19 22:11:23 +01:00
for ( std : : vector < int > : : const_iterator l = layers . begin ( ) ; l ! = layers . end ( ) ; + + l ) {
for ( std : : vector < int > : : const_iterator d = datatypes . begin ( ) ; d ! = datatypes . end ( ) ; + + d ) {
layer_map [ std : : make_pair ( w1 , * p ) ] . push_back ( db : : LayerProperties ( * l , * d , final_name ) ) ;
}
}
2020-04-19 16:54:41 +02:00
}
}
}
}
2022-04-23 22:26:37 +02:00
}
2020-04-19 16:54:41 +02:00
2022-04-23 22:26:37 +02:00
/**
* @ brief Returns true , if the layer purpose has a fallback
*/
static bool has_fallback ( LayerPurpose p )
{
return p = = RegionsFence | | p = = RegionsGuide | | p = = RegionsNone ;
2020-04-19 16:54:41 +02:00
}
2020-12-19 19:42:40 +01:00
std : : set < unsigned int >
2021-02-21 21:00:55 +01:00
LEFDEFReaderState : : open_layer ( db : : Layout & layout , const std : : string & n , LayerPurpose purpose , unsigned int mask , const db : : DVector & via_size )
2020-04-19 16:54:41 +02:00
{
2021-02-21 21:00:55 +01:00
std : : map < std : : pair < std : : string , LayerDetailsKey > , std : : set < unsigned int > > : : const_iterator nl ;
nl = m_layers . find ( std : : make_pair ( n , LayerDetailsKey ( purpose , mask , via_size ) ) ) ;
if ( nl = = m_layers . end ( ) ) {
nl = m_layers . find ( std : : make_pair ( n , LayerDetailsKey ( purpose , mask ) ) ) ;
}
2020-04-19 16:54:41 +02:00
if ( nl = = m_layers . end ( ) ) {
2020-12-19 19:42:40 +01:00
std : : set < unsigned int > ll ;
2020-04-19 16:54:41 +02:00
2022-04-23 22:26:37 +02:00
if ( ! m_has_explicit_layer_mapping ) {
2020-07-18 22:59:02 +02:00
ll = open_layer_uncached ( layout , n , purpose , mask ) ;
2020-04-19 16:54:41 +02:00
}
2021-02-21 21:00:55 +01:00
m_layers . insert ( std : : make_pair ( std : : make_pair ( n , LayerDetailsKey ( purpose , mask ) ) , ll ) ) ;
2022-03-05 14:57:09 +01:00
2022-04-23 22:26:37 +02:00
if ( ll . empty ( ) & & ! has_fallback ( purpose ) ) {
if ( n . empty ( ) ) {
tl : : warn < < tl : : to_string ( tr ( " No mapping for purpose " ) ) < < " ' " < < purpose_to_name ( purpose ) < < " ' " < < tl : : noendl ;
} else {
tl : : warn < < tl : : to_string ( tr ( " No mapping for layer " ) ) < < " ' " < < n < < " ', purpose ' " < < purpose_to_name ( purpose ) < < " ' " < < tl : : noendl ;
}
2022-03-05 14:57:09 +01:00
if ( mask > 0 ) {
tl : : warn < < tl : : to_string ( tr ( " Mask " ) ) < < mask < < tl : : noendl ;
}
2023-10-19 22:06:35 +02:00
// not printing via size - too confusing?
#if 0
2022-03-05 14:57:09 +01:00
if ( via_size ! = db : : DVector ( ) ) {
tl : : warn < < tl : : to_string ( tr ( " Via size " ) ) < < via_size . to_string ( ) < < tl : : noendl ;
}
2023-10-19 22:06:35 +02:00
# endif
2022-03-05 14:57:09 +01:00
tl : : warn < < tl : : to_string ( tr ( " - layer is ignored " ) ) ;
}
2020-04-19 16:54:41 +02:00
return ll ;
} else {
return nl - > second ;
}
}
2020-11-21 20:39:31 +01:00
/**
* @ brief Implements implicit layer mapping
*
* This is how Implicit layer mapping works :
*
* 1. For named layers ( e . g . routing , pin , etc .
*
* A decorated name is formed from the basic name and the purpose string ( e . g . " M1 " - > " M1.PIN " ) .
* With the example of " M1 " and purpose Pin ( decorated name " M1.PIN " ) and with a tech component datatype specification
* of " 5 " for " Pin " , the layer map entries have the following effect :
*
* Layer map Result
*
* ( nothing ) M1 . PIN ( default / 5 ) ( only if " create_all_layers " is ON , " default " is a default number assigned by the reader )
* M1 . PIN : 1 / 0 M1 . PIN ( 1 / 0 )
* M1 . PIN : 1 / 17 M1 . PIN ( 1 / 17 )
* M1 : 1 / 0 M1 . PIN ( 1 / 5 )
* M1 : 1 / 2 M1 . PIN ( 1 / 7 ) ( datatypes will add )
* M1 M1 . PIN ( default / 5 )
* M1 : METAL1 METAL1 . PIN ( default / 5 ) ( name is taken from layer map and decorated )
* M1 : METAL1 ( 1 / 2 ) METAL1 . PIN ( 1 / 7 )
* M1 . PIN : METAL1_PIN METAL1_PIN ( default / 5 ) ( specific name is used without decoration )
* M1 . PIN : METAL1_PIN ( 1 / 17 ) METAL1_PIN ( 1 / 17 ) ( full and specific mapping )
*
* 2. For general layers ( e . g . outline )
*
* By default , the name , layer and datatype are taken from the tech component ' s specification . The specification may
* lack the layer and datatype and even the name . If the name is missing , it is generated from the purpose .
*
* Here are some examples for the mapping of " OUTLINE " :
*
* Tech component Layer map Result
*
* ( nothing ) ( nothing ) OUTLINE ( only if " create_all_layers " is ON )
* OUTL ( nothing ) OUTL ( default / 0 ) ( " default " is a default number assigned by the reader )
* OUTL ( 4 / 17 ) ( nothing ) OUTL ( 4 / 17 )
* OUTL OUTL : 5 / 1 OUTL ( 5 / 1 )
* OUTL ( 4 / 17 ) OUTL : 4 / 11 OUTL 4 / 11
* OUTL ( 4 / 17 ) 4 / 17 : 4 / 11 OUTL 4 / 11
* 4 / 17 4 / 17 : 4 / 11 OUTLINE 4 / 11
*/
2020-12-19 19:42:40 +01:00
std : : set < unsigned int > LEFDEFReaderState : : open_layer_uncached ( db : : Layout & layout , const std : : string & n , LayerPurpose purpose , unsigned int mask )
2017-02-12 13:21:08 +01:00
{
2020-04-19 19:12:03 +02:00
if ( n . empty ( ) ) {
2017-02-12 13:21:08 +01:00
std : : string ld ;
2020-04-19 19:12:03 +02:00
bool produce = false ;
2017-02-12 13:21:08 +01:00
if ( purpose = = Outline ) {
produce = mp_tech_comp - > produce_cell_outlines ( ) ;
ld = mp_tech_comp - > cell_outline_layer ( ) ;
2020-04-19 20:14:12 +02:00
} else if ( purpose = = Regions ) {
2017-09-04 23:05:46 +02:00
produce = mp_tech_comp - > produce_regions ( ) ;
ld = mp_tech_comp - > region_layer ( ) ;
2020-04-19 20:14:12 +02:00
} else if ( purpose = = PlacementBlockage ) {
2017-02-12 13:21:08 +01:00
produce = mp_tech_comp - > produce_placement_blockages ( ) ;
ld = mp_tech_comp - > placement_blockage_layer ( ) ;
}
if ( ! produce ) {
2020-12-19 19:42:40 +01:00
return std : : set < unsigned int > ( ) ;
2017-02-12 13:21:08 +01:00
}
db : : LayerProperties lp ;
tl : : Extractor ex ( ld . c_str ( ) ) ;
try {
ex . read ( lp ) ;
} catch ( . . . ) {
lp . layer = 0 ;
lp . datatype = 0 ;
}
2020-11-21 20:39:31 +01:00
// if no name is given, derive one from the purpose
if ( lp . name . empty ( ) ) {
lp . name = purpose_to_name ( purpose ) ;
}
if ( lp . layer < 0 ) {
std : : map < std : : string , int > : : const_iterator ldef = m_default_number . find ( lp . name ) ;
if ( ldef ! = m_default_number . end ( ) ) {
lp . layer = ldef - > second ;
lp . datatype = 0 ;
2020-07-30 23:53:34 +02:00
}
2017-02-12 13:21:08 +01:00
}
2020-11-21 20:39:31 +01:00
// employ the layer map to find the target layer
2020-12-19 19:42:40 +01:00
std : : set < unsigned int > ll = m_layer_map . logical ( lp , layout ) ;
if ( ll . empty ( ) & & ! m_create_layers ) {
return std : : set < unsigned int > ( ) ;
}
std : : set < unsigned int > res ;
// map the layers to targets from the layout
// (NOTE: the other readers will do this in advance, but LEF/DEF is too dynamic)
bool at_least_once = true ;
for ( std : : set < unsigned int > : : const_iterator l = ll . begin ( ) ; l ! = ll . end ( ) | | at_least_once ; + + l ) {
2020-11-21 20:39:31 +01:00
2020-12-19 19:42:40 +01:00
at_least_once = false ;
2020-11-21 20:39:31 +01:00
// If the layer map provides a target, use that one for the layer
2020-12-19 19:42:40 +01:00
db : : LayerProperties lp_new = lp ;
const db : : LayerProperties * lpp = ( l = = ll . end ( ) ? 0 : m_layer_map . target ( * l ) ) ;
2020-11-21 20:39:31 +01:00
if ( lpp ) {
if ( ! lpp - > name . empty ( ) ) {
2020-12-19 19:42:40 +01:00
lp_new . name = lpp - > name ;
2020-11-21 20:39:31 +01:00
}
if ( lpp - > datatype > = 0 ) {
2020-12-19 19:42:40 +01:00
lp_new . datatype = lpp - > datatype ;
2020-11-21 20:39:31 +01:00
}
if ( lpp - > layer > = 0 ) {
2020-12-19 19:42:40 +01:00
lp_new . layer = lpp - > layer ;
2020-11-21 20:39:31 +01:00
}
}
2020-12-19 19:42:40 +01:00
bool found = false ;
for ( db : : Layout : : layer_iterator i = layout . begin_layers ( ) ; i ! = layout . end_layers ( ) & & ! found ; + + i ) {
if ( ( * i ) . second - > log_equal ( lp_new ) ) {
found = true ;
res . insert ( ( * i ) . first ) ;
}
}
2020-11-21 20:39:31 +01:00
2020-12-19 19:42:40 +01:00
if ( ! found ) {
res . insert ( layout . insert_layer ( lp_new ) ) ;
2020-07-30 23:53:34 +02:00
}
2020-12-19 19:42:40 +01:00
if ( l = = ll . end ( ) ) {
break ;
}
2017-02-12 13:21:08 +01:00
}
2020-12-19 19:42:40 +01:00
return res ;
2020-07-30 23:53:34 +02:00
2017-02-12 13:21:08 +01:00
} else {
2020-03-29 18:57:07 +02:00
if ( mp_tech_comp ) {
bool produce = true ;
switch ( purpose ) {
case Routing :
default :
produce = mp_tech_comp - > produce_routing ( ) ;
break ;
2020-04-19 14:38:14 +02:00
case SpecialRouting :
produce = mp_tech_comp - > produce_special_routing ( ) ;
break ;
2020-03-29 18:57:07 +02:00
case ViaGeometry :
produce = mp_tech_comp - > produce_via_geometry ( ) ;
break ;
case Label :
produce = mp_tech_comp - > produce_labels ( ) ;
break ;
2021-06-08 22:16:10 +02:00
case LEFLabel :
produce = mp_tech_comp - > produce_lef_labels ( ) ;
break ;
2020-03-29 18:57:07 +02:00
case Pins :
produce = mp_tech_comp - > produce_pins ( ) ;
break ;
2021-02-21 17:28:58 +01:00
case Fills :
case FillsOPC :
produce = mp_tech_comp - > produce_fills ( ) ;
break ;
2020-04-19 14:38:14 +02:00
case LEFPins :
produce = mp_tech_comp - > produce_lef_pins ( ) ;
break ;
2020-03-29 18:57:07 +02:00
case Obstructions :
produce = mp_tech_comp - > produce_obstructions ( ) ;
break ;
case Blockage :
produce = mp_tech_comp - > produce_blockages ( ) ;
break ;
}
if ( ! produce ) {
2020-12-19 19:42:40 +01:00
return std : : set < unsigned int > ( ) ;
2020-03-29 18:57:07 +02:00
}
}
2020-07-27 23:13:15 +02:00
std : : string name_suffix ;
2017-02-12 13:21:08 +01:00
int dt = 0 ;
if ( mp_tech_comp ) {
switch ( purpose ) {
case Routing :
default :
2020-07-27 23:13:15 +02:00
name_suffix = mp_tech_comp - > routing_suffix_per_mask ( mask ) ;
dt = mp_tech_comp - > routing_datatype_per_mask ( mask ) ;
2017-02-12 13:21:08 +01:00
break ;
2020-04-19 14:38:14 +02:00
case SpecialRouting :
2020-07-27 23:13:15 +02:00
name_suffix = mp_tech_comp - > special_routing_suffix_per_mask ( mask ) ;
dt = mp_tech_comp - > special_routing_datatype_per_mask ( mask ) ;
2020-04-19 14:38:14 +02:00
break ;
2017-02-12 13:21:08 +01:00
case ViaGeometry :
2020-07-27 23:13:15 +02:00
name_suffix = mp_tech_comp - > via_geometry_suffix_per_mask ( mask ) ;
dt = mp_tech_comp - > via_geometry_datatype_per_mask ( mask ) ;
2017-02-12 13:21:08 +01:00
break ;
case Label :
2020-07-27 23:13:15 +02:00
name_suffix = mp_tech_comp - > labels_suffix ( ) ;
dt = mp_tech_comp - > labels_datatype ( ) ;
2017-02-12 13:21:08 +01:00
break ;
2021-06-08 22:16:10 +02:00
case LEFLabel :
name_suffix = mp_tech_comp - > lef_labels_suffix ( ) ;
dt = mp_tech_comp - > lef_labels_datatype ( ) ;
break ;
2017-02-12 13:21:08 +01:00
case Pins :
2020-07-27 23:13:15 +02:00
name_suffix = mp_tech_comp - > pins_suffix_per_mask ( mask ) ;
dt = mp_tech_comp - > pins_datatype_per_mask ( mask ) ;
2017-02-12 13:21:08 +01:00
break ;
2021-02-21 17:28:58 +01:00
case Fills :
case FillsOPC :
name_suffix = mp_tech_comp - > fills_suffix_per_mask ( mask ) ;
dt = mp_tech_comp - > fills_datatype_per_mask ( mask ) ;
break ;
2020-04-19 14:38:14 +02:00
case LEFPins :
2020-07-27 23:13:15 +02:00
name_suffix = mp_tech_comp - > lef_pins_suffix_per_mask ( mask ) ;
dt = mp_tech_comp - > lef_pins_datatype_per_mask ( mask ) ;
2020-04-19 14:38:14 +02:00
break ;
2017-02-12 13:21:08 +01:00
case Obstructions :
2020-07-27 23:13:15 +02:00
name_suffix = mp_tech_comp - > obstructions_suffix ( ) ;
dt = mp_tech_comp - > obstructions_datatype ( ) ;
2017-02-12 13:21:08 +01:00
break ;
case Blockage :
2020-07-27 23:13:15 +02:00
name_suffix = mp_tech_comp - > blockages_suffix ( ) ;
dt = mp_tech_comp - > blockages_datatype ( ) ;
2017-02-12 13:21:08 +01:00
break ;
}
}
2020-11-21 20:39:31 +01:00
// "name" is the decorated name as provided by the tech component's x_suffix specifications.
2020-07-27 23:13:15 +02:00
std : : string name = n + name_suffix ;
2020-11-21 20:39:31 +01:00
// Assign a layer number (a default one for now) and the datatype from the tech component's x_datatype specification.
2020-07-30 23:53:34 +02:00
db : : LayerProperties lp ( name ) ;
2020-08-02 00:09:20 +02:00
lp . datatype = dt ;
std : : map < std : : string , int > : : const_iterator ldef = m_default_number . find ( n ) ;
if ( ldef ! = m_default_number . end ( ) ) {
lp . layer = ldef - > second ;
}
2017-02-12 13:21:08 +01:00
2020-11-21 20:39:31 +01:00
// Route the layer through the layer map, first the decorated name and if there is no mapping, the
// undecorated one.
2020-12-19 19:42:40 +01:00
std : : set < unsigned int > ll = m_layer_map . logical ( name , layout ) ;
2020-11-21 20:39:31 +01:00
bool generic_match = false ;
2020-12-19 19:42:40 +01:00
if ( ll . empty ( ) ) {
2020-08-02 00:09:20 +02:00
ll = m_layer_map . logical ( n , layout ) ;
2020-11-21 20:39:31 +01:00
generic_match = true ;
2020-11-21 21:06:05 +01:00
} else if ( n = = name ) {
// no suffix defined in tech component -> treat as generic match and combine datatypes
generic_match = true ;
2020-08-02 00:09:20 +02:00
}
2020-12-19 19:42:40 +01:00
if ( ll . empty ( ) & & ! m_create_layers ) {
return std : : set < unsigned int > ( ) ;
2020-08-02 00:09:20 +02:00
}
2020-12-19 19:42:40 +01:00
std : : set < unsigned int > res ;
2017-02-12 13:21:08 +01:00
2020-12-19 19:42:40 +01:00
bool at_least_once = true ;
for ( std : : set < unsigned int > : : const_iterator l = ll . begin ( ) ; l ! = ll . end ( ) | | at_least_once ; + + l ) {
at_least_once = false ;
2017-02-12 13:21:08 +01:00
2020-11-21 20:39:31 +01:00
// If the layer map provides a target, use that one for the layer
2020-12-19 19:42:40 +01:00
db : : LayerProperties lp_new = lp ;
const db : : LayerProperties * lpp = ( l = = ll . end ( ) ? 0 : m_layer_map . target ( * l ) ) ;
2020-07-30 23:53:34 +02:00
if ( lpp ) {
2020-12-19 19:42:40 +01:00
lp_new = * lpp ;
if ( lp_new . datatype < 0 ) {
lp_new . datatype = dt ;
2020-11-21 20:39:31 +01:00
} else if ( generic_match ) {
2020-12-19 19:42:40 +01:00
lp_new . datatype + = dt ;
2020-08-02 00:09:20 +02:00
}
2020-12-19 19:42:40 +01:00
if ( lp_new . name . empty ( ) ) {
lp_new . name = name ;
2020-11-21 20:39:31 +01:00
} else if ( generic_match ) {
2020-12-19 19:42:40 +01:00
lp_new . name + = name_suffix ;
2020-07-30 23:53:34 +02:00
}
}
2017-02-12 13:21:08 +01:00
2020-12-19 21:28:22 +01:00
int lfound = - 1 ;
2020-12-19 20:35:58 +01:00
if ( lp_new . layer > = 0 & & lp_new . datatype > = 0 ) {
2020-12-19 21:28:22 +01:00
for ( db : : Layout : : layer_iterator i = layout . begin_layers ( ) ; i ! = layout . end_layers ( ) & & lfound < 0 ; + + i ) {
2020-12-19 20:35:58 +01:00
if ( ( * i ) . second - > log_equal ( lp_new ) ) {
2020-12-19 21:28:22 +01:00
lfound = int ( ( * i ) . first ) ;
2020-12-19 20:35:58 +01:00
}
2020-08-02 00:09:20 +02:00
}
2017-02-12 13:21:08 +01:00
}
2020-12-19 19:42:40 +01:00
2020-12-19 21:28:22 +01:00
if ( lfound < 0 ) {
2020-12-19 19:42:40 +01:00
res . insert ( layout . insert_layer ( lp_new ) ) ;
2020-12-19 21:28:22 +01:00
} else {
res . insert ( ( unsigned int ) lfound ) ;
db : : LayerProperties lp_org = layout . get_properties ( ( unsigned int ) lfound ) ;
join_layer_names ( lp_org . name , name ) ;
layout . set_properties ( ( unsigned int ) lfound , lp_org ) ;
2020-12-19 19:42:40 +01:00
}
if ( l = = ll . end ( ) ) {
break ;
}
2017-02-12 13:21:08 +01:00
}
2020-12-19 19:42:40 +01:00
return res ;
2020-07-30 23:53:34 +02:00
2017-02-12 13:21:08 +01:00
}
}
void
2020-04-18 17:58:50 +02:00
LEFDEFReaderState : : finish ( db : : Layout & layout )
2017-02-12 13:21:08 +01:00
{
2022-04-23 22:26:37 +02:00
CommonReaderBase : : finish ( layout ) ;
2017-02-12 13:21:08 +01:00
int lnum = 0 ;
std : : set < int > used_numbers ;
for ( db : : Layout : : layer_iterator l = layout . begin_layers ( ) ; l ! = layout . end_layers ( ) ; + + l ) {
if ( ( * l ) . second - > layer > = 0 ) {
used_numbers . insert ( ( * l ) . second - > layer ) ;
}
}
2020-08-02 00:09:20 +02:00
std : : map < std : : string , int > number_for_name = m_default_number ;
for ( std : : map < std : : string , int > : : const_iterator ln = number_for_name . begin ( ) ; ln ! = number_for_name . end ( ) ; + + ln ) {
2017-02-12 13:21:08 +01:00
used_numbers . insert ( ln - > second ) ;
}
2020-08-02 00:09:20 +02:00
// Assign default numbers and generate a canonical mapping
db : : LayerMap lm ;
2021-02-21 21:00:55 +01:00
for ( std : : map < std : : pair < std : : string , LayerDetailsKey > , std : : set < unsigned int > > : : const_iterator l = m_layers . begin ( ) ; l ! = m_layers . end ( ) ; + + l ) {
2020-08-02 00:09:20 +02:00
2020-12-19 19:42:40 +01:00
if ( l - > second . empty ( ) ) {
2020-08-02 00:09:20 +02:00
continue ;
}
2021-02-21 21:00:55 +01:00
std : : string n = layer_spec_to_name ( l - > first . first , l - > first . second . purpose , l - > first . second . mask , l - > first . second . via_size ) ;
2020-08-02 00:09:20 +02:00
2020-12-19 19:42:40 +01:00
for ( std : : set < unsigned int > : : const_iterator li = l - > second . begin ( ) ; li ! = l - > second . end ( ) ; + + li ) {
unsigned int layer_index = * li ;
db : : LayerProperties lp = layout . get_properties ( layer_index ) ;
if ( lp . layer < 0 ) {
std : : map < std : : string , int > : : const_iterator n4n = number_for_name . end ( ) ;
if ( ! l - > first . first . empty ( ) ) {
n4n = number_for_name . find ( l - > first . first ) ;
}
if ( n4n = = number_for_name . end ( ) ) {
do {
+ + lnum ;
} while ( used_numbers . find ( lnum ) ! = used_numbers . end ( ) ) ;
number_for_name . insert ( std : : make_pair ( l - > first . first , lnum ) ) ;
lp . layer = lnum ;
} else {
lp . layer = n4n - > second ;
}
}
if ( lp . datatype < 0 ) {
lp . datatype = 0 ;
}
layout . set_properties ( layer_index , lp ) ;
lm . mmap ( db : : LayerProperties ( n ) , layer_index , lp ) ;
}
2017-02-12 13:21:08 +01:00
}
2020-08-02 00:09:20 +02:00
2020-11-21 20:39:31 +01:00
// On return we deliver the "canonical" map which lists the decorated name vs. the real ones.
2020-08-02 00:09:20 +02:00
m_layer_map = lm ;
2017-02-12 13:21:08 +01:00
}
2020-04-18 17:58:50 +02:00
void
2022-04-23 22:26:37 +02:00
LEFDEFReaderState : : register_via_cell ( const std : : string & vn , const std : : string & nondefaultrule , LEFDEFLayoutGenerator * generator )
2020-04-18 17:58:50 +02:00
{
2022-04-23 22:26:37 +02:00
if ( m_via_generators . find ( std : : make_pair ( vn , nondefaultrule ) ) ! = m_via_generators . end ( ) ) {
delete m_via_generators [ std : : make_pair ( vn , nondefaultrule ) ] ;
2020-07-25 22:15:09 +02:00
}
2022-04-23 22:26:37 +02:00
m_via_generators [ std : : make_pair ( vn , nondefaultrule ) ] = generator ;
2020-04-18 17:58:50 +02:00
}
2020-08-23 00:40:28 +02:00
LEFDEFLayoutGenerator *
2022-04-23 22:26:37 +02:00
LEFDEFReaderState : : via_generator ( const std : : string & vn , const std : : string & nondefaultrule )
2020-08-23 00:40:28 +02:00
{
2022-04-23 22:26:37 +02:00
std : : map < std : : pair < std : : string , std : : string > , LEFDEFLayoutGenerator * > : : const_iterator g = m_via_generators . find ( std : : make_pair ( vn , nondefaultrule ) ) ;
if ( g = = m_via_generators . end ( ) & & ! nondefaultrule . empty ( ) ) {
// default rule is fallback
g = m_via_generators . find ( std : : make_pair ( vn , std : : string ( ) ) ) ;
}
2020-08-23 00:40:28 +02:00
if ( g ! = m_via_generators . end ( ) ) {
return g - > second ;
} else {
return 0 ;
}
}
2020-04-18 17:58:50 +02:00
db : : Cell *
2022-04-23 22:26:37 +02:00
LEFDEFReaderState : : via_cell ( const std : : string & vn , const std : : string & nondefaultrule , db : : Layout & layout , unsigned int mask_bottom , unsigned int mask_cut , unsigned int mask_top , const LEFDEFNumberOfMasks * nm )
2020-04-18 17:58:50 +02:00
{
2022-04-23 22:26:37 +02:00
ViaKey vk ( vn , nondefaultrule , mask_bottom , mask_cut , mask_top ) ;
std : : map < std : : pair < std : : string , std : : string > , LEFDEFLayoutGenerator * > : : const_iterator g = m_via_generators . find ( std : : make_pair ( vn , nondefaultrule ) ) ;
if ( g = = m_via_generators . end ( ) & & ! vk . nondefaultrule . empty ( ) ) {
// default rule is fallback
g = m_via_generators . find ( std : : make_pair ( vn , std : : string ( ) ) ) ;
vk . nondefaultrule . clear ( ) ;
}
2020-07-25 22:15:09 +02:00
std : : map < ViaKey , db : : Cell * > : : const_iterator i = m_via_cells . find ( vk ) ;
if ( i = = m_via_cells . end ( ) ) {
db : : Cell * cell = 0 ;
if ( g ! = m_via_generators . end ( ) ) {
2020-08-22 21:15:39 +02:00
LEFDEFLayoutGenerator * vg = g - > second ;
2020-07-25 22:15:09 +02:00
2022-04-23 22:26:37 +02:00
std : : string n = vn ;
if ( ! vk . nondefaultrule . empty ( ) ) {
n + = " _ " ;
n + = vk . nondefaultrule ;
}
2020-07-25 22:15:09 +02:00
if ( mask_bottom > 0 | | mask_cut > 0 | | mask_top > 0 ) {
2022-04-23 22:26:37 +02:00
n + = " _ " ;
n + = tl : : to_string ( mask_bottom ) ;
n + = " _ " ;
n + = tl : : to_string ( mask_cut ) ;
n + = " _ " ;
n + = tl : : to_string ( mask_top ) ;
2020-07-25 22:15:09 +02:00
}
2022-04-23 22:26:37 +02:00
std : : string cn = mp_tech_comp - > via_cellname_prefix ( ) + n ;
cell = & layout . cell ( make_cell ( layout , cn . c_str ( ) ) ) ;
2020-07-25 22:15:09 +02:00
2020-08-22 21:15:39 +02:00
std : : vector < unsigned int > masks ;
masks . reserve ( 3 ) ;
masks . push_back ( mask_bottom ) ;
masks . push_back ( mask_cut ) ;
masks . push_back ( mask_top ) ;
2020-08-23 18:58:52 +02:00
vg - > create_cell ( * this , layout , * cell , 0 , masks , nm ) ;
2020-07-25 22:15:09 +02:00
}
m_via_cells [ vk ] = cell ;
return cell ;
} else {
tl_assert ( ! i - > second | | i - > second - > layout ( ) = = & layout ) ;
return i - > second ;
}
2020-04-18 17:58:50 +02:00
}
2020-08-23 00:40:28 +02:00
void
LEFDEFReaderState : : register_macro_cell ( const std : : string & mn , LEFDEFLayoutGenerator * generator )
{
if ( m_macro_generators . find ( mn ) ! = m_macro_generators . end ( ) ) {
delete m_macro_generators [ mn ] ;
}
m_macro_generators [ mn ] = generator ;
}
LEFDEFLayoutGenerator *
LEFDEFReaderState : : macro_generator ( const std : : string & mn )
{
std : : map < std : : string , LEFDEFLayoutGenerator * > : : const_iterator g = m_macro_generators . find ( mn ) ;
if ( g ! = m_macro_generators . end ( ) ) {
return g - > second ;
} else {
return 0 ;
}
}
2020-08-30 01:37:14 +02:00
db : : cell_index_type
LEFDEFReaderState : : foreign_cell ( Layout & layout , const std : : string & name )
{
std : : map < std : : string , db : : cell_index_type > : : const_iterator c = m_foreign_cells . find ( name ) ;
if ( c ! = m_foreign_cells . end ( ) ) {
return c - > second ;
2020-08-30 02:15:30 +02:00
}
std : : pair < bool , db : : cell_index_type > cc = layout . cell_by_name ( name . c_str ( ) ) ;
db : : cell_index_type ci ;
if ( cc . first ) {
ci = cc . second ;
2020-08-30 01:37:14 +02:00
} else {
2022-04-23 22:26:37 +02:00
ci = make_cell ( layout , name . c_str ( ) ) ;
2020-08-30 01:37:14 +02:00
layout . cell ( ci ) . set_ghost_cell ( true ) ;
}
2020-08-30 02:15:30 +02:00
m_foreign_cells . insert ( std : : make_pair ( name , ci ) ) ;
return ci ;
2020-08-30 01:37:14 +02:00
}
2020-08-23 00:40:28 +02:00
std : : pair < db : : Cell * , db : : Trans >
2020-08-23 18:58:52 +02:00
LEFDEFReaderState : : macro_cell ( const std : : string & mn , Layout & layout , const std : : vector < std : : string > & maskshift_layers , const std : : vector < unsigned int > & masks , const MacroDesc & macro_desc , const LEFDEFNumberOfMasks * nm )
2020-08-23 00:40:28 +02:00
{
2020-08-23 18:58:52 +02:00
std : : map < std : : string , LEFDEFLayoutGenerator * > : : const_iterator g = m_macro_generators . find ( mn ) ;
if ( g = = m_macro_generators . end ( ) ) {
return std : : make_pair ( ( db : : Cell * ) 0 , db : : Trans ( ) ) ;
}
LEFDEFLayoutGenerator * mg = g - > second ;
MacroKey mk ;
if ( mg - > is_fixedmask ( ) ) {
mk = MacroKey ( mn , std : : vector < unsigned int > ( ) ) ;
} else {
mk = MacroKey ( mn , masks ) ;
}
2020-08-23 00:40:28 +02:00
std : : map < MacroKey , std : : pair < db : : Cell * , db : : Trans > > : : const_iterator i = m_macro_cells . find ( mk ) ;
if ( i ! = m_macro_cells . end ( ) ) {
tl_assert ( ! i - > second . first | | i - > second . first - > layout ( ) = = & layout ) ;
return i - > second ;
}
db : : Cell * cell = 0 ;
db : : Trans tr ;
if ( ! macro_desc . foreign_name . empty ( ) ) {
2020-08-30 01:37:14 +02:00
db : : cell_index_type ci = foreign_cell ( layout , macro_desc . foreign_name ) ;
2020-08-23 00:40:28 +02:00
db : : Cell * foreign_cell = & layout . cell ( ci ) ;
if ( macro_desc . foreign_name ! = mn ) {
// create an indirection for renaming the cell
2022-04-23 22:26:37 +02:00
cell = & layout . cell ( make_cell ( layout , mn . c_str ( ) ) ) ;
2020-08-23 00:40:28 +02:00
cell - > insert ( db : : CellInstArray ( db : : CellInst ( foreign_cell - > cell_index ( ) ) , db : : Trans ( db : : Point ( ) - macro_desc . origin ) * macro_desc . foreign_trans ) ) ;
} else {
// use FOREIGN cell instead of new one
cell = foreign_cell ;
tr = db : : Trans ( db : : Point ( ) - macro_desc . origin ) * macro_desc . foreign_trans ;
}
} else if ( tech_comp ( ) - > macro_resolution_mode ( ) = = 2 ) {
// create a ghost cell always
2020-08-30 01:37:14 +02:00
db : : cell_index_type ci = foreign_cell ( layout , mn ) ;
2020-08-23 00:40:28 +02:00
cell = & layout . cell ( ci ) ;
} else {
// actually implement the real cell
std : : string mask_suffix ;
2020-08-23 18:58:52 +02:00
if ( ! mg - > is_fixedmask ( ) ) {
for ( std : : vector < unsigned int > : : const_iterator m = masks . begin ( ) ; m ! = masks . end ( ) ; + + m ) {
mask_suffix + = " _ " ;
mask_suffix + = tl : : to_string ( * m ) ;
}
2020-08-23 00:40:28 +02:00
}
std : : string cn = mn + mask_suffix ;
2022-04-23 22:26:37 +02:00
cell = & layout . cell ( make_cell ( layout , cn . c_str ( ) ) ) ;
2020-08-23 18:58:52 +02:00
if ( mg - > is_fixedmask ( ) ) {
mg - > create_cell ( * this , layout , * cell , 0 , std : : vector < unsigned int > ( ) , nm ) ;
} else {
mg - > create_cell ( * this , layout , * cell , & maskshift_layers , masks , nm ) ;
}
2020-08-23 00:40:28 +02:00
}
m_macro_cells [ mk ] = std : : make_pair ( cell , tr ) ;
return std : : make_pair ( cell , tr ) ;
}
2017-02-12 13:21:08 +01:00
// -----------------------------------------------------------------------------------
// LEFDEFImporter implementation
2022-08-13 22:15:07 +02:00
LEFDEFImporter : : LEFDEFImporter ( int warn_level )
2020-04-18 17:58:50 +02:00
: mp_progress ( 0 ) , mp_stream ( 0 ) , mp_reader_state ( 0 ) ,
2017-09-04 23:05:46 +02:00
m_produce_net_props ( false ) , m_net_prop_name_id ( 0 ) ,
2020-02-23 00:29:12 +01:00
m_produce_inst_props ( false ) , m_inst_prop_name_id ( 0 ) ,
2022-08-13 22:15:07 +02:00
m_produce_pin_props ( false ) , m_pin_prop_name_id ( 0 ) ,
m_warn_level ( warn_level )
2017-02-12 13:21:08 +01:00
{
// .. nothing yet ..
}
LEFDEFImporter : : ~ LEFDEFImporter ( )
{
// .. nothing yet ..
}
2020-07-18 22:59:02 +02:00
unsigned int
LEFDEFImporter : : get_mask ( long m )
{
2020-07-25 22:15:09 +02:00
return ( unsigned int ) m ;
2020-07-18 22:59:02 +02:00
}
2017-02-12 13:21:08 +01:00
void
2020-04-18 17:58:50 +02:00
LEFDEFImporter : : read ( tl : : InputStream & stream , db : : Layout & layout , LEFDEFReaderState & state )
2017-02-12 13:21:08 +01:00
{
2022-04-23 22:26:37 +02:00
tl : : log < < tl : : to_string ( tr ( " Reading LEF/DEF file " ) ) < < " " < < stream . absolute_path ( ) ;
2017-02-12 13:21:08 +01:00
m_fn = stream . filename ( ) ;
2018-07-03 00:51:36 +02:00
tl : : AbsoluteProgress progress ( tl : : to_string ( tr ( " Reading " ) ) + m_fn , 1000 ) ;
progress . set_format ( tl : : to_string ( tr ( " %.0fk lines " ) ) ) ;
2017-02-12 13:21:08 +01:00
progress . set_format_unit ( 1000.0 ) ;
progress . set_unit ( 10000.0 ) ;
2020-04-18 17:58:50 +02:00
mp_reader_state = & state ;
2022-04-23 22:26:37 +02:00
mp_reader_state - > attach_reader ( this ) ;
2020-04-18 17:58:50 +02:00
if ( state . tech_comp ( ) ) {
m_options = * state . tech_comp ( ) ;
}
2017-02-12 13:21:08 +01:00
m_produce_net_props = false ;
m_net_prop_name_id = 0 ;
2020-04-18 17:58:50 +02:00
if ( m_options . produce_net_names ( ) ) {
2017-02-12 13:21:08 +01:00
m_produce_net_props = true ;
2020-04-18 17:58:50 +02:00
m_net_prop_name_id = layout . properties_repository ( ) . prop_name_id ( m_options . net_property_name ( ) ) ;
2017-02-12 13:21:08 +01:00
}
2017-09-04 23:05:46 +02:00
m_produce_inst_props = false ;
m_inst_prop_name_id = 0 ;
2020-04-18 17:58:50 +02:00
if ( m_options . produce_inst_names ( ) ) {
2017-09-04 23:05:46 +02:00
m_produce_inst_props = true ;
2020-04-18 17:58:50 +02:00
m_inst_prop_name_id = layout . properties_repository ( ) . prop_name_id ( m_options . inst_property_name ( ) ) ;
2017-09-04 23:05:46 +02:00
}
2020-02-23 00:29:12 +01:00
m_produce_pin_props = false ;
m_pin_prop_name_id = 0 ;
2020-04-18 17:58:50 +02:00
if ( m_options . produce_pin_names ( ) ) {
2020-02-23 00:29:12 +01:00
m_produce_pin_props = true ;
2020-04-18 17:58:50 +02:00
m_pin_prop_name_id = layout . properties_repository ( ) . prop_name_id ( m_options . pin_property_name ( ) ) ;
2020-02-23 00:29:12 +01:00
}
2017-02-12 13:21:08 +01:00
try {
mp_progress = & progress ;
mp_stream = new tl : : TextInputStream ( stream ) ;
do_read ( layout ) ;
2022-04-23 22:26:37 +02:00
mp_reader_state - > attach_reader ( 0 ) ;
2017-02-12 13:21:08 +01:00
delete mp_stream ;
mp_stream = 0 ;
mp_progress = 0 ;
} catch ( . . . ) {
2022-04-23 22:26:37 +02:00
mp_reader_state - > attach_reader ( 0 ) ;
2017-02-12 13:21:08 +01:00
delete mp_stream ;
mp_stream = 0 ;
mp_progress = 0 ;
throw ;
}
}
void
LEFDEFImporter : : error ( const std : : string & msg )
{
2023-02-16 23:49:24 +01:00
if ( m_sections . empty ( ) ) {
throw LEFDEFReaderException ( msg , int ( mp_stream - > line_number ( ) ) , m_cellname , m_fn ) ;
} else {
throw LEFDEFReaderException ( msg + tl : : sprintf ( tl : : to_string ( tr ( " (inside %s) " )), tl::join (m_sections, " / " )), int (mp_stream->line_number ()), m_cellname, m_fn) ;
}
2017-02-12 13:21:08 +01:00
}
void
2022-08-13 22:15:07 +02:00
LEFDEFImporter : : warn ( const std : : string & msg , int wl )
2017-02-12 13:21:08 +01:00
{
2022-08-13 22:15:07 +02:00
if ( m_warn_level < wl ) {
return ;
}
2017-02-12 13:21:08 +01:00
tl : : warn < < msg
2018-07-03 00:51:36 +02:00
< < tl : : to_string ( tr ( " (line= " ) ) < < mp_stream - > line_number ( )
< < tl : : to_string ( tr ( " , cell= " ) ) < < m_cellname
< < tl : : to_string ( tr ( " , file= " ) ) < < m_fn
2017-02-12 13:21:08 +01:00
< < " ) " ;
}
bool
LEFDEFImporter : : at_end ( )
{
if ( m_last_token . empty ( ) ) {
if ( next ( ) . empty ( ) ) {
return true ;
}
}
return false ;
}
bool
LEFDEFImporter : : peek ( const std : : string & token )
{
if ( m_last_token . empty ( ) ) {
if ( next ( ) . empty ( ) ) {
error ( " Unexpected end of file " ) ;
}
}
const char * a = m_last_token . c_str ( ) ;
const char * b = token . c_str ( ) ;
while ( * a & & * b ) {
if ( std : : toupper ( * a ) ! = std : : toupper ( * b ) ) {
return false ;
}
+ + a , + + b ;
}
return * a = = * b ;
}
bool
LEFDEFImporter : : test ( const std : : string & token )
{
if ( peek ( token ) ) {
// consume when successful
m_last_token . clear ( ) ;
return true ;
} else {
return false ;
}
}
void
LEFDEFImporter : : expect ( const std : : string & token )
{
if ( ! test ( token ) ) {
error ( " Expected token: " + token ) ;
}
}
2020-04-04 00:40:01 +02:00
void
LEFDEFImporter : : expect ( const std : : string & token1 , const std : : string & token2 )
{
if ( ! test ( token1 ) & & ! test ( token2 ) ) {
error ( " Expected token: " + token1 + " or " + token2 ) ;
}
}
void
LEFDEFImporter : : expect ( const std : : string & token1 , const std : : string & token2 , const std : : string & token3 )
{
if ( ! test ( token1 ) & & ! test ( token2 ) & & ! test ( token3 ) ) {
error ( " Expected token: " + token1 + " , " + token2 + " or " + token3 ) ;
}
}
double
2017-02-12 13:21:08 +01:00
LEFDEFImporter : : get_double ( )
{
if ( m_last_token . empty ( ) ) {
if ( next ( ) . empty ( ) ) {
error ( " Unexpected end of file " ) ;
}
}
double d = 0 ;
try {
tl : : from_string ( m_last_token , d ) ;
} catch ( . . . ) {
error ( " Not a floating-point value: " + m_last_token ) ;
}
m_last_token . clear ( ) ;
return d ;
}
long
LEFDEFImporter : : get_long ( )
{
if ( m_last_token . empty ( ) ) {
if ( next ( ) . empty ( ) ) {
error ( " Unexpected end of file " ) ;
}
}
long l = 0 ;
try {
tl : : from_string ( m_last_token , l ) ;
} catch ( . . . ) {
error ( " Not an integer value: " + m_last_token ) ;
}
m_last_token . clear ( ) ;
return l ;
}
void
LEFDEFImporter : : take ( )
{
if ( m_last_token . empty ( ) ) {
if ( next ( ) . empty ( ) ) {
error ( " Unexpected end of file " ) ;
}
}
m_last_token . clear ( ) ;
}
std : : string
LEFDEFImporter : : get ( )
{
if ( m_last_token . empty ( ) ) {
if ( next ( ) . empty ( ) ) {
error ( " Unexpected end of file " ) ;
}
}
std : : string r ;
r . swap ( m_last_token ) ;
return r ;
}
2023-02-16 23:49:24 +01:00
void
LEFDEFImporter : : enter_section ( const std : : string & name )
{
m_sections . push_back ( name ) ;
}
void
LEFDEFImporter : : leave_section ( )
{
m_sections . pop_back ( ) ;
}
2017-02-12 13:21:08 +01:00
const std : : string &
LEFDEFImporter : : next ( )
{
2018-08-29 01:46:18 +02:00
unsigned int last_line = ( unsigned int ) mp_stream - > line_number ( ) ;
2017-02-12 13:21:08 +01:00
m_last_token . clear ( ) ;
char c ;
do {
while ( ( c = mp_stream - > get_char ( ) ) ! = 0 & & isspace ( c ) )
;
if ( c = = ' # ' ) {
while ( ( c = mp_stream - > get_char ( ) ) ! = 0 & & ( c ! = ' \015 ' & & c ! = ' \012 ' ) )
;
} else if ( c = = ' \' ' | | c = = ' " ' ) {
char quot = c ;
while ( ( c = mp_stream - > get_char ( ) ) ! = 0 & & c ! = quot ) {
if ( c = = ' \\ ' ) {
c = mp_stream - > get_char ( ) ;
}
if ( c ) {
m_last_token + = c ;
}
}
break ;
} else if ( c ) {
m_last_token + = c ;
while ( ( c = mp_stream - > get_char ( ) ) ! = 0 & & ! isspace ( c ) ) {
if ( c = = ' \\ ' ) {
c = mp_stream - > get_char ( ) ;
}
if ( c ) {
m_last_token + = c ;
}
}
break ;
}
} while ( c ) ;
if ( mp_stream - > line_number ( ) ! = last_line ) {
+ + * mp_progress ;
}
return m_last_token ;
}
2020-04-19 12:16:55 +02:00
db : : FTrans
LEFDEFImporter : : get_orient ( bool optional )
{
if ( test ( " N " ) ) {
return db : : FTrans ( db : : FTrans : : r0 ) ;
} else if ( test ( " S " ) ) {
return db : : FTrans ( db : : FTrans : : r180 ) ;
} else if ( test ( " W " ) ) {
return db : : FTrans ( db : : FTrans : : r90 ) ;
} else if ( test ( " E " ) ) {
return db : : FTrans ( db : : FTrans : : r270 ) ;
} else if ( test ( " FN " ) ) {
return db : : FTrans ( db : : FTrans : : m90 ) ;
} else if ( test ( " FS " ) ) {
return db : : FTrans ( db : : FTrans : : m0 ) ;
} else if ( test ( " FW " ) ) {
return db : : FTrans ( db : : FTrans : : m45 ) ;
} else if ( test ( " FE " ) ) {
return db : : FTrans ( db : : FTrans : : m135 ) ;
} else if ( optional ) {
return db : : FTrans ( db : : FTrans : : r0 ) ;
} else {
error ( tl : : to_string ( tr ( " Invalid orientation specification: " ) ) + get ( ) ) ;
return db : : FTrans ( db : : FTrans : : r0 ) ;
}
}
db : : Point
LEFDEFImporter : : get_point ( double scale )
{
double x = get_double ( ) ;
double y = get_double ( ) ;
return db : : Point ( db : : DPoint ( x * scale , y * scale ) ) ;
}
db : : Vector
LEFDEFImporter : : get_vector ( double scale )
{
double x = get_double ( ) ;
double y = get_double ( ) ;
return db : : Vector ( db : : DVector ( x * scale , y * scale ) ) ;
}
2017-02-12 13:21:08 +01:00
}