Merge branch 'lefdef-enhancments'

This commit is contained in:
Matthias Koefferlein 2020-06-01 13:37:45 +02:00
commit d7af7fc5c0
61 changed files with 3996 additions and 1815 deletions

View File

@ -140,7 +140,7 @@ struct XORData
double tile_size;
db::Layout *output_layout;
db::cell_index_type output_cell;
std::map<db::LayerProperties, std::pair<int, int> > l2l_map;
std::map<db::LayerProperties, std::pair<int, int>, db::LPLogicalLessFunc> l2l_map;
std::map<std::pair<int, db::LayerProperties>, ResultDescriptor> *results;
};
@ -299,7 +299,7 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
throw tl::Exception ("'" + top_b + "' is not a valid cell name in second layout");
}
std::map<db::LayerProperties, std::pair<int, int> > l2l_map;
std::map<db::LayerProperties, std::pair<int, int>, db::LPLogicalLessFunc> l2l_map;
for (db::Layout::layer_iterator l = layout_a.begin_layers (); l != layout_a.end_layers (); ++l) {
l2l_map.insert (std::make_pair (*(*l).second, std::make_pair (-1, -1))).first->second.first = (*l).first;

View File

@ -42,7 +42,7 @@ namespace db
*
* This implementation will create new layers if required.
*/
class DirectLayerMapping
class DB_PUBLIC DirectLayerMapping
: public ImportLayerMapping
{
public:

View File

@ -24,6 +24,8 @@
#include "dbReader.h"
#include "dbStream.h"
#include "tlClassRegistry.h"
#include "tlTimer.h"
#include "tlLog.h"
namespace db
{
@ -74,5 +76,21 @@ Reader::~Reader ()
}
}
const db::LayerMap &
Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading file: ")) + m_stream.source ());
return mp_actual_reader->read (layout, options);
}
const db::LayerMap &
Reader::read (db::Layout &layout)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading file: ")) + m_stream.source ());
return mp_actual_reader->read (layout);
}
}

View File

@ -125,10 +125,7 @@ public:
* @param layout The layout object to write to
* @param options The LayerMap object
*/
const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions &options)
{
return mp_actual_reader->read (layout, options);
}
const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions &options);
/**
* @brief The basic read method (without mapping)
@ -143,10 +140,7 @@ public:
* @param layout The layout object to write to
* @return The LayerMap object
*/
const db::LayerMap &read (db::Layout &layout)
{
return mp_actual_reader->read (layout);
}
const db::LayerMap &read (db::Layout &layout);
/**
* @brief Returns a format describing the file format found

View File

@ -26,6 +26,8 @@
#include "tlClassRegistry.h"
#include "tlAssert.h"
#include "tlStream.h"
#include "tlTimer.h"
#include "tlLog.h"
namespace db
{
@ -54,6 +56,8 @@ Writer::~Writer ()
void
Writer::write (db::Layout &layout, tl::OutputStream &stream)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Writing file: ")) + stream.path ());
tl_assert (mp_writer != 0);
mp_writer->write (layout, stream, m_options);
}

View File

@ -1839,10 +1839,15 @@ LayerPropertiesList::load (tl::XMLSource &stream, std::vector <lay::LayerPropert
lay::LayerPropertiesList properties_list;
layer_prop_list_structure.parse (stream, properties_list);
properties_lists.push_back (properties_list);
} catch (...) {
// "new" way
stream.reset ();
layer_prop_lists_structure.parse (stream, properties_lists);
} catch (tl::Exception &ex) {
try {
// "new" way
stream.reset ();
layer_prop_lists_structure.parse (stream, properties_lists);
} catch (tl::Exception &) {
// the first exception is likely to be the root cause, so let's rather throw this one
throw ex;
}
}
}

View File

@ -818,8 +818,6 @@ CIFReader::read_cell (db::Layout &layout, db::Cell &cell, double sf, int level)
void
CIFReader::do_read (db::Layout &layout)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_stream.source ());
try {
double sf = 0.01 / m_dbu;

View File

@ -379,8 +379,6 @@ DXFReader::open_layer (db::Layout &layout, const std::string &n)
void
DXFReader::do_read (db::Layout &layout, db::cell_index_type top)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_stream.source ());
// create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as
// a layer named "0".
std::pair<bool, unsigned int> ll = layer_map ().logical (zero_layer_name, layout);

View File

@ -233,8 +233,6 @@ eq_y (const GDS2XY &a, const GDS2XY &b)
void
GDS2ReaderBase::do_read (db::Layout &layout)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + path ());
m_cellname = "";
m_libname = "";
m_mapped_cellnames.clear ();

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,8 @@
namespace db
{
struct DEFImporterGroup;
/**
* @brief The DEF importer object
*/
@ -54,18 +56,33 @@ public:
* This method reads the layout specified into the given layout.
* Multiple LEF files can be read.
*/
void read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDelegate &ld);
void read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state);
protected:
void do_read (db::Layout &layout);
private:
LEFImporter m_lef_importer;
std::map<std::string, std::map<std::string, double> > m_nondefault_widths;
std::map<std::string, std::map<std::string, db::Coord> > m_nondefault_widths;
std::map<std::string, ViaDesc> m_via_desc;
std::map<int, db::Polygon> m_styles;
db::FTrans get_orient (bool optional);
void read_polygon (db::Polygon &poly, double scale);
void read_rect (db::Polygon &poly, double scale);
std::pair<Coord, Coord> get_wire_width_for_rule(const std::string &rule, const std::string &ln, double dbu);
std::pair<db::Coord, db::Coord> get_def_ext (const std::string &ln, const std::pair<db::Coord, db::Coord> &wxy, double dbu);
void read_diearea (db::Layout &layout, db::Cell &design, double scale);
void read_nondefaultrules (double scale);
void read_regions (std::map<std::string, std::vector<db::Polygon> > &regions, double scale);
void read_groups (std::list<DEFImporterGroup> &groups, double scale);
void read_blockages (db::Layout &layout, db::Cell &design, double scale);
void read_nets (db::Layout &layout, db::Cell &design, double scale, bool specialnets);
void read_vias (db::Layout &layout, db::Cell &design, double scale);
void read_pins (db::Layout &layout, db::Cell &design, double scale);
void read_styles (double scale);
void read_components (std::list<std::pair<std::string, db::CellInstArray> > &instances, double scale);
void read_single_net (std::string &nondefaultrule, db::Layout &layout, db::Cell &design, double scale, properties_id_type prop_id, bool specialnets);
void produce_routing_geometry (db::Cell &design, const db::Polygon *style, unsigned int layer, properties_id_type prop_id, const std::vector<db::Point> &pts, const std::vector<std::pair<db::Coord, db::Coord> > &ext, std::pair<db::Coord, db::Coord> w);
};
}

View File

@ -22,9 +22,11 @@
#include "dbLEFDEFImporter.h"
#include "dbLayoutUtils.h"
#include "tlStream.h"
#include "tlProgress.h"
#include "tlFileUtils.h"
#include <cctype>
@ -52,9 +54,13 @@ LEFDEFReaderOptions::LEFDEFReaderOptions ()
m_produce_via_geometry (true),
m_via_geometry_suffix (""),
m_via_geometry_datatype (0),
m_via_cellname_prefix ("VIA_"),
m_produce_pins (true),
m_pins_suffix (".PIN"),
m_pins_datatype (2),
m_produce_lef_pins (true),
m_lef_pins_suffix (".PIN"),
m_lef_pins_datatype (2),
m_produce_obstructions (true),
m_obstructions_suffix (".OBS"),
m_obstructions_datatype (3),
@ -66,7 +72,13 @@ LEFDEFReaderOptions::LEFDEFReaderOptions ()
m_labels_datatype (1),
m_produce_routing (true),
m_routing_suffix (""),
m_routing_datatype (0)
m_routing_datatype (0),
m_produce_special_routing (true),
m_special_routing_suffix (""),
m_special_routing_datatype (0),
m_separate_groups (false),
m_map_file (),
m_macro_resolution_mode (0)
{
// .. nothing yet ..
}
@ -99,9 +111,13 @@ LEFDEFReaderOptions &LEFDEFReaderOptions::operator= (const LEFDEFReaderOptions &
m_produce_via_geometry = d.m_produce_via_geometry;
m_via_geometry_suffix = d.m_via_geometry_suffix;
m_via_geometry_datatype = d.m_via_geometry_datatype;
m_via_cellname_prefix = d.m_via_cellname_prefix;
m_produce_pins = d.m_produce_pins;
m_pins_suffix = d.m_pins_suffix;
m_pins_datatype = d.m_pins_datatype;
m_produce_lef_pins = d.m_produce_lef_pins;
m_lef_pins_suffix = d.m_lef_pins_suffix;
m_lef_pins_datatype = d.m_lef_pins_datatype;
m_produce_obstructions = d.m_produce_obstructions;
m_obstructions_suffix = d.m_obstructions_suffix;
m_obstructions_datatype = d.m_obstructions_datatype;
@ -114,6 +130,12 @@ LEFDEFReaderOptions &LEFDEFReaderOptions::operator= (const LEFDEFReaderOptions &
m_produce_routing = d.m_produce_routing;
m_routing_suffix = d.m_routing_suffix;
m_routing_datatype = d.m_routing_datatype;
m_produce_special_routing = d.m_produce_special_routing;
m_special_routing_suffix = d.m_special_routing_suffix;
m_special_routing_datatype = d.m_special_routing_datatype;
m_separate_groups = d.m_separate_groups;
m_map_file = d.m_map_file;
m_macro_resolution_mode = d.m_macro_resolution_mode;
m_lef_files = d.m_lef_files;
}
return *this;
@ -135,37 +157,194 @@ LEFDEFReaderOptions::format_name () const
// -----------------------------------------------------------------------------------
// LEFDEFLayerDelegate implementation
LEFDEFLayerDelegate::LEFDEFLayerDelegate (const LEFDEFReaderOptions *tc)
: m_create_layers (true), m_laynum (1), mp_tech_comp (tc)
LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout)
: m_create_layers (true), m_has_explicit_layer_mapping (false), m_laynum (1), mp_tech_comp (tc)
{
if (tc) {
m_layer_map = tc->layer_map ();
m_create_layers = tc->read_all_layers ();
}
m_layer_map.prepare (layout);
}
void
LEFDEFLayerDelegate::register_layer (const std::string &ln)
LEFDEFReaderState::register_layer (const std::string &ln)
{
m_default_number.insert (std::make_pair (ln, m_laynum));
++m_laynum;
}
std::pair <bool, unsigned int>
LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose)
void
LEFDEFReaderState::set_explicit_layer_mapping (bool f)
{
if (purpose == Outline || purpose == PlacementBlockage || purpose == Region) {
m_has_explicit_layer_mapping = f;
if (! f) {
m_layers.clear ();
}
}
void
LEFDEFReaderState::map_layer_explicit (const std::string &n, LayerPurpose purpose, const db::LayerProperties &lp, unsigned int layer)
{
m_layers [std::make_pair (n, purpose)] = std::make_pair (true, layer);
m_layer_map.map (lp, layer);
}
void
LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
{
tl::log << tl::to_string (tr ("Reading LEF/DEF map file")) << " " << path;
tl::InputFile file (path);
tl::InputStream file_stream (file);
tl::TextInputStream ts (file_stream);
std::map<std::string, LayerPurpose> purpose_translation;
purpose_translation ["LEFPIN"] = LEFPins;
purpose_translation ["PIN"] = Pins;
purpose_translation ["LEFOBS"] = Obstructions;
purpose_translation ["SPNET"] = SpecialRouting;
purpose_translation ["NET"] = Routing;
purpose_translation ["VIA"] = ViaGeometry;
purpose_translation ["BLOCKAGE"] = Blockage;
std::map<std::pair<std::string, LayerPurpose>, db::LayerProperties> layer_map;
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;
int layer = 0, datatype = 0;
if (ex.try_read_word (w1) && ex.try_read_word (w2, "._$,/:") && ex.try_read (layer) && ex.try_read (datatype)) {
if (w1 == "DIEAREA") {
layer_map [std::make_pair (std::string (), Outline)] = db::LayerProperties (layer, datatype, "OUTLINE");
} else if (w1 == "REGIONS") {
layer_map [std::make_pair (std::string (), Regions)] = db::LayerProperties (layer, datatype, "REGIONS");
} else if (w1 == "BLOCKAGE") {
layer_map [std::make_pair (std::string (), PlacementBlockage)] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK");
} else if (w1 == "NAME") {
// converts a line like
// "NAME M1/PINS,M2/PINS ..."
// into a canonical name mapping like
// "(M1/LABELS): M1.LABEL"
// "(M2/LABELS): M2.LABEL"
std::vector<std::string> layers;
std::vector<std::string> purposes = tl::split (w2, ",");
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
layers.push_back (tl::split (*p, "/").front ());
}
std::string final_name = tl::join (layers, "/") + ".LABEL";
for (std::vector<std::string>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
layer_map [std::make_pair (*l, Label)] = db::LayerProperties (layer, datatype, final_name);
}
} else {
// 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)
std::set<LayerPurpose> translated_purposes;
std::string purpose_str;
std::vector<std::string> purposes = tl::split (w2, ",");
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
std::map<std::string, LayerPurpose>::const_iterator i = purpose_translation.find (tl::to_upper_case (*p));
if (i != purpose_translation.end ()) {
translated_purposes.insert (i->second);
if (! purpose_str.empty ()) {
purpose_str += "/";
}
purpose_str += i->first;
}
}
std::string final_name = w1 + "." + purpose_str;
for (std::set<LayerPurpose>::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
layer_map [std::make_pair (w1, *p)] = db::LayerProperties (layer, datatype, final_name);
}
}
}
}
}
set_explicit_layer_mapping (true);
db::DirectLayerMapping lm (&layout);
for (std::map<std::pair<std::string, LayerPurpose>, db::LayerProperties>::const_iterator i = layer_map.begin (); i != layer_map.end (); ++i) {
map_layer_explicit (i->first.first, i->first.second, i->second, lm.map_layer (i->second).second);
}
}
std::pair <bool, unsigned int>
LEFDEFReaderState::open_layer (db::Layout &layout, const std::string &n, LayerPurpose purpose)
{
std::map <std::pair<std::string, LayerPurpose>, std::pair<bool, unsigned int> >::const_iterator nl = m_layers.find (std::make_pair (n, purpose));
if (nl == m_layers.end ()) {
std::pair <bool, unsigned int> ll (false, 0);
if (n.empty () || ! m_has_explicit_layer_mapping) {
ll = open_layer_uncached (layout, n, purpose);
}
m_layers.insert (std::make_pair (std::make_pair (n, purpose), ll));
return ll;
} else {
return nl->second;
}
}
std::pair <bool, unsigned int>
LEFDEFReaderState::open_layer_uncached (db::Layout &layout, const std::string &n, LayerPurpose purpose)
{
if (n.empty ()) {
// NOTE: the canonical name is independent from the tech component's settings
// as is "(name)". It's used for implementing the automatic map file import
// feature.
std::string ld;
bool produce;
bool produce = false;
if (purpose == Outline) {
produce = mp_tech_comp->produce_cell_outlines ();
ld = mp_tech_comp->cell_outline_layer ();
} else if (purpose == Region) {
} else if (purpose == Regions) {
produce = mp_tech_comp->produce_regions ();
ld = mp_tech_comp->region_layer ();
} else {
} else if (purpose == PlacementBlockage) {
produce = mp_tech_comp->produce_placement_blockages ();
ld = mp_tech_comp->placement_blockage_layer ();
}
@ -187,11 +366,6 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
if (ll.first) {
// create the layer if it is not part of the layout yet.
if (! layout.is_valid_layer (ll.second)) {
layout.insert_layer (ll.second, m_layer_map.mapping (ll.second));
}
return ll;
} else if (! m_create_layers) {
@ -208,67 +382,95 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
} else {
if (mp_tech_comp) {
bool produce = true;
switch (purpose) {
case Routing:
default:
produce = mp_tech_comp->produce_routing ();
break;
case SpecialRouting:
produce = mp_tech_comp->produce_special_routing ();
break;
case ViaGeometry:
produce = mp_tech_comp->produce_via_geometry ();
break;
case Label:
produce = mp_tech_comp->produce_labels ();
break;
case Pins:
produce = mp_tech_comp->produce_pins ();
break;
case LEFPins:
produce = mp_tech_comp->produce_lef_pins ();
break;
case Obstructions:
produce = mp_tech_comp->produce_obstructions ();
break;
case Blockage:
produce = mp_tech_comp->produce_blockages ();
break;
}
if (! produce) {
return std::make_pair (false, 0);
}
}
// Note: "name" is the decorated name as provided by the tech component's
// x_suffix specifications.
std::string name (n);
bool produce = true;
int dt = 0;
if (mp_tech_comp) {
switch (purpose) {
case Routing:
default:
produce = mp_tech_comp->produce_routing ();
name += mp_tech_comp->routing_suffix ();
dt += mp_tech_comp->routing_datatype ();
break;
case SpecialRouting:
name += mp_tech_comp->special_routing_suffix ();
dt += mp_tech_comp->special_routing_datatype ();
break;
case ViaGeometry:
produce = mp_tech_comp->produce_via_geometry ();
name += mp_tech_comp->via_geometry_suffix ();
dt += mp_tech_comp->via_geometry_datatype ();
break;
case Label:
produce = mp_tech_comp->produce_labels ();
name += mp_tech_comp->labels_suffix ();
dt += mp_tech_comp->labels_datatype ();
break;
case Pins:
produce = mp_tech_comp->produce_pins ();
name += mp_tech_comp->pins_suffix ();
dt += mp_tech_comp->pins_datatype ();
break;
case LEFPins:
name += mp_tech_comp->lef_pins_suffix ();
dt += mp_tech_comp->lef_pins_datatype ();
break;
case Obstructions:
produce = mp_tech_comp->produce_obstructions ();
name += mp_tech_comp->obstructions_suffix ();
dt += mp_tech_comp->obstructions_datatype ();
break;
case Blockage:
produce = mp_tech_comp->produce_blockages ();
name += mp_tech_comp->blockages_suffix ();
dt += mp_tech_comp->blockages_datatype ();
break;
}
}
if (! produce) {
return std::make_pair (false, 0);
}
std::pair<bool, unsigned int> ll = m_layer_map.logical (name, layout);
if (ll.first) {
// create the layer if it is not part of the layout yet.
if (! layout.is_valid_layer (ll.second)) {
layout.insert_layer (ll.second, m_layer_map.mapping (ll.second));
}
return ll;
} else {
std::pair<bool, unsigned int> ll_raw = m_layer_map.logical (n, layout);
ll = m_layer_map.logical (n, layout);
int ln = -1;
if (ll_raw.first && (ln = layout.get_properties (ll_raw.second).layer) >= 0) {
if (ll.first && (ln = layout.get_properties (ll.second).layer) >= 0) {
m_layer_map.map (db::LayerProperties (name), layout.layers (), db::LayerProperties (ln, dt, name));
m_layer_map.prepare (layout);
@ -280,14 +482,14 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
} else {
std::map <std::pair<std::string, LayerPurpose>, unsigned int>::const_iterator nl = m_layers.find (std::make_pair (n, purpose));
if (nl == m_layers.end ()) {
unsigned int li = layout.insert_layer (db::LayerProperties (name));
m_layer_map.map (db::LayerProperties (name), li);
m_layers.insert (std::make_pair (std::make_pair (n, purpose), li));
return std::pair<bool, unsigned int> (true, li);
std::map <std::pair<std::string, LayerPurpose>, unsigned int>::const_iterator l = m_unassigned_layers.find (std::make_pair (n, purpose));
if (l != m_unassigned_layers.end ()) {
return std::pair<bool, unsigned int> (true, l->second);
} else {
return std::pair<bool, unsigned int> (true, nl->second);
unsigned int li = layout.insert_layer (db::LayerProperties (name));
m_unassigned_layers.insert (std::make_pair (std::make_pair (n, purpose), li));
m_layer_map.map (db::LayerProperties (name), li);
return std::pair<bool, unsigned int> (true, li);
}
}
@ -298,13 +500,7 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer
}
void
LEFDEFLayerDelegate::prepare (db::Layout &layout)
{
m_layer_map.prepare (layout);
}
void
LEFDEFLayerDelegate::finish (db::Layout &layout)
LEFDEFReaderState::finish (db::Layout &layout)
{
int lnum = 0;
@ -319,7 +515,7 @@ LEFDEFLayerDelegate::finish (db::Layout &layout)
used_numbers.insert (ln->second);
}
for (std::map<std::pair<std::string, LayerPurpose>, unsigned int>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
for (std::map<std::pair<std::string, LayerPurpose>, unsigned int>::const_iterator l = m_unassigned_layers.begin (); l != m_unassigned_layers.end (); ++l) {
int dt = 0;
switch (l->first.second) {
@ -327,6 +523,9 @@ LEFDEFLayerDelegate::finish (db::Layout &layout)
default:
dt = mp_tech_comp->routing_datatype ();
break;
case SpecialRouting:
dt = mp_tech_comp->special_routing_datatype ();
break;
case ViaGeometry:
dt = mp_tech_comp->via_geometry_datatype ();
break;
@ -336,6 +535,9 @@ LEFDEFLayerDelegate::finish (db::Layout &layout)
case Pins:
dt = mp_tech_comp->pins_datatype ();
break;
case LEFPins:
dt = mp_tech_comp->lef_pins_datatype ();
break;
case Obstructions:
dt = mp_tech_comp->obstructions_datatype ();
break;
@ -364,11 +566,24 @@ LEFDEFLayerDelegate::finish (db::Layout &layout)
}
}
void
LEFDEFReaderState::register_via_cell (const std::string &vn, db::Cell *cell)
{
m_via_cells [vn] = cell;
}
db::Cell *
LEFDEFReaderState::via_cell (const std::string &vn)
{
std::map<std::string, db::Cell *>::const_iterator i = m_via_cells.find (vn);
return i != m_via_cells.end () ? i->second : 0;
}
// -----------------------------------------------------------------------------------
// LEFDEFImporter implementation
LEFDEFImporter::LEFDEFImporter ()
: mp_progress (0), mp_stream (0), mp_layer_delegate (0),
: mp_progress (0), mp_stream (0), mp_reader_state (0),
m_produce_net_props (false), m_net_prop_name_id (0),
m_produce_inst_props (false), m_inst_prop_name_id (0),
m_produce_pin_props (false), m_pin_prop_name_id (0)
@ -382,7 +597,7 @@ LEFDEFImporter::~LEFDEFImporter ()
}
void
LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDelegate &ld)
LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state)
{
m_fn = stream.filename ();
@ -391,34 +606,39 @@ LEFDEFImporter::read (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDe
progress.set_format_unit (1000.0);
progress.set_unit (10000.0);
mp_reader_state = &state;
if (state.tech_comp ()) {
m_options = *state.tech_comp ();
}
m_produce_net_props = false;
m_net_prop_name_id = 0;
if (ld.tech_comp () && ld.tech_comp ()->produce_net_names ()) {
if (m_options.produce_net_names ()) {
m_produce_net_props = true;
m_net_prop_name_id = layout.properties_repository ().prop_name_id (ld.tech_comp ()->net_property_name ());
m_net_prop_name_id = layout.properties_repository ().prop_name_id (m_options.net_property_name ());
}
m_produce_inst_props = false;
m_inst_prop_name_id = 0;
if (ld.tech_comp () && ld.tech_comp ()->produce_inst_names ()) {
if (m_options.produce_inst_names ()) {
m_produce_inst_props = true;
m_inst_prop_name_id = layout.properties_repository ().prop_name_id (ld.tech_comp ()->inst_property_name ());
m_inst_prop_name_id = layout.properties_repository ().prop_name_id (m_options.inst_property_name ());
}
m_produce_pin_props = false;
m_pin_prop_name_id = 0;
if (ld.tech_comp () && ld.tech_comp ()->produce_pin_names ()) {
if (m_options.produce_pin_names ()) {
m_produce_pin_props = true;
m_pin_prop_name_id = layout.properties_repository ().prop_name_id (ld.tech_comp ()->pin_property_name ());
m_pin_prop_name_id = layout.properties_repository ().prop_name_id (m_options.pin_property_name ());
}
try {
mp_progress = &progress;
mp_layer_delegate = &ld;
mp_stream = new tl::TextInputStream (stream);
do_read (layout);
@ -502,7 +722,23 @@ LEFDEFImporter::expect (const std::string &token)
}
}
double
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
LEFDEFImporter::get_double ()
{
if (m_last_token.empty ()) {
@ -763,5 +999,48 @@ LEFDEFImporter::create_generated_via (std::vector<db::Polygon> &bottom,
}
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));
}
}

View File

@ -256,6 +256,16 @@ public:
m_via_geometry_datatype = s;
}
const std::string &via_cellname_prefix () const
{
return m_via_cellname_prefix;
}
void set_via_cellname_prefix (const std::string &s)
{
m_via_cellname_prefix = s;
}
bool produce_pins () const
{
return m_produce_pins;
@ -286,6 +296,36 @@ public:
m_pins_datatype = s;
}
bool produce_lef_pins () const
{
return m_produce_lef_pins;
}
void set_produce_lef_pins (bool f)
{
m_produce_lef_pins = f;
}
const std::string &lef_pins_suffix () const
{
return m_lef_pins_suffix;
}
void set_lef_pins_suffix (const std::string &s)
{
m_lef_pins_suffix = s;
}
int lef_pins_datatype () const
{
return m_lef_pins_datatype;
}
void set_lef_pins_datatype (int s)
{
m_lef_pins_datatype = s;
}
bool produce_obstructions () const
{
return m_produce_obstructions;
@ -406,6 +446,36 @@ public:
m_routing_datatype = s;
}
bool produce_special_routing () const
{
return m_produce_special_routing;
}
void set_produce_special_routing (bool f)
{
m_produce_special_routing = f;
}
const std::string &special_routing_suffix () const
{
return m_special_routing_suffix;
}
void set_special_routing_suffix (const std::string &s)
{
m_special_routing_suffix = s;
}
int special_routing_datatype () const
{
return m_special_routing_datatype;
}
void set_special_routing_datatype (int s)
{
m_special_routing_datatype = s;
}
void clear_lef_files ()
{
m_lef_files.clear ();
@ -436,6 +506,43 @@ public:
m_lef_files = lf;
}
bool separate_groups () const
{
return m_separate_groups;
}
void set_separate_groups (bool f)
{
m_separate_groups = f;
}
const std::string &map_file () const
{
return m_map_file;
}
void set_map_file (const std::string &f)
{
m_map_file = f;
}
/**
* @brief Specify the LEF macro resolution strategy
* Values are:
* 0: propduce LEF geometry unless a FOREIGN cell is specified (default)
* 1: produce LEF geometry always and ignore FOREIGN
* 2: produce a placeholder cell always (even if FOREIGN isn't given)
*/
unsigned int macro_resolution_mode () const
{
return m_macro_resolution_mode;
}
void set_macro_resolution_mode (unsigned int m)
{
m_macro_resolution_mode = m;
}
private:
bool m_read_all_layers;
db::LayerMap m_layer_map;
@ -455,9 +562,13 @@ private:
bool m_produce_via_geometry;
std::string m_via_geometry_suffix;
int m_via_geometry_datatype;
std::string m_via_cellname_prefix;
bool m_produce_pins;
std::string m_pins_suffix;
int m_pins_datatype;
bool m_produce_lef_pins;
std::string m_lef_pins_suffix;
int m_lef_pins_datatype;
bool m_produce_obstructions;
std::string m_obstructions_suffix;
int m_obstructions_datatype;
@ -470,6 +581,12 @@ private:
bool m_produce_routing;
std::string m_routing_suffix;
int m_routing_datatype;
bool m_produce_special_routing;
std::string m_special_routing_suffix;
int m_special_routing_datatype;
bool m_separate_groups;
std::string m_map_file;
unsigned int m_macro_resolution_mode;
std::vector<std::string> m_lef_files;
};
@ -478,15 +595,17 @@ private:
*/
enum LayerPurpose
{
Routing = 0,
ViaGeometry = 1,
Label = 2,
Pins = 3,
Obstructions = 4,
Outline = 5,
Blockage = 6,
PlacementBlockage = 7,
Region = 8
Routing = 0, // from DEF only
SpecialRouting, // from DEF only
ViaGeometry, // from LEF+DEF
Label, // from LEF+DEF
Pins, // from DEF
LEFPins, // from LEF
Obstructions, // from LEF only
Outline, // from LEF+DEF
Blockage, // from DEF only
PlacementBlockage, // from DEF only
Regions, // from DEF only
};
/**
@ -494,16 +613,33 @@ enum LayerPurpose
*
* This class will handle the creation and management of layers in the LEF/DEF reader context
*/
class DB_PLUGIN_PUBLIC LEFDEFLayerDelegate
class DB_PLUGIN_PUBLIC LEFDEFReaderState
{
public:
/**
* @brief Constructor
*/
LEFDEFLayerDelegate (const LEFDEFReaderOptions *tc);
LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout);
/**
* @brief Set the layer map
* @brief Provides an explicit layer mapping
* This method is used when reading the layer map file.
*/
void map_layer_explicit (const std::string &n, LayerPurpose purpose, const LayerProperties &lp, unsigned int layer);
/**
* @brief Provides an explicit layer mapping
* If this flag is set, the layer mapping specified in the reader options are ignored.
*/
void set_explicit_layer_mapping (bool f);
/**
* @brief Reads a map file
*/
void read_map_file (const std::string &path, db::Layout &layout);
/**
* @brief Sets the layer map
*/
virtual void set_layer_map (const db::LayerMap &lm, bool create_layers)
{
@ -512,13 +648,21 @@ public:
}
/**
* @brief Get the layer map
* @brief Gets the layer map
*/
const db::LayerMap &layer_map () const
{
return m_layer_map;
}
/**
* @brief Gets the layer map (non-const version)
*/
db::LayerMap &layer_map ()
{
return m_layer_map;
}
/**
* @brief Create a new layer or return the index of the given layer
*/
@ -529,16 +673,21 @@ public:
*/
void register_layer (const std::string &l);
/**
* @brief Prepare, i.e. create layers required by the layer map
*/
void prepare (db::Layout &layout);
/**
* @brief Finish, i.e. assign GDS layer numbers to the layers
*/
void finish (db::Layout &layout);
/**
* @brief Registers a via cell for the via with the given name
*/
void register_via_cell (const std::string &vn, db::Cell *cell);
/**
* @brief Gets the via cell for the given via name or 0 if no such via is registered
*/
db::Cell *via_cell (const std::string &vn);
/**
* @brief Get the technology component pointer
*/
@ -548,12 +697,17 @@ public:
}
private:
std::map <std::pair<std::string, LayerPurpose>, unsigned int> m_layers;
std::map <std::pair<std::string, LayerPurpose>, std::pair<bool, unsigned int> > m_layers;
std::map <std::pair<std::string, LayerPurpose>, unsigned int> m_unassigned_layers;
db::LayerMap m_layer_map;
bool m_create_layers;
bool m_has_explicit_layer_mapping;
int m_laynum;
std::map<std::string, int> m_default_number;
std::map<std::string, db::Cell *> m_via_cells;
const LEFDEFReaderOptions *mp_tech_comp;
std::pair <bool, unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose);
};
/**
@ -595,7 +749,7 @@ public:
*
* This method reads the layout specified into the given layout
*/
void read (tl::InputStream &stream, db::Layout &layout, LEFDEFLayerDelegate &layer_delegate);
void read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state);
protected:
/**
@ -635,6 +789,16 @@ protected:
*/
void expect (const std::string &token);
/**
* @brief Test whether the next token matches one of the given ones and raise an error if it does not
*/
void expect (const std::string &token1, const std::string &token2);
/**
* @brief Test whether the next token matches one of the given ones and raise an error if it does not
*/
void expect (const std::string &token, const std::string &token2, const std::string &token3);
/**
* @brief Gets the next token
*/
@ -655,12 +819,30 @@ protected:
*/
long get_long ();
/**
* @brief Gets an orientation code
* The orientation code is read employing the LEF/DEF convention ("N" for r0 etc.)
*/
db::FTrans get_orient (bool optional);
/**
* @brief Reads a point
* A point is given by two coordinates, x and y
*/
db::Point get_point (double scale);
/**
* @brief Reads a vector
* A vector is given by two coordinates, x and y
*/
db::Vector get_vector (double scale);
/**
* @brief Create a new layer or return the index of the given layer
*/
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose)
{
return mp_layer_delegate->open_layer (layout, name, purpose);
return mp_reader_state->open_layer (layout, name, purpose);
}
/**
@ -668,7 +850,7 @@ protected:
*/
void register_layer (const std::string &l)
{
mp_layer_delegate->register_layer (l);
mp_reader_state->register_layer (l);
}
/**
@ -735,7 +917,22 @@ protected:
return m_pin_prop_name_id;
}
protected:
/**
* @brief Gets the reader options
*/
const db::LEFDEFReaderOptions &options () const
{
return m_options;
}
/**
* @brief Gets the reader state object
*/
db::LEFDEFReaderState *reader_state ()
{
return mp_reader_state;
}
void create_generated_via (std::vector<db::Polygon> &bottom,
std::vector<db::Polygon> &cut,
std::vector<db::Polygon> &top,
@ -750,7 +947,7 @@ protected:
private:
tl::AbsoluteProgress *mp_progress;
tl::TextInputStream *mp_stream;
LEFDEFLayerDelegate *mp_layer_delegate;
LEFDEFReaderState *mp_reader_state;
std::string m_cellname;
std::string m_fn;
std::string m_last_token;
@ -760,6 +957,7 @@ private:
db::property_names_id_type m_inst_prop_name_id;
bool m_produce_pin_props;
db::property_names_id_type m_pin_prop_name_id;
db::LEFDEFReaderOptions m_options;
const std::string &next ();
};

View File

@ -30,6 +30,8 @@
#include "dbLEFImporter.h"
#include "dbDEFImporter.h"
#include "dbLEFDEFImporter.h"
#include "dbLayoutUtils.h"
#include "dbTechnology.h"
namespace db
{
@ -102,14 +104,32 @@ public:
{
return "LEFDEF";
}
private:
tl::InputStream &m_stream;
db::LayerMap m_layer_map;
std::string correct_path (const std::string &fn)
std::string correct_path (const std::string &fn, const db::Layout &layout)
{
if (! tl::is_absolute (fn)) {
return tl::combine_path (m_stream.absolute_path (), fn);
// if a technology is given and the file can be found in the technology's base path, take it
// from there.
std::string tn = layout.meta_info_value ("technology");
const db::Technology *tech = 0;
if (! tn.empty ()) {
tech = db::Technologies::instance ()->technology_by_name (tn);
}
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;
}
}
return tl::combine_path (tl::dirname (m_stream.absolute_path ()), fn);
} else {
return fn;
}
@ -123,49 +143,53 @@ private:
lefdef_options = &default_options;
}
// Take the layer map and the "read all layers" flag from the reader options - hence we override the
db::LEFDEFLayerDelegate layers (lefdef_options);
layers.prepare (layout);
db::LEFDEFReaderState state (lefdef_options, layout);
if (! lefdef_options->map_file ().empty ()) {
state.read_map_file (correct_path (lefdef_options->map_file (), layout), layout);
}
layout.dbu (lefdef_options->dbu ());
if (import_lef) {
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Reading LEF file")));
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file")));
db::LEFImporter importer;
for (std::vector<std::string>::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) {
std::string lp = correct_path (*l);
std::string lp = correct_path (*l, layout);
tl::InputStream lef_stream (lp);
tl::log << tl::to_string (tr ("Reading")) << " " << lp;
importer.read (lef_stream, layout, layers);
importer.read (lef_stream, layout, state);
}
tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source ();
importer.read (m_stream, layout, layers);
importer.read (m_stream, layout, state);
} else {
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Reading DEF file")));
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading DEF file")));
DEFImporter importer;
for (std::vector<std::string>::const_iterator l = lefdef_options->begin_lef_files (); l != lefdef_options->end_lef_files (); ++l) {
std::string lp = correct_path (*l);
std::string lp = correct_path (*l, layout);
tl::InputStream lef_stream (lp);
tl::log << tl::to_string (tr ("Reading")) << " " << lp;
importer.read_lef (lef_stream, layout, layers);
importer.read_lef (lef_stream, layout, state);
}
// Additionally read all LEF files next to the DEF file
std::string input_dir = tl::absolute_path (m_stream.absolute_path ());
if (tl::file_exists (input_dir)) {
std::vector<std::string> entries = tl::dir_entries (input_dir);
@ -174,9 +198,12 @@ private:
if (is_lef_format (*e)) {
std::string lp = tl::combine_path (input_dir, *e);
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file: ")) + lp);
tl::InputStream lef_stream (lp);
tl::log << tl::to_string (tr ("Reading")) << " " << lp;
importer.read_lef (lef_stream, layout, layers);
importer.read_lef (lef_stream, layout, state);
}
@ -185,17 +212,50 @@ private:
}
tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source ();
importer.read (m_stream, layout, layers);
importer.read (m_stream, layout, state);
}
layers.finish (layout);
state.finish (layout);
m_layer_map = layers.layer_map ();
m_layer_map = state.layer_map ();
return m_layer_map;
}
};
namespace {
struct MacroResolutionModeConverter
{
public:
MacroResolutionModeConverter ()
{
m_values.push_back ("default");
m_values.push_back ("always-lef");
m_values.push_back ("always-cellref");
}
std::string to_string (unsigned int v) const
{
return v < m_values.size () ? m_values[v] : std::string ();
}
void from_string (const std::string &s, unsigned int &v) const
{
v = 0;
for (unsigned int i = 0; i < (unsigned int) m_values.size (); ++i) {
if (m_values [i] == s) {
v = i;
}
}
}
private:
std::vector<std::string> m_values;
};
}
class LEFDEFFormatDeclaration
: public db::StreamFormatDeclaration
{
@ -253,6 +313,9 @@ class LEFDEFFormatDeclaration
tl::make_member (&LEFDEFReaderOptions::produce_pins, &LEFDEFReaderOptions::set_produce_pins, "produce-pins") +
tl::make_member (&LEFDEFReaderOptions::pins_suffix, &LEFDEFReaderOptions::set_pins_suffix, "pins-suffix") +
tl::make_member (&LEFDEFReaderOptions::pins_datatype, &LEFDEFReaderOptions::set_pins_datatype, "pins-datatype") +
tl::make_member (&LEFDEFReaderOptions::produce_lef_pins, &LEFDEFReaderOptions::set_produce_lef_pins, "produce-lef-pins") +
tl::make_member (&LEFDEFReaderOptions::lef_pins_suffix, &LEFDEFReaderOptions::set_lef_pins_suffix, "lef-pins-suffix") +
tl::make_member (&LEFDEFReaderOptions::lef_pins_datatype, &LEFDEFReaderOptions::set_lef_pins_datatype, "lef-pins-datatype") +
tl::make_member (&LEFDEFReaderOptions::produce_obstructions, &LEFDEFReaderOptions::set_produce_obstructions, "produce-obstructions") +
tl::make_member (&LEFDEFReaderOptions::obstructions_suffix, &LEFDEFReaderOptions::set_obstructions_suffix, "obstructions-suffix") +
tl::make_member (&LEFDEFReaderOptions::obstructions_datatype, &LEFDEFReaderOptions::set_obstructions_datatype, "obstructions-datatype") +
@ -265,7 +328,13 @@ class LEFDEFFormatDeclaration
tl::make_member (&LEFDEFReaderOptions::produce_routing, &LEFDEFReaderOptions::set_produce_routing, "produce-routing") +
tl::make_member (&LEFDEFReaderOptions::routing_suffix, &LEFDEFReaderOptions::set_routing_suffix, "routing-suffix") +
tl::make_member (&LEFDEFReaderOptions::routing_datatype, &LEFDEFReaderOptions::set_routing_datatype, "routing-datatype") +
tl::make_member (&LEFDEFReaderOptions::begin_lef_files, &LEFDEFReaderOptions::end_lef_files, &LEFDEFReaderOptions::push_lef_file, "lef-files")
tl::make_member (&LEFDEFReaderOptions::produce_special_routing, &LEFDEFReaderOptions::set_produce_special_routing, "produce-special-routing") +
tl::make_member (&LEFDEFReaderOptions::special_routing_suffix, &LEFDEFReaderOptions::set_special_routing_suffix, "special-routing-suffix") +
tl::make_member (&LEFDEFReaderOptions::special_routing_datatype, &LEFDEFReaderOptions::set_special_routing_datatype, "special-routing-datatype") +
tl::make_member (&LEFDEFReaderOptions::begin_lef_files, &LEFDEFReaderOptions::end_lef_files, &LEFDEFReaderOptions::push_lef_file, "lef-files") +
tl::make_member (&LEFDEFReaderOptions::macro_resolution_mode, &LEFDEFReaderOptions::set_macro_resolution_mode, "macro-resolution-mode", MacroResolutionModeConverter ()) +
tl::make_member (&LEFDEFReaderOptions::separate_groups, &LEFDEFReaderOptions::set_separate_groups, "separate-groups") +
tl::make_member (&LEFDEFReaderOptions::map_file, &LEFDEFReaderOptions::set_map_file, "map-file")
);
}
};

View File

@ -65,12 +65,23 @@ LEFImporter::layer_ext (const std::string &layer, double def_ext) const
}
}
double
LEFImporter::layer_width (const std::string &layer, const std::string &nondefaultrule, double def_width) const
std::pair<double, double>
LEFImporter::min_layer_width (const std::string &layer) const
{
std::map<std::string, std::map<std::string, double> >::const_iterator nd = m_nondefault_widths.find (nondefaultrule);
std::map<std::string, std::pair<double, double> >::const_iterator l = m_min_widths.find (layer);
if (l != m_min_widths.end ()) {
return l->second;
} else {
return std::make_pair (0.0, 0.0);
}
}
std::map<std::string, double>::const_iterator l;
std::pair<double, double>
LEFImporter::layer_width (const std::string &layer, const std::string &nondefaultrule, const std::pair<double, double> &def_width) const
{
std::map<std::string, std::map<std::string, std::pair<double, double> > >::const_iterator nd = m_nondefault_widths.find (nondefaultrule);
std::map<std::string, std::pair<double, double> >::const_iterator l;
bool has_width = false;
if (! nondefaultrule.empty () && nd != m_nondefault_widths.end ()) {
@ -94,14 +105,14 @@ LEFImporter::layer_width (const std::string &layer, const std::string &nondefaul
}
}
db::Cell *
std::pair<db::Cell *, db::Trans>
LEFImporter::macro_by_name (const std::string &name) const
{
std::map<std::string, db::Cell *>::const_iterator m = m_macros_by_name.find (name);
std::map<std::string, std::pair<db::Cell *, db::Trans> >::const_iterator m = m_macros_by_name.find (name);
if (m != m_macros_by_name.end ()) {
return m->second;
} else {
return 0;
return std::make_pair ((db::Cell *) 0, db::Trans ());
}
}
@ -174,9 +185,9 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
}
w = 0.0;
std::map<std::string, double>::const_iterator dw = m_default_widths.find (layer_name);
std::map<std::string, std::pair<double, double> >::const_iterator dw = m_default_widths.find (layer_name);
if (dw != m_default_widths.end ()) {
w = dw->second;
w = dw->second.first;
}
while (! test (";")) {
@ -334,20 +345,18 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
points.push_back (db::Vector (db::DVector (x / dbu, y / dbu)));
std::string vn = get ();
std::pair<bool, db::cell_index_type> cn = layout.cell_by_name (("VIA_" + vn).c_str ());
if (! cn.first) {
warn ("Unknown via: " + vn);
db::Cell *vc = reader_state ()->via_cell (vn);
if (! vc) {
warn (tl::to_string (tr ("Unknown via: ")) + vn);
}
if (iterate) {
std::vector<db::Trans> ti = get_iteration (layout);
if (cn.first) {
for (std::vector<db::Trans>::const_iterator t = ti.begin (); t != ti.end (); ++t) {
cell.insert (db::CellInstArray (db::CellInst (cn.second), *t * db::Trans (points [0])));
}
for (std::vector<db::Trans>::const_iterator t = ti.begin (); t != ti.end (); ++t) {
cell.insert (db::CellInstArray (db::CellInst (vc->cell_index ()), *t * db::Trans (points [0])));
}
} else if (cn.first) {
cell.insert (db::CellInstArray (db::CellInst (cn.second), db::Trans (points [0])));
} else {
cell.insert (db::CellInstArray (db::CellInst (vc->cell_index ()), db::Trans (points [0])));
}
expect (";");
@ -360,6 +369,568 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
}
}
void
LEFImporter::read_nondefaultrule (db::Layout & /*layout*/)
{
// read NONDEFAULTRULE sections
std::string n = get ();
while (! test ("END") || ! test (n)) {
if (test ("LAYER")) {
std::string l = get ();
// read the width for the layer
while (! test ("END")) {
if (test ("WIDTH")) {
double w = get_double ();
test (";");
m_nondefault_widths[n][l] = std::make_pair (w, w);
} else {
while (! test (";")) {
take ();
}
}
}
test (l);
} else if (test ("VIA")) {
// ignore VIA statements
std::string v = get ();
while (! test ("END") || ! test (v)) {
take ();
}
} else {
while (! test (";")) {
take ();
}
}
}
}
void
LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_desc, const std::string & /*n*/)
{
db::Vector cutsize, cutspacing;
db::Vector be, te;
db::Vector bo, to;
db::Point offset;
int rows = 1, columns = 1;
std::string pattern;
std::vector<std::pair<std::string, std::vector<db::Polygon> > > geometry;
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
while (! test ("END")) {
double x, y;
if (test ("CUTSIZE")) {
x = get_double ();
y = get_double ();
cutsize = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("CUTSPACING")) {
x = get_double ();
y = get_double ();
cutspacing = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("ORIGIN")) {
x = get_double ();
y = get_double ();
offset = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("ENCLOSURE")) {
x = get_double ();
y = get_double ();
be = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
x = get_double ();
y = get_double ();
te = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("OFFSET")) {
x = get_double ();
y = get_double ();
bo = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
x = get_double ();
y = get_double ();
to = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("ROWCOL")) {
rows = get_long ();
columns = get_long ();
test (";");
} else if (test ("PATTERN")) {
pattern = get ();
test (";");
} else if (test ("LAYERS")) {
via_desc.m1 = geometry[0].first = get ();
geometry[1].first = get ();
via_desc.m2 = geometry[2].first = get ();
test (";");
} else {
while (! test (";")) {
take ();
}
}
}
create_generated_via (geometry [0].second, geometry [1].second, geometry [2].second,
cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern);
for (std::vector<std::pair<std::string, std::vector<db::Polygon> > >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) {
std::pair <bool, unsigned int> dl = open_layer (layout, g->first, ViaGeometry);
if (dl.first) {
for (std::vector<db::Polygon>::const_iterator p = g->second.begin (); p != g->second.end (); ++p) {
cell.shapes (dl.second).insert (*p);
}
}
}
}
void
LEFImporter::read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &via_desc, const std::string &n)
{
// ignore resistance spec
if (test ("RESISTANCE")) {
get_double ();
test (";");
}
std::map<std::string, db::Box> bboxes;
read_geometries (layout, cell, ViaGeometry, &bboxes);
// determine m1 and m2 layers
std::vector<std::string> routing_layers;
for (std::map<std::string, db::Box>::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) {
if (m_routing_layers.find (b->first) != m_routing_layers.end ()) {
routing_layers.push_back (b->first);
}
}
if (routing_layers.size () == 2) {
via_desc.m1 = routing_layers[0];
via_desc.m2 = routing_layers[1];
} else {
warn (tl::to_string (tr ("Can't determine routing layers for via: ")) + n);
}
reset_cellname ();
expect ("END");
}
void
LEFImporter::read_viadef (Layout &layout)
{
std::string n = get ();
// produce a cell for vias
std::string cellname = options ().via_cellname_prefix () + n;
db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ()));
reader_state ()->register_via_cell (n, &cell);
ViaDesc &via_desc = m_vias[n];
via_desc.cell = &cell;
while (test ("DEFAULT") || test ("TOPOFSTACKONLY"))
;
test (";");
if (test ("VIARULE")) {
read_viadef_by_rule (layout, cell, via_desc, n);
} else {
read_viadef_by_geometry (layout, cell, via_desc, n);
}
test ("VIA");
expect (n);
}
void
LEFImporter::read_layer (Layout & /*layout*/)
{
std::string ln = get ();
double wmin = 0.0, wmin_wrongdir = 0.0;
double w = 0.0, w_wrongdir = 0.0;
bool is_horizontal = false;
register_layer (ln);
// just extract the width from the layer - we need that as the default width for paths
while (! at_end ()) {
if (test ("END")) {
expect (ln);
break;
} else if (test ("TYPE")) {
std::string type = get ();
if (type == "ROUTING" || type == "MASTERSLICE") {
m_routing_layers.insert (ln);
} else if (type == "CUT") {
m_cut_layers.insert (ln);
}
expect (";");
} else if (test ("WIDTH")) {
w = get_double ();
expect (";");
} else if (test ("MINWIDTH")) {
wmin = get_double ();
expect (";");
} else if (test ("DIRECTION")) {
if (test ("HORIZONTAL")) {
is_horizontal = true;
} else {
expect ("VERTICAL", "DIAG45", "DIAG135");
}
} else if (test ("WIREEXTENSION")) {
double v = get_double ();
m_default_ext.insert (std::make_pair (ln, v));
expect (";");
} else if (test ("ACCURRENTDENSITY")) {
// ACCURRENTDENSITY needs some special attention because it can contain nested WIDTH
// blocks following a semicolon
take ();
if (test ("FREQUENCY")) {
while (! test ("TABLEENTRIES")) {
take ();
}
}
while (! test (";")) {
take ();
}
} else if (test ("PROPERTY")) {
std::string name = get ();
tl::Variant value = get ();
if (name == "LEF58_MINWIDTH") {
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("MINWIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
wmin_wrongdir = v;
} else {
wmin = v;
}
}
} else if (name == "LEF58_WIDTH") {
// Cadence extension
tl::Extractor ex (value.to_string ());
double v = 0.0;
if (ex.test ("WIDTH") && ex.try_read (v)) {
if (ex.test ("WRONGDIRECTION")) {
w_wrongdir = v;
} else {
w = v;
}
}
}
expect (";");
} else {
while (! test (";")) {
take ();
}
}
}
if (w > 0.0 || w_wrongdir > 0.0) {
if (w_wrongdir == 0.0) {
w_wrongdir = w;
} else if (! is_horizontal) {
std::swap (w, w_wrongdir);
}
m_default_widths.insert (std::make_pair (ln, std::make_pair (w, w_wrongdir)));
}
if (wmin > 0.0 || wmin_wrongdir > 0.0) {
if (wmin_wrongdir == 0.0) {
wmin_wrongdir = wmin;
} else if (! is_horizontal) {
std::swap (wmin, wmin_wrongdir);
}
m_min_widths.insert (std::make_pair (ln, std::make_pair (wmin, wmin_wrongdir)));
}
}
void
LEFImporter::read_macro (Layout &layout)
{
std::string mn = get ();
if (m_macros_by_name.find (mn) != m_macros_by_name.end ()) {
error (tl::to_string (tr ("Duplicate MACRO name: ")) + mn);
}
set_cellname (mn);
db::Cell &cell = layout.cell (layout.add_cell ());
db::Cell *foreign_cell = 0;
db::Trans foreign_trans;
std::string foreign_name;
db::Point origin;
db::Vector size;
// read the macro
while (! at_end ()) {
if (test ("END")) {
expect (mn);
break;
} else if (test ("ORIGIN")) {
origin = get_point (1.0 / layout.dbu ());
expect (";");
} else if (test ("SIZE")) {
double x = get_double ();
test ("BY");
double y = get_double ();
expect (";");
size = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
} else if (test ("PIN")) {
std::string pn = get ();
std::string dir;
while (! at_end ()) {
if (test ("END")) {
break;
} else if (test ("DIRECTION")) {
dir = get ();
test (";");
} else if (test ("PORT")) {
// produce pin labels
// TODO: put a label on every single object?
std::string label = pn;
/* don't add the direction currently, a name is sufficient
if (! dir.empty ()) {
label += ":";
label += dir;
}
*/
db::properties_id_type prop_id = 0;
if (produce_pin_props ()) {
db::PropertiesRepository::properties_set props;
props.insert (std::make_pair (pin_prop_name_id (), tl::Variant (label)));
prop_id = layout.properties_repository ().properties_id (props);
}
std::map <std::string, db::Box> bboxes;
read_geometries (layout, cell, LEFPins, &bboxes, prop_id);
for (std::map <std::string, db::Box>::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) {
std::pair <bool, unsigned int> dl = open_layer (layout, b->first, Label);
if (dl.first) {
cell.shapes (dl.second).insert (db::Text (label.c_str (), db::Trans (b->second.center () - db::Point ())));
}
}
expect ("END");
} else {
while (! test (";")) {
take ();
}
}
}
expect (pn);
} else if (test ("FOREIGN")) {
if (foreign_cell) {
error (tl::to_string (tr ("Duplicate FOREIGN definition")));
}
std::string cn = get ();
db::Point vec;
db::FTrans ft;
if (! peek (";")) {
vec = get_point (1.0 / layout.dbu ());
ft = get_orient (true);
}
expect (";");
if (options ().macro_resolution_mode () != 1) {
db::cell_index_type ci;
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn.c_str ());
if (c.first) {
ci = c.second;
} else {
ci = layout.add_cell (cn.c_str ());
layout.cell (ci).set_ghost_cell (true);
}
foreign_cell = &layout.cell (ci);
// What is the definition of the FOREIGN transformation?
// Guessing: this transformation moves the lower-left origin to 0,0
foreign_trans = db::Trans (db::Point () - vec) * db::Trans (ft);
foreign_name = cn;
}
} else if (test ("OBS")) {
read_geometries (layout, cell, Obstructions);
expect ("END");
} else {
while (! test (";")) {
take ();
}
}
}
if (! foreign_cell) {
if (options ().macro_resolution_mode () != 2) {
// actually implement the real cell
layout.rename_cell (cell.cell_index (), mn.c_str ());
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Outline);
if (dl.first) {
cell.shapes (dl.second).insert (db::Box (-origin, -origin + size));
}
m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&cell, db::Trans ())));
} else {
// macro resolution mode #2 (always create a MACRO reference, no LEF geometry)
db::cell_index_type ci;
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (mn.c_str ());
if (c.first) {
ci = c.second;
} else {
ci = layout.add_cell (mn.c_str ());
layout.cell (ci).set_ghost_cell (true);
}
layout.delete_cell (cell.cell_index ());
m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&layout.cell (ci), db::Trans ())));
}
} else if (foreign_name != mn) {
warn (tl::to_string (tr ("FOREIGN name differs from MACRO name in macro: ")) + mn);
layout.rename_cell (cell.cell_index (), mn.c_str ());
// clear imported LEF geometry with a foreign cell, but provide a level of indirection so we have
// both the MACRO and the FOREIGN name
for (unsigned int l = 0; l < layout.layers (); ++l) {
if (layout.is_valid_layer (l)) {
cell.clear (l);
}
}
cell.clear_insts ();
cell.insert (db::CellInstArray (db::CellInst (foreign_cell->cell_index ()), db::Trans (db::Point () - origin) * foreign_trans));
m_macros_by_name.insert (std::make_pair (mn, std::make_pair (&cell, db::Trans ())));
} else {
// use FOREIGN cell instead of new one
layout.delete_cell (cell.cell_index ());
m_macros_by_name.insert (std::make_pair (mn, std::make_pair (foreign_cell, db::Trans (db::Point () - origin) * foreign_trans)));
}
m_macro_bboxes_by_name.insert (std::make_pair (mn, db::Box (-origin, -origin + size)));
reset_cellname ();
}
void
LEFImporter::do_read (db::Layout &layout)
{
@ -414,45 +985,7 @@ LEFImporter::do_read (db::Layout &layout)
} else if (test ("NONDEFAULTRULE")) {
// read NONDEFAULTRULE sections
std::string n = get ();
while (! test ("END") || ! test (n)) {
if (test ("LAYER")) {
std::string l = get ();
// read the width for the layer
while (! test ("END")) {
if (test ("WIDTH")) {
double w = get_double ();
test (";");
m_nondefault_widths[n][l] = w;
} else {
while (! test (";")) {
take ();
}
}
}
test (l);
} else if (test ("VIA")) {
// ignore VIA statements
std::string v = get ();
while (! test ("END") || ! test (v)) {
take ();
}
} else {
while (! test (";")) {
take ();
}
}
}
read_nondefaultrule (layout);
} else if (test ("SITE")) {
@ -472,146 +1005,7 @@ LEFImporter::do_read (db::Layout &layout)
} else if (test ("VIA")) {
std::string n = get ();
// produce a cell for vias
std::string cellname = "VIA_" + n;
db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ()));
ViaDesc &via_desc = m_vias[n];
via_desc.cell = &cell;
while (test ("DEFAULT") || test ("TOPOFSTACKONLY"))
;
test (";");
if (test ("VIARULE")) {
db::Vector cutsize, cutspacing;
db::Vector be, te;
db::Vector bo, to;
db::Point offset;
int rows = 1, columns = 1;
std::string pattern;
std::vector<std::pair<std::string, std::vector<db::Polygon> > > geometry;
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
geometry.push_back (std::pair<std::string, std::vector<db::Polygon> > ());
while (! test ("END")) {
double x, y;
if (test ("CUTSIZE")) {
x = get_double ();
y = get_double ();
cutsize = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("CUTSPACING")) {
x = get_double ();
y = get_double ();
cutspacing = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("ORIGIN")) {
x = get_double ();
y = get_double ();
offset = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("ENCLOSURE")) {
x = get_double ();
y = get_double ();
be = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
x = get_double ();
y = get_double ();
te = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("OFFSET")) {
x = get_double ();
y = get_double ();
bo = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
x = get_double ();
y = get_double ();
to = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
test (";");
} else if (test ("ROWCOL")) {
rows = get_long ();
columns = get_long ();
test (";");
} else if (test ("PATTERN")) {
pattern = get ();
test (";");
} else if (test ("LAYERS")) {
via_desc.m1 = geometry[0].first = get ();
geometry[1].first = get ();
via_desc.m2 = geometry[2].first = get ();
test (";");
} else {
while (! test (";")) {
take ();
}
}
}
create_generated_via (geometry [0].second, geometry [1].second, geometry [2].second,
cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern);
for (std::vector<std::pair<std::string, std::vector<db::Polygon> > >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) {
std::pair <bool, unsigned int> dl = open_layer (layout, g->first, ViaGeometry);
if (dl.first) {
for (std::vector<db::Polygon>::const_iterator p = g->second.begin (); p != g->second.end (); ++p) {
cell.shapes (dl.second).insert (*p);
}
}
}
} else {
// ignore resistance spec
if (test ("RESISTANCE")) {
get_double ();
test (";");
}
read_geometries (layout, cell, ViaGeometry);
reset_cellname ();
expect ("END");
}
test ("VIA");
expect (n);
read_viadef (layout);
} else if (test ("BEGINEXT")) {
@ -622,148 +1016,11 @@ LEFImporter::do_read (db::Layout &layout)
} else if (test ("LAYER")) {
std::string ln = get ();
register_layer (ln);
// just extract the width from the layer - we need that as the default width for paths
while (! at_end ()) {
if (test ("END")) {
expect (ln);
break;
} else if (test ("WIDTH")) {
double w = get_double ();
m_default_widths.insert (std::make_pair (ln, w));
expect (";");
} else if (test ("WIREEXTENSION")) {
double w = get_double ();
m_default_ext.insert (std::make_pair (ln, w));
expect (";");
} else if (test ("ACCURRENTDENSITY")) {
// ACCURRENTDENSITY needs some special attention because it can contain nested WIDTH
// blocks following a semicolon
take ();
if (test ("FREQUENCY")) {
while (! test ("TABLEENTRIES")) {
take ();
}
}
while (! test (";")) {
take ();
}
} else {
while (! test (";")) {
take ();
}
}
}
read_layer (layout);
} else if (test ("MACRO")) {
std::string mn = get ();
set_cellname (mn);
db::Cell &cell = layout.cell (layout.add_cell (mn.c_str ()));
m_macros_by_name.insert (std::make_pair (mn, &cell));
db::Point origin;
db::Vector size;
// read the macro
while (! at_end ()) {
if (test ("END")) {
expect (mn);
break;
} else if (test ("ORIGIN")) {
double x = get_double ();
double y = get_double ();
expect (";");
origin = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ()));
} else if (test ("SIZE")) {
double x = get_double ();
test ("BY");
double y = get_double ();
expect (";");
size = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
} else if (test ("PIN")) {
std::string pn = get ();
std::string dir;
while (! at_end ()) {
if (test ("END")) {
break;
} else if (test ("DIRECTION")) {
dir = get ();
test (";");
} else if (test ("PORT")) {
// produce pin labels
// TODO: put a label on every single object?
std::string label = pn;
/* don't add the direction currently, a name is sufficient
if (! dir.empty ()) {
label += ":";
label += dir;
}
*/
db::properties_id_type prop_id = 0;
if (produce_pin_props ()) {
db::PropertiesRepository::properties_set props;
props.insert (std::make_pair (pin_prop_name_id (), tl::Variant (label)));
prop_id = layout.properties_repository ().properties_id (props);
}
std::map <std::string, db::Box> bboxes;
read_geometries (layout, cell, Pins, &bboxes, prop_id);
for (std::map <std::string, db::Box>::const_iterator b = bboxes.begin (); b != bboxes.end (); ++b) {
std::pair <bool, unsigned int> dl = open_layer (layout, b->first, Label);
if (dl.first) {
cell.shapes (dl.second).insert (db::Text (label.c_str (), db::Trans (b->second.center () - db::Point ())));
}
}
expect ("END");
} else {
while (! test (";")) {
take ();
}
}
}
expect (pn);
} else if (test ("OBS")) {
read_geometries (layout, cell, Obstructions);
expect ("END");
} else {
while (! test (";")) {
take ();
}
}
}
std::pair <bool, unsigned int> dl = open_layer (layout, std::string (), Outline);
if (dl.first) {
cell.shapes (dl.second).insert (db::Box (-origin, -origin + size));
}
m_macro_bboxes_by_name.insert (std::make_pair (mn, db::Box (-origin, -origin + size)));
reset_cellname ();
read_macro (layout);
} else {
while (! test (";")) {

View File

@ -63,7 +63,7 @@ public:
* Returns 0 if the name is not a valid macro name. Otherwise it returns the pointer
* to the corresponding db::Cell object.
*/
db::Cell *macro_by_name (const std::string &macro_name) const;
std::pair<db::Cell *, db::Trans> macro_by_name (const std::string &macro_name) const;
/**
* @brief Get the cell bbox for the given macro name
@ -77,7 +77,7 @@ public:
* The nondefaultrule name gives the name of the nondefaultrule or an empty string if
* none is requested.
*/
double layer_width (const std::string &layer, const std::string &nondefaultrule, double def_width = 0.0) const;
std::pair<double, double> layer_width (const std::string &layer, const std::string &nondefaultrule, const std::pair<double, double> &def_width = std::make_pair (0.0, 0.0)) const;
/**
* @brief Get the extension for a layer with the given name
@ -86,6 +86,27 @@ public:
*/
double layer_ext (const std::string &layer, double def_ext = 0.0) const;
/**
* @brief Gets the minimum wire width in x and y direction for the given layer name
*/
std::pair<double, double> min_layer_width (const std::string &layer) const;
/**
* @brief Returns true if the given layer is a routing layer
*/
bool is_routing_layer (const std::string &layer) const
{
return m_routing_layers.find (layer) != m_routing_layers.end ();
}
/**
* @brief Returns true if the given layer is a cut layer
*/
bool is_cut_layer (const std::string &layer) const
{
return m_cut_layers.find (layer) != m_cut_layers.end ();
}
/**
* @brief Gets a map of the vias defined in this LEF file
*
@ -100,15 +121,23 @@ protected:
void do_read (db::Layout &layout);
private:
std::map<std::string, std::map<std::string, double> > m_nondefault_widths;
std::map<std::string, double> m_default_widths;
std::map<std::string, std::map<std::string, std::pair<double, double> > > m_nondefault_widths;
std::map<std::string, std::pair<double, double> > m_default_widths;
std::map<std::string, double> m_default_ext;
std::map<std::string, db::Cell *> m_macros_by_name;
std::map<std::string, std::pair<double, double> > m_min_widths;
std::map<std::string, std::pair<db::Cell *, db::Trans> > m_macros_by_name;
std::map<std::string, db::Box> m_macro_bboxes_by_name;
std::map<std::string, ViaDesc> m_vias;
std::set<std::string> m_routing_layers, m_cut_layers;
std::vector <db::Trans> get_iteration (db::Layout &layout);
void read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose purpose, std::map<std::string, db::Box> *collect_bboxes = 0, properties_id_type prop_id = 0);
void read_nondefaultrule (Layout &layout);
void read_viadef (Layout &layout);
void read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &desc, const std::string &n);
void read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &desc, const std::string &n);
void read_layer (Layout &layout);
void read_macro (Layout &layout);
};
}

View File

@ -260,6 +260,18 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
"@brief Sets the via geometry layer datatype value.\n"
"See \\produce_via_geometry for details about this property.\n"
) +
gsi::method ("via_cellname_prefix", &db::LEFDEFReaderOptions::via_cellname_prefix,
"@brief Gets the via cellname prefix.\n"
"Vias are represented by cells. The cell name is formed by combining the via cell name prefix and the via name.\n"
"\n"
"This property has been added in version 0.27.\n"
) +
gsi::method ("via_cellname_prefix=", &db::LEFDEFReaderOptions::set_via_cellname_prefix, gsi::arg ("prefix"),
"@brief Sets the via cellname prefix.\n"
"See \\via_cellname_prefix for details about this property.\n"
"\n"
"This property has been added in version 0.27.\n"
) +
gsi::method ("produce_pins", &db::LEFDEFReaderOptions::produce_pins,
"@brief Gets a value indicating whether pin geometries shall be produced.\n"
"See \\produce_via_geometry for details about the layer production rules."
@ -284,6 +296,30 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
"@brief Sets the pin geometry layer datatype value.\n"
"See \\produce_via_geometry for details about the layer production rules."
) +
gsi::method ("produce_lef_pins", &db::LEFDEFReaderOptions::produce_lef_pins,
"@brief Gets a value indicating whether LEF pin geometries shall be produced.\n"
"See \\produce_via_geometry for details about the layer production rules."
) +
gsi::method ("produce_lef_pins=", &db::LEFDEFReaderOptions::set_produce_lef_pins, gsi::arg ("produce"),
"@brief Sets a value indicating whether LEF pin geometries shall be produced.\n"
"See \\produce_via_geometry for details about the layer production rules."
) +
gsi::method ("lef_pins_suffix", &db::LEFDEFReaderOptions::lef_pins_suffix,
"@brief Gets the LEF pin geometry layer name suffix.\n"
"See \\produce_via_geometry for details about the layer production rules."
) +
gsi::method ("lef_pins_suffix=", &db::LEFDEFReaderOptions::set_lef_pins_suffix, gsi::arg ("suffix"),
"@brief Sets the LEF pin geometry layer name suffix.\n"
"See \\produce_via_geometry for details about the layer production rules."
) +
gsi::method ("lef_pins_datatype", &db::LEFDEFReaderOptions::lef_pins_datatype,
"@brief Gets the LEF pin geometry layer datatype value.\n"
"See \\produce_via_geometry for details about the layer production rules."
) +
gsi::method ("lef_pins_datatype=", &db::LEFDEFReaderOptions::set_lef_pins_datatype, gsi::arg ("datatype"),
"@brief Sets the LEF pin geometry layer datatype value.\n"
"See \\produce_via_geometry for details about the layer production rules."
) +
gsi::method ("produce_obstructions", &db::LEFDEFReaderOptions::produce_obstructions,
"@brief Gets a value indicating whether obstruction markers shall be produced.\n"
"See \\produce_via_geometry for details about the layer production rules."
@ -380,6 +416,92 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
"@brief Sets the routing layer datatype value.\n"
"See \\produce_via_geometry for details about the layer production rules."
) +
gsi::method ("produce_special_routing", &db::LEFDEFReaderOptions::produce_special_routing,
"@brief Gets a value indicating whether special routing geometry shall be produced.\n"
"See \\produce_via_geometry for details about the layer production rules.\n"
"\n"
"The differentiation between special and normal routing has been introduced in version 0.27."
) +
gsi::method ("produce_special_routing=", &db::LEFDEFReaderOptions::set_produce_special_routing, gsi::arg ("produce"),
"@brief Sets a value indicating whether special routing geometry shall be produced.\n"
"See \\produce_via_geometry for details about the layer production rules."
"\n"
"The differentiation between special and normal routing has been introduced in version 0.27."
) +
gsi::method ("special_routing_suffix", &db::LEFDEFReaderOptions::special_routing_suffix,
"@brief Gets the special routing layer name suffix.\n"
"See \\produce_via_geometry for details about the layer production rules."
"\n"
"The differentiation between special and normal routing has been introduced in version 0.27."
) +
gsi::method ("special_routing_suffix=", &db::LEFDEFReaderOptions::set_special_routing_suffix, gsi::arg ("suffix"),
"@brief Sets the special routing layer name suffix.\n"
"See \\produce_via_geometry for details about the layer production rules."
"\n"
"The differentiation between special and normal routing has been introduced in version 0.27."
) +
gsi::method ("special_routing_datatype", &db::LEFDEFReaderOptions::special_routing_datatype,
"@brief Gets the special routing layer datatype value.\n"
"See \\produce_via_geometry for details about the layer production rules."
"\n"
"The differentiation between special and normal routing has been introduced in version 0.27."
) +
gsi::method ("special_routing_datatype=", &db::LEFDEFReaderOptions::set_special_routing_datatype, gsi::arg ("datatype"),
"@brief Sets the special routing layer datatype value.\n"
"See \\produce_via_geometry for details about the layer production rules."
"\n"
"The differentiation between special and normal routing has been introduced in version 0.27."
) +
gsi::method ("separate_groups", &db::LEFDEFReaderOptions::separate_groups,
"@brief Gets a value indicating whether to create separate parent cells for individual groups.\n"
"If this property is set to true, instances belonging to different groups are separated by putting them into "
"individual parent cells. These parent cells are named after the groups and are put into the master top cell.\n"
"If this property is set to false (the default), no such group parents will be formed."
"\n"
"This property has been added in version 0.27.\n"
) +
gsi::method ("separate_groups=", &db::LEFDEFReaderOptions::set_separate_groups, gsi::arg ("flag"),
"@brief Sets a value indicating whether to create separate parent cells for individual groups.\n"
"See \\seperate_groups for details about this property.\n"
"\n"
"This property has been added in version 0.27.\n"
) +
gsi::method ("map_file", &db::LEFDEFReaderOptions::map_file,
"@brief Gets the layer map file to use.\n"
"If a layer map file is given, the reader will pull the layer mapping from this file. The layer mapping rules "
"specified in the reader options are ignored in this case. These are the name suffix rules for vias, blockages, routing, "
"special routing, pins etc. and the corresponding datatype rules. The \\layer_map attribute will also be ignored. "
"\n"
"The layer map file path will be resolved relative to the technology base path if the LEF/DEF reader options are "
"used in the context of a technology.\n"
"\n"
"This property has been added in version 0.27.\n"
) +
gsi::method ("map_file=", &db::LEFDEFReaderOptions::set_map_file, gsi::arg ("file"),
"@brief Sets the layer map file to use.\n"
"See \\map_file for details about this property.\n"
"\n"
"This property has been added in version 0.27.\n"
) +
gsi::method ("macro_resolution_mode", &db::LEFDEFReaderOptions::macro_resolution_mode,
"@brief Gets the macro resolution mode.\n"
"This property describes the way LEF macros are turned into GDS cells. There "
"are three modes available:\n"
"\n"
"@ul\n"
" @li 0: propduce LEF geometry unless a FOREIGN cell is specified (default) @/li\n"
" @li 1: produce LEF geometry always and ignore FOREIGN @/li\n"
" @li 2: produce a placeholder cell always (even if FOREIGN isn't given) @/li\n"
"@/ul\n"
"\n"
"This property has been added in version 0.27.\n"
) +
gsi::method ("macro_resolution_mode=", &db::LEFDEFReaderOptions::set_macro_resolution_mode, gsi::arg ("mode"),
"@brief Sets the macro resolution mode.\n"
"See \\macro_resolution_mode for details about this property.\n"
"\n"
"This property has been added in version 0.27.\n"
) +
gsi::method ("lef_files", &db::LEFDEFReaderOptions::lef_files,
"@brief Gets the list technology LEF files to additionally import\n"
"Returns a list of path names for technology LEF files to read in addition to the primary file. "
@ -394,6 +516,21 @@ gsi::Class<db::LEFDEFReaderOptions> decl_lefdef_config ("db", "LEFDEFReaderConfi
"@brief Detailed LEF/DEF reader options\n"
"This class is a aggregate belonging to the \\LoadLayoutOptions class. It provides options for the LEF/DEF reader. "
"These options have been placed into a separate class to account for their complexity."
"\n"
"This class specifically handles layer mapping. This is the process of generating layer names or GDS layer/datatypes "
"from LEF/DEF layers and purpose combinations. There are basically two ways: to use a map file or to use pattern-based production rules.\n"
"\n"
"To use a layer map file, set the \\map_file attribute to the name of the layer map file. The layer map "
"file lists the GDS layer and datatype numbers to generate for the geometry.\n"
"\n"
"The pattern-based approach will use the layer name and attach a purpose-dependent suffix to it. "
"Use the ..._suffix attributes to specify this suffix. For routing, the corresponding attribute is \\routing_suffix for example. "
"A purpose can also be mapped to a specific GDS datatype using the corresponding ..._datatype attributes.\n"
"The decorated or undecorated names are looked up in a layer mapping table in the next step. The layer mapping table "
"is specified using the \\layer_map attribute. This table can be used to map layer names to specific GDS layers "
"by using entries of the form 'NAME: layer-number'.\n"
"\n"
"If a layer map file is present, the pattern-based attributes are ignored.\n"
);
}

View File

@ -140,8 +140,7 @@ public:
}
}
db::LEFDEFLayerDelegate layers (&options);
layers.prepare (*layout);
db::LEFDEFReaderState state (&options, *layout);
layout->dbu (options.dbu ());
if (import_lef) {
@ -153,11 +152,11 @@ public:
for (std::vector<std::string>::const_iterator l = options.begin_lef_files (); l != options.end_lef_files (); ++l) {
tl::InputStream lef_stream (*l);
tl::log << tl::to_string (QObject::tr ("Reading")) << " " << *l;
importer.read (lef_stream, *layout, layers);
importer.read (lef_stream, *layout, state);
}
tl::log << tl::to_string (QObject::tr ("Reading")) << " " << data.file;
importer.read (stream, *layout, layers);
importer.read (stream, *layout, state);
} else {
@ -177,23 +176,23 @@ public:
if (fi.isAbsolute ()) {
tl::InputStream lef_stream (*l);
tl::log << tl::to_string (QObject::tr ("Reading")) << " " << *l;
importer.read_lef (lef_stream, *layout, layers);
importer.read_lef (lef_stream, *layout, state);
} else {
std::string ex_l = tl::to_string (def_fi.absoluteDir ().absoluteFilePath (tl::to_qstring (*l)));
tl::InputStream lef_stream (ex_l);
tl::log << tl::to_string (QObject::tr ("Reading")) << " " << *l;
importer.read_lef (lef_stream, *layout, layers);
importer.read_lef (lef_stream, *layout, state);
}
}
tl::log << tl::to_string (QObject::tr ("Reading")) << " " << data.file;
importer.read (stream, *layout, layers);
importer.read (stream, *layout, state);
}
layers.finish (*layout);
state.finish (*layout);
lay::LayoutView *view = lay::LayoutView::current ();
if (! view || data.mode == 1) {

View File

@ -353,14 +353,17 @@ LEFDEFReaderOptionsEditor::LEFDEFReaderOptionsEditor (QWidget *parent)
connect (produce_regions, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (produce_via_geometry, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (produce_pins, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (produce_lef_pins, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (produce_obstructions, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (produce_blockages, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (produce_routing, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (produce_special_routing, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (produce_labels, SIGNAL (stateChanged (int)), this, SLOT (checkbox_changed ()));
connect (add_lef_file, SIGNAL (clicked ()), this, SLOT (add_lef_file_clicked ()));
connect (del_lef_files, SIGNAL (clicked ()), this, SLOT (del_lef_files_clicked ()));
connect (move_lef_files_up, SIGNAL (clicked ()), this, SLOT (move_lef_files_up_clicked ()));
connect (move_lef_files_down, SIGNAL (clicked ()), this, SLOT (move_lef_files_down_clicked ()));
connect (browse_mapfile, SIGNAL (clicked ()), this, SLOT (browse_mapfile_clicked ()));
lay::activate_help_links (help_label);
}
@ -425,9 +428,13 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
data->set_produce_via_geometry (produce_via_geometry->isChecked ());
data->set_via_geometry_suffix (tl::to_string (suffix_via_geometry->text ()));
data->set_via_geometry_datatype (datatype_via_geometry->text ().toInt ());
data->set_via_cellname_prefix (tl::to_string (prefix_via_cellname->text ()));
data->set_produce_pins (produce_pins->isChecked ());
data->set_pins_suffix (tl::to_string (suffix_pins->text ()));
data->set_pins_datatype (datatype_pins->text ().toInt ());
data->set_produce_lef_pins (produce_lef_pins->isChecked ());
data->set_lef_pins_suffix (tl::to_string (suffix_lef_pins->text ()));
data->set_lef_pins_datatype (datatype_lef_pins->text ().toInt ());
data->set_produce_obstructions (produce_obstructions->isChecked ());
data->set_obstructions_suffix (tl::to_string (suffix_obstructions->text ()));
data->set_obstructions_datatype (datatype_obstructions->text ().toInt ());
@ -437,9 +444,15 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
data->set_produce_routing (produce_routing->isChecked ());
data->set_routing_suffix (tl::to_string (suffix_routing->text ()));
data->set_routing_datatype (datatype_routing->text ().toInt ());
data->set_produce_special_routing (produce_special_routing->isChecked ());
data->set_special_routing_suffix (tl::to_string (suffix_special_routing->text ()));
data->set_special_routing_datatype (datatype_special_routing->text ().toInt ());
data->set_produce_labels (produce_labels->isChecked ());
data->set_labels_suffix (tl::to_string (suffix_labels->text ()));
data->set_labels_datatype (datatype_labels->text ().toInt ());
data->set_separate_groups (separate_groups->isChecked ());
data->set_map_file (tl::to_string (mapfile_path->text ()));
data->set_macro_resolution_mode (foreign_mode->currentIndex ());
data->clear_lef_files ();
for (int i = 0; i < lef_files->count (); ++i) {
@ -477,9 +490,13 @@ LEFDEFReaderOptionsEditor::setup (const db::FormatSpecificReaderOptions *options
produce_via_geometry->setChecked (data->produce_via_geometry ());
suffix_via_geometry->setText (tl::to_qstring (data->via_geometry_suffix ()));
datatype_via_geometry->setText (QString::number (data->via_geometry_datatype ()));
prefix_via_cellname->setText (tl::to_qstring (data->via_cellname_prefix ()));
produce_pins->setChecked (data->produce_pins ());
suffix_pins->setText (tl::to_qstring (data->pins_suffix ()));
datatype_pins->setText (QString::number (data->pins_datatype ()));
produce_lef_pins->setChecked (data->produce_lef_pins ());
suffix_lef_pins->setText (tl::to_qstring (data->lef_pins_suffix ()));
datatype_lef_pins->setText (QString::number (data->lef_pins_datatype ()));
produce_obstructions->setChecked (data->produce_obstructions ());
suffix_obstructions->setText (tl::to_qstring (data->obstructions_suffix ()));
datatype_obstructions->setText (QString::number (data->obstructions_datatype ()));
@ -489,9 +506,16 @@ LEFDEFReaderOptionsEditor::setup (const db::FormatSpecificReaderOptions *options
produce_routing->setChecked (data->produce_routing ());
suffix_routing->setText (tl::to_qstring (data->routing_suffix ()));
datatype_routing->setText (QString::number (data->routing_datatype ()));
produce_special_routing->setChecked (data->produce_special_routing ());
suffix_special_routing->setText (tl::to_qstring (data->special_routing_suffix ()));
datatype_special_routing->setText (QString::number (data->special_routing_datatype ()));
produce_labels->setChecked (data->produce_labels ());
suffix_labels->setText (tl::to_qstring (data->labels_suffix ()));
datatype_labels->setText (QString::number (data->labels_datatype ()));
separate_groups->setChecked (data->separate_groups ());
mapfile_path->setText (tl::to_qstring (data->map_file ()));
layer_map_mode->setCurrentIndex (data->map_file ().empty () ? 1 : 0);
foreign_mode->setCurrentIndex (data->macro_resolution_mode ());
checkbox_changed ();
@ -519,25 +543,51 @@ LEFDEFReaderOptionsEditor::checkbox_changed ()
placement_blockage_layer->setEnabled (produce_placement_blockages->isChecked ());
suffix_via_geometry->setEnabled (produce_via_geometry->isChecked ());
suffix_pins->setEnabled (produce_pins->isChecked ());
suffix_lef_pins->setEnabled (produce_lef_pins->isChecked ());
suffix_obstructions->setEnabled (produce_obstructions->isChecked ());
suffix_blockages->setEnabled (produce_blockages->isChecked ());
suffix_routing->setEnabled (produce_routing->isChecked ());
suffix_special_routing->setEnabled (produce_special_routing->isChecked ());
suffix_labels->setEnabled (produce_labels->isChecked ());
datatype_via_geometry->setEnabled (produce_via_geometry->isChecked ());
datatype_pins->setEnabled (produce_pins->isChecked ());
datatype_lef_pins->setEnabled (produce_lef_pins->isChecked ());
datatype_obstructions->setEnabled (produce_obstructions->isChecked ());
datatype_blockages->setEnabled (produce_blockages->isChecked ());
datatype_routing->setEnabled (produce_routing->isChecked ());
datatype_special_routing->setEnabled (produce_special_routing->isChecked ());
datatype_labels->setEnabled (produce_labels->isChecked ());
}
void
LEFDEFReaderOptionsEditor::browse_mapfile_clicked ()
{
std::string title, filters;
title = tl::to_string (QObject::tr ("Select Layer Map File"));
filters = tl::to_string (QObject::tr ("LEF/DEF layer map files (*.map);;All files (*)"));
QString file = QFileDialog::getOpenFileName (this, tl::to_qstring (title), QString (), tl::to_qstring (filters));
if (! file.isNull ()) {
if (mp_tech) {
mapfile_path->setText (tl::to_qstring (mp_tech->correct_path (tl::to_string (file))));
} else {
mapfile_path->setText (file);
}
}
}
void
LEFDEFReaderOptionsEditor::add_lef_file_clicked ()
{
std::string title, filters;
title = tl::to_string (QObject::tr ("Add LEF Files"));
filters = tl::to_string (QObject::tr ("LEF files (*.lef *.LEF *.lef.gz *.LEF.gz);;All files (*)"));
QStringList files = QFileDialog::getOpenFileNames (this, tl::to_qstring (title), QString (), tl::to_qstring (filters));
std::string dir;
if (mp_tech) {
dir = mp_tech->base_path ();
}
QStringList files = QFileDialog::getOpenFileNames (this, tl::to_qstring (title), tl::to_qstring (dir), tl::to_qstring (filters));
for (QStringList::const_iterator f = files.begin (); f != files.end (); ++f) {
if (mp_tech) {
lef_files->addItem (tl::to_qstring (mp_tech->correct_path (tl::to_string (*f))));

View File

@ -98,6 +98,7 @@ private slots:
void del_lef_files_clicked ();
void move_lef_files_up_clicked ();
void move_lef_files_down_clicked ();
void browse_mapfile_clicked ();
private:
tl::weak_ptr<db::Technology> mp_tech;

View File

@ -49,28 +49,35 @@ static db::LEFDEFReaderOptions default_options ()
return tc;
}
static void run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &tc, bool priv = true)
static void run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &options, bool priv = true)
{
db::LEFDEFLayerDelegate ld (&tc);
std::string fn_path (priv ? tl::testsrc_private () : tl::testsrc ());
fn_path += "/testdata/lefdef/";
fn_path += lef_dir;
fn_path += "/";
db::Manager m (false);
db::Layout layout (&m), layout2 (&m), layout_au (&m);
tl::Extractor ex (filename);
ld.prepare (layout);
db::LEFDEFReaderState ld (&options, layout);
db::DEFImporter imp;
while (! ex.at_end ()) {
if (ex.test ("def:")) {
if (ex.test ("map:")) {
std::string fn (priv ? tl::testsrc_private () : tl::testsrc ());
fn += "/testdata/lefdef/";
fn += lef_dir;
fn += "/";
std::string f;
std::string fn = fn_path, f;
ex.read_word_or_quoted (f);
fn += f;
ld.read_map_file (fn, layout);
} else if (ex.test ("def:")) {
std::string fn = fn_path, f;
ex.read_word_or_quoted (f);
fn += f;
@ -79,17 +86,35 @@ static void run_test (tl::TestBase *_this, const char *lef_dir, const char *file
} else if (ex.test ("lef:")) {
std::string fn (priv ? tl::testsrc_private () : tl::testsrc ());
fn += "/testdata/lefdef/";
fn += lef_dir;
fn += "/";
std::string f;
std::string fn = fn_path, f;
ex.read_word_or_quoted (f);
fn += f;
tl::InputStream stream (fn);
imp.read_lef (stream, layout, ld);
} else if (ex.test ("gds:")) {
std::string fn = fn_path, f;
ex.read_word_or_quoted (f);
fn += f;
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (layout, db::LoadLayoutOptions ());
} else if (ex.test("read:")) {
std::string fn = fn_path, f;
ex.read_word_or_quoted (f);
fn += f;
tl::InputStream stream (fn);
db::Reader reader (stream);
db::LoadLayoutOptions lo;
lo.set_options (options);
reader.read (layout, lo);
} else {
break;
@ -112,6 +137,7 @@ static void run_test (tl::TestBase *_this, const char *lef_dir, const char *file
tl::OutputStream stream (tmp_file);
db::SaveLayoutOptions options;
options.set_format ("OASIS");
options.set_option_by_name ("oasis_permissive", tl::Variant (true));
db::Writer writer (options);
writer.write (layout, stream);
}
@ -222,6 +248,7 @@ TEST(15)
TEST(16)
{
run_test (_this, "def7", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au.oas.gz", default_options ());
run_test (_this, "def7", "map:in.map+lef:cells.lef+lef:tech.lef+def:in.def.gz", "au_with_map_file.oas.gz", default_options ());
}
TEST(17)
@ -231,7 +258,11 @@ TEST(17)
TEST(18)
{
run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au.oas.gz", default_options ());
db::LEFDEFReaderOptions options = default_options ();
options.set_separate_groups (true);
run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au.oas.gz", options);
run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au_nogroups.oas.gz", default_options ());
}
TEST(19)
@ -241,10 +272,20 @@ TEST(19)
TEST(20)
{
run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false);
run_test (_this, "def11", "lef:test.lef+def:test.def", "au.oas.gz", default_options ());
}
TEST(21)
{
run_test (_this, "def12", "lef:test.lef+def:test.def", "au.oas.gz", default_options ());
}
TEST(100)
{
run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false);
}
TEST(101)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_produce_pin_names (true);
@ -252,7 +293,7 @@ TEST(21)
run_test (_this, "issue-489", "lef:in.lef+def:in.def", "au.oas", opt, false);
}
TEST(22)
TEST(102)
{
db::LEFDEFReaderOptions opt = default_options ();
opt.set_produce_pin_names (true);
@ -260,8 +301,83 @@ TEST(22)
run_test (_this, "issue-489b", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", opt, false);
}
TEST(23)
TEST(103)
{
run_test (_this, "issue-517", "def:in.def", "au.oas.gz", default_options (), false);
}
TEST(104_doxy_vias)
{
run_test (_this, "doxy_vias", "def:test.def", "au.oas.gz", default_options (), false);
}
TEST(105_specialnets_geo)
{
run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
db::LEFDEFReaderOptions options = default_options ();
options.set_produce_special_routing (false);
run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au_no_spnet.oas.gz", options, false);
options.set_produce_special_routing (true);
options.set_special_routing_datatype (10);
options.set_special_routing_suffix (".SPNET");
options.set_via_geometry_datatype (11);
options.set_via_geometry_suffix (".VIA");
run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au_spnet_mapped.oas.gz", options, false);
}
TEST(106_wrongdirection)
{
run_test (_this, "wrongdirection", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
}
TEST(107_specialwidths)
{
run_test (_this, "specialwidths", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
}
TEST(108_scanchain)
{
run_test (_this, "scanchain", "def:test.def", "au.oas.gz", default_options (), false);
}
TEST(109_foreigncell)
{
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in.lef+def:in.def", "au.oas.gz", default_options (), false);
db::LEFDEFReaderOptions options = default_options ();
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in2.lef+def:in.def", "au_default.oas.gz", options, false);
options.set_macro_resolution_mode (1);
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in2.lef+def:in.def", "au_ignore_foreign.oas.gz", options, false);
options.set_macro_resolution_mode (2);
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in.lef+def:in.def", "au_always_foreign.oas.gz", options, false);
}
TEST(110_lefpins)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_produce_lef_pins (false);
run_test (_this, "lefpins", "lef:in_tech.lef+lef:in.lef+def:in.def", "au_no_lefpins.oas.gz", options, false);
options.set_produce_lef_pins (true);
options.set_lef_pins_datatype (10);
options.set_lef_pins_suffix (".LEFPIN");
run_test (_this, "lefpins", "lef:in_tech.lef+lef:in.lef+def:in.def", "au_lefpins_mapped.oas.gz", options, false);
}
TEST(111_mapfile)
{
db::LEFDEFReaderOptions options = default_options ();
options.set_map_file ("test.map");
run_test (_this, "mapfile", "read:in.def", "au.oas.gz", options, false);
}

View File

@ -6,7 +6,7 @@ TARGET = lefdef_tests
include($$PWD/../../../../lib_ut.pri)
SOURCES = \
dbLEFDEFImport.cc
dbLEFDEFImportTests.cc
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common

View File

@ -111,7 +111,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
m_tech.clear ();
{
tl::SelfTimer timer (tl::verbosity () >= 21, "Reading MAGIC file tree");
tl::SelfTimer timer (tl::verbosity () >= 11, "Reading MAGIC file tree");
// This is the seed
do_read (layout, top_cell, m_stream);

View File

@ -689,8 +689,6 @@ static const char magic_bytes[] = { "%SEMI-OASIS\015\012" };
void
OASISReader::do_read (db::Layout &layout)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_stream.source ());
unsigned char r;
char *mb;

BIN
testdata/lefdef/doxy_vias/au.oas.gz vendored Normal file

Binary file not shown.

28
testdata/lefdef/doxy_vias/test.def vendored Normal file
View File

@ -0,0 +1,28 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN chip_top ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 30000 3000 ) ( 10000000 4000 ) ;
VIAS 1 ;
- VIA1_dummy
+ RECT M1 ( -200 -140 ) ( 200 140 )
+ RECT VIA1 ( -100 -100 ) ( 100 100 )
+ RECT M2 ( -300 -120 ) ( 300 120 ) ;
END VIAS
SPECIALNETS 1 ;
- dummy
+ ROUTED M1 150 + SHAPE IOWIRE ( 40000 3600 ) VIA1_dummy DO 16000 BY 1 STEP 700 0
;
END SPECIALNETS
SCANCHAINS 77 ;
- chain1_clock1
+ PARTITION clock1
+ START block1/bsr_reg_0 Q
+ FLOATING
block1/pgm_cgm_en_reg_reg ( IN SD ) ( OUT QZ )
block1/start_reset_dd_reg ( IN SD ) ( OUT QZ )
+ STOP block1/start_reset_d_reg SD ;
END SCANCHAINS
END DESIGN

BIN
testdata/lefdef/foreigncell/au.oas.gz vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
testdata/lefdef/foreigncell/foreign.gds vendored Normal file

Binary file not shown.

17
testdata/lefdef/foreigncell/in.def vendored Normal file
View File

@ -0,0 +1,17 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN foreigncells ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 1000 2000 ) ;
COMPONENTS 3 ;
- macro1 macro1 + PLACED ( 0 0 ) N ;
- macro2 macro2 + PLACED ( 0 500 ) E ;
- macro3 macro3 + PLACED ( 0 1000 ) N ;
END COMPONENTS
END DESIGN

21
testdata/lefdef/foreigncell/in.lef vendored Normal file
View File

@ -0,0 +1,21 @@
MACRO macro1
CLASS CORE ;
FOREIGN foreign1 0.13 0.5 W ;
ORIGIN 0.035 0.235 ;
SIZE 0.07 BY 0.47 ;
END macro1
MACRO macro2
CLASS CORE ;
FOREIGN foreign2 -0.15 0.25 ;
ORIGIN 0.235 0.035 ;
SIZE 0.47 BY 0.07 ;
END macro2
MACRO macro3
CLASS CORE ;
FOREIGN macro3 -1.0 1.0 ;
ORIGIN 0.0 0.0 ;
SIZE 1.0 BY 0.4 ;
END macro3

44
testdata/lefdef/foreigncell/in2.lef vendored Normal file
View File

@ -0,0 +1,44 @@
MACRO macro1
CLASS CORE ;
ORIGIN 0.035 0.235 ;
SIZE 0.07 BY 0.47 ;
PIN Z
PORT
LAYER M1 ;
RECT -0.02 0 0.02 0.2 ;
RECT -0.03 -0.2 0.01 -0.1 ;
VIA 0.0 0.2 square ;
VIA 0.01 -0.2 square ;
END
END Z
END macro1
MACRO macro2
CLASS CORE ;
FOREIGN foreign2 -0.15 0.25 ;
ORIGIN 0.235 0.035 ;
SIZE 0.47 BY 0.07 ;
PIN Z
PORT
LAYER M1 ;
RECT 0 -0.02 -0.2 0.02 ;
RECT 0.2 -0.03 0.1 0.01 ;
VIA -0.2 0.0 square ;
VIA 0.2 0.01 square ;
END
END Z
END macro2
MACRO macro3
CLASS CORE ;
FOREIGN macro3 -1.0 1.0 ;
ORIGIN 0.0 0.0 ;
SIZE 1.0 BY 1.0 ;
PIN Z
PORT
LAYER M1 ;
RECT 0.2 0.2 0.3 0.5 ;
END
END Z
END macro3

36
testdata/lefdef/foreigncell/in_tech.lef vendored Normal file
View File

@ -0,0 +1,36 @@
LAYER OD
TYPE IMPLANT ;
END OD
LAYER VTS_N
TYPE IMPLANT ;
END VTS_N
LAYER VTS_P
TYPE IMPLANT ;
END VTS_P
LAYER M0OD
TYPE IMPLANT ;
END M0OD
LAYER M0PO
TYPE MASTERSLICE ;
END M0PO
LAYER VIA0
TYPE CUT ;
END VIA0
LAYER M1
TYPE MASTERSLICE ;
END M1
LAYER VIA1
TYPE CUT ;
END VIA1
LAYER M2
TYPE MASTERSLICE ;
END M2
VIA square
LAYER M0PO ;
RECT -0.006 -0.006 0.006 0.006 ;
LAYER VIA0 ;
RECT -0.006 -0.006 0.006 0.006 ;
LAYER M1 ;
RECT -0.006 -0.006 0.006 0.006 ;
END square

View File

@ -1,6 +1,5 @@
MACRO dummy
CLASS CORE ;
FOREIGN dummy 0.000 0.000 ;
ORIGIN 0.000 0.000 ;
SIZE 0.384 BY 0.480 ;
SYMMETRY X Y ;

Binary file not shown.

Binary file not shown.

15
testdata/lefdef/lefpins/in.def vendored Normal file
View File

@ -0,0 +1,15 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN foreigncells ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 1000 2000 ) ;
COMPONENTS 3 ;
- macro1 macro1 + PLACED ( 0 0 ) N ;
END COMPONENTS
END DESIGN

15
testdata/lefdef/lefpins/in.lef vendored Normal file
View File

@ -0,0 +1,15 @@
MACRO macro1
CLASS CORE ;
ORIGIN 0.000 0.000 ;
SIZE 0.384 BY 0.480 ;
PIN Z
PORT
LAYER M1 ;
RECT 0.306 0.357 0.318 0.403 ;
RECT 0.318 0.115 0.352 0.403 ;
VIA 0.336 0.167 square ;
VIA 0.336 0.351 square ;
END
END Z
END macro1

36
testdata/lefdef/lefpins/in_tech.lef vendored Normal file
View File

@ -0,0 +1,36 @@
LAYER OD
TYPE IMPLANT ;
END OD
LAYER VTS_N
TYPE IMPLANT ;
END VTS_N
LAYER VTS_P
TYPE IMPLANT ;
END VTS_P
LAYER M0OD
TYPE IMPLANT ;
END M0OD
LAYER M0PO
TYPE MASTERSLICE ;
END M0PO
LAYER VIA0
TYPE CUT ;
END VIA0
LAYER M1
TYPE MASTERSLICE ;
END M1
LAYER VIA1
TYPE CUT ;
END VIA1
LAYER M2
TYPE MASTERSLICE ;
END M2
VIA square
LAYER M0PO ;
RECT -0.006 -0.006 0.006 0.006 ;
LAYER VIA0 ;
RECT -0.006 -0.006 0.006 0.006 ;
LAYER M1 ;
RECT -0.006 -0.006 0.006 0.006 ;
END square

BIN
testdata/lefdef/mapfile/au.oas.gz vendored Normal file

Binary file not shown.

32
testdata/lefdef/mapfile/in.def vendored Normal file
View File

@ -0,0 +1,32 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN mapfile ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 1000 2000 ) ;
COMPONENTS 3 ;
- macro1 macro1 + PLACED ( 0 0 ) N ;
END COMPONENTS
SPECIALNETS 1 ;
- VDD ( * VDD )
+ ROUTED M1 50 + SHAPE STRIPE ( 500 0 ) ( 500 500 25 ) square ( 0 500 )
+ USE POWER ;
END SPECIALNETS
PINS 1 ;
- VDD + NET VDD + SPECIAL + DIRECTION INOUT + USE POWER
+ LAYER M1 ( 0 0 ) ( 50 70 )
;
END PINS
NETS 1 ;
- TOP
+ ROUTED M1 ( 100 700 ) ( 500 * ) ;
END NETS
END DESIGN

19
testdata/lefdef/mapfile/in.lef vendored Normal file
View File

@ -0,0 +1,19 @@
MACRO macro1
CLASS CORE ;
ORIGIN 0.035 0.235 ;
SIZE 0.07 BY 0.47 ;
PIN Z
PORT
LAYER M1 ;
RECT -0.02 0 0.02 0.2 ;
RECT -0.03 -0.2 0.01 -0.1 ;
VIA 0.0 0.2 square ;
VIA 0.01 -0.2 square ;
END
END Z
OBS
LAYER M1 ;
RECT -0.035 -0.235 0.035 0.235 ;
END
END macro1

27
testdata/lefdef/mapfile/in_tech.lef vendored Normal file
View File

@ -0,0 +1,27 @@
LAYER M0PO
TYPE MASTERSLICE ;
WIDTH 0.02 ;
END M0PO
LAYER VIA0
TYPE CUT ;
END VIA0
LAYER M1
TYPE MASTERSLICE ;
WIDTH 0.025 ;
END M1
LAYER VIA1
TYPE CUT ;
END VIA1
LAYER M2
TYPE MASTERSLICE ;
WIDTH 0.03 ;
END M2
VIA square
LAYER M0PO ;
RECT -0.006 -0.006 0.006 0.006 ;
LAYER VIA0 ;
RECT -0.006 -0.006 0.006 0.006 ;
LAYER M1 ;
RECT -0.006 -0.006 0.006 0.006 ;
END square

18
testdata/lefdef/mapfile/test.map vendored Normal file
View File

@ -0,0 +1,18 @@
DIEAREA ALL 100 0
M0PO LEFPIN,LEFOBS,PIN,NET,SPNET,VIA 10 0
VIA0 LEFPIN,LEFOBS,VIA,PIN,NET,SPNET 11 0
M1 LEFPIN 12 0
M1 LEFOBS 12 1
M1 PIN 12 2
M1 NET 12 3
M1 SPNET 12 4
M1 VIA 12 5
M1 FILLOPC 12 100
M1 FILLOPC:MASK:1 12 101
M1 FILLOPC:MASK:2 12 102
M1 BLOCKAGEFILL 12 150
M1 BLOCKAGE 12 151
M1 FILL 12 152
NAME M1/PIN 12 10
VIA1 LEFPIN,LEFOBS,VIA,PIN,NET,SPNET 13 0
M2 LEFPIN,LEFOBS,PIN,NET,SPNET,VIA 14 0

BIN
testdata/lefdef/scanchain/au.oas.gz vendored Normal file

Binary file not shown.

32
testdata/lefdef/scanchain/test.def vendored Normal file
View File

@ -0,0 +1,32 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN chip_top ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 8729280 8199360 ) ;
SCANCHAINS 9992 ;
- chain1
+ PARTITION part/Y_45_45_0.720000
+ START whereever/anchor_buf_8 Y
+ FLOATING
dumdidum/_reg_1_reg_2_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_2_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_7_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_8_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_5_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_9_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_6_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_4_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_7_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_1_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_3_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_1_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_0_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_4_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_0_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_6_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_3_ ( IN SI ) ( OUT Q )
dumdidum/_reg_1_reg_5_ ( IN SI ) ( OUT Q )
+ STOP somewhere/LOCKUP D ;
END SCANCHAINS
END DESIGN

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,27 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN chip_top ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 300 300 ) ;
STYLES 2 ;
- STYLE 1 ( 30 10 ) ( 10 30 ) ( -10 30 ) ( -30 10 ) ( -30 -10 ) ( -10 -30 ) ( 10 -30 ) ( 30 -10 ) ;
END STYLES
VIAS 1 ;
- VIA1_dummy
+ RECT M1 ( -20 -15 ) ( 20 15 )
+ RECT VIA1 ( -10 -10 ) ( 10 10 )
+ RECT M2 ( -25 -25 ) ( 25 25 ) ;
END VIAS
SPECIALNETS 1 ;
- dummy
+ ROUTED + RECT M2 ( 350 0 ) ( 200 100 )
+ POLYGON M1 ( 300 0 ) ( 300 50 ) ( 350 50 ) ( 400 100 ) ( 400 0 )
+ ROUTED + POLYGON M2 ( 300 150 ) ( 300 200 ) ( 350 200 ) ( 400 250 ) ( 400 150 )
+ RECT M1 ( 0 0 ) ( 100 200 )
+ ROUTED M1 30 ( 0 0 15 ) ( 100 0 0 ) VIA1_dummy ( 100 100 10 )
+ ROUTED M2 50 + SHAPE RING + STYLE 1 ( 0 100 ) ( 100 200 ) ( 200 200 )
;
END SPECIALNETS
END DESIGN

View File

@ -0,0 +1,24 @@
VERSION 5.8 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
MANUFACTURINGGRID 0.001 ;
LAYER M1
TYPE ROUTING ;
END M1
LAYER VIA1
TYPE CUT ;
END VIA1
LAYER M2
TYPE ROUTING ;
WIDTH 0.05 ;
END M2
END LIBRARY

BIN
testdata/lefdef/specialwidths/au.oas.gz vendored Normal file

Binary file not shown.

19
testdata/lefdef/specialwidths/test.def vendored Normal file
View File

@ -0,0 +1,19 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN test ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 10000 10000 ) ;
NONDEFAULTRULES 1 ;
- ndr
+ HARDSPACING
+ LAYER M3 WIDTH 500 SPACING 500
;
END NONDEFAULTRULES
NETS 1 ;
- net_b
+ NONDEFAULTRULE ndr
+ ROUTED M3 ( 0 2000 ) ( 0 0 ) ( 2000 0 ) via34 ( * 2000 ) ( 4000 * ) ( * 4000 )
;
END NETS
END DESIGN

43
testdata/lefdef/specialwidths/test.lef vendored Normal file
View File

@ -0,0 +1,43 @@
VERSION 5.8 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
MANUFACTURINGGRID 0.001 ;
PROPERTYDEFINITIONS
LAYER LEF58_MINWIDTH STRING ;
END PROPERTYDEFINITIONS
LAYER M3
TYPE ROUTING ;
DIRECTION VERTICAL ;
WIDTH 0.4 ;
PROPERTY LEF58_MINWIDTH "MINWIDTH 0.5 ; " ;
PROPERTY LEF58_MINWIDTH "MINWIDTH 0.8 WRONGDIRECTION ; " ;
END M3
LAYER VIA3
TYPE CUT ;
END VIA3
LAYER M4
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
PROPERTY LEF58_WIDTH "WIDTH 0.6 ; " ;
PROPERTY LEF58_WIDTH "WIDTH 1.0 WRONGDIRECTION ; " ;
END M4
VIA via34
LAYER M3 ;
RECT -0.4 -0.3 0.4 0.3 ;
LAYER VIA3 ;
RECT -0.3 -0.25 0.3 0.25 ;
LAYER M4 ;
RECT -1.00 -0.5 1.00 0.5 ;
END via34
END LIBRARY

BIN
testdata/lefdef/wrongdirection/au.oas.gz vendored Normal file

Binary file not shown.

19
testdata/lefdef/wrongdirection/test.def vendored Normal file
View File

@ -0,0 +1,19 @@
VERSION 5.8 ;
DIVIDERCHAR "/" ;
BUSBITCHARS "[]" ;
DESIGN test ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 10000 10000 ) ;
NONDEFAULTRULES 1 ;
- ndr
+ HARDSPACING
+ LAYER M3 WIDTH 500 SPACING 500
;
END NONDEFAULTRULES
NETS 1 ;
- net_b
+ NONDEFAULTRULE ndr
+ ROUTED M3 ( 0 0 ) ( 2000 0 ) via34 ( * 2000 ) ( 4000 * ) ( * 4000 )
;
END NETS
END DESIGN

41
testdata/lefdef/wrongdirection/test.lef vendored Normal file
View File

@ -0,0 +1,41 @@
VERSION 5.8 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
MANUFACTURINGGRID 0.001 ;
PROPERTYDEFINITIONS
LAYER LEF58_MINWIDTH STRING ;
END PROPERTYDEFINITIONS
LAYER M3
TYPE ROUTING ;
DIRECTION VERTICAL ;
WIDTH 0.6 ;
END M3
LAYER VIA3
TYPE CUT ;
END VIA3
LAYER M4
TYPE ROUTING ;
DIRECTION HORIZONTAL ;
WIDTH 0.5 ;
PROPERTY LEF58_MINWIDTH "MINWIDTH 1.0 WRONGDIRECTION ; " ;
END M4
VIA via34
LAYER M3 ;
RECT -0.4 -0.3 0.4 0.3 ;
LAYER VIA3 ;
RECT -0.3 -0.25 0.3 0.25 ;
LAYER M4 ;
RECT -1.00 -0.5 1.00 0.5 ;
END via34
END LIBRARY

View File

@ -249,6 +249,10 @@ class DBReaders_TestClass < TestBase
conf.via_geometry_suffix = "XVIA"
assert_equal(conf.via_geometry_suffix, "XVIA")
assert_equal(conf.via_cellname_prefix, "VIA_")
conf.via_cellname_prefix = "ABC"
assert_equal(conf.via_cellname_prefix, "ABC")
assert_equal(conf.via_geometry_datatype, 0)
conf.via_geometry_datatype = 17
assert_equal(conf.via_geometry_datatype, 17)
@ -265,6 +269,18 @@ class DBReaders_TestClass < TestBase
conf.pins_datatype = 18
assert_equal(conf.pins_datatype, 18)
assert_equal(conf.produce_lef_pins, true)
conf.produce_lef_pins = false
assert_equal(conf.produce_lef_pins, false)
assert_equal(conf.lef_pins_suffix, ".PIN")
conf.lef_pins_suffix = "LEFPIN"
assert_equal(conf.lef_pins_suffix, "LEFPIN")
assert_equal(conf.lef_pins_datatype, 2)
conf.lef_pins_datatype = 181
assert_equal(conf.lef_pins_datatype, 181)
assert_equal(conf.produce_obstructions, true)
conf.produce_obstructions = false
assert_equal(conf.produce_obstructions, false)
@ -313,6 +329,26 @@ class DBReaders_TestClass < TestBase
conf.routing_datatype = 22
assert_equal(conf.routing_datatype, 22)
assert_equal(conf.produce_special_routing, true)
conf.produce_special_routing = false
assert_equal(conf.produce_special_routing, false)
assert_equal(conf.special_routing_suffix, "")
conf.special_routing_suffix = "SPROUT"
assert_equal(conf.special_routing_suffix, "SPROUT")
assert_equal(conf.special_routing_datatype, 0)
conf.special_routing_datatype = 23
assert_equal(conf.special_routing_datatype, 23)
assert_equal(conf.separate_groups, false)
conf.separate_groups = true
assert_equal(conf.separate_groups, true)
assert_equal(conf.map_file, "")
conf.map_file = "xyz.map"
assert_equal(conf.map_file, "xyz.map")
assert_equal(conf.lef_files.join(","), "")
conf.lef_files = [ "u.lef", "v.lef" ]
assert_equal(conf.lef_files.join(","), "u.lef,v.lef")