mirror of https://github.com/KLayout/klayout.git
First implementation of masks for vias. Needs debugging.
This commit is contained in:
parent
0d52da77ee
commit
dbe5e19017
|
|
@ -517,13 +517,19 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
||||||
|
|
||||||
double x = 0.0, y = 0.0;
|
double x = 0.0, y = 0.0;
|
||||||
unsigned int mask = 0;
|
unsigned int mask = 0;
|
||||||
|
bool read_mask = true;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
if (test ("MASK")) {
|
if (read_mask) {
|
||||||
mask = get_mask (get_long ());
|
mask = 0;
|
||||||
|
if (test ("MASK")) {
|
||||||
|
mask = get_mask (get_long ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read_mask = true;
|
||||||
|
|
||||||
if (test ("RECT")) {
|
if (test ("RECT")) {
|
||||||
|
|
||||||
if (! test ("(")) {
|
if (! test ("(")) {
|
||||||
|
|
@ -567,12 +573,18 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
||||||
while (peek ("(") || peek ("MASK")) {
|
while (peek ("(") || peek ("MASK")) {
|
||||||
|
|
||||||
if (test ("MASK")) {
|
if (test ("MASK")) {
|
||||||
mask = get_mask (get_long ());
|
unsigned int m = get_mask (get_long ());
|
||||||
|
if (m != mask) {
|
||||||
|
// stop here with the segments and use the mask value for the next iteration
|
||||||
|
mask = m;
|
||||||
|
read_mask = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! test ("(")) {
|
if (! test ("(")) {
|
||||||
// We could have a via here: in that case we have swallowed MASK already, but
|
// We have a via here. MASK is already read, but the value did not change.
|
||||||
// since we don't do anything with that, this does not hurt for now.
|
read_mask = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -632,16 +644,27 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
||||||
|
|
||||||
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
|
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
|
||||||
if (vd != m_via_desc.end () && ! pts.empty ()) {
|
if (vd != m_via_desc.end () && ! pts.empty ()) {
|
||||||
if (nx <= 1 && ny <= 1) {
|
|
||||||
design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ()))));
|
// For the via, the masks are encoded in a three-digit number (<mask-top> <mask-cut> <mask_bottom>)
|
||||||
} else {
|
unsigned int mask_top = (mask / 100) % 10;
|
||||||
design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())), db::Vector (dx, 0), db::Vector (0, dy), (unsigned long) nx, (unsigned long) ny));
|
unsigned int mask_cut = (mask / 10) % 10;
|
||||||
|
unsigned int mask_bottom = mask % 10;
|
||||||
|
|
||||||
|
db::Cell *cell = reader_state ()->via_cell (vn, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer);
|
||||||
|
if (cell) {
|
||||||
|
if (nx <= 1 && ny <= 1) {
|
||||||
|
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ()))));
|
||||||
|
} else {
|
||||||
|
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())), db::Vector (dx, 0), db::Vector (0, dy), (unsigned long) nx, (unsigned long) ny));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ln == vd->second.m1) {
|
if (ln == vd->second.m1) {
|
||||||
ln = vd->second.m2;
|
ln = vd->second.m2;
|
||||||
} else if (ln == vd->second.m2) {
|
} else if (ln == vd->second.m2) {
|
||||||
ln = vd->second.m1;
|
ln = vd->second.m1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! specialnets) {
|
if (! specialnets) {
|
||||||
|
|
@ -799,7 +822,11 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
|
||||||
|
|
||||||
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
|
std::map<std::string, ViaDesc>::const_iterator vd = m_via_desc.find (vn);
|
||||||
if (vd != m_via_desc.end ()) {
|
if (vd != m_via_desc.end ()) {
|
||||||
design.insert (db::CellInstArray (db::CellInst (vd->second.cell->cell_index ()), db::Trans (ft.rot (), pt)));
|
// TODO: no mask specification here?
|
||||||
|
db::Cell *cell = reader_state ()->via_cell (vn, layout, 0, 0, 0, &m_lef_importer);
|
||||||
|
if (cell) {
|
||||||
|
design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt)));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
error (tl::to_string (tr ("Invalid via name: ")) + vn);
|
error (tl::to_string (tr ("Invalid via name: ")) + vn);
|
||||||
}
|
}
|
||||||
|
|
@ -844,7 +871,7 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
|
DEFImporter::read_vias (db::Layout & /*layout*/, db::Cell & /*design*/, double scale)
|
||||||
{
|
{
|
||||||
while (test ("-")) {
|
while (test ("-")) {
|
||||||
|
|
||||||
|
|
@ -852,100 +879,144 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
|
||||||
ViaDesc &vd = m_via_desc.insert (std::make_pair (n, ViaDesc ())).first->second;
|
ViaDesc &vd = m_via_desc.insert (std::make_pair (n, ViaDesc ())).first->second;
|
||||||
|
|
||||||
// produce a cell for vias
|
// produce a cell for vias
|
||||||
std::string cellname = options ().via_cellname_prefix () + n;
|
std::auto_ptr<RuleBasedViaGenerator> rule_based_vg;
|
||||||
db::Cell &cell = layout.cell (layout.add_cell (cellname.c_str ()));
|
std::auto_ptr<GeometryBasedViaGenerator> geo_based_vg;
|
||||||
reader_state ()->register_via_cell (n, &cell);
|
|
||||||
vd.cell = &cell;
|
|
||||||
|
|
||||||
bool has_via_rule = false;
|
|
||||||
|
|
||||||
db::Vector cutsize, cutspacing;
|
|
||||||
db::Vector be, te;
|
|
||||||
db::Vector bo, to;
|
|
||||||
db::Point offset;
|
|
||||||
int rows = 1, columns = 1;
|
|
||||||
std::string pattern;
|
|
||||||
unsigned int mask = 0;
|
unsigned int mask = 0;
|
||||||
|
|
||||||
std::map<std::string, std::vector<db::Polygon> > geometry;
|
std::auto_ptr<LEFDEFViaGenerator> via_generator;
|
||||||
std::vector<db::Polygon> *top = 0, *cut = 0, *bottom = 0;
|
std::set<std::string> seen_layers;
|
||||||
|
std::vector<std::string> routing_layers;
|
||||||
|
|
||||||
while (test ("+")) {
|
while (test ("+")) {
|
||||||
|
|
||||||
if (test ("VIARULE")) {
|
if (test ("VIARULE")) {
|
||||||
|
|
||||||
has_via_rule = true;
|
if (! rule_based_vg.get ()) {
|
||||||
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
take ();
|
take ();
|
||||||
|
|
||||||
} else if (test ("CUTSIZE")) {
|
} else if (test ("CUTSIZE")) {
|
||||||
|
|
||||||
cutsize = get_vector (scale);
|
if (! rule_based_vg.get ()) {
|
||||||
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
|
rule_based_vg->set_cutsize (get_vector (scale));
|
||||||
|
|
||||||
} else if (test ("CUTSPACING")) {
|
} else if (test ("CUTSPACING")) {
|
||||||
|
|
||||||
cutspacing = get_vector (scale);
|
if (! rule_based_vg.get ()) {
|
||||||
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
|
rule_based_vg->set_cutspacing (get_vector (scale));
|
||||||
|
|
||||||
} else if (test ("ORIGIN")) {
|
} else if (test ("ORIGIN")) {
|
||||||
|
|
||||||
offset = get_point (scale);
|
if (! rule_based_vg.get ()) {
|
||||||
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
|
rule_based_vg->set_offset (get_point (scale));
|
||||||
|
|
||||||
} else if (test ("ENCLOSURE")) {
|
} else if (test ("ENCLOSURE")) {
|
||||||
|
|
||||||
be = get_vector (scale);
|
if (! rule_based_vg.get ()) {
|
||||||
te = get_vector (scale);
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
|
rule_based_vg->set_be (get_vector (scale));
|
||||||
|
rule_based_vg->set_te (get_vector (scale));
|
||||||
|
|
||||||
} else if (test ("OFFSET")) {
|
} else if (test ("OFFSET")) {
|
||||||
|
|
||||||
bo = get_vector (scale);
|
if (! rule_based_vg.get ()) {
|
||||||
to = get_vector (scale);
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
|
rule_based_vg->set_bo (get_vector (scale));
|
||||||
|
rule_based_vg->set_to (get_vector (scale));
|
||||||
|
|
||||||
} else if (test ("ROWCOL")) {
|
} else if (test ("ROWCOL")) {
|
||||||
|
|
||||||
rows = get_long ();
|
if (! rule_based_vg.get ()) {
|
||||||
columns = get_long ();
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
|
rule_based_vg->set_rows (get_long ());
|
||||||
|
rule_based_vg->set_columns (get_long ());
|
||||||
|
|
||||||
} else if (test ("PATTERN")) {
|
} else if (test ("PATTERN")) {
|
||||||
|
|
||||||
pattern = get ();
|
if (! rule_based_vg.get ()) {
|
||||||
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
|
rule_based_vg->set_pattern (get ());
|
||||||
|
|
||||||
} else if (test ("LAYERS")) {
|
} else if (test ("LAYERS")) {
|
||||||
|
|
||||||
|
if (! rule_based_vg.get ()) {
|
||||||
|
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
std::string bn = get ();
|
std::string bn = get ();
|
||||||
std::string cn = get ();
|
std::string cn = get ();
|
||||||
std::string tn = get ();
|
std::string tn = get ();
|
||||||
|
|
||||||
bottom = &geometry.insert (std::make_pair (bn, std::vector<db::Polygon> ())).first->second;
|
rule_based_vg->set_bottom_layer (bn);
|
||||||
cut = &geometry.insert (std::make_pair (cn, std::vector<db::Polygon> ())).first->second;
|
rule_based_vg->set_cut_layer (cn);
|
||||||
top = &geometry.insert (std::make_pair (tn, std::vector<db::Polygon> ())).first->second;
|
rule_based_vg->set_top_layer (tn);
|
||||||
|
|
||||||
vd.m1 = bn;
|
vd.m1 = bn;
|
||||||
vd.m2 = tn;
|
vd.m2 = tn;
|
||||||
|
|
||||||
} else if (test ("POLYGON")) {
|
} else if (test ("POLYGON")) {
|
||||||
|
|
||||||
|
if (! geo_based_vg.get ()) {
|
||||||
|
geo_based_vg.reset (new GeometryBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
std::string ln = get ();
|
std::string ln = get ();
|
||||||
|
|
||||||
|
if (m_lef_importer.is_routing_layer (ln) && seen_layers.find (ln) != seen_layers.end ()) {
|
||||||
|
seen_layers.insert (ln);
|
||||||
|
routing_layers.push_back (ln);
|
||||||
|
}
|
||||||
|
|
||||||
if (test ("+")) {
|
if (test ("+")) {
|
||||||
expect ("MASK");
|
expect ("MASK");
|
||||||
mask = get_mask (get_long ());
|
mask = get_mask (get_long ());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<db::Polygon> &polygons = geometry.insert (std::make_pair (ln, std::vector<db::Polygon> ())).first->second;
|
db::Polygon poly;
|
||||||
polygons.push_back (db::Polygon ());
|
read_polygon (poly, scale);
|
||||||
read_polygon (polygons.back (), scale);
|
geo_based_vg->add_polygon (ln, poly, mask);
|
||||||
|
|
||||||
} else if (test ("RECT")) {
|
} else if (test ("RECT")) {
|
||||||
|
|
||||||
|
if (! geo_based_vg.get ()) {
|
||||||
|
geo_based_vg.reset (new GeometryBasedViaGenerator ());
|
||||||
|
}
|
||||||
|
|
||||||
std::string ln = get ();
|
std::string ln = get ();
|
||||||
|
|
||||||
|
if (m_lef_importer.is_routing_layer (ln) && seen_layers.find (ln) != seen_layers.end ()) {
|
||||||
|
seen_layers.insert (ln);
|
||||||
|
routing_layers.push_back (ln);
|
||||||
|
}
|
||||||
|
|
||||||
if (test ("+")) {
|
if (test ("+")) {
|
||||||
expect ("MASK");
|
expect ("MASK");
|
||||||
mask = get_mask (get_long ());
|
mask = get_mask (get_long ());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<db::Polygon> &polygons = geometry.insert (std::make_pair (ln, std::vector<db::Polygon> ())).first->second;
|
db::Polygon poly;
|
||||||
polygons.push_back (db::Polygon ());
|
read_polygon (poly, scale);
|
||||||
read_rect (polygons.back (), scale);
|
geo_based_vg->add_polygon (ln, poly, mask);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -954,13 +1025,6 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
|
||||||
if (vd.m1.empty () && vd.m2.empty ()) {
|
if (vd.m1.empty () && vd.m2.empty ()) {
|
||||||
|
|
||||||
// analyze the layers to find the metals
|
// analyze the layers to find the metals
|
||||||
std::vector<std::string> routing_layers;
|
|
||||||
for (std::map<std::string, std::vector<db::Polygon> >::const_iterator b = geometry.begin (); b != geometry.end (); ++b) {
|
|
||||||
if (m_lef_importer.is_routing_layer (b->first)) {
|
|
||||||
routing_layers.push_back (b->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routing_layers.size () == 2) {
|
if (routing_layers.size () == 2) {
|
||||||
vd.m1 = routing_layers[0];
|
vd.m1 = routing_layers[0];
|
||||||
vd.m2 = routing_layers[1];
|
vd.m2 = routing_layers[1];
|
||||||
|
|
@ -970,22 +1034,18 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rule_based_vg.get () && geo_based_vg.get ()) {
|
||||||
|
error (tl::to_string (tr ("A via can only be defined through a VIARULE or geometry, not both ways")));
|
||||||
|
} else if (rule_based_vg.get ()) {
|
||||||
|
reader_state ()->register_via_cell (n, rule_based_vg.release ());
|
||||||
|
} else if (geo_based_vg.get ()) {
|
||||||
|
reader_state ()->register_via_cell (n, geo_based_vg.release ());
|
||||||
|
} else {
|
||||||
|
error (tl::to_string (tr ("Too little information to generate a via")));
|
||||||
|
}
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
if (has_via_rule && top && cut && bottom) {
|
|
||||||
create_generated_via (*bottom, *cut, *top,
|
|
||||||
cutsize, cutspacing, be, te, bo, to, offset, rows, columns, pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::map<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, mask);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,206 @@ std::string correct_path (const std::string &fn, const db::Layout &layout, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// Utilities
|
||||||
|
|
||||||
|
static bool is_hex_digit (char c)
|
||||||
|
{
|
||||||
|
char cup = toupper (c);
|
||||||
|
return (cup >= 'A' && cup <= 'F') || (c >= '0' && c <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hex_value (char c)
|
||||||
|
{
|
||||||
|
char cup = toupper (c);
|
||||||
|
if (cup >= 'A' && cup <= 'F') {
|
||||||
|
return (cup - 'A') + 10;
|
||||||
|
} else if (c >= '0' && c <= '9') {
|
||||||
|
return c - '0';
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// RuleBasedViaGenerator implementation
|
||||||
|
|
||||||
|
RuleBasedViaGenerator::RuleBasedViaGenerator ()
|
||||||
|
: LEFDEFViaGenerator (), m_bottom_mask (0), m_cut_mask (0), m_top_mask (0), m_rows (1), m_columns (1)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void
|
||||||
|
RuleBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm)
|
||||||
|
{
|
||||||
|
if (mask_bottom == 0) {
|
||||||
|
mask_bottom = m_bottom_mask;
|
||||||
|
}
|
||||||
|
if (mask_cut == 0) {
|
||||||
|
mask_cut = m_cut_mask;
|
||||||
|
}
|
||||||
|
if (mask_top == 0) {
|
||||||
|
mask_top = m_top_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int num_cut_masks = nm ? nm->number_of_masks (m_cut_layer) : 1;
|
||||||
|
|
||||||
|
// NOTE: missing cuts due to pattern holes don't change mask assignment
|
||||||
|
|
||||||
|
db::Vector vs ((m_cutsize.x () * m_columns + m_cutspacing.x () * (m_columns - 1)) / 2, (m_cutsize.y () * m_rows + m_cutspacing.y () * (m_rows - 1)) / 2);
|
||||||
|
db::Box via_box (m_offset - vs, m_offset + vs);
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int> dl (false, 0);
|
||||||
|
|
||||||
|
dl = reader.open_layer (layout, m_bottom_layer, ViaGeometry, mask_bottom);
|
||||||
|
if (dl.first) {
|
||||||
|
cell.shapes (dl.second).insert (db::Polygon (via_box.enlarged (m_be).moved (m_bo)));
|
||||||
|
}
|
||||||
|
|
||||||
|
dl = reader.open_layer (layout, m_top_layer, ViaGeometry, mask_top);
|
||||||
|
if (dl.first) {
|
||||||
|
cell.shapes (dl.second).insert (db::Polygon (via_box.enlarged (m_te).moved (m_bo)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *p = m_pattern.c_str ();
|
||||||
|
int rp = m_pattern.empty () ? -1 : 0;
|
||||||
|
const char *p0 = p, *p1 = p;
|
||||||
|
|
||||||
|
for (int r = 0; r < m_rows; ++r) {
|
||||||
|
|
||||||
|
if (rp == 0) {
|
||||||
|
|
||||||
|
if (*p) {
|
||||||
|
|
||||||
|
// read a new row specification
|
||||||
|
rp = 0;
|
||||||
|
while (*p && is_hex_digit (*p)) {
|
||||||
|
rp = (rp * 16) + hex_value (*p++);
|
||||||
|
}
|
||||||
|
if (*p == '_') {
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
p0 = p;
|
||||||
|
if (*p) {
|
||||||
|
while (*p && (is_hex_digit (*p) || toupper (*p) == 'R')) {
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p1 = p;
|
||||||
|
if (*p == '_') {
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rp != 0) {
|
||||||
|
|
||||||
|
if (rp > 0) {
|
||||||
|
--rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *pp = p0;
|
||||||
|
unsigned int d = 0;
|
||||||
|
int cp = (p == p0 ? -1 : 0);
|
||||||
|
int bit = 0;
|
||||||
|
|
||||||
|
for (int c = 0; c < m_columns; ++c) {
|
||||||
|
|
||||||
|
if (cp == 0) {
|
||||||
|
|
||||||
|
d = 0;
|
||||||
|
cp = 4;
|
||||||
|
bit = 0;
|
||||||
|
|
||||||
|
if (*pp && pp < p1 && toupper (*pp) == 'R') {
|
||||||
|
|
||||||
|
++pp;
|
||||||
|
if (*pp && pp < p1) {
|
||||||
|
cp = 4 * hex_value (*pp++);
|
||||||
|
if (*pp && pp < p1) {
|
||||||
|
d = (unsigned int) hex_value (*pp++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (*pp && pp < p1) {
|
||||||
|
|
||||||
|
d = (unsigned int) hex_value (*pp++);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cp > 0) {
|
||||||
|
--cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (cp > 0) {
|
||||||
|
|
||||||
|
--cp;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
d = 0xf;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((d & (0x8 >> (bit++ % 4))) != 0) {
|
||||||
|
|
||||||
|
db::Vector vbl ((m_cutsize + m_cutspacing).x () * c, (m_cutsize + m_cutspacing).y () * r);
|
||||||
|
db::Box vb (via_box.lower_left () + vbl, via_box.lower_left () + vbl + m_cutsize);
|
||||||
|
|
||||||
|
unsigned int cm = 0;
|
||||||
|
if (mask_cut > 0) {
|
||||||
|
// This is the core algorithm for mask assignment in patterned vias
|
||||||
|
cm = (mask_cut + r + c - 1) % num_cut_masks + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl = reader.open_layer (layout, m_cut_layer, ViaGeometry, cm);
|
||||||
|
if (dl.first) {
|
||||||
|
cell.shapes (dl.second).insert (db::Polygon (vb));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------
|
||||||
|
// GeometryBasedViaGenerator implementation
|
||||||
|
|
||||||
|
GeometryBasedViaGenerator::GeometryBasedViaGenerator ()
|
||||||
|
: LEFDEFViaGenerator ()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void
|
||||||
|
GeometryBasedViaGenerator::create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, unsigned int /*mask_bottom*/, unsigned int /*mask_cut*/, unsigned int /*mask_top*/, const LEFDEFNumberOfMasks * /*nm*/)
|
||||||
|
{
|
||||||
|
for (std::map <std::string, std::list<std::pair<unsigned int, db::Polygon> > >::const_iterator g = m_geometries.begin (); g != m_geometries.end (); ++g) {
|
||||||
|
|
||||||
|
for (std::list<std::pair<unsigned int, db::Polygon> >::const_iterator i = g->second.begin (); i != g->second.end (); ++i) {
|
||||||
|
|
||||||
|
std::pair <bool, unsigned int> dl (false, 0);
|
||||||
|
|
||||||
|
dl = reader.open_layer (layout, g->first, ViaGeometry, i->first);
|
||||||
|
if (dl.first) {
|
||||||
|
cell.shapes (dl.second).insert (i->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GeometryBasedViaGenerator::add_polygon (const std::string &ln, const db::Polygon &poly, unsigned int mask)
|
||||||
|
{
|
||||||
|
m_geometries [ln].push_back (std::make_pair (mask, poly));
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// LEFDEFTechnologyComponent implementation
|
// LEFDEFTechnologyComponent implementation
|
||||||
|
|
||||||
|
|
@ -449,6 +649,15 @@ LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LEFDEFReaderState::~LEFDEFReaderState ()
|
||||||
|
{
|
||||||
|
for (std::map<std::string, LEFDEFViaGenerator *>::const_iterator i = m_via_generators.begin (); i != m_via_generators.end (); ++i) {
|
||||||
|
delete i->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_via_generators.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LEFDEFReaderState::register_layer (const std::string &ln)
|
LEFDEFReaderState::register_layer (const std::string &ln)
|
||||||
{
|
{
|
||||||
|
|
@ -484,7 +693,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
purpose_translation ["VIA"] = ViaGeometry;
|
purpose_translation ["VIA"] = ViaGeometry;
|
||||||
purpose_translation ["BLOCKAGE"] = Blockage;
|
purpose_translation ["BLOCKAGE"] = Blockage;
|
||||||
|
|
||||||
std::map<std::pair<std::string, LayerPurpose>, db::LayerProperties> layer_map;
|
std::map<std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, db::LayerProperties> layer_map;
|
||||||
|
|
||||||
while (! ts.at_end ()) {
|
while (! ts.at_end ()) {
|
||||||
|
|
||||||
|
|
@ -504,15 +713,15 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
|
|
||||||
if (w1 == "DIEAREA") {
|
if (w1 == "DIEAREA") {
|
||||||
|
|
||||||
layer_map [std::make_pair (std::string (), Outline)] = db::LayerProperties (layer, datatype, "OUTLINE");
|
layer_map [std::make_pair (std::string (), std::make_pair (Outline, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "OUTLINE");
|
||||||
|
|
||||||
} else if (w1 == "REGIONS") {
|
} else if (w1 == "REGIONS") {
|
||||||
|
|
||||||
layer_map [std::make_pair (std::string (), Regions)] = db::LayerProperties (layer, datatype, "REGIONS");
|
layer_map [std::make_pair (std::string (), std::make_pair (Regions, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "REGIONS");
|
||||||
|
|
||||||
} else if (w1 == "BLOCKAGE") {
|
} else if (w1 == "BLOCKAGE") {
|
||||||
|
|
||||||
layer_map [std::make_pair (std::string (), PlacementBlockage)] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK");
|
layer_map [std::make_pair (std::string (), std::make_pair (PlacementBlockage, (unsigned int) 0))] = db::LayerProperties (layer, datatype, "PLACEMENT_BLK");
|
||||||
|
|
||||||
} else if (w1 == "NAME") {
|
} else if (w1 == "NAME") {
|
||||||
|
|
||||||
|
|
@ -530,7 +739,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
|
|
||||||
std::string final_name = tl::join (layers, "/") + ".LABEL";
|
std::string final_name = tl::join (layers, "/") + ".LABEL";
|
||||||
for (std::vector<std::string>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
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);
|
layer_map [std::make_pair (*l, std::make_pair (Label, (unsigned int) 0))] = db::LayerProperties (layer, datatype, final_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -542,15 +751,30 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
// "(M1,PINS): M1.NET/PINS"
|
// "(M1,PINS): M1.NET/PINS"
|
||||||
// (separating, translating and recombing the purposes)
|
// (separating, translating and recombing the purposes)
|
||||||
|
|
||||||
std::set<LayerPurpose> translated_purposes;
|
std::set<std::pair<LayerPurpose, unsigned int> > translated_purposes;
|
||||||
std::string purpose_str;
|
std::string purpose_str;
|
||||||
|
|
||||||
std::vector<std::string> purposes = tl::split (w2, ",");
|
std::vector<std::string> purposes = tl::split (w2, ",");
|
||||||
for (std::vector<std::string>::const_iterator p = purposes.begin (); p != purposes.end (); ++p) {
|
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));
|
std::string p_uc = tl::to_upper_case (*p);
|
||||||
|
tl::Extractor ex (p_uc.c_str ());
|
||||||
|
|
||||||
|
std::string ps;
|
||||||
|
ex.read (ps);
|
||||||
|
|
||||||
|
unsigned int mask = 0;
|
||||||
|
|
||||||
|
if (ex.test (":")) {
|
||||||
|
if (ex.test ("MASK") && ex.test (":")) {
|
||||||
|
ex.read (mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, LayerPurpose>::const_iterator i = purpose_translation.find (ps);
|
||||||
if (i != purpose_translation.end ()) {
|
if (i != purpose_translation.end ()) {
|
||||||
|
|
||||||
translated_purposes.insert (i->second);
|
translated_purposes.insert (std::make_pair (i->second, mask));
|
||||||
|
|
||||||
if (! purpose_str.empty ()) {
|
if (! purpose_str.empty ()) {
|
||||||
purpose_str += "/";
|
purpose_str += "/";
|
||||||
|
|
@ -558,11 +782,12 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
purpose_str += i->first;
|
purpose_str += i->first;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string final_name = w1 + "." + purpose_str;
|
std::string final_name = w1 + "." + purpose_str;
|
||||||
|
|
||||||
for (std::set<LayerPurpose>::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
|
for (std::set<std::pair<LayerPurpose, unsigned int> >::const_iterator p = translated_purposes.begin (); p != translated_purposes.end (); ++p) {
|
||||||
layer_map [std::make_pair (w1, *p)] = db::LayerProperties (layer, datatype, final_name);
|
layer_map [std::make_pair (w1, *p)] = db::LayerProperties (layer, datatype, final_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -575,8 +800,8 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
db::DirectLayerMapping lm (&layout);
|
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) {
|
for (std::map<std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, 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);
|
map_layer_explicit (i->first.first, i->first.second.first, i->second, lm.map_layer (i->second).second, i->first.second.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -840,16 +1065,52 @@ LEFDEFReaderState::finish (db::Layout &layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LEFDEFReaderState::register_via_cell (const std::string &vn, db::Cell *cell)
|
LEFDEFReaderState::register_via_cell (const std::string &vn, LEFDEFViaGenerator *generator)
|
||||||
{
|
{
|
||||||
m_via_cells [vn] = cell;
|
if (m_via_generators.find (vn) != m_via_generators.end ()) {
|
||||||
|
delete m_via_generators [vn];
|
||||||
|
}
|
||||||
|
m_via_generators [vn] = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
db::Cell *
|
db::Cell *
|
||||||
LEFDEFReaderState::via_cell (const std::string &vn)
|
LEFDEFReaderState::via_cell (const std::string &vn, db::Layout &layout, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm)
|
||||||
{
|
{
|
||||||
std::map<std::string, db::Cell *>::const_iterator i = m_via_cells.find (vn);
|
ViaKey vk (vn, mask_bottom, mask_cut, mask_top);
|
||||||
return i != m_via_cells.end () ? i->second : 0;
|
std::map<ViaKey, db::Cell *>::const_iterator i = m_via_cells.find (vk);
|
||||||
|
if (i == m_via_cells.end ()) {
|
||||||
|
|
||||||
|
db::Cell *cell = 0;
|
||||||
|
|
||||||
|
std::map<std::string, LEFDEFViaGenerator *>::const_iterator g = m_via_generators.find (vn);
|
||||||
|
if (g != m_via_generators.end ()) {
|
||||||
|
|
||||||
|
LEFDEFViaGenerator *vg = g->second;
|
||||||
|
|
||||||
|
std::string mask_suffix;
|
||||||
|
if (mask_bottom > 0 || mask_cut > 0 || mask_top > 0) {
|
||||||
|
mask_suffix += "_";
|
||||||
|
mask_suffix += tl::to_string (mask_bottom);
|
||||||
|
mask_suffix += "_";
|
||||||
|
mask_suffix += tl::to_string (mask_cut);
|
||||||
|
mask_suffix += "_";
|
||||||
|
mask_suffix += tl::to_string (mask_top);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cn = mp_tech_comp->via_cellname_prefix () + vn + mask_suffix;
|
||||||
|
cell = &layout.cell (layout.add_cell (cn.c_str ()));
|
||||||
|
|
||||||
|
vg->create_cell (*this, layout, *cell, mask_bottom, mask_cut, mask_bottom, nm);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
m_via_cells[vk] = cell;
|
||||||
|
return cell;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
tl_assert (! i->second || i->second->layout () == &layout);
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
|
|
@ -872,10 +1133,7 @@ LEFDEFImporter::~LEFDEFImporter ()
|
||||||
unsigned int
|
unsigned int
|
||||||
LEFDEFImporter::get_mask (long m)
|
LEFDEFImporter::get_mask (long m)
|
||||||
{
|
{
|
||||||
if (m < 1 || m > 16) {
|
return (unsigned int) m;
|
||||||
error (tl::to_string (tr ("Invalid mask number: ")) + tl::to_string (m));
|
|
||||||
}
|
|
||||||
return (unsigned int) (m - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1146,141 +1404,6 @@ LEFDEFImporter::next ()
|
||||||
return m_last_token;
|
return m_last_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_hex_digit (char c)
|
|
||||||
{
|
|
||||||
char cup = toupper (c);
|
|
||||||
return (cup >= 'A' && cup <= 'F') || (c >= '0' && c <= '9');
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hex_value (char c)
|
|
||||||
{
|
|
||||||
char cup = toupper (c);
|
|
||||||
if (cup >= 'A' && cup <= 'F') {
|
|
||||||
return (cup - 'A') + 10;
|
|
||||||
} else if (c >= '0' && c <= '9') {
|
|
||||||
return c - '0';
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
LEFDEFImporter::create_generated_via (std::vector<db::Polygon> &bottom,
|
|
||||||
std::vector<db::Polygon> &cut,
|
|
||||||
std::vector<db::Polygon> &top,
|
|
||||||
const db::Vector &cutsize,
|
|
||||||
const db::Vector &cutspacing,
|
|
||||||
const db::Vector &be, const db::Vector &te,
|
|
||||||
const db::Vector &bo, const db::Vector &to,
|
|
||||||
const db::Point &o,
|
|
||||||
int rows, int columns,
|
|
||||||
const std::string &pattern)
|
|
||||||
{
|
|
||||||
db::Vector vs ((cutsize.x () * columns + cutspacing.x () * (columns - 1)) / 2, (cutsize.y () * rows + cutspacing.y () * (rows - 1)) / 2);
|
|
||||||
db::Box via_box (o - vs, o + vs);
|
|
||||||
|
|
||||||
bottom.push_back (db::Polygon (via_box.enlarged (be).moved (bo)));
|
|
||||||
top.push_back (db::Polygon (via_box.enlarged (te).moved (to)));
|
|
||||||
|
|
||||||
const char *p = pattern.c_str ();
|
|
||||||
int rp = pattern.empty () ? -1 : 0;
|
|
||||||
const char *p0 = p, *p1 = p;
|
|
||||||
|
|
||||||
for (int r = 0; r < rows; ++r) {
|
|
||||||
|
|
||||||
if (rp == 0) {
|
|
||||||
|
|
||||||
if (*p) {
|
|
||||||
|
|
||||||
// read a new row specification
|
|
||||||
rp = 0;
|
|
||||||
while (*p && is_hex_digit (*p)) {
|
|
||||||
rp = (rp * 16) + hex_value (*p++);
|
|
||||||
}
|
|
||||||
if (*p == '_') {
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
|
|
||||||
p0 = p;
|
|
||||||
if (*p) {
|
|
||||||
while (*p && (is_hex_digit (*p) || toupper (*p) == 'R')) {
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p1 = p;
|
|
||||||
if (*p == '_') {
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rp != 0) {
|
|
||||||
|
|
||||||
if (rp > 0) {
|
|
||||||
--rp;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *pp = p0;
|
|
||||||
unsigned int d = 0;
|
|
||||||
int cp = (p == p0 ? -1 : 0);
|
|
||||||
int bit = 0;
|
|
||||||
|
|
||||||
for (int c = 0; c < columns; ++c) {
|
|
||||||
|
|
||||||
if (cp == 0) {
|
|
||||||
|
|
||||||
d = 0;
|
|
||||||
cp = 4;
|
|
||||||
bit = 0;
|
|
||||||
|
|
||||||
if (*pp && pp < p1 && toupper (*pp) == 'R') {
|
|
||||||
|
|
||||||
++pp;
|
|
||||||
if (*pp && pp < p1) {
|
|
||||||
cp = 4 * hex_value (*pp++);
|
|
||||||
if (*pp && pp < p1) {
|
|
||||||
d = (unsigned int) hex_value (*pp++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (*pp && pp < p1) {
|
|
||||||
|
|
||||||
d = (unsigned int) hex_value (*pp++);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cp > 0) {
|
|
||||||
--cp;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (cp > 0) {
|
|
||||||
|
|
||||||
--cp;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
d = 0xf;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((d & (0x8 >> (bit++ % 4))) != 0) {
|
|
||||||
|
|
||||||
db::Vector vbl ((cutsize + cutspacing).x () * c, (cutsize + cutspacing).y () * r);
|
|
||||||
db::Box vb (via_box.lower_left () + vbl, via_box.lower_left () + vbl + cutsize);
|
|
||||||
cut.push_back (db::Polygon (vb));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
db::FTrans
|
db::FTrans
|
||||||
LEFDEFImporter::get_orient (bool optional)
|
LEFDEFImporter::get_orient (bool optional)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ namespace tl
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class LEFDEFReaderState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Correct a path relative to the stream and technology
|
* @brief Correct a path relative to the stream and technology
|
||||||
*/
|
*/
|
||||||
|
|
@ -848,6 +850,86 @@ enum LayerPurpose
|
||||||
Regions, // from DEF only
|
Regions, // from DEF only
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An interface for resolving the number of masks from a layer name
|
||||||
|
*/
|
||||||
|
class DB_PLUGIN_PUBLIC LEFDEFNumberOfMasks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LEFDEFNumberOfMasks () { }
|
||||||
|
virtual ~LEFDEFNumberOfMasks () { }
|
||||||
|
|
||||||
|
virtual unsigned int number_of_masks (const std::string &layer_name) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides a via generator base class
|
||||||
|
*/
|
||||||
|
class DB_PLUGIN_PUBLIC LEFDEFViaGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LEFDEFViaGenerator () { }
|
||||||
|
virtual ~LEFDEFViaGenerator () { }
|
||||||
|
|
||||||
|
virtual void create_cell (LEFDEFReaderState &reader, db::Layout &layout, db::Cell &cell, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides a via generator implementation for rule-based vias
|
||||||
|
*/
|
||||||
|
class DB_PLUGIN_PUBLIC RuleBasedViaGenerator
|
||||||
|
: public LEFDEFViaGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RuleBasedViaGenerator ();
|
||||||
|
|
||||||
|
virtual void create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm);
|
||||||
|
|
||||||
|
void set_cutsize (const db::Vector &cutsize) { m_cutsize = cutsize; }
|
||||||
|
void set_cutspacing (const db::Vector &cutspacing) { m_cutspacing = cutspacing; }
|
||||||
|
void set_offset (const db::Point &offset) { m_offset = offset; }
|
||||||
|
void set_be (const db::Vector &be) { m_be = be; }
|
||||||
|
void set_te (const db::Vector &te) { m_te = te; }
|
||||||
|
void set_bo (const db::Vector &bo) { m_bo = bo; }
|
||||||
|
void set_to (const db::Vector &to) { m_to = to; }
|
||||||
|
void set_rows (int rows) { m_rows = rows; }
|
||||||
|
void set_columns (int columns) { m_columns = columns; }
|
||||||
|
void set_pattern (const std::string &pattern) { m_pattern = pattern; }
|
||||||
|
void set_bottom_layer (const std::string &ln) { m_bottom_layer = ln; }
|
||||||
|
void set_cut_layer (const std::string &ln) { m_cut_layer = ln; }
|
||||||
|
void set_top_layer (const std::string &ln) { m_top_layer = ln; }
|
||||||
|
void set_bottom_mask (unsigned int m) { m_bottom_mask = m; }
|
||||||
|
void set_cut_mask (unsigned int m) { m_cut_mask = m; }
|
||||||
|
void set_top_mask (unsigned int m) { m_top_mask = m; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_bottom_layer, m_cut_layer, m_top_layer;
|
||||||
|
unsigned int m_bottom_mask, m_cut_mask, m_top_mask;
|
||||||
|
db::Vector m_cutsize, m_cutspacing;
|
||||||
|
db::Vector m_be, m_te;
|
||||||
|
db::Vector m_bo, m_to;
|
||||||
|
db::Point m_offset;
|
||||||
|
int m_rows, m_columns;
|
||||||
|
std::string m_pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides a geometry-based via generator implementation
|
||||||
|
*/
|
||||||
|
class DB_PLUGIN_PUBLIC GeometryBasedViaGenerator
|
||||||
|
: public LEFDEFViaGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GeometryBasedViaGenerator ();
|
||||||
|
|
||||||
|
virtual void create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *num_cut_masks);
|
||||||
|
|
||||||
|
void add_polygon (const std::string &ln, const db::Polygon &poly, unsigned int mask);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map <std::string, std::list<std::pair<unsigned int, db::Polygon> > > m_geometries;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Layer handler delegate
|
* @brief Layer handler delegate
|
||||||
*
|
*
|
||||||
|
|
@ -861,6 +943,11 @@ public:
|
||||||
*/
|
*/
|
||||||
LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path = std::string ());
|
LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path = std::string ());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
~LEFDEFReaderState ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reads the given map file
|
* @brief Reads the given map file
|
||||||
*
|
*
|
||||||
|
|
@ -892,14 +979,16 @@ public:
|
||||||
void finish (db::Layout &layout);
|
void finish (db::Layout &layout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registers a via cell for the via with the given name
|
* @brief Registers a via generator for the via with the given name
|
||||||
|
*
|
||||||
|
* The generator is capable of creating a via for a specific mask configuration
|
||||||
*/
|
*/
|
||||||
void register_via_cell (const std::string &vn, db::Cell *cell);
|
void register_via_cell (const std::string &vn, LEFDEFViaGenerator *generator);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the via cell for the given via name or 0 if no such via is registered
|
* @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);
|
db::Cell *via_cell (const std::string &vn, Layout &layout, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the technology component pointer
|
* @brief Get the technology component pointer
|
||||||
|
|
@ -910,6 +999,45 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief A key for the via cache
|
||||||
|
*/
|
||||||
|
struct ViaKey
|
||||||
|
{
|
||||||
|
ViaKey (const std::string &n, unsigned int mb, unsigned int mc, unsigned int mt)
|
||||||
|
: name (n), mask_bottom (mb), mask_cut (mc), mask_top (mt)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool operator== (const ViaKey &other) const
|
||||||
|
{
|
||||||
|
return name == other.name && mask_bottom == other.mask_bottom && mask_cut == other.mask_cut && mask_top == other.mask_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator< (const ViaKey &other) const
|
||||||
|
{
|
||||||
|
if (name != other.name) {
|
||||||
|
return name < other.name;
|
||||||
|
}
|
||||||
|
if (mask_bottom != other.mask_bottom) {
|
||||||
|
return mask_bottom < other.mask_bottom;
|
||||||
|
}
|
||||||
|
if (mask_cut != other.mask_cut) {
|
||||||
|
return mask_cut < other.mask_cut;
|
||||||
|
}
|
||||||
|
if (mask_top != other.mask_top) {
|
||||||
|
return mask_top < other.mask_top;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
unsigned int mask_bottom, mask_cut, mask_top;
|
||||||
|
};
|
||||||
|
|
||||||
|
// no copying
|
||||||
|
LEFDEFReaderState (const LEFDEFReaderState &);
|
||||||
|
LEFDEFReaderState &operator= (const LEFDEFReaderState &);
|
||||||
|
|
||||||
std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::pair<bool, unsigned int> > m_layers;
|
std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, std::pair<bool, unsigned int> > m_layers;
|
||||||
std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, unsigned int> m_unassigned_layers;
|
std::map <std::pair<std::string, std::pair<LayerPurpose, unsigned int> >, unsigned int> m_unassigned_layers;
|
||||||
db::LayerMap m_layer_map;
|
db::LayerMap m_layer_map;
|
||||||
|
|
@ -917,8 +1045,9 @@ private:
|
||||||
bool m_has_explicit_layer_mapping;
|
bool m_has_explicit_layer_mapping;
|
||||||
int m_laynum;
|
int m_laynum;
|
||||||
std::map<std::string, int> m_default_number;
|
std::map<std::string, int> m_default_number;
|
||||||
std::map<std::string, db::Cell *> m_via_cells;
|
std::map<ViaKey, db::Cell *> m_via_cells;
|
||||||
const LEFDEFReaderOptions *mp_tech_comp;
|
const LEFDEFReaderOptions *mp_tech_comp;
|
||||||
|
std::map<std::string, LEFDEFViaGenerator *> m_via_generators;
|
||||||
|
|
||||||
std::pair <bool, unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
|
std::pair <bool, unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
|
||||||
void map_layer_explicit (const std::string &n, LayerPurpose purpose, const LayerProperties &lp, unsigned int layer, unsigned int mask);
|
void map_layer_explicit (const std::string &n, LayerPurpose purpose, const LayerProperties &lp, unsigned int layer, unsigned int mask);
|
||||||
|
|
@ -929,12 +1058,7 @@ private:
|
||||||
*/
|
*/
|
||||||
struct DB_PLUGIN_PUBLIC ViaDesc
|
struct DB_PLUGIN_PUBLIC ViaDesc
|
||||||
{
|
{
|
||||||
ViaDesc () : cell (0) { }
|
ViaDesc () { }
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The cell representing the via
|
|
||||||
*/
|
|
||||||
db::Cell *cell;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The names of bottom and top metal respectively
|
* @brief The names of bottom and top metal respectively
|
||||||
|
|
@ -1152,17 +1276,6 @@ protected:
|
||||||
return mp_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,
|
|
||||||
const db::Vector &cutsize,
|
|
||||||
const db::Vector &cutspacing,
|
|
||||||
const db::Vector &be, const db::Vector &te,
|
|
||||||
const db::Vector &bo, const db::Vector &to,
|
|
||||||
const db::Point &o,
|
|
||||||
int rows, int columns,
|
|
||||||
const std::string &pattern);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tl::AbsoluteProgress *mp_progress;
|
tl::AbsoluteProgress *mp_progress;
|
||||||
tl::TextInputStream *mp_stream;
|
tl::TextInputStream *mp_stream;
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,6 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
||||||
std::string layer_name;
|
std::string layer_name;
|
||||||
double dbu = layout.dbu ();
|
double dbu = layout.dbu ();
|
||||||
double w = 0.0;
|
double w = 0.0;
|
||||||
unsigned int mask = 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
|
|
@ -197,6 +196,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
||||||
|
|
||||||
std::vector<db::Point> points;
|
std::vector<db::Point> points;
|
||||||
|
|
||||||
|
unsigned int mask = 0;
|
||||||
if (test ("MASK")) {
|
if (test ("MASK")) {
|
||||||
mask = get_mask (get_long ());
|
mask = get_mask (get_long ());
|
||||||
}
|
}
|
||||||
|
|
@ -243,6 +243,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
||||||
|
|
||||||
std::vector<db::Point> points;
|
std::vector<db::Point> points;
|
||||||
|
|
||||||
|
unsigned int mask = 0;
|
||||||
if (test ("MASK")) {
|
if (test ("MASK")) {
|
||||||
mask = get_mask (get_long ());
|
mask = get_mask (get_long ());
|
||||||
}
|
}
|
||||||
|
|
@ -289,6 +290,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
||||||
|
|
||||||
std::vector<db::Point> points;
|
std::vector<db::Point> points;
|
||||||
|
|
||||||
|
unsigned int mask = 0;
|
||||||
if (test ("MASK")) {
|
if (test ("MASK")) {
|
||||||
mask = get_mask (get_long ());
|
mask = get_mask (get_long ());
|
||||||
}
|
}
|
||||||
|
|
@ -337,10 +339,15 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
||||||
// note: the 5.8 spec says ITERATE comes before MASK for VIA
|
// note: the 5.8 spec says ITERATE comes before MASK for VIA
|
||||||
bool iterate = test ("ITERATE");
|
bool iterate = test ("ITERATE");
|
||||||
|
|
||||||
|
unsigned int mask = 0;
|
||||||
if (test ("MASK")) {
|
if (test ("MASK")) {
|
||||||
mask = get_mask (get_long ());
|
mask = get_mask (get_long ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int mask_bottom = mask % 10;
|
||||||
|
unsigned int mask_cut = (mask / 10) % 10;
|
||||||
|
unsigned int mask_top = (mask / 100) % 10;
|
||||||
|
|
||||||
int layer_id = -1;
|
int layer_id = -1;
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, layer_name, purpose, mask);
|
std::pair <bool, unsigned int> dl = open_layer (layout, layer_name, purpose, mask);
|
||||||
if (dl.first) {
|
if (dl.first) {
|
||||||
|
|
@ -359,7 +366,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
||||||
points.push_back (db::Vector (db::DVector (x / dbu, y / dbu)));
|
points.push_back (db::Vector (db::DVector (x / dbu, y / dbu)));
|
||||||
|
|
||||||
std::string vn = get ();
|
std::string vn = get ();
|
||||||
db::Cell *vc = reader_state ()->via_cell (vn);
|
db::Cell *vc = reader_state ()->via_cell (vn, layout, mask_bottom, mask_cut, mask_top, this);
|
||||||
if (! vc) {
|
if (! vc) {
|
||||||
warn (tl::to_string (tr ("Unknown via: ")) + vn);
|
warn (tl::to_string (tr ("Unknown via: ")) + vn);
|
||||||
}
|
}
|
||||||
|
|
@ -437,21 +444,8 @@ LEFImporter::read_nondefaultrule (db::Layout & /*layout*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_desc, const std::string & /*n*/)
|
LEFImporter::read_viadef_by_rule (RuleBasedViaGenerator *vg, ViaDesc &via_desc, const std::string & /*n*/, double dbu)
|
||||||
{
|
{
|
||||||
db::Vector cutsize, cutspacing;
|
|
||||||
db::Vector be, te;
|
|
||||||
db::Vector bo, to;
|
|
||||||
db::Point offset;
|
|
||||||
int rows = 1, columns = 1;
|
|
||||||
std::string pattern;
|
|
||||||
|
|
||||||
// @@@ there is something with masks here ...
|
|
||||||
std::vector<std::pair<std::pair<std::string, unsigned int>, std::vector<db::Polygon> > > geometry;
|
|
||||||
geometry.push_back (std::pair<std::pair<std::string, unsigned int>, std::vector<db::Polygon> > ());
|
|
||||||
geometry.push_back (std::pair<std::pair<std::string, unsigned int>, std::vector<db::Polygon> > ());
|
|
||||||
geometry.push_back (std::pair<std::pair<std::string, unsigned int>, std::vector<db::Polygon> > ());
|
|
||||||
|
|
||||||
while (! test ("END")) {
|
while (! test ("END")) {
|
||||||
|
|
||||||
double x, y;
|
double x, y;
|
||||||
|
|
@ -460,7 +454,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
||||||
|
|
||||||
x = get_double ();
|
x = get_double ();
|
||||||
y = get_double ();
|
y = get_double ();
|
||||||
cutsize = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
vg->set_cutsize (db::Vector (db::DVector (x / dbu, y / dbu)));
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
|
|
@ -468,7 +462,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
||||||
|
|
||||||
x = get_double ();
|
x = get_double ();
|
||||||
y = get_double ();
|
y = get_double ();
|
||||||
cutspacing = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
vg->set_cutspacing (db::Vector (db::DVector (x / dbu, y / dbu)));
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
|
|
@ -476,7 +470,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
||||||
|
|
||||||
x = get_double ();
|
x = get_double ();
|
||||||
y = get_double ();
|
y = get_double ();
|
||||||
offset = db::Point (db::DPoint (x / layout.dbu (), y / layout.dbu ()));
|
vg->set_offset (db::Point (db::DPoint (x / dbu, y / dbu)));
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
|
|
@ -484,11 +478,11 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
||||||
|
|
||||||
x = get_double ();
|
x = get_double ();
|
||||||
y = get_double ();
|
y = get_double ();
|
||||||
be = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
vg->set_be (db::Vector (db::DVector (x / dbu, y / dbu)));
|
||||||
|
|
||||||
x = get_double ();
|
x = get_double ();
|
||||||
y = get_double ();
|
y = get_double ();
|
||||||
te = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
vg->set_te (db::Vector (db::DVector (x / dbu, y / dbu)));
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
|
|
@ -496,32 +490,39 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
||||||
|
|
||||||
x = get_double ();
|
x = get_double ();
|
||||||
y = get_double ();
|
y = get_double ();
|
||||||
bo = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
vg->set_bo (db::Vector (db::DVector (x / dbu, y / dbu)));
|
||||||
|
|
||||||
x = get_double ();
|
x = get_double ();
|
||||||
y = get_double ();
|
y = get_double ();
|
||||||
to = db::Vector (db::DVector (x / layout.dbu (), y / layout.dbu ()));
|
vg->set_to (db::Vector (db::DVector (x / dbu, y / dbu)));
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
} else if (test ("ROWCOL")) {
|
} else if (test ("ROWCOL")) {
|
||||||
|
|
||||||
rows = get_long ();
|
vg->set_rows (get_long ());
|
||||||
columns = get_long ();
|
vg->set_columns (get_long ());
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
} else if (test ("PATTERN")) {
|
} else if (test ("PATTERN")) {
|
||||||
|
|
||||||
pattern = get ();
|
vg->set_pattern (get ());
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
} else if (test ("LAYERS")) {
|
} else if (test ("LAYERS")) {
|
||||||
|
|
||||||
via_desc.m1 = geometry[0].first.first = get ();
|
std::string lb, lc, lt;
|
||||||
geometry[1].first.first = get ();
|
lb = get ();
|
||||||
via_desc.m2 = geometry[2].first.first = get ();
|
lc = get ();
|
||||||
|
lt = get ();
|
||||||
|
via_desc.m1 = lb;
|
||||||
|
via_desc.m2 = lt;
|
||||||
|
|
||||||
|
vg->set_bottom_layer (lb);
|
||||||
|
vg->set_cut_layer (lc);
|
||||||
|
vg->set_top_layer (lt);
|
||||||
|
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
|
|
@ -534,22 +535,10 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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::pair<std::string, unsigned int>, std::vector<db::Polygon> > >::const_iterator g = geometry.begin (); g != geometry.end (); ++g) {
|
|
||||||
std::pair <bool, unsigned int> dl = open_layer (layout, g->first.first, ViaGeometry, g->first.second);
|
|
||||||
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
|
void
|
||||||
LEFImporter::read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &via_desc, const std::string &n)
|
LEFImporter::read_viadef_by_geometry (GeometryBasedViaGenerator *vg, ViaDesc &via_desc, const std::string &n, double dbu)
|
||||||
{
|
{
|
||||||
// ignore resistance spec
|
// ignore resistance spec
|
||||||
if (test ("RESISTANCE")) {
|
if (test ("RESISTANCE")) {
|
||||||
|
|
@ -557,18 +546,80 @@ LEFImporter::read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &v
|
||||||
test (";");
|
test (";");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, db::Box> bboxes;
|
std::string layer_name;
|
||||||
read_geometries (layout, cell, ViaGeometry, &bboxes);
|
std::set<std::string> seen_layers;
|
||||||
|
std::vector<std::string> routing_layers;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
if (test ("LAYER")) {
|
||||||
|
|
||||||
|
layer_name = get ();
|
||||||
|
|
||||||
|
if (m_routing_layers.find (layer_name) != m_routing_layers.end () && seen_layers.find (layer_name) == seen_layers.end ()) {
|
||||||
|
seen_layers.insert (layer_name);
|
||||||
|
routing_layers.push_back (layer_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! test (";")) {
|
||||||
|
take ();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (test ("POLYGON")) {
|
||||||
|
|
||||||
|
std::vector<db::Point> points;
|
||||||
|
|
||||||
|
unsigned int mask = 0;
|
||||||
|
if (test ("MASK")) {
|
||||||
|
mask = get_mask (get_long ());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (! peek (";")) {
|
||||||
|
test ("(");
|
||||||
|
double x = get_double ();
|
||||||
|
double y = get_double ();
|
||||||
|
points.push_back (db::Point (db::DPoint (x / dbu, y / dbu)));
|
||||||
|
test (")");
|
||||||
|
}
|
||||||
|
|
||||||
|
db::Polygon p;
|
||||||
|
p.assign_hull (points.begin (), points.end ());
|
||||||
|
|
||||||
|
vg->add_polygon (layer_name, p, mask);
|
||||||
|
|
||||||
|
expect (";");
|
||||||
|
|
||||||
|
} else if (test ("RECT")) {
|
||||||
|
|
||||||
|
std::vector<db::Point> points;
|
||||||
|
|
||||||
|
unsigned int mask = 0;
|
||||||
|
if (test ("MASK")) {
|
||||||
|
mask = get_mask (get_long ());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
test ("(");
|
||||||
|
double x = get_double ();
|
||||||
|
double y = get_double ();
|
||||||
|
points.push_back (db::Point (db::DPoint (x / dbu, y / dbu)));
|
||||||
|
test (")");
|
||||||
|
}
|
||||||
|
|
||||||
|
db::Box b (points [0], points [1]);
|
||||||
|
vg->add_polygon (layer_name, db::Polygon (b), mask);
|
||||||
|
|
||||||
|
expect (";");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// stop at unknown token
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// determine m1 and m2 layers
|
// 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) {
|
if (routing_layers.size () == 2) {
|
||||||
via_desc.m1 = routing_layers[0];
|
via_desc.m1 = routing_layers[0];
|
||||||
via_desc.m2 = routing_layers[1];
|
via_desc.m2 = routing_layers[1];
|
||||||
|
|
@ -586,22 +637,20 @@ LEFImporter::read_viadef (Layout &layout)
|
||||||
{
|
{
|
||||||
std::string n = get ();
|
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];
|
ViaDesc &via_desc = m_vias[n];
|
||||||
via_desc.cell = &cell;
|
|
||||||
|
|
||||||
while (test ("DEFAULT") || test ("TOPOFSTACKONLY"))
|
while (test ("DEFAULT") || test ("TOPOFSTACKONLY"))
|
||||||
;
|
;
|
||||||
test (";");
|
test (";");
|
||||||
|
|
||||||
if (test ("VIARULE")) {
|
if (test ("VIARULE")) {
|
||||||
read_viadef_by_rule (layout, cell, via_desc, n);
|
std::auto_ptr<RuleBasedViaGenerator> vg (new RuleBasedViaGenerator ());
|
||||||
|
read_viadef_by_rule (vg.get (), via_desc, n, layout.dbu ());
|
||||||
|
reader_state ()->register_via_cell (n, vg.release ());
|
||||||
} else {
|
} else {
|
||||||
read_viadef_by_geometry (layout, cell, via_desc, n);
|
std::auto_ptr<GeometryBasedViaGenerator> vg (new GeometryBasedViaGenerator ());
|
||||||
|
read_viadef_by_geometry (vg.get (), via_desc, n, layout.dbu ());
|
||||||
|
reader_state ()->register_via_cell (n, vg.release ());
|
||||||
}
|
}
|
||||||
|
|
||||||
test ("VIA");
|
test ("VIA");
|
||||||
|
|
@ -637,6 +686,12 @@ LEFImporter::read_layer (Layout & /*layout*/)
|
||||||
}
|
}
|
||||||
expect (";");
|
expect (";");
|
||||||
|
|
||||||
|
} else if (test ("MASK")) {
|
||||||
|
|
||||||
|
unsigned int num = (unsigned int) std::max (1l, get_long ());
|
||||||
|
test (";");
|
||||||
|
m_num_masks [ln] = num;
|
||||||
|
|
||||||
} else if (test ("WIDTH")) {
|
} else if (test ("WIDTH")) {
|
||||||
|
|
||||||
w = get_double ();
|
w = get_double ();
|
||||||
|
|
@ -880,6 +935,11 @@ LEFImporter::read_macro (Layout &layout)
|
||||||
read_geometries (layout, cell, Obstructions);
|
read_geometries (layout, cell, Obstructions);
|
||||||
expect ("END");
|
expect ("END");
|
||||||
|
|
||||||
|
} else if (test ("FIXEDMASK")) {
|
||||||
|
|
||||||
|
// we do actually expect FIXEDMASK to be the case always.
|
||||||
|
expect (";");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
while (! test (";")) {
|
while (! test (";")) {
|
||||||
take ();
|
take ();
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace db
|
||||||
* @brief The LEF importer object
|
* @brief The LEF importer object
|
||||||
*/
|
*/
|
||||||
class DB_PLUGIN_PUBLIC LEFImporter
|
class DB_PLUGIN_PUBLIC LEFImporter
|
||||||
: public LEFDEFImporter
|
: public LEFDEFImporter, public LEFDEFNumberOfMasks
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
@ -107,6 +107,15 @@ public:
|
||||||
return m_cut_layers.find (layer) != m_cut_layers.end ();
|
return m_cut_layers.find (layer) != m_cut_layers.end ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the number of masks for the given layer
|
||||||
|
*/
|
||||||
|
virtual unsigned int number_of_masks (const std::string &layer) const
|
||||||
|
{
|
||||||
|
std::map<std::string, unsigned int>::const_iterator nm = m_num_masks.find (layer);
|
||||||
|
return nm != m_num_masks.end () ? nm->second : 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets a map of the vias defined in this LEF file
|
* @brief Gets a map of the vias defined in this LEF file
|
||||||
*
|
*
|
||||||
|
|
@ -129,13 +138,14 @@ private:
|
||||||
std::map<std::string, db::Box> m_macro_bboxes_by_name;
|
std::map<std::string, db::Box> m_macro_bboxes_by_name;
|
||||||
std::map<std::string, ViaDesc> m_vias;
|
std::map<std::string, ViaDesc> m_vias;
|
||||||
std::set<std::string> m_routing_layers, m_cut_layers;
|
std::set<std::string> m_routing_layers, m_cut_layers;
|
||||||
|
std::map<std::string, unsigned int> m_num_masks;
|
||||||
|
|
||||||
std::vector <db::Trans> get_iteration (db::Layout &layout);
|
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_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_nondefaultrule (Layout &layout);
|
||||||
void read_viadef (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_rule (RuleBasedViaGenerator *vg, ViaDesc &desc, const std::string &n, double dbu);
|
||||||
void read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &desc, const std::string &n);
|
void read_viadef_by_geometry (GeometryBasedViaGenerator *vg, ViaDesc &desc, const std::string &n, double dbu);
|
||||||
void read_layer (Layout &layout);
|
void read_layer (Layout &layout);
|
||||||
void read_macro (Layout &layout);
|
void read_macro (Layout &layout);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue