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;
|
return m_empty_layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int new_empty_layer ()
|
||||||
|
{
|
||||||
|
return layout.insert_layer ();
|
||||||
|
}
|
||||||
|
|
||||||
void add_layer_ref (unsigned int layer)
|
void add_layer_ref (unsigned int layer)
|
||||||
{
|
{
|
||||||
layer_refs [layer] += 1;
|
layer_refs [layer] += 1;
|
||||||
|
|
@ -577,6 +582,17 @@ DeepLayer DeepShapeStore::empty_layer () const
|
||||||
return empty_layer (0);
|
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)
|
DeepLayer DeepShapeStore::create_custom_layer (const db::RecursiveShapeIterator &si, HierarchyBuilderShapeReceiver *pipe, const db::ICplxTrans &trans)
|
||||||
{
|
{
|
||||||
unsigned int layout_index = layout_for_iter (si, trans);
|
unsigned int layout_index = layout_for_iter (si, trans);
|
||||||
|
|
|
||||||
|
|
@ -356,6 +356,19 @@ public:
|
||||||
*/
|
*/
|
||||||
DeepLayer empty_layer () const;
|
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
|
* @brief Inserts the deep layer's shapes into some target layout
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,14 @@ LayoutToNetlist::~LayoutToNetlist ()
|
||||||
m_net_clusters.clear ();
|
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 ()
|
void LayoutToNetlist::init ()
|
||||||
{
|
{
|
||||||
dss ().set_text_enlargement (1);
|
dss ().set_text_enlargement (1);
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,11 @@ public:
|
||||||
*/
|
*/
|
||||||
~LayoutToNetlist ();
|
~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
|
* @brief Gets the database description
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,8 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo
|
||||||
l = layer_map.find (ln);
|
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)
|
// use deep layer alias for a given flat one (if found)
|
||||||
layers.push_back (alias.second.layer ());
|
layers.push_back (alias.second.layer ());
|
||||||
} else if (l->second->empty ()) {
|
} else if (l->second->empty ()) {
|
||||||
// provide a substitute empty layer
|
// provide a substitute empty layer (CAUTION: we can't use the
|
||||||
layers.push_back (dss.empty_layer (layout_index).layer ());
|
// singleton "empty_layer" because this may be used as OUTPUT).
|
||||||
|
layers.push_back (dss.new_empty_layer (layout_index).layer ());
|
||||||
} else {
|
} 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 ()));
|
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"
|
"add layers (regions) inside the 'dss' object.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The make_... methods will not create new layers as there is no particular place "
|
"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"),
|
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"
|
"@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 "
|
"The database unit is mandatory because the physical parameter extraction "
|
||||||
"for devices requires this unit for translation of layout to physical dimensions.\n"
|
"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"),
|
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"
|
"@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_layout = cv && cv.layout
|
||||||
@def_cell = cv && cv.cell
|
@def_cell = cv && cv.cell
|
||||||
|
@def_path = cv && cv.filename
|
||||||
@def_source = nil
|
@def_source = nil
|
||||||
@dbu_read = false
|
@dbu_read = false
|
||||||
use_dbu(@def_layout && @def_layout.dbu)
|
use_dbu(@def_layout && @def_layout.dbu)
|
||||||
|
|
@ -27,6 +28,11 @@ module DRC
|
||||||
@output_rdb = nil
|
@output_rdb = nil
|
||||||
@output_rdb_file = nil
|
@output_rdb_file = nil
|
||||||
@output_rdb_cell = 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 = {}
|
@used_output_layers = {}
|
||||||
@output_layers = []
|
@output_layers = []
|
||||||
@vnum = 1
|
@vnum = 1
|
||||||
|
|
@ -109,6 +115,128 @@ module DRC
|
||||||
DRCAsDots::new(false)
|
DRCAsDots::new(false)
|
||||||
end
|
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%
|
# %DRC%
|
||||||
# @name verbose?
|
# @name verbose?
|
||||||
# @brief Returns true, if verbose mode is enabled
|
# @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}")
|
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||||
cv = view.cellview(n)
|
cv = view.cellview(n)
|
||||||
cv.is_valid? || raise("Invalid layout @#{n + 1}")
|
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
|
else
|
||||||
layout = RBA::Layout::new
|
layout = RBA::Layout::new
|
||||||
info("Reading #{arg} ..")
|
info("Reading #{arg} ..")
|
||||||
|
|
@ -462,7 +590,7 @@ module DRC
|
||||||
cell = layout.cell(arg2)
|
cell = layout.cell(arg2)
|
||||||
cell || raise("Cell name #{arg2} not found in input layout")
|
cell || raise("Cell name #{arg2} not found in input layout")
|
||||||
end
|
end
|
||||||
@def_source = make_source(layout, cell)
|
@def_source = make_source(layout, cell, arg)
|
||||||
end
|
end
|
||||||
|
|
||||||
elsif arg.is_a?(RBA::Layout)
|
elsif arg.is_a?(RBA::Layout)
|
||||||
|
|
@ -484,12 +612,13 @@ module DRC
|
||||||
|
|
||||||
else
|
else
|
||||||
@def_source || @def_layout || raise("No layout loaded - no default layout. Use 'layout' or 'source' to explicitly specify a layout.")
|
@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
|
end
|
||||||
|
|
||||||
# make default input also default output if none is set yet.
|
# make default input also default output if none is set yet.
|
||||||
@def_layout ||= @def_source.layout
|
@def_layout ||= @def_source.layout
|
||||||
@def_cell ||= @def_source.cell_obj
|
@def_cell ||= @def_source.cell_obj
|
||||||
|
@def_path ||= @def_source.path
|
||||||
|
|
||||||
# use the DBU of the new input as DBU reference
|
# use the DBU of the new input as DBU reference
|
||||||
@dbu_read || use_dbu(@def_source.layout.dbu)
|
@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}")
|
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||||
cv = view.cellview(n)
|
cv = view.cellview(n)
|
||||||
cv.is_valid? || raise("Invalid layout @#{n + 1}")
|
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
|
else
|
||||||
layout = RBA::Layout::new
|
layout = RBA::Layout::new
|
||||||
info("Reading #{arg} ..")
|
info("Reading #{arg} ..")
|
||||||
|
|
@ -556,7 +685,7 @@ module DRC
|
||||||
cell = layout.cell(arg2)
|
cell = layout.cell(arg2)
|
||||||
cell || raise("Cell name #{arg2} not found in input layout")
|
cell || raise("Cell name #{arg2} not found in input layout")
|
||||||
end
|
end
|
||||||
return make_source(layout, cell)
|
return make_source(layout, cell, arg)
|
||||||
end
|
end
|
||||||
|
|
||||||
elsif arg.is_a?(RBA::Layout)
|
elsif arg.is_a?(RBA::Layout)
|
||||||
|
|
@ -569,7 +698,7 @@ module DRC
|
||||||
|
|
||||||
else
|
else
|
||||||
@def_source || @def_layout || raise("No layout loaded - no default layout. Use 'layout' or 'source' to explicitly specify a layout.")
|
@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
|
@def_source
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -627,7 +756,53 @@ module DRC
|
||||||
@output_rdb.description = description
|
@output_rdb.description = description
|
||||||
|
|
||||||
end
|
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%
|
# %DRC%
|
||||||
# @name output_cell
|
# @name output_cell
|
||||||
# @brief Specifies a target cell, but does not change the target layout
|
# @brief Specifies a target cell, but does not change the target layout
|
||||||
|
|
@ -958,33 +1133,41 @@ CODE
|
||||||
# @name clear_connections
|
# @name clear_connections
|
||||||
# @brief Clears all connections stored so far
|
# @brief Clears all connections stored so far
|
||||||
# @synopsis clear_connections
|
# @synopsis clear_connections
|
||||||
# See \Netter#clear_connections for a description of that function
|
# See \Netter#clear_connections for a description of that function.
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name join_nets
|
# @name connect_implicit
|
||||||
# @brief Specifies a label pattern for implicit net connections
|
# @brief Specifies a label pattern for implicit net connections
|
||||||
# @synopsis join_nets(label_pattern)
|
# @synopsis connect_implicit(label_pattern)
|
||||||
# See \Netter#join_nets for a description of that function
|
# See \Netter#connect_implicit for a description of that function.
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name antenna_check
|
# @name antenna_check
|
||||||
# @brief Performs an antenna check
|
# @brief Performs an antenna check
|
||||||
# @synopsis antenna_check(gate, metal, ratio, [ diode_specs ... ])
|
# @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%
|
# %DRC%
|
||||||
# @name l2n_data
|
# @name l2n_data
|
||||||
# @brief Gets the internal RBA::LayoutToNetlist object for the default \Netter
|
# @brief Gets the internal RBA::LayoutToNetlist object for the default \Netter
|
||||||
# @synopsis l2n_data
|
# @synopsis l2n_data
|
||||||
# See \Netter#l2n_data for a description of that function
|
# See \Netter#l2n_data for a description of that function.
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name extract_devices
|
# @name extract_devices
|
||||||
# @brief Extracts devices for a given device extractor and device layer selection
|
# @brief Extracts devices for a given device extractor and device layer selection
|
||||||
# @synopsis extract_devices(extractor, layer_hash)
|
# @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"
|
eval <<"CODE"
|
||||||
def #{f}(*args)
|
def #{f}(*args)
|
||||||
_netter.#{f}(*args)
|
_netter.#{f}(*args)
|
||||||
|
|
@ -1154,8 +1337,9 @@ CODE
|
||||||
|
|
||||||
# save the report database if requested
|
# save the report database if requested
|
||||||
if @output_rdb_file
|
if @output_rdb_file
|
||||||
info("Writing #{@output_rdb_file} ..")
|
rdb_file = make_path(@output_rdb_file)
|
||||||
@output_rdb.save(@output_rdb_file)
|
info("Writing report database: #{rdb_file} ..")
|
||||||
|
@output_rdb.save(rdb_file)
|
||||||
end
|
end
|
||||||
if @output_rdb && final && view
|
if @output_rdb && final && view
|
||||||
view.show_rdb(@output_rdb_index, view.active_cellview_index)
|
view.show_rdb(@output_rdb_index, view.active_cellview_index)
|
||||||
|
|
@ -1165,7 +1349,7 @@ CODE
|
||||||
if @output_layout && @output_layout_file
|
if @output_layout && @output_layout_file
|
||||||
opt = RBA::SaveLayoutOptions::new
|
opt = RBA::SaveLayoutOptions::new
|
||||||
gzip = opt.set_format_from_filename(@output_layout_file)
|
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)
|
@output_layout.write(@output_layout_file, gzip, opt)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1213,7 +1397,41 @@ CODE
|
||||||
end
|
end
|
||||||
|
|
||||||
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 = nil
|
||||||
@output_layout_file = nil
|
@output_layout_file = nil
|
||||||
@output_cell = nil
|
@output_cell = nil
|
||||||
|
|
@ -1221,6 +1439,8 @@ CODE
|
||||||
@output_rdb_cell = nil
|
@output_rdb_cell = nil
|
||||||
@output_rdb = nil
|
@output_rdb = nil
|
||||||
@output_rdb_index = nil
|
@output_rdb_index = nil
|
||||||
|
@output_l2ndb = nil
|
||||||
|
@output_l2ndb_file = nil
|
||||||
|
|
||||||
# clean up temp data
|
# clean up temp data
|
||||||
@dss && @dss._destroy
|
@dss && @dss._destroy
|
||||||
|
|
@ -1243,6 +1463,16 @@ CODE
|
||||||
|
|
||||||
private
|
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)
|
def _make_string(v)
|
||||||
if v.class.respond_to?(:from_s)
|
if v.class.respond_to?(:from_s)
|
||||||
v.class.to_s + "::from_s(" + v.to_s.inspect + ")"
|
v.class.to_s + "::from_s(" + v.to_s.inspect + ")"
|
||||||
|
|
@ -1399,11 +1629,11 @@ CODE
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_source(layout, cell = nil)
|
def make_source(layout, cell = nil, path = nil)
|
||||||
name = "layout" + @lnum.to_s
|
name = "layout" + @lnum.to_s
|
||||||
@lnum += 1
|
@lnum += 1
|
||||||
@dbu ||= layout.dbu
|
@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
|
@layout_sources[name] = src
|
||||||
src
|
src
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -119,10 +119,14 @@ module DRC
|
||||||
# @name extract_devices
|
# @name extract_devices
|
||||||
# @brief Extracts devices based on the given extractor class, name and device layer selection
|
# @brief Extracts devices based on the given extractor class, name and device layer selection
|
||||||
# @synopsis extract_devices(extractor, layer_hash)
|
# @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
|
# 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
|
# algorithms for deriving the device parameters from the device geometry. It needs
|
||||||
# several device recognition layers which are passed in the layer hash.
|
# several device recognition layers which are passed in the layer hash.
|
||||||
#
|
#
|
||||||
|
|
@ -141,17 +145,17 @@ module DRC
|
||||||
# poly = input(3, 0)
|
# poly = input(3, 0)
|
||||||
# bulk = make_layer # renders an empty layer used for putting the terminals on
|
# bulk = make_layer # renders an empty layer used for putting the terminals on
|
||||||
#
|
#
|
||||||
# nactive = active - nwell # active area of NMOS
|
# nactive = active - nwell # active area of NMOS
|
||||||
# nsd = nactive - poly # source/drain area
|
# nsd = nactive - poly # source/drain area
|
||||||
# gate = nactive & poly # gate area
|
# gate = nactive & poly # gate area
|
||||||
#
|
#
|
||||||
# mos4_ex = RBA::DeviceExtractorMOS4Transistor::new("NMOS4")
|
# extract_devices(mos4("NMOS4"), { :SD => nsd, :G => gate, :P => poly, :W => bulk })
|
||||||
# extract_devices(mos4_ex, { :SD => nsd, :G => gate, :P => poly, :W => bulk })
|
|
||||||
# @/code
|
# @/code
|
||||||
|
|
||||||
def extract_devices(devex, layer_selection)
|
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")
|
layer_selection.is_a?(Hash) || raise("Second argument of Netter#extract_devices must be a hash")
|
||||||
|
|
||||||
ls = {}
|
ls = {}
|
||||||
|
|
@ -177,20 +181,20 @@ module DRC
|
||||||
@connections = []
|
@connections = []
|
||||||
@global_connections = []
|
@global_connections = []
|
||||||
@layers = {}
|
@layers = {}
|
||||||
@join_nets = ""
|
@connect_implicit = ""
|
||||||
modified
|
modified
|
||||||
end
|
end
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name join_nets
|
# @name connect_implicit
|
||||||
# @brief Specifies a search pattern for labels which create implicit net connections
|
# @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
|
# 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
|
# 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
|
# 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
|
# 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
|
# 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
|
# achive this if these islands are labelled with the same text on the top level of the
|
||||||
# component.
|
# component.
|
||||||
#
|
#
|
||||||
|
|
@ -202,8 +206,8 @@ module DRC
|
||||||
# The search pattern is applied on the next net extraction. The search pattern is cleared
|
# The search pattern is applied on the next net extraction. The search pattern is cleared
|
||||||
# on "clear_connections".
|
# on "clear_connections".
|
||||||
|
|
||||||
def join_nets(arg)
|
def connect_implicit(arg)
|
||||||
@join_nets = arg
|
@connect_implicit = arg
|
||||||
modified
|
modified
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -320,6 +324,18 @@ module DRC
|
||||||
@l2n || make_l2n
|
@l2n || make_l2n
|
||||||
@l2n
|
@l2n
|
||||||
end
|
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
|
def _finish
|
||||||
clear_connections
|
clear_connections
|
||||||
|
|
@ -327,6 +343,12 @@ module DRC
|
||||||
modified
|
modified
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def _take_l2n_data
|
||||||
|
l2ndb = self.l2n_data
|
||||||
|
@l2n = nil
|
||||||
|
l2ndb
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def modified
|
def modified
|
||||||
|
|
@ -357,7 +379,7 @@ module DRC
|
||||||
@global_connections.each { |l,n| @l2n.connect_global(@layers[l], n) }
|
@global_connections.each { |l,n| @l2n.connect_global(@layers[l], n) }
|
||||||
|
|
||||||
# run extraction in a timed environment
|
# run extraction in a timed environment
|
||||||
@engine._cmd(@l2n, :extract_netlist, @join_nets)
|
@engine._cmd(@l2n, :extract_netlist, @connect_implicit)
|
||||||
@l2n
|
@l2n
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,11 @@ module DRC
|
||||||
|
|
||||||
class DRCSource
|
class DRCSource
|
||||||
|
|
||||||
def initialize(engine, layout, layout_var, cell)
|
def initialize(engine, layout, layout_var, cell, path)
|
||||||
@engine = engine
|
@engine = engine
|
||||||
@layout = layout
|
@layout = layout
|
||||||
@layout_var = layout_var
|
@layout_var = layout_var
|
||||||
|
@path = path
|
||||||
@cell = cell
|
@cell = cell
|
||||||
@inside = nil
|
@inside = nil
|
||||||
@box = nil
|
@box = nil
|
||||||
|
|
@ -355,6 +356,13 @@ CODE
|
||||||
def layers
|
def layers
|
||||||
@layout.layer_indices.collect { |li| @layout.get_info(li) }
|
@layout.layer_indices.collect { |li| @layout.get_info(li) }
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,6 @@ module DRC
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -708,6 +708,11 @@ NetlistBrowserPage::show_all (bool f)
|
||||||
void
|
void
|
||||||
NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
|
NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
|
||||||
{
|
{
|
||||||
|
if (l2ndb == mp_database.get ()) {
|
||||||
|
// not change
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mp_info_dialog) {
|
if (mp_info_dialog) {
|
||||||
delete mp_info_dialog;
|
delete mp_info_dialog;
|
||||||
mp_info_dialog = 0;
|
mp_info_dialog = 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue