mirror of https://github.com/KLayout/klayout.git
WIP: enhancements to DRC DSL for net extraction, some bug fixes in L2N browser etc.
This commit is contained in:
parent
0f9c50c405
commit
464a1f35fb
|
|
@ -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<DeepShapeStore *> (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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 ()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,9 @@ Class<db::LayoutToNetlist> 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<db::LayoutToNetlist> 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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,6 @@ module DRC
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue