First implementation of masks for vias. Needs debugging.

This commit is contained in:
Matthias Koefferlein 2020-07-25 22:15:09 +02:00
parent 0d52da77ee
commit dbe5e19017
5 changed files with 670 additions and 304 deletions

View File

@ -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);
}
}
}
}
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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 ();

View File

@ -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);
};