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;
|
||||
unsigned int mask = 0;
|
||||
bool read_mask = true;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (test ("MASK")) {
|
||||
mask = get_mask (get_long ());
|
||||
if (read_mask) {
|
||||
mask = 0;
|
||||
if (test ("MASK")) {
|
||||
mask = get_mask (get_long ());
|
||||
}
|
||||
}
|
||||
|
||||
read_mask = true;
|
||||
|
||||
if (test ("RECT")) {
|
||||
|
||||
if (! test ("(")) {
|
||||
|
|
@ -567,12 +573,18 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
|||
while (peek ("(") || peek ("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 ("(")) {
|
||||
// We could have a via here: in that case we have swallowed MASK already, but
|
||||
// since we don't do anything with that, this does not hurt for now.
|
||||
// We have a via here. MASK is already read, but the value did not change.
|
||||
read_mask = false;
|
||||
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);
|
||||
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 ()))));
|
||||
} else {
|
||||
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));
|
||||
|
||||
// For the via, the masks are encoded in a three-digit number (<mask-top> <mask-cut> <mask_bottom>)
|
||||
unsigned int mask_top = (mask / 100) % 10;
|
||||
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) {
|
||||
ln = vd->second.m2;
|
||||
} else if (ln == vd->second.m2) {
|
||||
ln = vd->second.m1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
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 {
|
||||
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
|
||||
DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
|
||||
DEFImporter::read_vias (db::Layout & /*layout*/, db::Cell & /*design*/, double scale)
|
||||
{
|
||||
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;
|
||||
|
||||
// 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);
|
||||
vd.cell = &cell;
|
||||
std::auto_ptr<RuleBasedViaGenerator> rule_based_vg;
|
||||
std::auto_ptr<GeometryBasedViaGenerator> geo_based_vg;
|
||||
|
||||
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;
|
||||
|
||||
std::map<std::string, std::vector<db::Polygon> > geometry;
|
||||
std::vector<db::Polygon> *top = 0, *cut = 0, *bottom = 0;
|
||||
std::auto_ptr<LEFDEFViaGenerator> via_generator;
|
||||
std::set<std::string> seen_layers;
|
||||
std::vector<std::string> routing_layers;
|
||||
|
||||
while (test ("+")) {
|
||||
|
||||
if (test ("VIARULE")) {
|
||||
|
||||
has_via_rule = true;
|
||||
if (! rule_based_vg.get ()) {
|
||||
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||
}
|
||||
|
||||
take ();
|
||||
|
||||
} 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")) {
|
||||
|
||||
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")) {
|
||||
|
||||
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")) {
|
||||
|
||||
be = get_vector (scale);
|
||||
te = get_vector (scale);
|
||||
if (! rule_based_vg.get ()) {
|
||||
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")) {
|
||||
|
||||
bo = get_vector (scale);
|
||||
to = get_vector (scale);
|
||||
if (! rule_based_vg.get ()) {
|
||||
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")) {
|
||||
|
||||
rows = get_long ();
|
||||
columns = get_long ();
|
||||
if (! rule_based_vg.get ()) {
|
||||
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||
}
|
||||
|
||||
rule_based_vg->set_rows (get_long ());
|
||||
rule_based_vg->set_columns (get_long ());
|
||||
|
||||
} 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")) {
|
||||
|
||||
if (! rule_based_vg.get ()) {
|
||||
rule_based_vg.reset (new RuleBasedViaGenerator ());
|
||||
}
|
||||
|
||||
std::string bn = get ();
|
||||
std::string cn = get ();
|
||||
std::string tn = get ();
|
||||
|
||||
bottom = &geometry.insert (std::make_pair (bn, std::vector<db::Polygon> ())).first->second;
|
||||
cut = &geometry.insert (std::make_pair (cn, std::vector<db::Polygon> ())).first->second;
|
||||
top = &geometry.insert (std::make_pair (tn, std::vector<db::Polygon> ())).first->second;
|
||||
rule_based_vg->set_bottom_layer (bn);
|
||||
rule_based_vg->set_cut_layer (cn);
|
||||
rule_based_vg->set_top_layer (tn);
|
||||
|
||||
vd.m1 = bn;
|
||||
vd.m2 = tn;
|
||||
|
||||
} else if (test ("POLYGON")) {
|
||||
|
||||
if (! geo_based_vg.get ()) {
|
||||
geo_based_vg.reset (new GeometryBasedViaGenerator ());
|
||||
}
|
||||
|
||||
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 ("+")) {
|
||||
expect ("MASK");
|
||||
mask = get_mask (get_long ());
|
||||
}
|
||||
|
||||
std::vector<db::Polygon> &polygons = geometry.insert (std::make_pair (ln, std::vector<db::Polygon> ())).first->second;
|
||||
polygons.push_back (db::Polygon ());
|
||||
read_polygon (polygons.back (), scale);
|
||||
db::Polygon poly;
|
||||
read_polygon (poly, scale);
|
||||
geo_based_vg->add_polygon (ln, poly, mask);
|
||||
|
||||
} else if (test ("RECT")) {
|
||||
|
||||
if (! geo_based_vg.get ()) {
|
||||
geo_based_vg.reset (new GeometryBasedViaGenerator ());
|
||||
}
|
||||
|
||||
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 ("+")) {
|
||||
expect ("MASK");
|
||||
mask = get_mask (get_long ());
|
||||
}
|
||||
|
||||
std::vector<db::Polygon> &polygons = geometry.insert (std::make_pair (ln, std::vector<db::Polygon> ())).first->second;
|
||||
polygons.push_back (db::Polygon ());
|
||||
read_rect (polygons.back (), scale);
|
||||
db::Polygon poly;
|
||||
read_polygon (poly, 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 ()) {
|
||||
|
||||
// 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) {
|
||||
vd.m1 = routing_layers[0];
|
||||
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 (";");
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -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
|
||||
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 ["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 ()) {
|
||||
|
||||
|
|
@ -504,15 +713,15 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
|||
|
||||
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") {
|
||||
|
||||
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") {
|
||||
|
||||
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") {
|
||||
|
||||
|
|
@ -530,7 +739,7 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
|||
|
||||
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);
|
||||
layer_map [std::make_pair (*l, std::make_pair (Label, (unsigned int) 0))] = db::LayerProperties (layer, datatype, final_name);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -542,15 +751,30 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
|||
// "(M1,PINS): M1.NET/PINS"
|
||||
// (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::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));
|
||||
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 ()) {
|
||||
|
||||
translated_purposes.insert (i->second);
|
||||
translated_purposes.insert (std::make_pair (i->second, mask));
|
||||
|
||||
if (! purpose_str.empty ()) {
|
||||
purpose_str += "/";
|
||||
|
|
@ -558,11 +782,12 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &layout)
|
|||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -575,8 +800,8 @@ LEFDEFReaderState::read_map_file (const std::string &path, db::Layout &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) {
|
||||
map_layer_explicit (i->first.first, i->first.second, i->second, lm.map_layer (i->second).second);
|
||||
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.first, i->second, lm.map_layer (i->second).second, i->first.second.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -840,16 +1065,52 @@ LEFDEFReaderState::finish (db::Layout &layout)
|
|||
}
|
||||
|
||||
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 *
|
||||
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);
|
||||
return i != m_via_cells.end () ? i->second : 0;
|
||||
ViaKey vk (vn, mask_bottom, mask_cut, mask_top);
|
||||
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
|
||||
LEFDEFImporter::get_mask (long m)
|
||||
{
|
||||
if (m < 1 || m > 16) {
|
||||
error (tl::to_string (tr ("Invalid mask number: ")) + tl::to_string (m));
|
||||
}
|
||||
return (unsigned int) (m - 1);
|
||||
return (unsigned int) m;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1146,141 +1404,6 @@ LEFDEFImporter::next ()
|
|||
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
|
||||
LEFDEFImporter::get_orient (bool optional)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ namespace tl
|
|||
namespace db
|
||||
{
|
||||
|
||||
class LEFDEFReaderState;
|
||||
|
||||
/**
|
||||
* @brief Correct a path relative to the stream and technology
|
||||
*/
|
||||
|
|
@ -848,6 +850,86 @@ enum LayerPurpose
|
|||
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
|
||||
*
|
||||
|
|
@ -861,6 +943,11 @@ public:
|
|||
*/
|
||||
LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~LEFDEFReaderState ();
|
||||
|
||||
/**
|
||||
* @brief Reads the given map file
|
||||
*
|
||||
|
|
@ -892,14 +979,16 @@ public:
|
|||
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
|
||||
*/
|
||||
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
|
||||
|
|
@ -910,6 +999,45 @@ public:
|
|||
}
|
||||
|
||||
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> >, unsigned int> m_unassigned_layers;
|
||||
db::LayerMap m_layer_map;
|
||||
|
|
@ -917,8 +1045,9 @@ private:
|
|||
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;
|
||||
std::map<ViaKey, db::Cell *> m_via_cells;
|
||||
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);
|
||||
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
|
||||
{
|
||||
ViaDesc () : cell (0) { }
|
||||
|
||||
/**
|
||||
* @brief The cell representing the via
|
||||
*/
|
||||
db::Cell *cell;
|
||||
ViaDesc () { }
|
||||
|
||||
/**
|
||||
* @brief The names of bottom and top metal respectively
|
||||
|
|
@ -1152,17 +1276,6 @@ protected:
|
|||
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:
|
||||
tl::AbsoluteProgress *mp_progress;
|
||||
tl::TextInputStream *mp_stream;
|
||||
|
|
|
|||
|
|
@ -163,7 +163,6 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
|||
std::string layer_name;
|
||||
double dbu = layout.dbu ();
|
||||
double w = 0.0;
|
||||
unsigned int mask = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
|
|
@ -197,6 +196,7 @@ LEFImporter::read_geometries (db::Layout &layout, db::Cell &cell, LayerPurpose p
|
|||
|
||||
std::vector<db::Point> points;
|
||||
|
||||
unsigned int mask = 0;
|
||||
if (test ("MASK")) {
|
||||
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;
|
||||
|
||||
unsigned int mask = 0;
|
||||
if (test ("MASK")) {
|
||||
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;
|
||||
|
||||
unsigned int mask = 0;
|
||||
if (test ("MASK")) {
|
||||
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
|
||||
bool iterate = test ("ITERATE");
|
||||
|
||||
unsigned int mask = 0;
|
||||
if (test ("MASK")) {
|
||||
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;
|
||||
std::pair <bool, unsigned int> dl = open_layer (layout, layer_name, purpose, mask);
|
||||
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)));
|
||||
|
||||
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) {
|
||||
warn (tl::to_string (tr ("Unknown via: ")) + vn);
|
||||
}
|
||||
|
|
@ -437,21 +444,8 @@ LEFImporter::read_nondefaultrule (db::Layout & /*layout*/)
|
|||
}
|
||||
|
||||
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")) {
|
||||
|
||||
double x, y;
|
||||
|
|
@ -460,7 +454,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
|||
|
||||
x = 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 (";");
|
||||
|
||||
|
|
@ -468,7 +462,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
|||
|
||||
x = 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 (";");
|
||||
|
||||
|
|
@ -476,7 +470,7 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
|||
|
||||
x = 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 (";");
|
||||
|
||||
|
|
@ -484,11 +478,11 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
|||
|
||||
x = 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 ();
|
||||
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 (";");
|
||||
|
||||
|
|
@ -496,32 +490,39 @@ LEFImporter::read_viadef_by_rule (Layout &layout, db::Cell &cell, ViaDesc &via_d
|
|||
|
||||
x = 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 ();
|
||||
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 (";");
|
||||
|
||||
} else if (test ("ROWCOL")) {
|
||||
|
||||
rows = get_long ();
|
||||
columns = get_long ();
|
||||
vg->set_rows (get_long ());
|
||||
vg->set_columns (get_long ());
|
||||
|
||||
test (";");
|
||||
|
||||
} else if (test ("PATTERN")) {
|
||||
|
||||
pattern = get ();
|
||||
vg->set_pattern (get ());
|
||||
|
||||
test (";");
|
||||
|
||||
} else if (test ("LAYERS")) {
|
||||
|
||||
via_desc.m1 = geometry[0].first.first = get ();
|
||||
geometry[1].first.first = get ();
|
||||
via_desc.m2 = geometry[2].first.first = get ();
|
||||
std::string lb, lc, lt;
|
||||
lb = 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 (";");
|
||||
|
||||
|
|
@ -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
|
||||
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
|
||||
if (test ("RESISTANCE")) {
|
||||
|
|
@ -557,18 +546,80 @@ LEFImporter::read_viadef_by_geometry (Layout &layout, db::Cell &cell, ViaDesc &v
|
|||
test (";");
|
||||
}
|
||||
|
||||
std::map<std::string, db::Box> bboxes;
|
||||
read_geometries (layout, cell, ViaGeometry, &bboxes);
|
||||
std::string layer_name;
|
||||
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
|
||||
|
||||
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];
|
||||
|
|
@ -586,22 +637,20 @@ 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);
|
||||
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 {
|
||||
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");
|
||||
|
|
@ -637,6 +686,12 @@ LEFImporter::read_layer (Layout & /*layout*/)
|
|||
}
|
||||
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")) {
|
||||
|
||||
w = get_double ();
|
||||
|
|
@ -880,6 +935,11 @@ LEFImporter::read_macro (Layout &layout)
|
|||
read_geometries (layout, cell, Obstructions);
|
||||
expect ("END");
|
||||
|
||||
} else if (test ("FIXEDMASK")) {
|
||||
|
||||
// we do actually expect FIXEDMASK to be the case always.
|
||||
expect (";");
|
||||
|
||||
} else {
|
||||
while (! test (";")) {
|
||||
take ();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace db
|
|||
* @brief The LEF importer object
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC LEFImporter
|
||||
: public LEFDEFImporter
|
||||
: public LEFDEFImporter, public LEFDEFNumberOfMasks
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
|
@ -107,6 +107,15 @@ public:
|
|||
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
|
||||
*
|
||||
|
|
@ -129,13 +138,14 @@ private:
|
|||
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::map<std::string, unsigned int> m_num_masks;
|
||||
|
||||
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_viadef_by_rule (RuleBasedViaGenerator *vg, ViaDesc &desc, const std::string &n, double dbu);
|
||||
void read_viadef_by_geometry (GeometryBasedViaGenerator *vg, ViaDesc &desc, const std::string &n, double dbu);
|
||||
void read_layer (Layout &layout);
|
||||
void read_macro (Layout &layout);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue