diff --git a/samples/lvs/ringo.gds b/samples/lvs/ringo.gds new file mode 100644 index 000000000..fa116f14d Binary files /dev/null and b/samples/lvs/ringo.gds differ diff --git a/samples/lvs/schematic.cir b/samples/lvs/schematic.cir new file mode 100644 index 000000000..13d6d09f5 --- /dev/null +++ b/samples/lvs/schematic.cir @@ -0,0 +1,27 @@ + +.SUBCKT RINGO VSS VDD FB ENABLE OUT +X$1 VDD 1 VSS VDD FB ENABLE VSS ND2X1 +X$2 VDD 2 VSS VDD 1 VSS INVX1 +X$3 VDD 3 VSS VDD 2 VSS INVX1 +X$4 VDD 4 VSS VDD 3 VSS INVX1 +X$5 VDD 5 VSS VDD 4 VSS INVX1 +X$6 VDD 6 VSS VDD 5 VSS INVX1 +X$7 VDD 7 VSS VDD 6 VSS INVX1 +X$8 VDD 8 VSS VDD 7 VSS INVX1 +X$9 VDD 9 VSS VDD 8 VSS INVX1 +X$10 VDD 10 VSS VDD 9 VSS INVX1 +X$11 VDD FB VSS VDD 10 VSS INVX1 +X$12 VDD OUT VSS VDD FB VSS INVX1 +.ENDS RINGO + +.SUBCKT ND2X1 VDD OUT VSS NWELL B A BULK +M$1 OUT A VDD NWELL PMOS L=0.25U W=1.5U +M$2 VDD B OUT NWELL PMOS L=0.25U W=1.5U +M$3 VSS A 1 BULK NMOS L=0.25U W=0.95U +M$4 1 B OUT BULK NMOS L=0.25U W=0.95U +.ENDS ND2X1 + +.SUBCKT INVX1 VDD OUT VSS NWELL IN BULK +M$1 VDD IN OUT NWELL PMOS L=0.25U W=1.5U +M$2 VSS IN OUT BULK NMOS L=0.25U W=0.95U +.ENDS INVX1 diff --git a/samples/lvs/tech.lyp b/samples/lvs/tech.lyp new file mode 100644 index 000000000..2b5b553ca --- /dev/null +++ b/samples/lvs/tech.lyp @@ -0,0 +1,303 @@ + + + + #c0c0c0 + #c0c0c0 + 0 + 0 + I9 + I2 + true + true + false + 2 + false + false + 0 + 1 - NWELL + 1/0@1 + + + #c0c0c0 + #c0c0c0 + 48 + 48 + C0 + I4 + true + true + false + 1 + false + false + 0 + 3 - PPLUS + 3/0@1 + + + #c0c0c0 + #c0c0c0 + 48 + 48 + C1 + I4 + true + true + false + 1 + false + false + 0 + 4 - NPLUS + 4/0@1 + + + #ff0000 + #ff9d9d + -64 + -64 + I3 + I2 + true + true + false + 2 + false + false + 0 + 2 - DIFF + 2/0@1 + + + #91ff00 + #91ff00 + -48 + -48 + I8 + + true + true + false + 2 + false + false + 0 + 5 - POLY + 5/0@1 + + + #008000 + #808000 + 0 + 0 + I3 + I4 + true + true + false + 1 + false + false + 0 + 6 - THICKOX + THICKOX 6/0@1 + + + #805000 + #805000 + 0 + 0 + I3 + I4 + true + true + false + 1 + false + false + 0 + 7 - POLYRES + '7 - SALBL' 7/0@1 + + + #ff00ff + #ffffff + 0 + 0 + I0 + + true + true + false + 2 + false + true + 0 + 8 - CONTACT + 8/0@1 + + + #8000ff + #9580ff + 0 + 0 + I4 + + true + true + false + 2 + false + false + 0 + 9 - METAL1 + 9/0@1 + + + #e872ff + #e872ff + -48 + -48 + I1 + + true + true + false + 2 + false + true + 0 + 10 - VIA + 10/0@1 + + + #0000ff + #8086ff + 0 + 0 + I8 + + true + true + false + 2 + false + false + 0 + 11 - METAL2 + 11/0@1 + + + #808080 + #c0c0c0 + 0 + 128 + I43 + + true + true + true + 1 + false + false + 0 + 12 - PAD + 12/0@1 + + + #c0c0c0 + #c0c0c0 + 0 + 0 + I1 + I4 + true + true + false + 1 + false + false + 0 + 13 - BORDER + 13/0@1 + + + #606060 + #606060 + 0 + 0 + I1 + I2 + true + true + false + 1 + false + true + 0 + 1000 - MARKING 1 + 1000/0@1 + + + #000000 + #000000 + 0 + 0 + I1 + I2 + true + true + false + 1 + false + false + 0 + 1001 - MARKING 2 + 1001/0@1 + + + + + ................ + ...*............ + ...*............ + ...*............ + *******......... + ...*............ + ...*............ + ...*............ + ................ + ...........*.... + ...........*.... + ...........*.... + ........*******. + ...........*.... + ...........*.... + ...........*.... + + 1 + custom plus + + + + ................ + ................ + ................ + ................ + *******......... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ........*******. + ................ + ................ + ................ + + 2 + + + diff --git a/scripts/extract_doc.rb b/scripts/extract_doc.rb index 8d8789958..9e01f759c 100755 --- a/scripts/extract_doc.rb +++ b/scripts/extract_doc.rb @@ -2,15 +2,21 @@ $script_call = $0 + " " + ARGV.join(" ") -$key="%DRC%" -$infile="src/drc/drc/built-in-macros/drc.lym" -$loc = "about/drc_ref" +$indir="src/drc/drc/built-in-macros" +$loc = "about" $outfiles="src/lay/lay/doc" -$title="DRC Reference" -def create_ref(s) - if s =~ /(.*)#(.*)/ - "#{s}" +def create_ref(mod, s) + if s =~ /(.*)::(.*)#(.*)/ + "#{s}" + elsif s =~ /(.*)::(.*)/ + "#{s}" + elsif s =~ /(.*)#(.*)/ + if $2 != "" + "#{s}" + else + "#{$1}" + end else "#{s}" end @@ -20,11 +26,11 @@ def create_class_doc_ref(s) "#{s}" end -def escape(s) +def escape(mod, s) s.gsub("&", "&"). gsub("<", "<"). gsub(">", ">"). - gsub(/\\([\w#]+)/) { create_ref($1) }. + gsub(/\\([\w:#]+)/) { create_ref(mod, $1) }. gsub(/RBA::([\w#]+)/) { create_class_doc_ref($1) } end @@ -38,12 +44,14 @@ class DocItem attr_accessor :synopsis attr_accessor :name attr_accessor :doc + attr_accessor :mod - def initialize(block) + def initialize(mod, block) @paragraphs = [] para = nil self.synopsis = [] + self.mod = mod in_code = false block.each do |b| @@ -91,7 +99,7 @@ class DocItem i > 0 && doc += "

\n" p.each do |pp| - doc += escape(pp). + doc += escape(self.mod, pp). gsub(/\\@/, "&at;"). gsub(/\s*@code\s*/, "

").
               gsub(/\s*@\/code\s*/, "
"). @@ -113,13 +121,13 @@ end class Scope < DocItem - def initialize(block) - super(block) + def initialize(mod, block) + super(mod, block) @items = {} end - def add_doc_item(block) - item = DocItem::new(block) + def add_doc_item(mod, block) + item = DocItem::new(mod, block) @items[item.name] = item end @@ -137,8 +145,8 @@ class Scope < DocItem HEAD doc += "\n" - doc += "" + escape(self.brief) + "\n" - doc += "\n" + doc += "" + escape(self.mod, self.brief) + "\n" + doc += "\n" doc += super_produce_doc @@ -151,14 +159,14 @@ HEAD item.name || raise("Missing @name for item #{item_key}") item.brief || raise("Missing @brief for item #{item_key}") - doc += "

\"" + escape(item.name) + "\" - " + escape(item.brief) + "

\n" - doc += "\n" - doc += "" + doc += "

\"" + escape(self.mod, item.name) + "\" - " + escape(self.mod, item.brief) + "

\n" + doc += "\n" + doc += "
" if ! item.synopsis.empty? doc += "

Usage:

\n" doc += "
    \n" item.synopsis.each do |s| - doc += "
  • " + escape(s) + "
  • \n" + doc += "
  • " + escape(self.mod, s) + "
  • \n" end doc += "
\n" end @@ -177,17 +185,22 @@ end class Collector + def initialize(mod, title) + @mod = mod + @title = title + end + def add_block(block) if block.find { |l| l =~ /^@scope/ } # is a scope block @scopes ||= {} - @current_scope = Scope::new(block) + @current_scope = Scope::new(@mod, block) @scopes[@current_scope.name] = @current_scope else - @current_scope && @current_scope.add_doc_item(block) + @current_scope && @current_scope.add_doc_item(@mod, block) end end @@ -196,7 +209,7 @@ class Collector @scopes.keys.sort.each do |k| suffix = k.downcase - outfile = $outfiles + "/" + $loc + "_" + suffix + ".xml" + outfile = $outfiles + "/" + $loc + "/" + @mod + "_ref_" + suffix + ".xml" File.open(outfile, "w") do |file| file.write(@scopes[k].produce_doc) puts "---> #{outfile} written." @@ -207,7 +220,7 @@ class Collector def produce_index - outfile = $outfiles + "/" + $loc + ".xml" + outfile = $outfiles + "/" + $loc + "/" + @mod + "_ref.xml" File.open(outfile, "w") do |file| doc = <\n" + doc += "#{escape(@mod, @title)}\n" + doc += "\n" doc += "\n" @scopes.keys.sort.each do |k| suffix = k.downcase - doc += "\n" + doc += "\n" end doc += "\n" @@ -244,36 +257,68 @@ HEAD end -collector = Collector::new +collectors = { + "DRC" => Collector::new("drc", "DRC Reference"), + "LVS" => Collector::new("lvs", "LVS Reference") +} -File.open($infile, "r") do |file| +Dir.entries($indir).each do |p| - block = nil - line = 0 + if p !~ /\.rb$/ + next + end - file.each_line do |l| + infile = File.join($indir, p) + puts "Extracting doc from #{infile} .." - line += 1 + File.open(infile, "r") do |file| - begin - l = unescape(l) - if l =~ /^\s*#\s*#{$key}/ - block = [] - elsif l =~ /^\s*#\s*(.*)\s*$/ - block && block.push($1) - elsif l =~ /^\s*$/ - block && collector.add_block(block) - block = nil + block = [] + collector = nil + line = 0 + + file.each_line do |l| + + line += 1 + + begin + + l = unescape(l) + + if ! collector + collectors.each do |k,c| + if l =~ /^\s*#\s*%#{k}%/ + collector = c + l = nil + block = [] + break + end + end + end + + if l + if l =~ /^\s*#\s*(.*)\s*$/ + collector && block.push($1) + elsif l =~ /^\s*$/ + collector && collector.add_block(block) + collector = nil + end + end + + rescue => ex + puts "ERROR in line #{line}:\n" + ex.to_s + puts ex.backtrace # @@@ + exit 1 end - rescue => ex - puts "ERROR in line #{line}:\n" + ex.to_s - exit 1 + end end end -collector.produce_doc -collector.produce_index +collectors.each do |k,collector| + collector.produce_doc + collector.produce_index +end diff --git a/src/ant/ant/RulerConfigPage4.ui b/src/ant/ant/RulerConfigPage4.ui index 44bd546f2..9e3f13904 100644 --- a/src/ant/ant/RulerConfigPage4.ui +++ b/src/ant/ant/RulerConfigPage4.ui @@ -89,7 +89,7 @@ ... - + :/up.png:/up.png @@ -103,7 +103,7 @@ ... - + :/add.png:/add.png @@ -117,7 +117,7 @@ ... - + :/del.png:/del.png @@ -131,7 +131,7 @@ ... - + :/down.png:/down.png @@ -866,7 +866,7 @@ t_snap_cbx - + diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 1556c253a..770575fd7 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -176,7 +176,14 @@ SOURCES = \ dbNetlistCompare.cc \ dbNetlistReader.cc \ dbNetlistSpiceReader.cc \ - gsiDeclDbNetlistCompare.cc + gsiDeclDbNetlistCompare.cc \ + dbNetlistCrossReference.cc \ + dbLayoutVsSchematicWriter.cc \ + dbLayoutVsSchematicReader.cc \ + dbLayoutVsSchematicFormatDefs.cc \ + dbLayoutVsSchematic.cc \ + gsiDeclDbNetlistCrossReference.cc \ + gsiDeclDbLayoutVsSchematic.cc HEADERS = \ dbArray.h \ @@ -317,7 +324,12 @@ HEADERS = \ gsiDeclDbHelpers.h \ dbNetlistCompare.h \ dbNetlistReader.h \ - dbNetlistSpiceReader.h + dbNetlistSpiceReader.h \ + dbNetlistCrossReference.h \ + dbLayoutVsSchematicWriter.h \ + dbLayoutVsSchematicReader.h \ + dbLayoutVsSchematicFormatDefs.h \ + dbLayoutVsSchematic.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbCellMapping.cc b/src/db/db/dbCellMapping.cc index 7d29d5d13..0b10257b4 100644 --- a/src/db/db/dbCellMapping.cc +++ b/src/db/db/dbCellMapping.cc @@ -295,7 +295,7 @@ CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type } std::vector -CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells) +CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells) { std::vector new_cells; std::vector new_cells_b; @@ -305,7 +305,9 @@ CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type / called_b.insert (cell_index_b); for (std::set::const_iterator b = called_b.begin (); b != called_b.end (); ++b) { - if (m_b2a_mapping.find (*b) == m_b2a_mapping.end () && (! exclude_cells || exclude_cells->find (*b) == exclude_cells->end ())) { + if (m_b2a_mapping.find (*b) == m_b2a_mapping.end () + && (! exclude_cells || exclude_cells->find (*b) == exclude_cells->end ()) + && (! include_cells || include_cells->find (*b) != include_cells->end ())) { db::cell_index_type new_cell = layout_a.add_cell (layout_b.cell_name (*b)); new_cells.push_back (new_cell); new_cells_b.push_back (*b); diff --git a/src/db/db/dbCellMapping.h b/src/db/db/dbCellMapping.h index 63740b1ca..858028659 100644 --- a/src/db/db/dbCellMapping.h +++ b/src/db/db/dbCellMapping.h @@ -190,9 +190,12 @@ public: * * If given, "exclude_cells" can specify a list of cells not to map. * + * If given, "include_cells" can specify a list of cells which are included in the + * cell tree to create. Cells not in the "include_cells" list are ignored. + * * The returned vector lists the new cells. */ - std::vector create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0); + std::vector create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0); private: void extract_unique (std::map >::const_iterator cand, diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index 2b5b6a09d..dd3c6dc03 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -22,6 +22,9 @@ #include "dbCircuit.h" #include "dbNetlist.h" +#include "dbLayout.h" + +#include namespace db { @@ -30,7 +33,7 @@ namespace db // Circuit class implementation Circuit::Circuit () - : m_cell_index (0), mp_netlist (0), + : m_dont_purge (false), m_cell_index (0), mp_netlist (0), m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices), m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets), @@ -44,8 +47,25 @@ Circuit::Circuit () m_subcircuits.changed ().add (this, &Circuit::subcircuits_changed); } +Circuit::Circuit (const db::Layout &layout, db::cell_index_type ci) + : m_name (layout.cell_name (ci)), m_dont_purge (false), m_cell_index (ci), mp_netlist (0), + m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices), + m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), + m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets), + m_device_by_name (this, &Circuit::begin_devices, &Circuit::end_devices), + m_subcircuit_by_name (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), + m_net_by_name (this, &Circuit::begin_nets, &Circuit::end_nets), + m_index (0) +{ + m_devices.changed ().add (this, &Circuit::devices_changed); + m_nets.changed ().add (this, &Circuit::nets_changed); + m_subcircuits.changed ().add (this, &Circuit::subcircuits_changed); + + set_boundary (db::DPolygon (db::CplxTrans (layout.dbu ()) * layout.cell (ci).bbox ())); +} + Circuit::Circuit (const Circuit &other) - : gsi::ObjectBase (other), tl::Object (other), m_cell_index (0), mp_netlist (0), + : gsi::ObjectBase (other), tl::Object (other), m_dont_purge (false), m_cell_index (0), mp_netlist (0), m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices), m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets), @@ -80,6 +100,8 @@ Circuit &Circuit::operator= (const Circuit &other) clear (); m_name = other.m_name; + m_boundary = other.m_boundary; + m_dont_purge = other.m_dont_purge; m_cell_index = other.m_cell_index; m_pins = other.m_pins; @@ -142,6 +164,13 @@ const Pin *Circuit::pin_by_id (size_t id) const } } +void Circuit::rename_pin (size_t id, const std::string &name) +{ + if (id < m_pins.size ()) { + m_pins [id].set_name (name); + } +} + const Pin *Circuit::pin_by_name (const std::string &name) const { for (Circuit::const_pin_iterator p = begin_pins (); p != end_pins (); ++p) { @@ -181,6 +210,7 @@ void Circuit::clear () m_devices.clear (); m_nets.clear (); m_subcircuits.clear (); + m_boundary.clear (); } void Circuit::set_name (const std::string &name) @@ -191,6 +221,16 @@ void Circuit::set_name (const std::string &name) } } +void Circuit::set_boundary (const db::DPolygon &boundary) +{ + m_boundary = boundary; +} + +void Circuit::set_dont_purge (bool dp) +{ + m_dont_purge = dp; +} + void Circuit::set_cell_index (const db::cell_index_type ci) { m_cell_index = ci; @@ -358,6 +398,7 @@ void Circuit::flatten_subcircuit (SubCircuit *subcircuit) if (! d->name ().empty ()) { device->set_name (subcircuit->expanded_name () + "." + d->name ()); } + device->set_trans (subcircuit->trans () * device->trans ()); add_device (device); const std::vector &td = d->device_class ()->terminal_definitions (); @@ -382,6 +423,7 @@ void Circuit::flatten_subcircuit (SubCircuit *subcircuit) if (! new_subcircuit->name ().empty ()) { new_subcircuit->set_name (subcircuit->expanded_name () + "." + new_subcircuit->name ()); } + new_subcircuit->set_trans (subcircuit->trans () * new_subcircuit->trans ()); add_subcircuit (new_subcircuit); const db::Circuit *cr = sc->circuit_ref (); @@ -422,11 +464,7 @@ void Circuit::translate_device_classes (const std::map &map) { for (device_iterator i = m_devices.begin (); i != m_devices.end (); ++i) { - if (i->device_abstract ()) { - std::map::const_iterator m = map.find (i->device_abstract ()); - tl_assert (m != map.end ()); - i->set_device_abstract (m->second); - } + i->translate_device_abstracts (map); } } @@ -438,6 +476,35 @@ void Circuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter) m_pin_refs [pin_id] = iter; } +void Circuit::blank () +{ + tl_assert (netlist () != 0); + + std::set cs; + for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) { + cs.insert (i->circuit_ref ()); + } + + // weak pointers are good because deleting a subcircuit might delete others ahead in + // this list: + std::list > called_circuits; + for (std::set::const_iterator c = cs.begin (); c != cs.end (); ++c) { + called_circuits.push_back (*c); + } + + m_nets.clear (); + m_subcircuits.clear (); + m_devices.clear (); + + for (std::list >::iterator c = called_circuits.begin (); c != called_circuits.end (); ++c) { + if (c->get () && ! (*c)->has_refs ()) { + netlist ()->purge_circuit (c->get ()); + } + } + + set_dont_purge (true); +} + const Net *Circuit::net_for_pin (size_t pin_id) const { if (pin_id < m_pin_refs.size ()) { @@ -534,6 +601,7 @@ bool Circuit::combine_parallel_devices (const db::DeviceClass &cls) for (size_t i = 0; i < cl.size () - 1; ++i) { for (size_t j = i + 1; j < cl.size (); ) { if (cls.combine_devices (cl [i], cl [j])) { + cl [i]->join_device (cl [j]); check_device_before_remove (this, cl [j]); // sanity check delete cl [j]; cl.erase (cl.begin () + j); @@ -623,6 +691,7 @@ bool Circuit::combine_serial_devices(const db::DeviceClass &cls) // found a combination candidate if (cls.combine_devices (dd.first, dd.second)) { + dd.first->join_device (dd.second); check_device_before_remove (this, dd.second); // sanity check delete dd.second; any = true; diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index 042a3e144..3092fb6cd 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -30,6 +30,7 @@ #include "dbPin.h" #include "dbSubCircuit.h" #include "dbNetlistUtils.h" +#include "dbPolygon.h" #include "tlObject.h" #include "tlObjectCollection.h" @@ -40,6 +41,43 @@ namespace db { class Netlist; +class Layout; + +/** + * @brief An iterator wrapper for the child and parent circuit iterator + */ +template +struct DB_PUBLIC_TEMPLATE dereferencing_iterator + : public Iter +{ +public: + typedef Value *pointer; + typedef Value &reference; + typedef typename Iter::difference_type difference_type; + + dereferencing_iterator () { } + dereferencing_iterator (const dereferencing_iterator &d) : Iter (d) { } + dereferencing_iterator (const Iter &d) : Iter (d) { } + dereferencing_iterator &operator= (const dereferencing_iterator &d) + { + Iter::operator= (d); + return *this; + } + + dereferencing_iterator operator+ (difference_type offset) const + { + return dereferencing_iterator (Iter::operator+ (offset)); + } + + dereferencing_iterator &operator+= (difference_type offset) + { + Iter::operator+= (offset); + return *this; + } + + pointer operator-> () const { return Iter::operator* (); } + reference operator* () const { return *Iter::operator* (); } +}; /** * @brief A circuit @@ -65,10 +103,10 @@ public: typedef subcircuit_list::iterator subcircuit_iterator; typedef tl::weak_collection::const_iterator const_refs_iterator; typedef tl::weak_collection::iterator refs_iterator; - typedef tl::vector::const_iterator child_circuit_iterator; - typedef tl::vector::const_iterator const_child_circuit_iterator; - typedef tl::vector::const_iterator parent_circuit_iterator; - typedef tl::vector::const_iterator const_parent_circuit_iterator; + typedef dereferencing_iterator::const_iterator, Circuit> child_circuit_iterator; + typedef dereferencing_iterator::const_iterator, const Circuit> const_child_circuit_iterator; + typedef dereferencing_iterator::const_iterator, Circuit> parent_circuit_iterator; + typedef dereferencing_iterator::const_iterator, const Circuit> const_parent_circuit_iterator; /** * @brief Constructor @@ -77,6 +115,13 @@ public: */ Circuit (); + /** + * @brief Constructor + * + * Creates a circuit corresponding to a layout cell + */ + Circuit (const db::Layout &layout, db::cell_index_type ci); + /** * @brief Copy constructor */ @@ -128,6 +173,33 @@ public: return m_name; } + /** + * @brief Sets the boundary + */ + void set_boundary (const db::DPolygon &boundary); + + /** + * @brief Gets the boundary + */ + const db::DPolygon &boundary () const + { + return m_boundary; + } + + /** + * @brief Sets or resets the "don't purge" flag + * This flag will prevent "purge" from deleting this circuit. It is set by "blank". + */ + void set_dont_purge (bool dp); + + /** + * @brief Gets or resets the "don't purge" flag + */ + bool dont_purge () const + { + return m_dont_purge; + } + /** * @brief The index of the circuit in the netlist * CAUTION: this attribute is used for internal purposes and may not be valid always. @@ -179,6 +251,23 @@ public: return m_refs.begin (); } + /** + * @brief Gets the references to this circuit (end, const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + const_refs_iterator end_refs () const + { + return m_refs.end (); + } + + /** + * @brief Returns a value indicating whether the circuit has references + */ + bool has_refs () const + { + return begin_refs () != end_refs (); + } + /** * @brief Gets the child circuits iterator (begin) * The child circuits are the circuits referenced by all subcircuits @@ -225,15 +314,6 @@ public: */ const_parent_circuit_iterator end_parents () const; - /** - * @brief Gets the references to this circuit (end, const version) - * This iterator will deliver all subcircuits referencing this circuit - */ - const_refs_iterator end_refs () const - { - return m_refs.end (); - } - /** * @brief Clears the pins */ @@ -309,6 +389,14 @@ public: */ void remove_net (Net *net); + /** + * @brief Gets the number of nets + */ + size_t net_count () const + { + return m_nets.size (); + } + /** * @brief Begin iterator for the nets of the circuit (non-const version) */ @@ -393,6 +481,14 @@ public: */ void remove_device (Device *device); + /** + * @brief Gets the number of devices + */ + size_t device_count () const + { + return m_devices.size (); + } + /** * @brief Gets the device from a given ID (const version) * @@ -477,6 +573,14 @@ public: */ void remove_subcircuit (SubCircuit *subcircuit); + /** + * @brief Gets the number of subcircuits + */ + size_t subcircuit_count () const + { + return m_subcircuits.size (); + } + /** * @brief Gets the subcircuit from a given ID (const version) * @@ -574,6 +678,11 @@ public: */ void connect_pin (size_t pin_id, Net *net); + /** + * @brief Renames the pin with the given ID + */ + void rename_pin (size_t pin_id, const std::string &name); + /** * @brief Purge unused nets * @@ -598,6 +707,16 @@ public: */ void flatten_subcircuit (SubCircuit *subcircuit); + /** + * @brief Blanks out the circuit + * + * This will remove all innards of the circuit (nets, devices, subcircuits) + * and circuits which will itself are not longer be called after this. + * This operation will eventually leave a blackbox model of the circuit + * containing only pins. + */ + void blank (); + private: friend class Netlist; friend class Net; @@ -605,6 +724,8 @@ private: friend class Device; std::string m_name; + db::DPolygon m_boundary; + bool m_dont_purge; db::cell_index_type m_cell_index; net_list m_nets; pin_list m_pins; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 1d2cd5673..149555c20 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -23,7 +23,6 @@ #include "dbDeepRegion.h" #include "dbDeepShapeStore.h" -#include "dbEmptyRegion.h" #include "dbEmptyEdgePairs.h" #include "dbRegion.h" #include "dbRegionUtils.h" @@ -462,10 +461,13 @@ DeepRegion::and_with (const Region &other) const { const DeepRegion *other_deep = dynamic_cast (other.delegate ()); - if (empty () || other.empty ()) { + if (empty ()) { - // Nothing to do - return new EmptyRegion (); + return clone (); + + } else if (other.empty ()) { + + return other.delegate ()->clone (); } else if (! other_deep) { @@ -483,14 +485,8 @@ DeepRegion::not_with (const Region &other) const { const DeepRegion *other_deep = dynamic_cast (other.delegate ()); - if (empty ()) { + if (empty () || other.empty ()) { - // Nothing to do - return new EmptyRegion (); - - } else if (other.empty ()) { - - // Nothing to do return clone (); } else if (! other_deep) { @@ -1231,6 +1227,12 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const RegionDelegate * DeepRegion::sized (coord_type d, unsigned int mode) const { + if (empty ()) { + // Nothing to do - NOTE: don't return EmptyRegion because we want to + // maintain "deepness" + return clone (); + } + ensure_merged_polygons_valid (); db::Layout &layout = m_merged_polygons.layout (); @@ -1299,6 +1301,12 @@ struct XYAnisotropyAndMagnificationReducer RegionDelegate * DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const { + if (empty ()) { + // Nothing to do - NOTE: don't return EmptyRegion because we want to + // maintain "deepness" + return clone (); + } + if (dx == dy) { return sized (dx, mode); } diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 1e0c1e96b..7fa787440 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -222,19 +222,11 @@ DeepLayer::check_dss () const struct DeepShapeStore::LayoutHolder { LayoutHolder (const db::ICplxTrans &trans) - : refs (0), layout (false), builder (&layout, trans), m_empty_layer (std::numeric_limits::max ()) + : refs (0), layout (false), builder (&layout, trans) { // .. nothing yet .. } - unsigned int empty_layer () const - { - if (m_empty_layer == std::numeric_limits::max ()) { - const_cast (this)->make_empty_layer (); - } - return m_empty_layer; - } - void add_layer_ref (unsigned int layer) { layer_refs [layer] += 1; @@ -255,15 +247,6 @@ struct DeepShapeStore::LayoutHolder db::Layout layout; db::HierarchyBuilder builder; std::map layer_refs; - -private: - unsigned int m_empty_layer; - - void make_empty_layer () - { - m_empty_layer = layout.insert_layer (); - layer_refs [m_empty_layer] += 1; // the empty layer is not deleted - } }; // ---------------------------------------------------------------------------------- @@ -514,6 +497,18 @@ void DeepShapeStore::make_layout (unsigned int layout_index, const db::Recursive m_layout_map[std::make_pair (si, trans)] = layout_index; } +static unsigned int init_layer (db::Layout &layout, const db::RecursiveShapeIterator &si) +{ + unsigned int layer_index = layout.insert_layer (); + + if (si.layout () && si.layer () < si.layout ()->layers ()) { + // try to preserve the layer properties + layout.set_properties (layer_index, si.layout ()->get_properties (si.layer ())); + } + + return layer_index; +} + DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count, const db::ICplxTrans &trans) { if (max_area_ratio == 0.0) { @@ -528,7 +523,7 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator db::Layout &layout = m_layouts[layout_index]->layout; db::HierarchyBuilder &builder = m_layouts[layout_index]->builder; - unsigned int layer_index = layout.insert_layer (); + unsigned int layer_index = init_layer (layout, si); builder.set_target_layer (layer_index); // The chain of operators for producing clipped and reduced polygon references @@ -540,6 +535,7 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator try { tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy"))); + db::LayoutLocker ll (&layout, true /*no update*/); builder.set_shape_receiver (&clip); db::RecursiveShapeIterator (si).push (& builder); @@ -553,17 +549,6 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator return DeepLayer (this, layout_index, layer_index); } -DeepLayer DeepShapeStore::empty_layer (unsigned int layout_index) const -{ - return DeepLayer (const_cast (this), layout_index, m_layouts[layout_index]->empty_layer ()); -} - -DeepLayer DeepShapeStore::empty_layer () const -{ - require_singular (); - return empty_layer (0); -} - DeepLayer DeepShapeStore::create_custom_layer (const db::RecursiveShapeIterator &si, HierarchyBuilderShapeReceiver *pipe, const db::ICplxTrans &trans) { unsigned int layout_index = layout_for_iter (si, trans); @@ -571,13 +556,14 @@ DeepLayer DeepShapeStore::create_custom_layer (const db::RecursiveShapeIterator db::Layout &layout = m_layouts[layout_index]->layout; db::HierarchyBuilder &builder = m_layouts[layout_index]->builder; - unsigned int layer_index = layout.insert_layer (); + unsigned int layer_index = init_layer (layout, si); builder.set_target_layer (layer_index); // Build the working hierarchy from the recursive shape iterator try { tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy"))); + db::LayoutLocker ll (&layout, true /*no update*/); builder.set_shape_receiver (pipe); db::RecursiveShapeIterator (si).push (& builder); @@ -624,7 +610,7 @@ DeepLayer DeepShapeStore::create_edge_layer (const db::RecursiveShapeIterator &s db::Layout &layout = m_layouts[layout_index]->layout; db::HierarchyBuilder &builder = m_layouts[layout_index]->builder; - unsigned int layer_index = layout.insert_layer (); + unsigned int layer_index = init_layer (layout, si); builder.set_target_layer (layer_index); // The chain of operators for producing edges @@ -634,6 +620,7 @@ DeepLayer DeepShapeStore::create_edge_layer (const db::RecursiveShapeIterator &s try { tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy"))); + db::LayoutLocker ll (&layout, true /*no update*/); builder.set_shape_receiver (&refs); db::RecursiveShapeIterator (si).push (& builder); @@ -654,7 +641,7 @@ DeepLayer DeepShapeStore::create_edge_pair_layer (const db::RecursiveShapeIterat db::Layout &layout = m_layouts[layout_index]->layout; db::HierarchyBuilder &builder = m_layouts[layout_index]->builder; - unsigned int layer_index = layout.insert_layer (); + unsigned int layer_index = init_layer (layout, si); builder.set_target_layer (layer_index); // The chain of operators for producing the edge pairs @@ -664,6 +651,7 @@ DeepLayer DeepShapeStore::create_edge_pair_layer (const db::RecursiveShapeIterat try { tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy"))); + db::LayoutLocker ll (&layout, true /*no update*/); builder.set_shape_receiver (&refs); db::RecursiveShapeIterator (si).push (& builder); @@ -697,7 +685,7 @@ DeepShapeStore::issue_variants (unsigned int layout_index, const std::map *excluded_cells) +DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout *into_layout, db::cell_index_type into_cell, const std::set *excluded_cells, const std::set *included_cells) { const db::Layout *source_layout = &m_layouts [layout_index]->layout; if (source_layout->begin_top_down () == source_layout->end_top_cells ()) { @@ -758,7 +746,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout // Add new cells for the variants and (possible) devices which are cells added during the device // extraction process - cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top, excluded_cells); + cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells); } diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 2246e8a18..79c5c7495 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -343,19 +343,6 @@ public: */ DeepLayer create_copy (const DeepLayer &source, HierarchyBuilderShapeReceiver *pipe); - /** - * @brief Gets the empty working layer - * - * This method will deliver an empty layer for the given layout index. CAUTION: don't modify this layer as it may - * be reused. - */ - DeepLayer empty_layer (unsigned int layout_index) const; - - /** - * @brief Gets the empty working layer for the singular layout - */ - DeepLayer empty_layer () const; - /** * @brief Inserts the deep layer's shapes into some target layout */ @@ -375,9 +362,11 @@ public: * "layout_index" is the layout to return to it's original. "into_layout" is the original layout, "into_cell" * the original cell. * - * "excluded_cells" - if not 0 - will exclude the given cells (and flatten them). + * "excluded_cells" - if not 0 - will exclude the given cells + * + * "included_cells" - if not 0 - will only include the given cells in the cell mapping */ - const db::CellMapping &cell_mapping_to_original (unsigned int layout_index, db::Layout *into_layout, db::cell_index_type into_cell, const std::set *excluded_cells = 0); + const db::CellMapping &cell_mapping_to_original (unsigned int layout_index, db::Layout *into_layout, db::cell_index_type into_cell, const std::set *excluded_cells = 0, const std::set *included_cells = 0); /** * @brief Create cell variants from the given variant collector diff --git a/src/db/db/dbDevice.cc b/src/db/db/dbDevice.cc index e803cec08..ca950ad2e 100644 --- a/src/db/db/dbDevice.cc +++ b/src/db/db/dbDevice.cc @@ -67,7 +67,7 @@ Device &Device::operator= (const Device &other) { if (this != &other) { m_name = other.m_name; - m_position = other.m_position; + m_trans = other.m_trans; m_parameters = other.m_parameters; mp_device_class = other.mp_device_class; mp_device_abstract = other.mp_device_abstract; @@ -97,9 +97,9 @@ void Device::set_name (const std::string &n) } } -void Device::set_position (const db::DPoint &pt) +void Device::set_trans (const db::DCplxTrans &tr) { - m_position = pt; + m_trans = tr; } void Device::set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter) @@ -187,4 +187,103 @@ void Device::set_parameter_value (const std::string &name, double v) } } +void Device::add_others_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal) +{ + std::vector &terminals = m_reconnected_terminals [this_terminal]; + + std::map >::const_iterator ot = other->m_reconnected_terminals.find (other_terminal); + if (ot == other->m_reconnected_terminals.end ()) { + + terminals.push_back (DeviceReconnectedTerminal (other_abstracts ().size () + 1, other_terminal)); + + } else { + + size_t n = terminals.size (); + terminals.insert (terminals.end (), ot->second.begin (), ot->second.end ()); + + while (n < terminals.size ()) { + terminals [n].device_index += other_abstracts ().size () + 1; + ++n; + } + + } +} + +void Device::init_terminal_routes () +{ + if (! device_class ()) { + return; + } + + size_t n = device_class ()->terminal_definitions ().size (); + for (size_t i = 0; i < n; ++i) { + m_reconnected_terminals [i].push_back (DeviceReconnectedTerminal (0, i)); + } +} + +void Device::join_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal) +{ + if (m_reconnected_terminals.empty ()) { + init_terminal_routes (); + } + + other->connect_terminal (other_terminal, 0); + + add_others_terminals (this_terminal, other, other_terminal); +} + +void Device::reroute_terminal (unsigned int this_terminal, db::Device *other, unsigned int from_other_terminal, unsigned int other_terminal) +{ + // TODO: the internal connection is not represented currently ... + + if (m_reconnected_terminals.empty ()) { + init_terminal_routes (); + } + + if (! m_reconnected_terminals.empty ()) { + m_reconnected_terminals.erase (this_terminal); + } + + add_others_terminals (this_terminal, other, other_terminal); + + connect_terminal (this_terminal, other->net_for_terminal (other_terminal)); + + other->connect_terminal (from_other_terminal, 0); + other->connect_terminal (other_terminal, 0); +} + +void Device::join_device (db::Device *other) +{ + db::DCplxTrans d = trans ().inverted () * other->trans (); + + m_other_abstracts.reserve (m_other_abstracts.size () + 1 + other->m_other_abstracts.size ()); + + m_other_abstracts.push_back (db::DeviceAbstractRef (other->device_abstract (), d)); + + for (std::vector::const_iterator a = other->m_other_abstracts.begin (); a != other->m_other_abstracts.end (); ++a) { + m_other_abstracts.push_back (*a); + m_other_abstracts.back ().trans = d * m_other_abstracts.back ().trans; + } +} + +static db::DeviceAbstract *map_da (const std::map &map, const db::DeviceAbstract *da) +{ + if (! da) { + return 0; + } else { + std::map::const_iterator m = map.find (da); + tl_assert (m != map.end ()); + return m->second; + } +} + +void Device::translate_device_abstracts (const std::map &map) +{ + set_device_abstract (map_da (map, device_abstract ())); + + for (std::vector::iterator a = m_other_abstracts.begin (); a != m_other_abstracts.end (); ++a) { + a->device_abstract = map_da (map, a->device_abstract); + } +} + } diff --git a/src/db/db/dbDevice.h b/src/db/db/dbDevice.h index 5b12d25d5..7e6b8af3e 100644 --- a/src/db/db/dbDevice.h +++ b/src/db/db/dbDevice.h @@ -26,6 +26,8 @@ #include "dbCommon.h" #include "dbNet.h" #include "dbPoint.h" +#include "dbVector.h" +#include "dbTrans.h" #include "tlObject.h" @@ -38,6 +40,51 @@ class Circuit; class DeviceClass; class DeviceAbstract; +/** + * @brief A structure describing a terminal reference into another device abstract + */ +struct DeviceReconnectedTerminal +{ + DeviceReconnectedTerminal (size_t _device_index, unsigned int _other_terminal_id) + : device_index (_device_index), other_terminal_id (_other_terminal_id) + { + // .. nothing yet .. + } + + DeviceReconnectedTerminal () + : device_index (0), other_terminal_id (0) + { + // .. nothing yet .. + } + + size_t device_index; + unsigned int other_terminal_id; +}; + +/** + * @brief A structure describing a reference to another device abstract + * + * This structure is used within Device to reference more than the standard + * device abstract. + */ +struct DeviceAbstractRef +{ + DeviceAbstractRef (const db::DeviceAbstract *_device_abstract, const db::DCplxTrans &_trans) + : device_abstract (_device_abstract), trans (_trans) + { + // .. nothing yet .. + } + + DeviceAbstractRef () + : device_abstract (0), trans () + { + // .. nothing yet .. + } + + const db::DeviceAbstract *device_abstract; + db::DCplxTrans trans; +}; + /** * @brief An actual device * @@ -166,19 +213,19 @@ public: /** * @brief Sets the device position - * The device position should be the center of the recognition shape or something similar. + * The device position should be the center and orientation of the recognition shape or something similar. * Giving the device a position allows combining multiple devices with the same * relative geometry into a single cell. - * The position has to be given in micrometer units. + * The transformation has to be given in micrometer units. */ - void set_position (const db::DPoint &pos); + void set_trans (const db::DCplxTrans &tr); /** * @brief Gets the device position */ - const db::DPoint &position () const + const db::DCplxTrans &trans () const { - return m_position; + return m_trans; } /** @@ -228,6 +275,80 @@ public: */ void set_parameter_value (const std::string &name, double v); + /** + * @brief Used for device combination: join terminals with other device + */ + void join_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal); + + /** + * @brief Used for device combination: reroute terminal to other device + * + * This will disconnect "this_terminal" from the device and make a connection to + * "other_terminal" of the "other" device instead. + * + * An internal connection between "this_terminal" and "from_other_terminal" is + * implied. + */ + void reroute_terminal (unsigned int this_terminal, db::Device *other, unsigned int from_other_terminal, unsigned int other_terminal); + + /** + * @brief Gets the set of other terminal references + * + * This method will return 0 if the device isn't a combined device or the given terminal + * is not connector to a different abstract. + * + * The returned vector (if any) is a complete list of terminals connected to the given + * logical device terminal. + */ + const std::vector *reconnected_terminals_for (unsigned int this_terminal) const + { + std::map >::const_iterator t = m_reconnected_terminals.find (this_terminal); + if (t != m_reconnected_terminals.end ()) { + return & t->second; + } else { + return 0; + } + } + + /** + * @brief Gets the map of reconnected terminals + */ + const std::map > &reconnected_terminals () const + { + return m_reconnected_terminals; + } + + /** + * @brief Gets the map of reconnected terminals (non-const version) + * + * NOTE: don't use this method to modify this container! It's provided for persistence implementation only. + */ + std::map > &reconnected_terminals () + { + return m_reconnected_terminals; + } + + /** + * @brief Gets the set of other device abstracts + * + * This list does not include the intrinsic original abstract of the device. + * This vector is non-empty if this device is a combined one. + */ + const std::vector &other_abstracts () const + { + return m_other_abstracts; + } + + /** + * @brief Gets the set of other device abstracts (non-const version) + * + * NOTE: don't use this method to modify this container! It's provided for persistence implementation only. + */ + std::vector &other_abstracts () + { + return m_other_abstracts; + } + private: friend class Circuit; friend class Net; @@ -235,11 +356,23 @@ private: DeviceClass *mp_device_class; DeviceAbstract *mp_device_abstract; std::string m_name; - db::DPoint m_position; + db::DCplxTrans m_trans; std::vector m_terminal_refs; std::vector m_parameters; size_t m_id; Circuit *mp_circuit; + std::vector m_other_abstracts; + std::map > m_reconnected_terminals; + + /** + * @brief Translates the device abstracts + */ + void translate_device_abstracts (const std::map &map); + + /** + * @brief Joins this device with another + */ + void join_device (db::Device *other); /** * @brief Sets the terminal reference for a specific terminal @@ -258,6 +391,9 @@ private: * @brief Sets the circuit */ void set_circuit (Circuit *circuit); + + void add_others_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal); + void init_terminal_routes (); }; } diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index b42ddfcd0..322885071 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -22,6 +22,7 @@ #include "dbDeviceClass.h" #include "dbDevice.h" +#include "tlClassRegistry.h" namespace db { @@ -273,4 +274,29 @@ bool DeviceClass::equal (const db::Device &a, const db::Device &b) } } +// -------------------------------------------------------------------------------- +// DeviceClassTemplateBase class implementation + +DeviceClassTemplateBase * +DeviceClassTemplateBase::template_by_name (const std::string &name) +{ + for (tl::Registrar::iterator i = tl::Registrar::begin (); i != tl::Registrar::end (); ++i) { + if (i->name () == name) { + return i.operator-> (); + } + } + return 0; +} + +DeviceClassTemplateBase * +DeviceClassTemplateBase::is_a (const db::DeviceClass *dc) +{ + for (tl::Registrar::iterator i = tl::Registrar::begin (); i != tl::Registrar::end (); ++i) { + if (i->is_of (dc)) { + return i.operator-> (); + } + } + return 0; +} + } diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 6b0388a79..bb433ea92 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -124,7 +124,7 @@ public: * @brief Creates an empty device parameter definition */ DeviceParameterDefinition () - : m_name (), m_description (), m_default_value (0.0), m_id (0), m_is_primary (true) + : m_name (), m_description (), m_default_value (0.0), m_id (0), m_is_primary (true), m_si_scaling (1.0) { // .. nothing yet .. } @@ -132,8 +132,8 @@ public: /** * @brief Creates a device parameter definition with the given name and description */ - DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0, bool is_primary = true) - : m_name (name), m_description (description), m_default_value (default_value), m_id (0), m_is_primary (is_primary) + DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0, bool is_primary = true, double si_scaling = 1.0) + : m_name (name), m_description (description), m_default_value (default_value), m_id (0), m_is_primary (is_primary), m_si_scaling (si_scaling) { // .. nothing yet .. } @@ -178,6 +178,17 @@ public: return m_default_value; } + /** + * @brief Gets the SI unit scaling factor + * + * Some parameters are given in micrometers for example. This + * scaling factor gives the translation to SI units (1e-6 for micrometers). + */ + double si_scaling () const + { + return m_si_scaling; + } + /** * @brief Sets the parameter description */ @@ -220,6 +231,7 @@ private: double m_default_value; size_t m_id; bool m_is_primary; + double m_si_scaling; void set_id (size_t id) { @@ -536,6 +548,74 @@ private: } }; +/** + * @brief A device class template + * + * This is a registered class which provides a device class template. + * The built-in classes serve as templates and registering a template + * allows regenerating the class from an abstract description (template + * name). + * + * NOTE: device classes derived from one of the built-in classes + * cannot be distinguished from pure built-in classes. Entirely + * customized classes are treated as "non-template based" (i.e. + * "is_a" returns 0). + */ +class DB_PUBLIC DeviceClassTemplateBase +{ +public: + DeviceClassTemplateBase (const std::string &name) + : m_name (name) + { + // .. nothing yet .. + } + + virtual ~DeviceClassTemplateBase () { } + + const std::string &name () const + { + return m_name; + } + + virtual bool is_of (const db::DeviceClass *) const = 0; + virtual DeviceClass *create () const = 0; + + static DeviceClassTemplateBase *template_by_name (const std::string &name); + static DeviceClassTemplateBase *is_a (const db::DeviceClass *dc); + +private: + std::string m_name; + + DeviceClassTemplateBase (const DeviceClassTemplateBase &); + DeviceClassTemplateBase &operator= (const DeviceClassTemplateBase &); +}; + +template +class DB_PUBLIC_TEMPLATE device_class_template + : public DeviceClassTemplateBase +{ +public: + device_class_template (const std::string &name) + : DeviceClassTemplateBase (name) + { + // .. nothing yet .. + } + + virtual bool is_of (const db::DeviceClass *dc) const + { + return dynamic_cast (dc) != 0; + } + + virtual DeviceClass *create () const + { + return new T (); + } + +private: + device_class_template (const device_class_template &); + device_class_template &operator= (const device_class_template &); +}; + } #endif diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 593f031c2..2005b010c 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -145,6 +145,12 @@ Connectivity::global_net_id (const std::string &gn) return id; } +size_t +Connectivity::global_nets () const +{ + return m_global_net_names.size (); +} + Connectivity::layer_iterator Connectivity::begin_layers () const { @@ -1270,6 +1276,11 @@ private: for (db::CellInstArray::iterator ii2 = i2.begin_touching (ib1.transformed (t2i), mp_layout); ! ii2.at_end (); ++ii2) { db::ICplxTrans tt2 = t2 * i2.complex_trans (*ii2); + if (i1.cell_index () == i2.cell_index () && tt1 == tt2) { + // skip interactions between identical instances (duplicate instance removal) + continue; + } + box_type ib2 = bb2.transformed (tt2); box_type common12 = ib1 & ib2 & common; @@ -1653,6 +1664,8 @@ hier_clusters::make_path (const db::Layout &layout, const db::Cell &cell, siz connected_clusters &child_cc = clusters_per_cell (p->inst_cell_index ()); if (child_cc.is_root (id)) { + std::set > seen; // to avoid duplicate connections + const db::Cell &child_cell = layout.cell (p->inst_cell_index ()); for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { @@ -1662,7 +1675,7 @@ hier_clusters::make_path (const db::Layout &layout, const db::Cell &cell, siz for (db::CellInstArray::iterator pii = child_inst.begin (); ! pii.at_end (); ++pii) { ClusterInstance ci2 (id, child_inst.cell_index (), child_inst.complex_trans (*pii), child_inst.prop_id ()); - if (cell.cell_index () != pi->parent_cell_index () || ci != ci2) { + if ((cell.cell_index () != pi->parent_cell_index () || ci != ci2) && seen.find (std::make_pair (pi->parent_cell_index (), ci2)) == seen.end ()) { size_t id_dummy; @@ -1676,6 +1689,7 @@ hier_clusters::make_path (const db::Layout &layout, const db::Cell &cell, siz } parent_cc.add_connection (id_dummy, ci2); + seen.insert (std::make_pair (pi->parent_cell_index (), ci2)); } @@ -1709,6 +1723,8 @@ hier_clusters::make_path (const db::Layout &layout, const db::Cell &cell, siz connected_clusters &child_cc = clusters_per_cell (p->inst_cell_index ()); if (child_cc.is_root (id)) { + std::set > seen; // to avoid duplicate connections + const db::Cell &child_cell = layout.cell (p->inst_cell_index ()); for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { @@ -1717,22 +1733,27 @@ hier_clusters::make_path (const db::Layout &layout, const db::Cell &cell, siz connected_clusters &parent_cc = clusters_per_cell (pi->parent_cell_index ()); for (db::CellInstArray::iterator pii = child_inst.begin (); ! pii.at_end (); ++pii) { - size_t id_dummy; - - const typename db::local_cluster::global_nets &gn = child_cc.cluster_by_id (id).get_global_nets (); - if (gn.empty ()) { - id_dummy = parent_cc.insert_dummy (); - } else { - local_cluster *lc = parent_cc.insert (); - lc->set_global_nets (gn); - id_dummy = lc->id (); - } - ClusterInstance ci2 (id, child_inst.cell_index (), child_inst.complex_trans (*pii), child_inst.prop_id ()); - parent_cc.add_connection (id_dummy, ci2); + if (seen.find (std::make_pair (pi->parent_cell_index (), ci2)) == seen.end ()) { + + size_t id_dummy; + + const typename db::local_cluster::global_nets &gn = child_cc.cluster_by_id (id).get_global_nets (); + if (gn.empty ()) { + id_dummy = parent_cc.insert_dummy (); + } else { + local_cluster *lc = parent_cc.insert (); + lc->set_global_nets (gn); + id_dummy = lc->id (); + } + + parent_cc.add_connection (id_dummy, ci2); + seen.insert (std::make_pair (pi->parent_cell_index (), ci2)); + + if (pci == pi->parent_cell_index () && ci == ci2) { + id_new = id_dummy; + } - if (pci == pi->parent_cell_index () && ci == ci2) { - id_new = id_dummy; } } @@ -1821,7 +1842,7 @@ hier_clusters::build_local_cluster (const db::Layout &layout, const db::Cell tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 20, msg); connected_clusters &local = m_per_cell_clusters [cell.cell_index ()]; - local.build_clusters (cell, shape_flags, conn, attr_equivalence, tl::verbosity () >= m_base_verbosity + 30); + local.build_clusters (cell, shape_flags, conn, attr_equivalence, true); } template @@ -1950,8 +1971,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c static std::string desc = tl::to_string (tr ("Instance to instance treatment")); tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 30, desc); - bool report_progress = tl::verbosity () >= m_base_verbosity + 30; - db::box_scanner bs (report_progress, desc); + db::box_scanner bs (true, desc); for (std::vector::const_iterator inst = inst_storage.begin (); inst != inst_storage.end (); ++inst) { bs.insert (inst.operator-> (), 0); @@ -1969,8 +1989,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c static std::string desc = tl::to_string (tr ("Local to instance treatment")); tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 30, desc); - bool report_progress = tl::verbosity () >= m_base_verbosity + 30; - db::box_scanner2, unsigned int, db::Instance, unsigned int> bs2 (report_progress, desc); + db::box_scanner2, unsigned int, db::Instance, unsigned int> bs2 (true, desc); for (typename connected_clusters::const_iterator c = local.begin (); c != local.end (); ++c) { @@ -2025,8 +2044,9 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c // insert the global nets from here for (typename db::connected_clusters::const_iterator cl = local.begin (); cl != local.end (); ++cl) { - if (! cl->get_global_nets ().empty ()) { - global_net_clusters.add (cl->get_global_nets (), db::ClusterInstance (cl->id ())); + const typename db::local_cluster::global_nets &gn = cl->get_global_nets (); + if (! gn.empty ()) { + global_net_clusters.add (gn, db::ClusterInstance (cl->id ())); } } @@ -2153,6 +2173,10 @@ template recursive_cluster_shape_iterator::recursive_cluster_shape_iterator (const hier_clusters &hc, unsigned int layer, db::cell_index_type ci, typename local_cluster::id_type id) : mp_hc (&hc), m_layer (layer), m_id (id) { + if (id == 0) { + return; + } + down (ci, id, db::ICplxTrans ()); while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) { diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 5d14a904a..112648e9c 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -131,6 +131,11 @@ public: */ size_t global_net_id (const std::string &gn); + /** + * @brief Gets the number of global nets (it's also the max ID + 1) + */ + size_t global_nets () const; + /** * @brief Begin iterator for the layers involved */ diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 08e06fb1a..27724cf78 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -1562,6 +1562,17 @@ public: } } + /** + * @brief Cancel the "in changes" state (see "start_changes") + * This version does not force an update + */ + void end_changes_no_update () + { + if (m_invalid > 0) { + --m_invalid; + } + } + /** * @brief Tell if the layout object is under construction * @@ -1763,8 +1774,8 @@ mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const class DB_PUBLIC LayoutLocker { public: - explicit LayoutLocker (db::Layout *layout = 0) - : mp_layout (layout) + explicit LayoutLocker (db::Layout *layout = 0, bool no_update = false) + : mp_layout (layout), m_no_update (no_update) { if (mp_layout) { mp_layout->start_changes (); @@ -1773,13 +1784,11 @@ public: ~LayoutLocker () { - if (mp_layout) { - mp_layout->end_changes (); - } + set (0, false); } LayoutLocker (const LayoutLocker &other) - : mp_layout (other.mp_layout) + : mp_layout (other.mp_layout), m_no_update (other.m_no_update) { if (mp_layout) { mp_layout->start_changes (); @@ -1792,20 +1801,30 @@ public: return *this; } - if (mp_layout) { - mp_layout->end_changes (); - } - mp_layout = other.mp_layout; - if (mp_layout) { - mp_layout->start_changes (); - } - + set (other.mp_layout, other.m_no_update); return *this; } private: - db::Layout *mp_layout; + bool m_no_update; + + void set (db::Layout *layout, bool no_update) + { + if (mp_layout) { + if (m_no_update) { + mp_layout->end_changes_no_update (); + } else { + mp_layout->end_changes (); + } + } + mp_layout = layout; + m_no_update = no_update; + if (mp_layout) { + mp_layout->start_changes (); + } + } + }; } diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index b9bb376ca..4e339c96e 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -26,6 +26,11 @@ #include "dbDeepRegion.h" #include "dbShapeRepository.h" #include "dbCellMapping.h" +#include "dbLayoutToNetlistWriter.h" +#include "dbLayoutToNetlistReader.h" +#include "dbLayoutVsSchematic.h" +#include "dbLayoutToNetlistFormatDefs.h" +#include "dbLayoutVsSchematicFormatDefs.h" namespace db { @@ -87,6 +92,14 @@ LayoutToNetlist::~LayoutToNetlist () m_net_clusters.clear (); } +void LayoutToNetlist::keep_dss () +{ + if (mp_dss.get () && ! mp_internal_dss.get ()) { + mp_dss->keep (); + mp_internal_dss.reset (mp_dss.get ()); + } +} + void LayoutToNetlist::init () { dss ().set_text_enlargement (1); @@ -155,7 +168,9 @@ db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const st si.shape_flags (db::ShapeIterator::Texts); std::auto_ptr region (new db::Region (si, dss ())); - register_layer (*region, n); + if (! n.empty ()) { + register_layer (*region, n); + } return region.release (); } @@ -166,7 +181,9 @@ db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const si.shape_flags (db::ShapeIterator::Paths | db::ShapeIterator::Polygons | db::ShapeIterator::Boxes); std::auto_ptr region (new db::Region (si, dss ())); - register_layer (*region, n); + if (! n.empty ()) { + register_layer (*region, n); + } return region.release (); } @@ -188,7 +205,7 @@ void LayoutToNetlist::connect (const db::Region &l) } if (! is_persisted (l)) { - throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in intra-layer connectivity for netlist extraction")))); + register_layer (l, make_new_name ()); } // we need to keep a reference, so we can safely delete the region @@ -204,10 +221,10 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b) throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } if (! is_persisted (a)) { - throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in inter-layer connectivity (first layer) for netlist extraction")))); + register_layer (a, make_new_name ()); } if (! is_persisted (b)) { - throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in inter-layer connectivity (second layer) for netlist extraction")))); + register_layer (b, make_new_name ()); } // we need to keep a reference, so we can safely delete the region @@ -225,7 +242,7 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string & throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } if (! is_persisted (l)) { - throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in global connectivity for netlist extraction")))); + register_layer (l, make_new_name ()); } // we need to keep a reference, so we can safely delete the region @@ -320,11 +337,7 @@ void LayoutToNetlist::register_layer (const db::Region ®ion, const std::strin db::DeepRegion *delegate = dynamic_cast (region.delegate()); if (! delegate) { - if (region.empty ()) { - dl = dss ().empty_layer (m_layout_index); - } else { - dl = dss ().create_from_flat (region, true); - } + dl = dss ().create_from_flat (region, true); } else { @@ -343,6 +356,29 @@ void LayoutToNetlist::register_layer (const db::Region ®ion, const std::strin m_name_of_layer [dl.layer ()] = n; } +std::string LayoutToNetlist::make_new_name (const std::string &stem) +{ + int m = std::numeric_limits::max () / 2 + 1; + int n = m; + + std::string name; + while (m > 0) { + + m /= 2; + + name = stem; + name += std::string ("$"); + name += tl::to_string (n - m); + + if (m_named_regions.find (name) == m_named_regions.end ()) { + n -= m; + } + + } + + return name; +} + std::string LayoutToNetlist::name (const db::Region ®ion) const { std::map::const_iterator n = m_name_of_layer.find (layer_of (region)); @@ -396,9 +432,6 @@ db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) const std::pair lff = dss ().layer_for_flat (region); if (lff.first) { return lff.second; - } else if (region.empty ()) { - // provide a substitute empty layer for empty - return dss ().empty_layer (m_layout_index); } else { throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in netlist extraction")))); } @@ -413,7 +446,7 @@ unsigned int LayoutToNetlist::layer_of (const db::Region ®ion) const return deep_layer_of (region).layer (); } -db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells) +db::CellMapping LayoutToNetlist::make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector *nets, bool with_device_cells) { std::set device_cells; if (! with_device_cells && mp_netlist.get ()) { @@ -422,7 +455,31 @@ db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell } } - return dss ().cell_mapping_to_original (m_layout_index, &layout, cell.cell_index (), &device_cells); + std::set net_cells; + if (nets) { + // Compute the "included cell" list for cell_mapping_to_original: these are all cells which + // are required to represent the net hierarchically. + for (std::vector::const_iterator n = nets->begin (); n != nets->end (); ++n) { + const db::Net *net = *n; + db::cell_index_type net_cell = net->circuit ()->cell_index (); + if (net_cells.find (net_cell) == net_cells.end ()) { + net_cells.insert (net_cell); + internal_layout()->cell (net_cell).collect_caller_cells (net_cells); + } + } + } + + return dss ().cell_mapping_to_original (m_layout_index, &layout, cell.cell_index (), &device_cells, nets ? &net_cells : 0); +} + +db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector &nets, bool with_device_cells) +{ + return make_cell_mapping_into (layout, cell, &nets, with_device_cells); +} + +db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells) +{ + return make_cell_mapping_into (layout, cell, 0, with_device_cells); } db::CellMapping LayoutToNetlist::const_cell_mapping_into (const db::Layout &layout, const db::Cell &cell) @@ -436,6 +493,36 @@ db::CellMapping LayoutToNetlist::const_cell_mapping_into (const db::Layout &layo return cm; } +std::map +LayoutToNetlist::create_layermap (db::Layout &target_layout, int ln) const +{ + std::map lm; + if (! internal_layout ()) { + return lm; + } + + const db::Layout &source_layout = *internal_layout (); + + std::set layers_to_copy; + const db::Connectivity &conn = connectivity (); + for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + layers_to_copy.insert (*layer); + } + + for (std::set::const_iterator l = layers_to_copy.begin (); l != layers_to_copy.end (); ++l) { + const db::LayerProperties &lp = source_layout.get_properties (*l); + unsigned int tl; + if (! lp.is_null ()) { + tl = target_layout.insert_layer (lp); + } else { + tl = target_layout.insert_layer (db::LayerProperties (ln++, 0, name (*l))); + } + lm.insert (std::make_pair (tl, const_cast (this)->layer_by_index (*l))); + } + + return lm; +} + db::Netlist *LayoutToNetlist::netlist () const { return mp_netlist.get (); @@ -455,13 +542,13 @@ namespace } template -static bool deliver_shape (const db::PolygonRef &, StopOnFirst, const Tr &) +static bool deliver_shape (const db::PolygonRef &, StopOnFirst, const Tr &, db::properties_id_type) { return false; } template -static bool deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr) +static bool deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr, db::properties_id_type /*propid*/) { if (pr.obj ().is_box ()) { region.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); @@ -472,76 +559,102 @@ static bool deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const T } template -static bool deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const Tr &tr) +static bool deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const Tr &tr, db::properties_id_type propid) { if (pr.obj ().is_box ()) { - shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); + if (propid) { + shapes.insert (db::BoxWithProperties (pr.obj ().box ().transformed (pr.trans ()).transformed (tr), propid)); + } else { + shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); + } } else { db::Layout *layout = shapes.layout (); if (layout) { - shapes.insert (db::PolygonRef (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ())); + db::PolygonRef polygon_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ()); + if (propid) { + shapes.insert (db::PolygonRefWithProperties (polygon_ref, propid)); + } else { + shapes.insert (polygon_ref); + } } else { - shapes.insert (pr.obj ().transformed (pr.trans ()).transformed (tr)); + db::Polygon polygon (pr.obj ().transformed (pr.trans ()).transformed (tr)); + if (propid) { + shapes.insert (db::PolygonWithProperties (polygon, propid)); + } else { + shapes.insert (polygon); + } } } return true; } -template -static bool deliver_shapes_of_net_recursive (const db::Netlist * /*nl*/, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to) +template +static bool deliver_shapes_of_net_recursive (const db::Netlist * /*nl*/, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to, db::properties_id_type propid) { // deliver the net shapes - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { - if (! deliver_shape (*rci, to, tr * rci.trans ())) { + for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + if (! deliver_shape (*rci, to, tr * rci.trans (), propid)) { return false; } } return true; } -template -static bool deliver_shapes_of_net_nonrecursive (const db::Netlist *nl, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to) +template +static bool deliver_shapes_of_net (bool recursive, const db::Netlist *nl, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, const std::map &lmap, const db::ICplxTrans &tr, db::properties_id_type propid) { - // NOTE: this scheme will deliver the shapes from the cell, including (!) - // subcells that are purged + // shortcut + if (lmap.empty ()) { + return true; + } - db::cell_index_type prev_ci = ci; + const db::connected_clusters &cc = clusters.clusters_per_cell (ci); + const db::local_cluster &lc = cc.cluster_by_id (cid); - // deliver the net shapes - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ) { - - db::cell_index_type cci = rci.cell_index (); - if (cci != prev_ci && cci != ci && (! nl || nl->circuit_by_cell_index (cci) || nl->device_abstract_by_cell_index (cci))) { - - rci.skip_cell (); - - } else { - - if (! deliver_shape (*rci, to, tr * rci.trans ())) { + for (typename std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { + for (typename db::local_cluster::shape_iterator s = lc.begin (l->first); ! s.at_end (); ++s) { + if (! deliver_shape (*s, *l->second, tr, propid)) { return false; } - prev_ci = cci; - - ++rci; - } + } + + const typename db::connected_clusters::connections_type &conn = cc.connections_for_cluster (cid); + for (typename db::connected_clusters::connections_type::const_iterator c = conn.begin (); c != conn.end (); ) { + + db::cell_index_type cci = c->inst_cell_index (); + if (! recursive && (! nl || nl->circuit_by_cell_index (cci) || nl->device_abstract_by_cell_index (cci))) { + // skip this cell in non-recursive mode (and all following instances of the same cell too) + typename db::connected_clusters::connections_type::const_iterator cc = c; + while (++cc != conn.end ()) { + if (cc->inst_cell_index () != cci) { + break; + } + } + c = cc; + continue; + } + + if (! deliver_shapes_of_net (recursive, nl, clusters, cci, c->id (), lmap, tr * c->inst_trans (), propid)) { + return false; + } + ++c; } return true; } -void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to) const +void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to, db::properties_id_type propid) const { unsigned int lid = layer_of (of_layer); const db::Circuit *circuit = net.circuit (); tl_assert (circuit != 0); - if (! recursive) { - deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), to); - } else { - deliver_shapes_of_net_recursive (mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), to); - } + std::map lmap; + lmap [lid] = &to; + + deliver_shapes_of_net (recursive, mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lmap, db::ICplxTrans (), propid); } db::Region *LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive) const @@ -551,27 +664,25 @@ db::Region *LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region tl_assert (circuit != 0); std::auto_ptr res (new db::Region ()); + std::map lmap; + lmap [lid] = res.get (); - if (! recursive) { - deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), *res); - } else { - deliver_shapes_of_net_recursive (mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), *res); - } + deliver_shapes_of_net (recursive, mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lmap, db::ICplxTrans (), 0); return res.release (); } void -LayoutToNetlist::build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const db::ICplxTrans &tr) const +LayoutToNetlist::build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const db::ICplxTrans &tr) const { const db::Circuit *circuit = net.circuit (); tl_assert (circuit != 0); - build_net_rec (circuit->cell_index (), net.cluster_id (), target, target_cell, lmap, &net, net_cell_name_prefix, cell_name_prefix, device_cell_name_prefix, cmap, tr); + build_net_rec (circuit->cell_index (), net.cluster_id (), target, target_cell, lmap, &net, net_cell_name_prefix, netname_propid, hier_mode, cell_name_prefix, device_cell_name_prefix, reuse_table, tr); } void -LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &tc, const std::map &lmap, const db::Net *net, const char *net_cell_name_prefix, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const db::ICplxTrans &tr) const +LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &tc, const std::map &lmap, const db::Net *net, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const db::ICplxTrans &tr) const { db::Cell *target_cell = &tc; @@ -582,14 +693,15 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & bool any_connections = circuit_cell_name_prefix && ! ccl.connections_for_cluster (cid).empty (); if (! any_connections) { - bool consider_cell = any_connections; - for (std::map::const_iterator l = lmap.begin (); l != lmap.end () && !consider_cell; ++l) { + StopOnFirst sof; + std::map sof_lmap; + for (std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { if (l->second) { - StopOnFirst sof; - consider_cell = !deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, sof); + sof_lmap.insert (std::make_pair (layer_of (*l->second), &sof)); } } + bool consider_cell = ! deliver_shapes_of_net (hier_mode == BNH_Flatten, mp_netlist.get (), m_net_clusters, ci, cid, sof_lmap, tr, 0); if (! consider_cell) { // shortcut if cell is empty -> no net cell will be produced return; @@ -604,13 +716,16 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & } + std::map target_lmap; for (std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { if (l->second) { - deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, target_cell->shapes (l->first)); + target_lmap.insert (std::make_pair (layer_of (*l->second), &target_cell->shapes (l->first))); } } - if (! circuit_cell_name_prefix && ! device_cell_name_prefix) { + deliver_shapes_of_net (hier_mode == BNH_Flatten, mp_netlist.get (), m_net_clusters, ci, cid, target_lmap, tr, netname_propid); + + if (hier_mode != BNH_SubcircuitCells && ! device_cell_name_prefix) { return; } @@ -627,8 +742,10 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & db::cell_index_type subci = c->inst_cell_index (); size_t subcid = c->id (); - std::map, db::cell_index_type>::const_iterator cm = cmap.find (std::make_pair (subci, subcid)); - if (cm == cmap.end ()) { + CellReuseTableKey cmap_key (subci, netname_propid, subcid); + + cell_reuse_table_type::const_iterator cm = reuse_table.find (cmap_key); + if (cm == reuse_table.end ()) { const char *name_prefix = 0; if (mp_netlist->device_abstract_by_cell_index (subci)) { @@ -642,12 +759,12 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & std::string cell_name = internal_layout ()->cell_name (subci); db::cell_index_type target_ci = target.add_cell ((std::string (name_prefix) + cell_name).c_str ()); - cm = cmap.insert (std::make_pair (std::make_pair (subci, subcid), target_ci)).first; + cm = reuse_table.insert (std::make_pair (cmap_key, target_ci)).first; - build_net_rec (subci, subcid, target, target.cell (target_ci), lmap, 0, 0, circuit_cell_name_prefix, device_cell_name_prefix, cmap, tr_mag); + build_net_rec (subci, subcid, target, target.cell (target_ci), lmap, 0, 0, netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, reuse_table, tr_mag); } else { - cm = cmap.insert (std::make_pair (std::make_pair (subci, subcid), std::numeric_limits::max ())).first; + cm = reuse_table.insert (std::make_pair (cmap_key, std::numeric_limits::max ())).first; } } @@ -661,57 +778,113 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & } } -void -LayoutToNetlist::build_net (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix, const char *device_cell_name_prefix) const +db::properties_id_type +LayoutToNetlist::make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const { - if (! m_netlist_extracted) { - throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); + if (! netname_prop.is_nil ()) { + + db::property_names_id_type name_propnameid = ly.properties_repository ().prop_name_id (netname_prop); + db::PropertiesRepository::properties_set propset; + propset.insert (std::make_pair (name_propnameid, tl::Variant (net.expanded_name ()))); + + return ly.properties_repository ().properties_id (propset); + + } else { + return 0; } - - std::map, db::cell_index_type> cell_map; - - double mag = internal_layout ()->dbu () / target.dbu (); - build_net_rec (net, target, target_cell, lmap, 0, cell_name_prefix, device_cell_name_prefix, cell_map, db::ICplxTrans (mag)); } void -LayoutToNetlist::build_all_nets (const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const +LayoutToNetlist::build_net (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix) const { if (! m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); } - std::map, db::cell_index_type> cell_map; + cell_reuse_table_type cell_reuse_table; + double mag = internal_layout ()->dbu () / target.dbu (); + db::properties_id_type netname_propid = make_netname_propid (target, netname_prop, net); + build_net_rec (net, target, target_cell, lmap, 0, netname_propid, hier_mode, cell_name_prefix, device_cell_name_prefix, cell_reuse_table, db::ICplxTrans (mag)); +} + +void +LayoutToNetlist::build_all_nets (const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const +{ + build_nets (0, cmap, target, lmap, net_cell_name_prefix, netname_prop, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix); +} + +void +LayoutToNetlist::build_net_rec (const db::Net &net, db::Layout &target, db::cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const +{ + if (! cmap.has_mapping (circuit_cell)) { + + const db::Cell &cc = internal_layout ()->cell (circuit_cell); + + for (db::Cell::parent_inst_iterator p = cc.begin_parent_insts (); ! p.at_end (); ++p) { + + db::CellInstArray ci = p->child_inst ().cell_inst (); + for (db::CellInstArray::iterator ia = ci.begin (); ! ia.at_end(); ++ia) { + + db::ICplxTrans tr_parent = ci.complex_trans (*ia) * tr; + build_net_rec (net, target, p->parent_cell_index (), cmap, lmap, net_cell_name_prefix, netname_propid, hier_mode, cell_name_prefix, device_cell_name_prefix, reuse_table, tr_parent); + + } + + } + + } else { + + double mag = internal_layout ()->dbu () / target.dbu (); + + db::cell_index_type target_ci = cmap.cell_mapping (circuit_cell); + build_net_rec (net, target, target.cell (target_ci), lmap, net_cell_name_prefix, netname_propid, hier_mode, cell_name_prefix, device_cell_name_prefix, reuse_table, db::ICplxTrans (mag) * tr); + + } +} + +void +LayoutToNetlist::build_nets (const std::vector *nets, const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const +{ + if (! m_netlist_extracted) { + throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); + } + + std::set net_set; + if (nets) { + net_set.insert (nets->begin (), nets->end ()); + } + + cell_reuse_table_type cell_reuse_table; + const db::Netlist *netlist = mp_netlist.get (); for (db::Netlist::const_circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) { - if (! cmap.has_mapping (c->cell_index ())) { - continue; - } - bool is_top_circuit = c->begin_parents () == c->end_parents (); - db::cell_index_type target_ci = cmap.cell_mapping (c->cell_index ()); - for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { - // exlude local nets in recursive mode - if (circuit_cell_name_prefix && ! is_top_circuit && n->pin_count () > 0) { + // exlude local nets in recursive mode except if they are explicitly selected + if (! nets && hier_mode != BNH_Disconnected && ! is_top_circuit && n->pin_count () > 0) { continue; } - build_net_rec (*n, target, target.cell (target_ci), lmap, net_cell_name_prefix, circuit_cell_name_prefix, device_cell_name_prefix, cell_map, db::ICplxTrans (mag)); + if (! nets || net_set.find (n.operator-> ()) != net_set.end ()) { + db::properties_id_type netname_propid = make_netname_propid (target, netname_prop, *n); + build_net_rec (*n, target, c->cell_index (), cmap, lmap, net_cell_name_prefix, netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, db::ICplxTrans ()); + } } - if (circuit_cell_name_prefix) { + if (hier_mode != BNH_Disconnected && ! nets) { - // with recursive nets we skip nets in subcircuits which are connected upwards. This means, nets will + // With recursive nets we skip nets in subcircuits which are connected upwards. This means, nets will // get lost if there is no connection to this pin from the outside. Hence we need to deliver nets from // subcircuits as part of the circuit which calls the subcircuit - but NOT in a subcircuit cell, because // this will just apply to nets from certain instances. But the net cell name will be formed as "subcircuit:net" + // + // In explicit selection mode we don't care about this as nets are explicitly taken or not. const db::Circuit &circuit = *c; for (db::Circuit::const_subcircuit_iterator sc = circuit.begin_subcircuits (); sc != circuit.end_subcircuits (); ++sc) { @@ -725,13 +898,15 @@ LayoutToNetlist::build_all_nets (const db::CellMapping &cmap, db::Layout &target if (n) { double dbu = target.dbu (); - db::ICplxTrans tr = db::ICplxTrans (mag) * (db::CplxTrans (dbu).inverted () * subcircuit.trans () * db::CplxTrans (dbu)); + db::ICplxTrans tr = db::CplxTrans (dbu).inverted () * subcircuit.trans () * db::CplxTrans (dbu); + + db::properties_id_type netname_propid = make_netname_propid (target, netname_prop, *n); if (net_cell_name_prefix) { std::string ncn = std::string (net_cell_name_prefix) + subcircuit.expanded_name () + ":"; - build_net_rec (*n, target, target.cell (target_ci), lmap, ncn.c_str (), circuit_cell_name_prefix, device_cell_name_prefix, cell_map, tr); + build_net_rec (*n, target, c->cell_index (), cmap, lmap, ncn.c_str (), netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, tr); } else { - build_net_rec (*n, target, target.cell (target_ci), lmap, net_cell_name_prefix, circuit_cell_name_prefix, device_cell_name_prefix, cell_map, tr); + build_net_rec (*n, target, c->cell_index (), cmap, lmap, net_cell_name_prefix, netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, tr); } } @@ -893,8 +1068,8 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg db::Region rgate, rmetal; - deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (gate), db::ICplxTrans (), rgate); - deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (metal), db::ICplxTrans (), rmetal); + deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (gate), db::ICplxTrans (), rgate, 0); + deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (metal), db::ICplxTrans (), rmetal, 0); double agate = rgate.area () * dbu * dbu; double ametal = rmetal.area () * dbu * dbu; @@ -905,7 +1080,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg for (std::vector >::const_iterator d = diodes.begin (); d != diodes.end () && ! skip; ++d) { db::Region rdiode; - deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (*d->first), db::ICplxTrans (), rdiode); + deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (*d->first), db::ICplxTrans (), rdiode, 0); if (fabs (d->second) < db::epsilon) { if (rdiode.area () > 0) { @@ -939,4 +1114,46 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg return db::Region (new db::DeepRegion (dl)); } + +void db::LayoutToNetlist::save (const std::string &path, bool short_format) +{ + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, short_format); + set_filename (path); + writer.write (this); +} + +void db::LayoutToNetlist::load (const std::string &path) +{ + tl::InputStream stream (path); + db::LayoutToNetlistStandardReader reader (stream); + set_filename (path); + set_name (stream.filename ()); + reader.read (this); +} + +db::LayoutToNetlist *db::LayoutToNetlist::create_from_file (const std::string &path) +{ + std::auto_ptr db; + + // TODO: generic concept to detect format + std::string first_line; + { + tl::InputStream stream (path); + tl::TextInputStream text_stream (stream); + first_line = text_stream.get_line (); + } + + if (first_line.find (db::lvs_std_format::keys::lvs_magic_string) == 0) { + db::LayoutVsSchematic *lvs_db = new db::LayoutVsSchematic (); + db.reset (lvs_db); + lvs_db->load (path); + } else { + db.reset (new db::LayoutToNetlist ()); + db->load (path); + } + + return db.release (); +} + } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 5003deb03..cb5485a8b 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -20,8 +20,8 @@ */ -#ifndef _HDR_dbLayout2Netlist -#define _HDR_dbLayout2Netlist +#ifndef _HDR_dbLayoutToNetlist +#define _HDR_dbLayoutToNetlist #include "dbCommon.h" #include "dbCellMapping.h" @@ -114,6 +114,78 @@ public: */ ~LayoutToNetlist (); + /** + * @brief Makes the extractor take over ownership over the DSS when it was created with an external DSS + */ + void keep_dss (); + + /** + * @brief Gets the database description + */ + const std::string &description () const + { + return m_description; + } + + /** + * @brief Sets the database description + */ + void set_description (const std::string &description) + { + m_description = description; + } + + /** + * @brief Gets the original file + * + * The original file describes what original file the netlist database + * was derived from. + */ + const std::string &original_file () const + { + return m_original_file; + } + + /** + * @brief Sets the database original file + */ + void set_original_file (const std::string &original_file) + { + m_original_file = original_file; + } + + /** + * @brief Gets the database name + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Sets the database name + */ + void set_name (const std::string &name) + { + m_name = name; + } + + /** + * @brief Gets the file name + */ + const std::string &filename () const + { + return m_filename; + } + + /** + * @brief Sets the file name + */ + void set_filename (const std::string &filename) + { + m_filename = filename; + } + /** * @brief Sets the number of threads to use for operations which support multiple threads */ @@ -154,8 +226,7 @@ public: * (see below) enhances readability of backannotated information * if layers are involved. Use this method to attach a name to a region * derived by boolean operations for example. - * Named regions are persisted inside the LayoutToNetlist object. Only - * named regions can be put into "connect". + * Named regions are persisted inside the LayoutToNetlist object. */ void register_layer (const db::Region ®ion, const std::string &name); @@ -264,21 +335,18 @@ public: * a derived layer. Certain limitations apply. It's safe to use * boolean operations for deriving layers. Other operations are applicable as long as they are * capable of delivering hierarchical layers. - * Regions put into "connect" need to be named. */ void connect (const db::Region &l); /** * @brief Defines an inter-layer connection for the given layers. * The conditions mentioned with intra-layer "connect" apply for this method too. - * Regions put into "connect" need to be named. */ void connect (const db::Region &a, const db::Region &b); /** * @brief Connects the given layer with a global net with the given name * Returns the global net ID - * Regions put into "connect" need to be named. */ size_t connect_global (const db::Region &l, const std::string &gn); @@ -372,13 +440,31 @@ public: */ db::CellMapping cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells = false); + /** + * @brief Creates a cell mapping for copying shapes from the internal layout to the given target layout for a given list of nets + * This version will only create cells which are required to represent the given nets. + * If 'with_device_cells' is true, cells will be produced for devices. These are cells not corresponding to circuits, so they are disabled normally. + * Use this option, if you want to access device terminal shapes per device. + * CAUTION: This function may create new cells in "layout". + */ + db::CellMapping cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector &nets, bool with_device_cells = false); + /** * @brief Creates a cell mapping for copying shapes from the internal layout to the given target layout. * This version will not create new cells in the target layout. - * If the required cells do not exist there yet, flatting will happen. + * If the required cells do not exist there yet, flattening will happen. */ db::CellMapping const_cell_mapping_into (const db::Layout &layout, const db::Cell &cell); + /** + * @brief Creates a layer mapping for build_nets etc. + * This method will create new layers inside the target layout corresponding to the + * original layers as kept inside the LayoutToNetlist database. + * It will return a layer mapping table suitable for use with build_all_nets, build_nets etc. + * Layers without original layer information will be given layer numbers ln, ln+1 etc. + */ + std::map create_layermap (db::Layout &target_layout, int ln) const; + /** * @brief gets the netlist extracted (0 if no extraction happened yet) */ @@ -428,32 +514,64 @@ public: * * This methods returns a new'd Region. It's the responsibility of the caller * to delete this object. + * + * propid is an optional properties ID which is attached to the shapes if not 0. */ - void shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to) const; + void shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to, properties_id_type propid = 0) const; + + /** + * @brief An enum describing the way the net hierarchy is mapped + */ + enum BuildNetHierarchyMode + { + /** + * @brief Flatten the net + * Collects all shapes of a net and puts that into the net cell or circuit cell + */ + BNH_Flatten = 0, + /** + * @brief Build a net hierarchy adding cells for each subcircuit on the net + * Uses the circuit_cell_prefix to build the subcircuit cell names + */ + BNH_SubcircuitCells = 1, + /** + * @brief No hierarchy + * Just output the shapes of the net belonging to the circuit cell. + * Connections are not indicated! + */ + BNH_Disconnected = 2 + }; /** * @brief Builds a net representation in the given layout and cell * - * This method has two modes: recursive and top-level mode. In recursive mode, - * it will create a proper hierarchy below the given target cell to hold all subcircuits the - * net connects to. It will copy the net's parts from this subcircuits into these cells. + * This method puts the shapes of a net into the given target cell using a variety of options + * to represent the net name and the hierarchy of the net. * - * In top-level mode, only the shapes from the net inside it's circuit are copied to - * the given target cell. No other cells are created. + * If the netname_prop name is not nil, a property with the given name is created and assigned + * the net name. * - * Recursive mode is picked when a cell name prefix is given. The new cells will be - * named like cell_name_prefix + circuit name. + * Net hierarchy is covered in three ways: + * * No connection indicated (hier_mode == BNH_Disconnected: the net shapes are simply put into their + * respective circuits. The connections are not indicated. + * * Subnet hierarchy (hier_mode == BNH_SubcircuitCells): for each root net, a full hierarchy is built + * to accommodate the subnets (see build_net in recursive mode). + * * Flat (hier_mode == BNH_Flatten): each net is flattened and put into the circuit it + * belongs to. * * If a device cell name prefix is given, cells will be produced for each device abstract - * using a name like device_cell_name_prefix + device name. + * using a name like device_cell_name_prefix + device name. Otherwise the device shapes are + * treated as part of the net. * * @param target The target layout * @param target_cell The target cell * @param lmap Target layer indexes (keys) and net regions (values) + * @param hier_mode See description of this method + * @param netname_prop An (optional) property name to which to attach the net name * @param cell_name_prefix Chooses recursive mode if non-null * @param device_cell_name_prefix See above */ - void build_net (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *cell_name_prefix, const char *device_cell_name_prefix) const; + void build_net (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix) const; /** * @brief Builds a full hierarchical representation of the nets @@ -462,28 +580,42 @@ public: * object to determine the target cell (create them with "cell_mapping_into" or "const_cell_mapping_into"). * If no mapping is requested, the specific circuit it skipped. * - * The method has two net annotation modes: - * * No annotation (net_cell_name_prefix == 0): the shapes will be put into the target cell simply + * The method has three net annotation modes: + * * No annotation (net_cell_name_prefix == 0 and netname_prop == nil): the shapes will be put + * into the target cell simply + * * Net name property (net_cell_name_prefix == 0 and netname_prop != nil): the shapes will be + * annotated with a property named with netname_prop and containing the net name string. * * Individual subcells per net (net_cell_name_prefix != 0): for each net, a subcell is created * and the net shapes will be put there (name of the subcell = net_cell_name_prefix + net name). + * (this mode can be combined with netname_prop too). * - * In addition, net hierarchy is covered in two ways: - * * No connection indicated (circuit_cell_name_prefix == 0: the net shapes are simply put into their + * In addition, net hierarchy is covered in three ways: + * * No connection indicated (hier_mode == BNH_Disconnected: the net shapes are simply put into their * respective circuits. The connections are not indicated. - * * Subnet hierarchy (circuit_cell_name_prefix != 0): for each root net, a full hierarchy is built + * * Subnet hierarchy (hier_mode == BNH_SubcircuitCells): for each root net, a full hierarchy is built * to accommodate the subnets (see build_net in recursive mode). + * * Flat (hier_mode == BNH_Flatten): each net is flattened and put into the circuit it + * belongs to. * * If a device cell name prefix is given, cells will be produced for each device abstract - * using a name like device_cell_name_prefix + device name. + * using a name like device_cell_name_prefix + device name. Otherwise the device shapes are + * treated as part of the net. * * @param cmap The mapping of internal layout to target layout for the circuit mapping * @param target The target layout * @param lmap Target layer indexes (keys) and net regions (values) + * @param hier_mode See description of this method + * @param netname_prop An (optional) property name to which to attach the net name * @param circuit_cell_name_prefix See method description * @param net_cell_name_prefix See method description * @param device_cell_name_prefix See above */ - void build_all_nets (const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const; + void build_all_nets (const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const; + + /** + * @brief Like build_all_nets, but with the ability to select some nets + */ + void build_nets (const std::vector *nets, const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const; /** * @brief Finds the net by probing a specific location on the given layer @@ -531,11 +663,42 @@ public: */ db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector > &diodes = std::vector > ()); + /** + * @brief Saves the database to the given path + * + * Currently, the internal format will be used. If "short_format" is true, the short version + * of the format is used. + * + * This is a convenience method. The low-level functionality is the LayoutToNetlistWriter. + */ + void save (const std::string &path, bool short_format); + + /** + * @brief Loads the database from the given path + * + * This is a convenience method. The low-level functionality is the LayoutToNetlistReader. + */ + void load (const std::string &path); + + /** + * @brief Creates a LayoutToNetlist object from a file + * + * This method analyses the file and will create a LayoutToNetlist object + * or one of a derived class (specifically LayoutVsSchematic). + * + * The returned object is new'd one and must be deleted by the caller. + */ + static db::LayoutToNetlist *create_from_file (const std::string &path); + private: // no copying LayoutToNetlist (const db::LayoutToNetlist &other); LayoutToNetlist &operator= (const db::LayoutToNetlist &other); + std::string m_description; + std::string m_name; + std::string m_original_file; + std::string m_filename; db::RecursiveShapeIterator m_iter; std::auto_ptr mp_internal_dss; tl::weak_ptr mp_dss; @@ -550,12 +713,45 @@ private: bool m_is_flat; db::DeepLayer m_dummy_layer; + struct CellReuseTableKey + { + CellReuseTableKey (db::cell_index_type _cell_index, db::properties_id_type _netname_propid, size_t _cluster_id) + : cell_index (_cell_index), netname_propid (_netname_propid), cluster_id (_cluster_id) + { + // .. nothing yet .. + } + + bool operator< (const CellReuseTableKey &other) const + { + if (cell_index != other.cell_index) { + return cell_index < other.cell_index; + } + if (netname_propid != other.netname_propid) { + return netname_propid < other.netname_propid; + } + if (cluster_id != other.cluster_id) { + return cluster_id < other.cluster_id; + } + return false; + } + + db::cell_index_type cell_index; + db::properties_id_type netname_propid; + size_t cluster_id; + }; + + typedef std::map cell_reuse_table_type; + void init (); size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path); - void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const ICplxTrans &tr) const; - void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const Net *net, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const ICplxTrans &tr) const; + void build_net_rec (const db::Net &net, db::Layout &target, cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; + void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; + void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const Net *net, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; db::DeepLayer deep_layer_of (const db::Region ®ion) const; void ensure_layout () const; + std::string make_new_name (const std::string &stem = std::string ()); + db::properties_id_type make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const; + db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector *nets, bool with_device_cells); }; } diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index 3a00f45e0..eabcaa83a 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -27,49 +27,57 @@ namespace db namespace l2n_std_format { - template<> DB_PUBLIC const std::string keys::version_key ("version"); - template<> DB_PUBLIC const std::string keys::description_key ("description"); - template<> DB_PUBLIC const std::string keys::top_key ("top"); - template<> DB_PUBLIC const std::string keys::unit_key ("unit"); - template<> DB_PUBLIC const std::string keys::layer_key ("layer"); - template<> DB_PUBLIC const std::string keys::connect_key ("connect"); - template<> DB_PUBLIC const std::string keys::global_key ("global"); - template<> DB_PUBLIC const std::string keys::circuit_key ("circuit"); - template<> DB_PUBLIC const std::string keys::net_key ("net"); - template<> DB_PUBLIC const std::string keys::name_key ("name"); - template<> DB_PUBLIC const std::string keys::device_key ("device"); - template<> DB_PUBLIC const std::string keys::polygon_key ("polygon"); - template<> DB_PUBLIC const std::string keys::rect_key ("rect"); - template<> DB_PUBLIC const std::string keys::terminal_key ("terminal"); - template<> DB_PUBLIC const std::string keys::abstract_key ("abstract"); - template<> DB_PUBLIC const std::string keys::param_key ("param"); - template<> DB_PUBLIC const std::string keys::location_key ("location"); - template<> DB_PUBLIC const std::string keys::rotation_key ("rotation"); - template<> DB_PUBLIC const std::string keys::mirror_key ("mirror"); - template<> DB_PUBLIC const std::string keys::scale_key ("scale"); - template<> DB_PUBLIC const std::string keys::pin_key ("pin"); + const char *l2n_magic_string_cstr = "#%l2n-klayout"; - template<> DB_PUBLIC const std::string keys::version_key ("V"); - template<> DB_PUBLIC const std::string keys::description_key ("B"); - template<> DB_PUBLIC const std::string keys::top_key ("W"); - template<> DB_PUBLIC const std::string keys::unit_key ("U"); - template<> DB_PUBLIC const std::string keys::layer_key ("L"); - template<> DB_PUBLIC const std::string keys::connect_key ("C"); - template<> DB_PUBLIC const std::string keys::global_key ("G"); - template<> DB_PUBLIC const std::string keys::circuit_key ("X"); - template<> DB_PUBLIC const std::string keys::net_key ("N"); - template<> DB_PUBLIC const std::string keys::name_key ("I"); - template<> DB_PUBLIC const std::string keys::device_key ("D"); - template<> DB_PUBLIC const std::string keys::polygon_key ("Q"); - template<> DB_PUBLIC const std::string keys::rect_key ("R"); - template<> DB_PUBLIC const std::string keys::terminal_key ("T"); - template<> DB_PUBLIC const std::string keys::abstract_key ("A"); - template<> DB_PUBLIC const std::string keys::param_key ("E"); - template<> DB_PUBLIC const std::string keys::location_key ("Y"); - template<> DB_PUBLIC const std::string keys::rotation_key ("O"); - template<> DB_PUBLIC const std::string keys::mirror_key ("M"); - template<> DB_PUBLIC const std::string keys::scale_key ("S"); - template<> DB_PUBLIC const std::string keys::pin_key ("P"); + DB_PUBLIC std::string LongKeys::l2n_magic_string (l2n_magic_string_cstr); + DB_PUBLIC std::string ShortKeys::l2n_magic_string (l2n_magic_string_cstr); + + DB_PUBLIC std::string LongKeys::version_key ("version"); + DB_PUBLIC std::string LongKeys::description_key ("description"); + DB_PUBLIC std::string LongKeys::top_key ("top"); + DB_PUBLIC std::string LongKeys::unit_key ("unit"); + DB_PUBLIC std::string LongKeys::layer_key ("layer"); + DB_PUBLIC std::string LongKeys::class_key ("class"); + DB_PUBLIC std::string LongKeys::connect_key ("connect"); + DB_PUBLIC std::string LongKeys::global_key ("global"); + DB_PUBLIC std::string LongKeys::circuit_key ("circuit"); + DB_PUBLIC std::string LongKeys::net_key ("net"); + DB_PUBLIC std::string LongKeys::name_key ("name"); + DB_PUBLIC std::string LongKeys::device_key ("device"); + DB_PUBLIC std::string LongKeys::polygon_key ("polygon"); + DB_PUBLIC std::string LongKeys::rect_key ("rect"); + DB_PUBLIC std::string LongKeys::terminal_key ("terminal"); + DB_PUBLIC std::string LongKeys::abstract_key ("abstract"); + DB_PUBLIC std::string LongKeys::param_key ("param"); + DB_PUBLIC std::string LongKeys::location_key ("location"); + DB_PUBLIC std::string LongKeys::rotation_key ("rotation"); + DB_PUBLIC std::string LongKeys::mirror_key ("mirror"); + DB_PUBLIC std::string LongKeys::scale_key ("scale"); + DB_PUBLIC std::string LongKeys::pin_key ("pin"); + + // A, B, C, D, E, G, I, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y + DB_PUBLIC std::string ShortKeys::version_key ("V"); + DB_PUBLIC std::string ShortKeys::description_key ("B"); + DB_PUBLIC std::string ShortKeys::top_key ("W"); + DB_PUBLIC std::string ShortKeys::unit_key ("U"); + DB_PUBLIC std::string ShortKeys::layer_key ("L"); + DB_PUBLIC std::string ShortKeys::class_key ("K"); + DB_PUBLIC std::string ShortKeys::connect_key ("C"); + DB_PUBLIC std::string ShortKeys::global_key ("G"); + DB_PUBLIC std::string ShortKeys::circuit_key ("X"); + DB_PUBLIC std::string ShortKeys::net_key ("N"); + DB_PUBLIC std::string ShortKeys::name_key ("I"); + DB_PUBLIC std::string ShortKeys::device_key ("D"); + DB_PUBLIC std::string ShortKeys::polygon_key ("Q"); + DB_PUBLIC std::string ShortKeys::rect_key ("R"); + DB_PUBLIC std::string ShortKeys::terminal_key ("T"); + DB_PUBLIC std::string ShortKeys::abstract_key ("A"); + DB_PUBLIC std::string ShortKeys::param_key ("E"); + DB_PUBLIC std::string ShortKeys::location_key ("Y"); + DB_PUBLIC std::string ShortKeys::rotation_key ("O"); + DB_PUBLIC std::string ShortKeys::mirror_key ("M"); + DB_PUBLIC std::string ShortKeys::scale_key ("S"); + DB_PUBLIC std::string ShortKeys::pin_key ("P"); } } diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 8bb38dbec..8d70abcbc 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -52,35 +52,69 @@ namespace db * description() - an arbitrary description text [short key: B] * unit() - specifies the database unit [short key: U] * top() - specifies the name of the top circuit [short key: W] - * layer() - define a layer [short key: L] + * layer( ?) - define a layer [short key: L] * connect( ...) - connects layer1 with the following layers [short key: C] * global( ...) * - connects the shapes of the layer with the given global * nets [short key: G] * circuit( [circuit-def]) - circuit (cell) [short key: X] + * class(