diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index e7fc66bcb..9d3f117d1 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -235,6 +235,11 @@ struct DeepShapeStore::LayoutHolder return m_empty_layer; } + unsigned int new_empty_layer () + { + return layout.insert_layer (); + } + void add_layer_ref (unsigned int layer) { layer_refs [layer] += 1; @@ -577,6 +582,17 @@ DeepLayer DeepShapeStore::empty_layer () const return empty_layer (0); } +DeepLayer DeepShapeStore::new_empty_layer (unsigned int layout_index) const +{ + return DeepLayer (const_cast (this), layout_index, m_layouts[layout_index]->new_empty_layer ()); +} + +DeepLayer DeepShapeStore::new_empty_layer () const +{ + require_singular (); + return new_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); diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 2c92f39f7..ff914a621 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -356,6 +356,19 @@ public: */ DeepLayer empty_layer () const; + /** + * @brief Gets a new empty working layer + * + * This method will deliver an empty layer for the given layout index. This layer is a fresh one and can be + * modified. + */ + DeepLayer new_empty_layer (unsigned int layout_index) const; + + /** + * @brief Gets a new empty working layer for the singular layout + */ + DeepLayer new_empty_layer () const; + /** * @brief Inserts the deep layer's shapes into some target layout */ diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index eb72fad6e..ad86e969d 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -92,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); diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 5e61137c7..cb5485a8b 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -114,6 +114,11 @@ 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 */ diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index b2b4218a0..cfaa1e352 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -154,7 +154,8 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo l = layer_map.find (ln); } - throw tl::Exception (tl::to_string (tr ("Missing input layer for device extraction: ")) + layer_names); + // TODO: maybe use empty layers for optional ones? + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Missing input layer for device extraction (device %s): %s")), name (), layer_names)); } @@ -167,8 +168,9 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo // use deep layer alias for a given flat one (if found) layers.push_back (alias.second.layer ()); } else if (l->second->empty ()) { - // provide a substitute empty layer - layers.push_back (dss.empty_layer (layout_index).layer ()); + // provide a substitute empty layer (CAUTION: we can't use the + // singleton "empty_layer" because this may be used as OUTPUT). + layers.push_back (dss.new_empty_layer (layout_index).layer ()); } else { throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction (device %s): must be of deep region kind")), ld->name, name ())); } diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index c7db7b5fe..02b8d31a1 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -147,7 +147,9 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "add layers (regions) inside the 'dss' object.\n" "\n" "The make_... methods will not create new layers as there is no particular place " - "defined where to create the layers." + "defined where to create the layers.\n" + "\n" + "The extractor will not take ownership of the dss object unless you call \\keep_dss." ) + gsi::constructor ("new", &make_l2n_from_existing_dss_with_layout, gsi::arg ("dss"), gsi::arg ("layout_index"), "@brief Creates a new extractor object reusing an existing \\DeepShapeStore object\n" @@ -167,6 +169,12 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "The database unit is mandatory because the physical parameter extraction " "for devices requires this unit for translation of layout to physical dimensions.\n" ) + + gsi::method ("dss", (db::DeepShapeStore &(db::LayoutToNetlist::*) ()) &db::LayoutToNetlist::dss, + "@brief Gets a reference to the internal DSS object.\n" + ) + + gsi::method ("keep_dss", &db::LayoutToNetlist::keep_dss, + "@brief Resumes ownership over the DSS object if created with an external one.\n" + ) + gsi::method ("threads=", &db::LayoutToNetlist::set_threads, gsi::arg ("n"), "@brief Sets the number of threads to use for operations which support multiple threads\n" ) + diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 0029eb3dd..b02612ab3 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -20,6 +20,7 @@ module DRC @def_layout = cv && cv.layout @def_cell = cv && cv.cell + @def_path = cv && cv.filename @def_source = nil @dbu_read = false use_dbu(@def_layout && @def_layout.dbu) @@ -27,6 +28,11 @@ module DRC @output_rdb = nil @output_rdb_file = nil @output_rdb_cell = nil + @output_l2ndb = nil + @output_l2ndb_file = nil + @target_netlist_file = nil + @target_netlist_format = nil + @target_netlist_comment = nil @used_output_layers = {} @output_layers = [] @vnum = 1 @@ -109,6 +115,128 @@ module DRC DRCAsDots::new(false) end + # %DRC% + # @brief Defines SPICE output format (with options) + # @name write_spice + # @synopsis write_spice([ use_net_names [, with_comments ] ]) + # Use this option in \target_netlist for the format parameter to + # specify SPICE format. + # "use_net_names" and "with_comments" are boolean parameters indicating + # whether to use named nets (numbers if false) and whether to add + # information comments such as instance coordinates or pin names. + + def write_spice(use_net_names = nil, with_comments = nil) + writer = RBA::NetlistSpiceWriter::new + if use_net_names != nil + writer.use_net_names = use_net_names + end + if with_comments != nil + writer.with_comments = with_comments + end + writer + end + + # %DRC% + # @brief Supplies the MOS3 transistor extractor class + # @name mos3 + # @synopsis mos3(name) + # Use this class with \device_extract to specify extraction of a + # three-terminal MOS transistor + + def mos3(name) + RBA::DeviceExtractorMOS3Transistor::new(name) + end + + # %DRC% + # @brief Supplies the MOS4 transistor extractor class + # @name mos4 + # @synopsis mos4(name) + # Use this class with \device_extract to specify extraction of a + # four-terminal MOS transistor + + def mos4(name) + RBA::DeviceExtractorMOS4Transistor::new(name) + end + + # %DRC% + # @brief Supplies the BJT3 transistor extractor class + # @name bjt3 + # @synopsis bjt3(name) + # Use this class with \device_extract to specify extraction of a + # bipolar junction transistor + + def bjt3(name) + RBA::DeviceExtractorBJT3Transistor::new(name) + end + + # %DRC% + # @brief Supplies the BJT4 transistor extractor class + # @name bjt4 + # @synopsis bjt4(name) + # Use this class with \device_extract to specify extraction of a + # bipolar junction transistor with a substrate terminal + + def bjt4(name) + RBA::DeviceExtractorBJT4Transistor::new(name) + end + + # %DRC% + # @brief Supplies the diode extractor class + # @name diode + # @synopsis diode(name) + # Use this class with \device_extract to specify extraction of a + # planar diode + + def diode(name) + RBA::DeviceExtractorDiode::new(name) + end + + # %DRC% + # @brief Supplies the resistor extractor class + # @name resistor + # @synopsis resistor(name, sheet_rho) + # Use this class with \device_extract to specify extraction of a resistor. + # The sheet_rho value is the sheet resistance in ohms/square. + + def resistor(name, sheet_rho) + RBA::DeviceExtractorResistor::new(name, sheet_rho) + end + + # %DRC% + # @brief Supplies the resistor extractor class that includes a bulk terminal + # @name resistor_with_bulk + # @synopsis resistor_with_bulk(name) + # Use this class with \device_extract to specify extraction of a resistor + # with a bulk terminal. + # The sheet_rho value is the sheet resistance in ohms/square. + + def resistor_with_bulk(name, sheet_rho) + RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho) + end + + # %DRC% + # @brief Supplies the capacitor extractor class + # @name capacitor + # @synopsis capacitor(name, area_cap) + # Use this class with \device_extract to specify extraction of a capacitor. + # The area_cap argument is the capacitance in Farad per square micrometer. + + def capacitor(name, area_cap) + RBA::DeviceExtractorCapacitor::new(name, area_cap) + end + + # %DRC% + # @brief Supplies the capacitor extractor class that includes a bulk terminal + # @name capacitor_with_bulk + # @synopsis capacitor_with_bulk(name) + # Use this class with \device_extract to specify extraction of a capacitor + # with a bulk terminal. + # The area_cap argument is the capacitance in Farad per square micrometer. + + def capacitor_with_bulk(name, area_cap) + RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap) + end + # %DRC% # @name verbose? # @brief Returns true, if verbose mode is enabled @@ -451,7 +579,7 @@ module DRC (n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}") cv = view.cellview(n) cv.is_valid? || raise("Invalid layout @#{n + 1}") - @def_source = make_source(cv.layout, cv.cell) + @def_source = make_source(cv.layout, cv.cell, cv.filename) else layout = RBA::Layout::new info("Reading #{arg} ..") @@ -462,7 +590,7 @@ module DRC cell = layout.cell(arg2) cell || raise("Cell name #{arg2} not found in input layout") end - @def_source = make_source(layout, cell) + @def_source = make_source(layout, cell, arg) end elsif arg.is_a?(RBA::Layout) @@ -484,12 +612,13 @@ module DRC else @def_source || @def_layout || raise("No layout loaded - no default layout. Use 'layout' or 'source' to explicitly specify a layout.") - @def_source ||= make_source(@def_layout, @def_cell) + @def_source ||= make_source(@def_layout, @def_cell, @def_path) end # make default input also default output if none is set yet. @def_layout ||= @def_source.layout @def_cell ||= @def_source.cell_obj + @def_path ||= @def_source.path # use the DBU of the new input as DBU reference @dbu_read || use_dbu(@def_source.layout.dbu) @@ -545,7 +674,7 @@ module DRC (n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}") cv = view.cellview(n) cv.is_valid? || raise("Invalid layout @#{n + 1}") - return make_source(cv.layout, cv.cell) + return make_source(cv.layout, cv.cell, cv.filename) else layout = RBA::Layout::new info("Reading #{arg} ..") @@ -556,7 +685,7 @@ module DRC cell = layout.cell(arg2) cell || raise("Cell name #{arg2} not found in input layout") end - return make_source(layout, cell) + return make_source(layout, cell, arg) end elsif arg.is_a?(RBA::Layout) @@ -569,7 +698,7 @@ module DRC else @def_source || @def_layout || raise("No layout loaded - no default layout. Use 'layout' or 'source' to explicitly specify a layout.") - @def_source ||= make_source(@def_layout, @def_cell) + @def_source ||= make_source(@def_layout, @def_cell, @def_path) @def_source end @@ -627,7 +756,53 @@ module DRC @output_rdb.description = description end + + # %DRC% + # @name report_netlist + # @brief Specifies an extracted netlist report for output + # @synopsis report_netlist([ filename ]) + # This method applies to runsets creating a netlist through + # extraction. Extraction happens when connections and/or device + # extractions are made. If this statement is used, the extracted + # netlist plus the net and device shapes are turned into a + # layout-to-netlist report (L2N database) and shown in the + # netlist browser window. If a file name is given, the report + # will also be written to the given file. + def report_netlist(filename = nil) + @output_l2ndb = true + if filename + filename.is_a?(String) || raise("Argument must be string in report_netlist") + end + @output_l2ndb_file = filename + end + + # %DRC% + # @name target_netlist + # @brief With this statement, an extracted netlist is finally written to a file + # @synopsis target_netlist(filename [, format [, comment ] ]) + # This method applies to runsets creating a netlist through + # extraction. Extraction happens when connections and/or device + # extractions are made. If this statement is used, the extracted + # netlist is written to the given file. + # + # The format parameter specifies the writer to use. You can use nil + # to use the standard format or produce a SPICE writer with \write_spice. + # See \write_spice for more details. + + def target_netlist(filename, format = nil, comment = nil) + filename.is_a?(String) || raise("First argument must be string in target_netlist") + @target_netlist_file = filename + if format + format.is_a?(RBA::NetlistWriter) || raise("Second argument must be netlist writer object in target_netlist") + end + @target_netlist_format = format + if comment + comment.is_a?(String) || raise("Third argument must be string in target_netlist") + end + @target_netlist_comment = comment + end + # %DRC% # @name output_cell # @brief Specifies a target cell, but does not change the target layout @@ -958,33 +1133,41 @@ CODE # @name clear_connections # @brief Clears all connections stored so far # @synopsis clear_connections - # See \Netter#clear_connections for a description of that function + # See \Netter#clear_connections for a description of that function. # %DRC% - # @name join_nets + # @name connect_implicit # @brief Specifies a label pattern for implicit net connections - # @synopsis join_nets(label_pattern) - # See \Netter#join_nets for a description of that function + # @synopsis connect_implicit(label_pattern) + # See \Netter#connect_implicit for a description of that function. # %DRC% # @name antenna_check # @brief Performs an antenna check # @synopsis antenna_check(gate, metal, ratio, [ diode_specs ... ]) - # See \Netter#antenna_check for a description of that function + # See \Netter#antenna_check for a description of that function. # %DRC% # @name l2n_data # @brief Gets the internal RBA::LayoutToNetlist object for the default \Netter # @synopsis l2n_data - # See \Netter#l2n_data for a description of that function + # See \Netter#l2n_data for a description of that function. # %DRC% # @name extract_devices # @brief Extracts devices for a given device extractor and device layer selection # @synopsis extract_devices(extractor, layer_hash) - # See \Netter#extract_devices for a description of that function + # @synopsis extract_devices(extractor_class, name, layer_hash) + # See \Netter#extract_devices for a description of that function. - %w(connect connect_global clear_connections join_nets antenna_check l2n_data extract_devices).each do |f| + # %DRC% + # @name netlist + # @brief Obtains the extracted netlist from the default \Netter + # The netlist is a RBA::Netlist object. If no netlist is extracted + # yet, this method will trigger the extraction process. + # See \Netter#netlist for a description of this function. + + %w(connect connect_global clear_connections connect_implicit antenna_check l2n_data extract_devices netlist).each do |f| eval <<"CODE" def #{f}(*args) _netter.#{f}(*args) @@ -1154,8 +1337,9 @@ CODE # save the report database if requested if @output_rdb_file - info("Writing #{@output_rdb_file} ..") - @output_rdb.save(@output_rdb_file) + rdb_file = make_path(@output_rdb_file) + info("Writing report database: #{rdb_file} ..") + @output_rdb.save(rdb_file) end if @output_rdb && final && view view.show_rdb(@output_rdb_index, view.active_cellview_index) @@ -1165,7 +1349,7 @@ CODE if @output_layout && @output_layout_file opt = RBA::SaveLayoutOptions::new gzip = opt.set_format_from_filename(@output_layout_file) - info("Writing #{@output_layout_file} ..") + info("Writing layout file: #{@output_layout_file} ..") @output_layout.write(@output_layout_file, gzip, opt) end @@ -1213,7 +1397,41 @@ CODE end end - + + # save the netlist if required + if @target_netlist_file && @netter && @netter.l2n_data + + writer = @target_netlist_format || RBA::NetlistSpiceWriter::new + + netlist_file = make_path(@target_netlist_file) + info("Writing netlist: #{netlist_file} ..") + self.netlist.write(netlist_file, writer, @target_netlist_comment || "") + + end + + # save the netlist database if requested + if @output_l2ndb && @netter && @netter.l2n_data + + if @output_l2ndb_file + l2ndb_file = make_path(@output_l2ndb_file) + info("Writing netlist database: #{l2ndb_file} ..") + @netter.l2n_data.save(l2ndb_file) + end + if @output_l2ndb && final && view + # NOTE: to prevent the netter destroying the database, we need to take it + l2ndb = @netter._take_l2n_data + # we also need to make the extractor take over ownership over the DSS + # because otherwise we can't free the resources. + if l2ndb.dss == @dss + l2ndb.keep_dss + @dss = nil + end + l2ndb_index = view.add_l2ndb(l2ndb) + view.show_l2ndb(l2ndb_index, view.active_cellview_index) + end + + end + @output_layout = nil @output_layout_file = nil @output_cell = nil @@ -1221,6 +1439,8 @@ CODE @output_rdb_cell = nil @output_rdb = nil @output_rdb_index = nil + @output_l2ndb = nil + @output_l2ndb_file = nil # clean up temp data @dss && @dss._destroy @@ -1243,6 +1463,16 @@ CODE private + def make_path(file) + # resolves the file path relative to the source's path + sp = self.source.path + if sp + return File::absolute_path(file, File::dirname(sp)) + else + return file + end + end + def _make_string(v) if v.class.respond_to?(:from_s) v.class.to_s + "::from_s(" + v.to_s.inspect + ")" @@ -1399,11 +1629,11 @@ CODE end end - def make_source(layout, cell = nil) + def make_source(layout, cell = nil, path = nil) name = "layout" + @lnum.to_s @lnum += 1 @dbu ||= layout.dbu - src = DRCSource::new(self, layout, layout, cell || layout.top_cell) + src = DRCSource::new(self, layout, layout, cell || layout.top_cell, path) @layout_sources[name] = src src end diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index eed364f48..de07f9413 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -119,10 +119,14 @@ module DRC # @name extract_devices # @brief Extracts devices based on the given extractor class, name and device layer selection # @synopsis extract_devices(extractor, layer_hash) - # Runs the device extraction for given device extractor class. + # @synopsis extract_devices(extractor_class, name, layer_hash) + # Runs the device extraction for given device extractor class. In the first + # form, the extractor object is given. In the second form, the extractor's + # class object and the new extractor's name is given. # # The device extractor is either an instance of one of the predefined extractor - # classes (e.g. RBA::DeviceExtractorMOS4Transistor) or a custom class. It provides the + # classes (e.g. obtained from the utility methods such as \mos4) or a custom class. + # It provides the # algorithms for deriving the device parameters from the device geometry. It needs # several device recognition layers which are passed in the layer hash. # @@ -141,17 +145,17 @@ module DRC # poly = input(3, 0) # bulk = make_layer # renders an empty layer used for putting the terminals on # - # nactive = active - nwell # active area of NMOS - # nsd = nactive - poly # source/drain area + # nactive = active - nwell # active area of NMOS + # nsd = nactive - poly # source/drain area # gate = nactive & poly # gate area # - # mos4_ex = RBA::DeviceExtractorMOS4Transistor::new("NMOS4") - # extract_devices(mos4_ex, { :SD => nsd, :G => gate, :P => poly, :W => bulk }) + # extract_devices(mos4("NMOS4"), { :SD => nsd, :G => gate, :P => poly, :W => bulk }) # @/code def extract_devices(devex, layer_selection) - devex.is_a?(RBA::DeviceExtractorBase) || raise("First argument of Netter#extract_devices must be a device extractor instance") + devex.is_a?(RBA::DeviceExtractorBase) || raise("First argument of Netter#extract_devices must be a device extractor instance in the two-arguments form") + layer_selection.is_a?(Hash) || raise("Second argument of Netter#extract_devices must be a hash") ls = {} @@ -177,20 +181,20 @@ module DRC @connections = [] @global_connections = [] @layers = {} - @join_nets = "" + @connect_implicit = "" modified end # %DRC% - # @name join_nets + # @name connect_implicit # @brief Specifies a search pattern for labels which create implicit net connections - # @synopsis join_nets(label_pattern) + # @synopsis connect_implicit(label_pattern) # Use this method to supply a glob pattern for labels which create implicit net connections # on the top level circuit. This feature is useful to connect identically labelled nets # while a component isn't integrated yet. If the component is integrated, net may be connected # on a higher hierarchy level - e.g. by a power mesh. Inside the component this net consists # of individual islands. To properly perform netlist extraction and comparison, these islands - # need to be connected even though there isn't a physical connection. "join_nets" can + # need to be connected even though there isn't a physical connection. "connect_implicit" can # achive this if these islands are labelled with the same text on the top level of the # component. # @@ -202,8 +206,8 @@ module DRC # The search pattern is applied on the next net extraction. The search pattern is cleared # on "clear_connections". - def join_nets(arg) - @join_nets = arg + def connect_implicit(arg) + @connect_implicit = arg modified end @@ -320,6 +324,18 @@ module DRC @l2n || make_l2n @l2n end + + # %DRC% + # @name netlist + # @brief Gets the extracted netlist or triggers extraction if not done yet + # @synopsis netlist + # If no extraction has been performed yet, this method will start the + # layout analysis. Hence, all \connect, \connect_global and \connect_implicit + # calls must have been made before this method is used. Further \connect + # statements will clear the netlist and re-extract it again. + def netlist + l2n_data && @l2n.netlist + end def _finish clear_connections @@ -327,6 +343,12 @@ module DRC modified end + def _take_l2n_data + l2ndb = self.l2n_data + @l2n = nil + l2ndb + end + private def modified @@ -357,7 +379,7 @@ module DRC @global_connections.each { |l,n| @l2n.connect_global(@layers[l], n) } # run extraction in a timed environment - @engine._cmd(@l2n, :extract_netlist, @join_nets) + @engine._cmd(@l2n, :extract_netlist, @connect_implicit) @l2n end diff --git a/src/drc/drc/built-in-macros/_drc_source.rb b/src/drc/drc/built-in-macros/_drc_source.rb index 90973a7ce..d278d534e 100644 --- a/src/drc/drc/built-in-macros/_drc_source.rb +++ b/src/drc/drc/built-in-macros/_drc_source.rb @@ -16,10 +16,11 @@ module DRC class DRCSource - def initialize(engine, layout, layout_var, cell) + def initialize(engine, layout, layout_var, cell, path) @engine = engine @layout = layout @layout_var = layout_var + @path = path @cell = cell @inside = nil @box = nil @@ -355,6 +356,13 @@ CODE def layers @layout.layer_indices.collect { |li| @layout.get_info(li) } end + + # %DRC% + # @brief Gets the path of the corresponding layout file or nil if there is no path + # @synopsis path + def path + @path + end private diff --git a/src/drc/drc/built-in-macros/_drc_tags.rb b/src/drc/drc/built-in-macros/_drc_tags.rb index 510918dd0..d8f19dfae 100644 --- a/src/drc/drc/built-in-macros/_drc_tags.rb +++ b/src/drc/drc/built-in-macros/_drc_tags.rb @@ -111,6 +111,6 @@ module DRC end end end - + end diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index aeacbebb7..2bcad5d8f 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -708,6 +708,11 @@ NetlistBrowserPage::show_all (bool f) void NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) { + if (l2ndb == mp_database.get ()) { + // not change + return; + } + if (mp_info_dialog) { delete mp_info_dialog; mp_info_dialog = 0;