mirror of
https://github.com/KLayout/klayout.git
synced 2026-09-07 03:21:34 +02:00
Added "device_scaling" to LVS
Plus: added some missing files Implementation details: * scaling factor was introduced in DeviceExtractor::extract * for easy implementation this is available in "sdbu" * "sdbu" is made available in GSI * to test this, the db::compare_netlist had to be enhanced to exactly check device parameters * enhancement of LVS script framework and doc updates
This commit is contained in:
@@ -97,6 +97,41 @@ EqualDeviceParameters &EqualDeviceParameters::operator+= (const EqualDeviceParam
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// AllDeviceParametersAreEqual class implementation
|
||||
|
||||
AllDeviceParametersAreEqual::AllDeviceParametersAreEqual (double relative)
|
||||
: m_relative (relative)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool AllDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b) const
|
||||
{
|
||||
const std::vector<db::DeviceParameterDefinition> ¶meters = a.device_class ()->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator c = parameters.begin (); c != parameters.end (); ++c) {
|
||||
int cmp = compare_parameters (a.parameter_value (c->id ()), b.parameter_value (c->id ()), 0.0, m_relative);
|
||||
if (cmp != 0) {
|
||||
return cmp < 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AllDeviceParametersAreEqual::equal (const db::Device &a, const db::Device &b) const
|
||||
{
|
||||
const std::vector<db::DeviceParameterDefinition> ¶meters = a.device_class ()->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator c = parameters.begin (); c != parameters.end (); ++c) {
|
||||
int cmp = compare_parameters (a.parameter_value (c->id ()), b.parameter_value (c->id ()), 0.0, m_relative);
|
||||
if (cmp != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// DeviceClass class implementation
|
||||
|
||||
|
||||
@@ -286,6 +286,22 @@ private:
|
||||
std::vector<std::pair<size_t, std::pair<double, double> > > m_compare_set;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A parameter compare delegate that compares all parameters in a relative fashion
|
||||
*/
|
||||
class DB_PUBLIC AllDeviceParametersAreEqual
|
||||
: public DeviceParameterCompareDelegate
|
||||
{
|
||||
public:
|
||||
AllDeviceParametersAreEqual (double relative);
|
||||
|
||||
virtual bool less (const db::Device &a, const db::Device &b) const;
|
||||
virtual bool equal (const db::Device &a, const db::Device &b) const;
|
||||
|
||||
private:
|
||||
double m_relative;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A device class
|
||||
*
|
||||
|
||||
@@ -58,7 +58,7 @@ LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter)
|
||||
}
|
||||
|
||||
LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_index)
|
||||
: mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false)
|
||||
: mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0)
|
||||
{
|
||||
if (dss->is_valid_layout_index (m_layout_index)) {
|
||||
m_iter = db::RecursiveShapeIterator (dss->layout (m_layout_index), dss->initial_cell (m_layout_index), std::set<unsigned int> ());
|
||||
@@ -66,7 +66,7 @@ LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_i
|
||||
}
|
||||
|
||||
LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
||||
: m_iter (), m_netlist_extracted (false), m_is_flat (true)
|
||||
: m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0)
|
||||
{
|
||||
mp_internal_dss.reset (new db::DeepShapeStore (topcell_name, dbu));
|
||||
mp_dss.reset (mp_internal_dss.get ());
|
||||
@@ -77,7 +77,7 @@ LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
||||
|
||||
LayoutToNetlist::LayoutToNetlist ()
|
||||
: m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_layout_index (0),
|
||||
m_netlist_extracted (false), m_is_flat (false)
|
||||
m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
@@ -136,6 +136,16 @@ size_t LayoutToNetlist::max_vertex_count () const
|
||||
return dss ().max_vertex_count ();
|
||||
}
|
||||
|
||||
void LayoutToNetlist::set_device_scaling (double s)
|
||||
{
|
||||
m_device_scaling = s;
|
||||
}
|
||||
|
||||
double LayoutToNetlist::device_scaling () const
|
||||
{
|
||||
return m_device_scaling;
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::make_layer (const std::string &n)
|
||||
{
|
||||
db::RecursiveShapeIterator si (m_iter);
|
||||
@@ -195,7 +205,7 @@ void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, co
|
||||
if (! mp_netlist.get ()) {
|
||||
mp_netlist.reset (new db::Netlist ());
|
||||
}
|
||||
extractor.extract (dss (), m_layout_index, layers, *mp_netlist, m_net_clusters);
|
||||
extractor.extract (dss (), m_layout_index, layers, *mp_netlist, m_net_clusters, m_device_scaling);
|
||||
}
|
||||
|
||||
void LayoutToNetlist::connect (const db::Region &l)
|
||||
|
||||
@@ -220,6 +220,18 @@ public:
|
||||
*/
|
||||
size_t max_vertex_count () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the device scaling factor
|
||||
* This factor will scale the physical properties of the extracted devices
|
||||
* accordingly. The scale factor applies an isotropic shrink (<1) or expansion (>1).
|
||||
*/
|
||||
void set_device_scaling (double s);
|
||||
|
||||
/**
|
||||
* @brief Gets the device scaling factor
|
||||
*/
|
||||
double device_scaling () const;
|
||||
|
||||
/**
|
||||
* @brief Register a layer under the given name
|
||||
* This is a formal name for the layer. Using a name or layer properties
|
||||
@@ -711,6 +723,7 @@ private:
|
||||
std::map<unsigned int, std::string> m_name_of_layer;
|
||||
bool m_netlist_extracted;
|
||||
bool m_is_flat;
|
||||
double m_device_scaling;
|
||||
db::DeepLayer m_dummy_layer;
|
||||
|
||||
struct CellReuseTableKey
|
||||
|
||||
@@ -75,7 +75,7 @@ std::string NetlistDeviceExtractorError::to_string () const
|
||||
// NetlistDeviceExtractor implementation
|
||||
|
||||
NetlistDeviceExtractor::NetlistDeviceExtractor (const std::string &name)
|
||||
: mp_layout (0), m_cell_index (0), mp_circuit (0)
|
||||
: mp_layout (0), m_cell_index (0), m_device_scaling (1.0), mp_circuit (0)
|
||||
{
|
||||
m_name = name;
|
||||
m_terminal_id_propname_id = 0;
|
||||
@@ -110,6 +110,7 @@ void NetlistDeviceExtractor::initialize (db::Netlist *nl)
|
||||
{
|
||||
m_layer_definitions.clear ();
|
||||
mp_device_class = 0;
|
||||
m_device_scaling = 1.0;
|
||||
m_terminal_id_propname_id = 0;
|
||||
m_device_id_propname_id = 0;
|
||||
m_device_class_propname_id = 0;
|
||||
@@ -123,7 +124,7 @@ static void insert_into_region (const db::PolygonRef &s, const db::ICplxTrans &t
|
||||
region.insert (s.obj ().transformed (tr * db::ICplxTrans (s.trans ())));
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layout_index, const NetlistDeviceExtractor::input_layers &layer_map, db::Netlist &nl, hier_clusters_type &clusters)
|
||||
void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layout_index, const NetlistDeviceExtractor::input_layers &layer_map, db::Netlist &nl, hier_clusters_type &clusters, double device_scaling)
|
||||
{
|
||||
initialize (&nl);
|
||||
|
||||
@@ -183,13 +184,13 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo
|
||||
|
||||
}
|
||||
|
||||
extract_without_initialize (dss.layout (layout_index), dss.initial_cell (layout_index), clusters, layers);
|
||||
extract_without_initialize (dss.layout (layout_index), dss.initial_cell (layout_index), clusters, layers, device_scaling);
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, db::Netlist *nl, hier_clusters_type &clusters)
|
||||
void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, db::Netlist *nl, hier_clusters_type &clusters, double device_scaling)
|
||||
{
|
||||
initialize (nl);
|
||||
extract_without_initialize (layout, cell, clusters, layers);
|
||||
extract_without_initialize (layout, cell, clusters, layers, device_scaling);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -202,7 +203,7 @@ struct ExtractorCacheValueType {
|
||||
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector<unsigned int> &layers)
|
||||
void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector<unsigned int> &layers, double device_scaling)
|
||||
{
|
||||
tl_assert (layers.size () == m_layer_definitions.size ());
|
||||
|
||||
@@ -212,6 +213,7 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
||||
mp_layout = &layout;
|
||||
m_layers = layers;
|
||||
mp_clusters = &clusters;
|
||||
m_device_scaling = device_scaling;
|
||||
|
||||
// terminal properties are kept in a property with the terminal_property_name name
|
||||
m_terminal_id_propname_id = mp_layout->properties_repository ().prop_name_id (terminal_id_property_name ());
|
||||
|
||||
@@ -263,7 +263,7 @@ public:
|
||||
*
|
||||
* NOTE: The extractor expects "PolygonRef" type layers.
|
||||
*/
|
||||
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &layers, Netlist *netlist, hier_clusters_type &clusters);
|
||||
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &layers, Netlist *netlist, hier_clusters_type &clusters, double device_scaling = 1.0);
|
||||
|
||||
/**
|
||||
* @brief Extracts the devices from a list of regions
|
||||
@@ -272,7 +272,7 @@ public:
|
||||
* named regions for input. These regions need to be of deep region type and
|
||||
* originate from the same layout than the DeepShapeStore.
|
||||
*/
|
||||
void extract (DeepShapeStore &dss, unsigned int layout_index, const input_layers &layers, Netlist &netlist, hier_clusters_type &clusters);
|
||||
void extract (DeepShapeStore &dss, unsigned int layout_index, const input_layers &layers, Netlist &netlist, hier_clusters_type &clusters, double device_scaling = 1.0);
|
||||
|
||||
/**
|
||||
* @brief Gets the error iterator, begin
|
||||
@@ -416,6 +416,16 @@ public:
|
||||
return mp_layout->dbu ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the scaled database unit
|
||||
* Use this unit to compute device properties. It is the database unit multiplied with the
|
||||
* device scaling factor.
|
||||
*/
|
||||
double sdbu () const
|
||||
{
|
||||
return m_device_scaling * mp_layout->dbu ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the layout the shapes are taken from
|
||||
* NOTE: this method is provided for testing purposes mainly.
|
||||
@@ -523,6 +533,7 @@ private:
|
||||
db::properties_id_type m_terminal_id_propname_id, m_device_id_propname_id, m_device_class_propname_id;
|
||||
hier_clusters_type *mp_clusters;
|
||||
db::cell_index_type m_cell_index;
|
||||
double m_device_scaling;
|
||||
db::Circuit *mp_circuit;
|
||||
db::DeviceClass *mp_device_class;
|
||||
std::string m_name;
|
||||
@@ -542,7 +553,7 @@ private:
|
||||
*/
|
||||
void initialize (db::Netlist *nl);
|
||||
|
||||
void extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector<unsigned int> &layers);
|
||||
void extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector<unsigned int> &layers, double device_scaling);
|
||||
void push_new_devices (const Vector &disp_cache);
|
||||
void push_cached_devices (const tl::vector<Device *> &cached_devices, const db::Vector &disp_cache, const db::Vector &new_disp);
|
||||
};
|
||||
|
||||
@@ -112,8 +112,8 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
|
||||
|
||||
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
|
||||
|
||||
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, dbu () * edges.length () * 0.5);
|
||||
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, dbu () * (p->perimeter () - edges.length ()) * 0.5);
|
||||
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5);
|
||||
device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5);
|
||||
|
||||
int diff_index = 0;
|
||||
for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) {
|
||||
@@ -123,8 +123,8 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
|
||||
size_t n = rgates.selected_interacting (db::Region (*d)).size ();
|
||||
tl_assert (n > 0);
|
||||
|
||||
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, dbu () * dbu () * d->area () / double (n));
|
||||
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, dbu () * d->perimeter () / double (n));
|
||||
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * d->area () / double (n));
|
||||
device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * d->perimeter () / double (n));
|
||||
|
||||
unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index;
|
||||
define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *d);
|
||||
@@ -262,10 +262,10 @@ void NetlistDeviceExtractorResistor::extract_devices (const std::vector<db::Regi
|
||||
}
|
||||
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_R, m_sheet_rho * double (length) / double (width));
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_L, dbu () * length);
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_W, dbu () * width);
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_A, dbu () * dbu () * p->area ());
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_P, dbu () * p->perimeter ());
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_L, sdbu () * length);
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_W, sdbu () * width);
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_A, sdbu () * sdbu () * p->area ());
|
||||
device->set_parameter_value (db::DeviceClassResistor::param_id_P, sdbu () * p->perimeter ());
|
||||
|
||||
int cont_index = 0;
|
||||
for (db::Region::const_iterator d = contacts_per_res.begin (); !d.at_end () && cont_index < 2; ++d, ++cont_index) {
|
||||
@@ -366,11 +366,11 @@ void NetlistDeviceExtractorCapacitor::extract_devices (const std::vector<db::Reg
|
||||
|
||||
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
|
||||
|
||||
double area = p->area () * dbu () * dbu ();
|
||||
double area = p->area () * sdbu () * sdbu ();
|
||||
|
||||
device->set_parameter_value (db::DeviceClassCapacitor::param_id_C, m_area_cap * area);
|
||||
device->set_parameter_value (db::DeviceClassCapacitor::param_id_A, area);
|
||||
device->set_parameter_value (db::DeviceClassCapacitor::param_id_P, dbu () * p->perimeter ());
|
||||
device->set_parameter_value (db::DeviceClassCapacitor::param_id_P, sdbu () * p->perimeter ());
|
||||
|
||||
define_terminal (device, db::DeviceClassCapacitor::terminal_id_A, a_terminal_geometry_index, *p);
|
||||
define_terminal (device, db::DeviceClassCapacitor::terminal_id_B, b_terminal_geometry_index, *p);
|
||||
@@ -498,11 +498,11 @@ void NetlistDeviceExtractorBJT3Transistor::extract_devices (const std::vector<db
|
||||
// emitter wins over collector for the collector contact
|
||||
rcollector -= remitter2base;
|
||||
|
||||
double ab = dbu () * dbu () * p->area ();
|
||||
double pb = dbu () * p->perimeter ();
|
||||
double ab = sdbu () * sdbu () * p->area ();
|
||||
double pb = sdbu () * p->perimeter ();
|
||||
|
||||
double ac = dbu () * dbu () * rcollector2base.area ();
|
||||
double pc = dbu () * rcollector2base.perimeter ();
|
||||
double ac = sdbu () * sdbu () * rcollector2base.area ();
|
||||
double pc = sdbu () * rcollector2base.perimeter ();
|
||||
|
||||
for (db::Region::const_iterator pe = remitter2base.begin_merged (); !pe.at_end (); ++pe) {
|
||||
|
||||
@@ -512,8 +512,8 @@ void NetlistDeviceExtractorBJT3Transistor::extract_devices (const std::vector<db
|
||||
|
||||
device->set_parameter_value (db::DeviceClassBJT3Transistor::param_id_NE, 1.0);
|
||||
|
||||
device->set_parameter_value (db::DeviceClassBJT3Transistor::param_id_AE, dbu () * dbu () * pe->area ());
|
||||
device->set_parameter_value (db::DeviceClassBJT3Transistor::param_id_PE, dbu () * pe->perimeter ());
|
||||
device->set_parameter_value (db::DeviceClassBJT3Transistor::param_id_AE, sdbu () * sdbu () * pe->area ());
|
||||
device->set_parameter_value (db::DeviceClassBJT3Transistor::param_id_PE, sdbu () * pe->perimeter ());
|
||||
|
||||
device->set_parameter_value (db::DeviceClassBJT3Transistor::param_id_AB, ab);
|
||||
device->set_parameter_value (db::DeviceClassBJT3Transistor::param_id_PB, pb);
|
||||
@@ -629,10 +629,10 @@ void NetlistDeviceExtractorDiode::extract_devices (const std::vector<db::Region>
|
||||
|
||||
device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ()));
|
||||
|
||||
double area = p->area () * dbu () * dbu ();
|
||||
double area = p->area () * sdbu () * sdbu ();
|
||||
|
||||
device->set_parameter_value (db::DeviceClassDiode::param_id_A, area);
|
||||
device->set_parameter_value (db::DeviceClassDiode::param_id_P, dbu () * p->perimeter ());
|
||||
device->set_parameter_value (db::DeviceClassDiode::param_id_P, sdbu () * p->perimeter ());
|
||||
|
||||
define_terminal (device, db::DeviceClassDiode::terminal_id_A, a_terminal_geometry_index, *p);
|
||||
define_terminal (device, db::DeviceClassDiode::terminal_id_C, c_terminal_geometry_index, *p);
|
||||
|
||||
+16
-14
@@ -291,7 +291,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string)
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string, bool exact_parameter_match)
|
||||
{
|
||||
db::Netlist au_nl;
|
||||
for (db::Netlist::const_device_class_iterator d = netlist.begin_device_classes (); d != netlist.end_device_classes (); ++d) {
|
||||
@@ -300,27 +300,29 @@ void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist,
|
||||
|
||||
au_nl.from_string (au_nl_string);
|
||||
|
||||
db::NetlistComparer comp (0);
|
||||
|
||||
if (! comp.compare (&netlist, &au_nl)) {
|
||||
_this->raise ("Compare failed - see log for details.\n\nActual:\n" + netlist.to_string () + "\nGolden:\n" + au_nl_string);
|
||||
// Compare once again - this time with logger
|
||||
CompareLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.compare (&netlist, &au_nl);
|
||||
}
|
||||
compare_netlist (_this, netlist, au_nl, exact_parameter_match);
|
||||
}
|
||||
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const db::Netlist &netlist_au)
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const db::Netlist &netlist_au, bool exact_parameter_match)
|
||||
{
|
||||
db::NetlistComparer comp (0);
|
||||
|
||||
if (! comp.compare (&netlist, &netlist_au)) {
|
||||
_this->raise ("Compare failed - see log for details.\n\nActual:\n" + netlist.to_string () + "\nGolden:\n" + netlist_au.to_string ());
|
||||
db::Netlist netlist_copy (netlist);
|
||||
|
||||
if (exact_parameter_match) {
|
||||
// install a "all parameters are equal" device parameter comparer so we make sure the devices are compared exactly
|
||||
for (db::Netlist::device_class_iterator dc = netlist_copy.begin_device_classes (); dc != netlist_copy.end_device_classes (); ++dc) {
|
||||
db::DeviceClass &cls = *dc;
|
||||
cls.set_parameter_compare_delegate (new db::AllDeviceParametersAreEqual (0.01));
|
||||
}
|
||||
}
|
||||
|
||||
if (! comp.compare (&netlist_copy, &netlist_au)) {
|
||||
_this->raise ("Compare failed - see log for details.\n\nActual:\n" + netlist_copy.to_string () + "\nGolden:\n" + netlist_au.to_string ());
|
||||
// Compare once again - this time with logger
|
||||
CompareLogger logger;
|
||||
db::NetlistComparer comp (&logger);
|
||||
comp.compare (&netlist, &netlist_au);
|
||||
comp.compare (&netlist_copy, &netlist_au);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,12 +77,12 @@ void DB_PUBLIC compare_layouts (tl::TestBase *_this, const db::Layout &layout, c
|
||||
/**
|
||||
* @brief Compares a netlist against a string
|
||||
*/
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string);
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string, bool exact_parameter_match = false);
|
||||
|
||||
/**
|
||||
* @brief Compares a netlist against another netlist
|
||||
*/
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const db::Netlist &netlist_au);
|
||||
void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const db::Netlist &netlist_au, bool exact_parameter_match = false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -198,6 +198,15 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
||||
gsi::method ("max_vertex_count", &db::LayoutToNetlist::max_vertex_count,
|
||||
"See \\max_vertex_count= for details about this attribute."
|
||||
) +
|
||||
gsi::method ("device_scaling=", &db::LayoutToNetlist::set_device_scaling, gsi::arg ("f"),
|
||||
"@brief Sets the device scaling factor\n"
|
||||
"This factor will scale the physical properties of the extracted devices\n"
|
||||
"accordingly. The scale factor applies an isotropic shrink (<1) or expansion (>1).\n"
|
||||
) +
|
||||
gsi::method ("device_scaling", &db::LayoutToNetlist::device_scaling,
|
||||
"@brief Gets the device scaling factor\n"
|
||||
"See \\device_scaling= for details about this attribute."
|
||||
) +
|
||||
gsi::method ("name", (const std::string &(db::LayoutToNetlist::*) () const) &db::LayoutToNetlist::name,
|
||||
"@brief Gets the name of the database\n"
|
||||
) +
|
||||
|
||||
@@ -283,6 +283,15 @@ Class<db::Device> decl_dbDevice ("db", "Device",
|
||||
gsi::method ("name", &db::Device::name,
|
||||
"@brief Gets the name of the device.\n"
|
||||
) +
|
||||
gsi::method ("trans=", &db::Device::set_trans, gsi::arg ("t"),
|
||||
"@brief Sets the location of the device.\n"
|
||||
"The device location is essentially describing the position of the device. The position is typically the center of some "
|
||||
"recognition shape. In this case the transformation is a plain displacement to the center of this shape."
|
||||
) +
|
||||
gsi::method ("trans", &db::Device::trans,
|
||||
"@brief Gets the location of the device.\n"
|
||||
"See \\trans= for details about this method."
|
||||
) +
|
||||
gsi::method ("expanded_name", &db::Device::expanded_name,
|
||||
"@brief Gets the expanded name of the device.\n"
|
||||
"The expanded name takes the name of the device. If the name is empty, the numeric ID will be used to build a name. "
|
||||
|
||||
@@ -331,6 +331,11 @@ Class<GenericDeviceExtractor> decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
|
||||
gsi::method ("dbu", &GenericDeviceExtractor::dbu,
|
||||
"@brief Gets the database unit\n"
|
||||
) +
|
||||
gsi::method ("sdbu", &GenericDeviceExtractor::sdbu,
|
||||
"@brief Gets the scaled database unit\n"
|
||||
"Use this unit to compute device properties. It is the database unit multiplied with the\n"
|
||||
"device scaling factor."
|
||||
) +
|
||||
gsi::method ("error", (void (GenericDeviceExtractor::*) (const std::string &)) &GenericDeviceExtractor::error,
|
||||
gsi::arg ("message"),
|
||||
"@brief Issues an error with the given message\n"
|
||||
|
||||
@@ -1066,10 +1066,11 @@ TEST(4_ResAndCapExtraction)
|
||||
" device PMOS $2 (S=VDD,G=IN,D=$3) (L=0.4,W=2.3,AS=1.38,AD=1.38,PS=5.8,PD=5.8);\n"
|
||||
" device NMOS $3 (S=VSS,G=$4,D=OUT) (L=0.4,W=4.6,AS=2.185,AD=2.185,PS=8.8,PD=8.8);\n"
|
||||
" device MIM_CAP $5 (A=$4,B=VSS) (C=2.622e-14,A=26.22,P=29.8);\n"
|
||||
" device POLY_RES $7 (A=$3,B=$4) (R=750,A=2.4,P=13.6);\n"
|
||||
" device POLY_RES $9 (A=$4,B=VSS) (R=1825,A=5.84,P=30);\n"
|
||||
" device POLY_RES $7 (A=$3,B=$4) (R=750,L=12,W=0.8,A=2.4,P=13.6);\n"
|
||||
" device POLY_RES $9 (A=$4,B=VSS) (R=1825,L=29.2,W=0.8,A=5.84,P=30);\n"
|
||||
" device NMOS $10 (S=VSS,G=IN,D=$3) (L=0.4,W=3.1,AS=1.86,AD=1.86,PS=7.4,PD=7.4);\n"
|
||||
"end;\n"
|
||||
"end;\n",
|
||||
true /*exact parameter compare*/
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
@@ -1339,10 +1340,11 @@ TEST(5_ResAndCapWithBulkExtraction)
|
||||
" device NMOS $3 (S=VSS,G=$4,D=OUT,B=BULK) (L=0.4,W=4.6,AS=2.185,AD=2.185,PS=8.8,PD=8.8);\n"
|
||||
" device MIM_CAP_SUBSTRATE $5 (A=$4,B=VSS,W=BULK) (C=1.334e-14,A=13.34,P=15);\n"
|
||||
" device MIM_CAP_NWELL $6 (A=$4,B=VSS,W=NWELL) (C=1.288e-14,A=12.88,P=14.8);\n"
|
||||
" device POLY_RES_NWELL $7 (A=$3,B=$4,W=NWELL) (R=750,A=2.4,P=13.6);\n"
|
||||
" device POLY_RES_SUBSTRATE $9 (A=$4,B=VSS,W=BULK) (R=1825,A=5.84,P=30);\n"
|
||||
" device POLY_RES_NWELL $7 (A=$3,B=$4,W=NWELL) (R=750,L=12,W=0.8,A=2.4,P=13.6);\n"
|
||||
" device POLY_RES_SUBSTRATE $9 (A=$4,B=VSS,W=BULK) (R=1825,L=29.2,W=0.8,A=5.84,P=30);\n"
|
||||
" device NMOS $10 (S=VSS,G=IN,D=$3,B=BULK) (L=0.4,W=3.1,AS=1.86,AD=1.86,PS=7.4,PD=7.4);\n"
|
||||
"end;\n"
|
||||
"end;\n",
|
||||
true /*exact parameter compare*/
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
@@ -1582,9 +1584,10 @@ TEST(6_BJT3TransistorExtraction)
|
||||
" device PMOS $3 (S=VDD,G=IN,D=$3,B=VDD) (L=0.4,W=2.3,AS=1.38,AD=1.38,PS=5.8,PD=5.8);\n"
|
||||
" device NMOS $4 (S=VSS,G=$4,D=OUT,B=BULK) (L=0.4,W=4.6,AS=2.185,AD=2.185,PS=8.8,PD=8.8);\n"
|
||||
" device PNP $6 (C=BULK,B=$3,E=$3) (AE=3.06,PE=7,AB=25.2,PB=21.2,AC=25.2,PC=21.2,NE=1);\n"
|
||||
" device PNP $7 (C=BULK,B=$3,E=$4) (AE=6.12,PE=14,AB=50.4,PB=42.4,AC=50.4,PC=42.4,NE=2);\n"
|
||||
" device PNP $7 (C=BULK,B=$3,E=$4) (AE=6.12,PE=14,AB=25.2,PB=21.2,AC=25.2,PC=21.2,NE=2);\n"
|
||||
" device NMOS $9 (S=VSS,G=IN,D=$3,B=BULK) (L=0.4,W=3.1,AS=1.86,AD=1.86,PS=7.4,PD=7.4);\n"
|
||||
"end;\n"
|
||||
"end;\n",
|
||||
true /*exact parameter compare*/
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
@@ -1716,7 +1719,140 @@ TEST(7_DiodeExtraction)
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit TOP (A=A,C=C);\n"
|
||||
" device DIODE $1 (A=A,C=C) (A=9.18,P=21);\n"
|
||||
"end;\n"
|
||||
"end;\n",
|
||||
true /*exact parameter compare*/
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au = tl::combine_path (au, "testdata");
|
||||
au = tl::combine_path (au, "algo");
|
||||
au = tl::combine_path (au, "diode_devices_nets.gds");
|
||||
|
||||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
TEST(8_DiodeExtractionScaled)
|
||||
{
|
||||
db::Layout ly;
|
||||
db::LayerMap lmap;
|
||||
|
||||
unsigned int nwell = define_layer (ly, lmap, 1);
|
||||
unsigned int active = define_layer (ly, lmap, 2);
|
||||
unsigned int diff_cont = define_layer (ly, lmap, 4);
|
||||
unsigned int metal1 = define_layer (ly, lmap, 6);
|
||||
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
|
||||
unsigned int pplus = define_layer (ly, lmap, 9);
|
||||
unsigned int nplus = define_layer (ly, lmap, 10);
|
||||
|
||||
{
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
|
||||
std::string fn (tl::testsrc ());
|
||||
fn = tl::combine_path (fn, "testdata");
|
||||
fn = tl::combine_path (fn, "algo");
|
||||
fn = tl::combine_path (fn, "diode_devices_test.oas");
|
||||
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly, options);
|
||||
}
|
||||
|
||||
db::Cell &tc = ly.cell (*ly.begin_top_down ());
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_text_enlargement (1);
|
||||
dss.set_text_property_name (tl::Variant ("LABEL"));
|
||||
|
||||
// original layers
|
||||
db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss);
|
||||
db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss);
|
||||
db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss);
|
||||
db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss);
|
||||
db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss);
|
||||
db::Region rpplus (db::RecursiveShapeIterator (ly, tc, pplus), dss);
|
||||
db::Region rnplus (db::RecursiveShapeIterator (ly, tc, nplus), dss);
|
||||
|
||||
// derived regions
|
||||
|
||||
db::Region rn = ractive & rnwell;
|
||||
db::Region rntie = rnwell & rnplus;
|
||||
|
||||
// return the computed layers into the original layout and write it for debugging purposes
|
||||
|
||||
unsigned int ln = ly.insert_layer (db::LayerProperties (10, 0)); // 10/0 -> N layer
|
||||
unsigned int lntie = ly.insert_layer (db::LayerProperties (11, 0)); // 11/0 -> N contact
|
||||
rn.insert_into (&ly, tc.cell_index (), ln);
|
||||
rntie.insert_into (&ly, tc.cell_index (), lntie);
|
||||
|
||||
// perform the extraction
|
||||
|
||||
db::Netlist nl;
|
||||
db::hier_clusters<db::PolygonRef> cl;
|
||||
|
||||
db::NetlistDeviceExtractorDiode diode_ex ("DIODE");
|
||||
|
||||
db::NetlistDeviceExtractor::input_layers dl;
|
||||
|
||||
dl["N"] = &rn;
|
||||
dl["P"] = &rpplus;
|
||||
dl["tC"] = &rnwell;
|
||||
diode_ex.extract (dss, 0, dl, nl, cl, 2.0);
|
||||
|
||||
// perform the net extraction
|
||||
|
||||
db::NetlistExtractor net_ex;
|
||||
|
||||
db::Connectivity conn;
|
||||
// Intra-layer
|
||||
conn.connect (rnwell);
|
||||
conn.connect (rntie);
|
||||
conn.connect (rpplus);
|
||||
conn.connect (rdiff_cont);
|
||||
conn.connect (rmetal1);
|
||||
// Inter-layer
|
||||
conn.connect (rntie, rnwell);
|
||||
conn.connect (rntie, rdiff_cont);
|
||||
conn.connect (rpplus, rdiff_cont);
|
||||
conn.connect (rdiff_cont, rmetal1);
|
||||
conn.connect (rmetal1, rmetal1_lbl); // attaches labels
|
||||
|
||||
// extract the nets
|
||||
|
||||
net_ex.extract_nets (dss, 0, conn, nl, cl, "*");
|
||||
|
||||
// cleanup + completion
|
||||
nl.combine_devices ();
|
||||
nl.make_top_level_pins ();
|
||||
nl.purge ();
|
||||
|
||||
EXPECT_EQ (all_net_names_unique (nl), true);
|
||||
|
||||
// debug layers produced for nets
|
||||
// 201/0 -> n well
|
||||
// 204/0 -> Diffusion contacts
|
||||
// 206/0 -> Metal1
|
||||
// 210/0 -> N tiedown
|
||||
std::map<unsigned int, unsigned int> dump_map;
|
||||
dump_map [layer_of (rntie) ] = ly.insert_layer (db::LayerProperties (210, 0));
|
||||
dump_map [layer_of (rnwell) ] = ly.insert_layer (db::LayerProperties (201, 0));
|
||||
dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0));
|
||||
dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0));
|
||||
|
||||
// write nets to layout
|
||||
db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ());
|
||||
dump_nets_to_layout (nl, cl, ly, dump_map, cm, true /*with device cells*/);
|
||||
|
||||
// compare netlist as string
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, nl,
|
||||
"circuit TOP (A=A,C=C);\n"
|
||||
" device DIODE $1 (A=A,C=C) (A=36.72,P=42);\n"
|
||||
"end;\n",
|
||||
true /*exact parameter compare*/
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
||||
@@ -1159,6 +1159,12 @@ CODE
|
||||
# @synopsis l2n_data
|
||||
# See \Netter#l2n_data for a description of that function.
|
||||
|
||||
# %DRC%
|
||||
# @name device_scaling
|
||||
# @brief Specifies a dimension scale factor for the geometrical device properties
|
||||
# @synopsis device_scaling(factor)
|
||||
# See \Netter#device_scaling for a description of that function.
|
||||
|
||||
# %DRC%
|
||||
# @name extract_devices
|
||||
# @brief Extracts devices for a given device extractor and device layer selection
|
||||
@@ -1173,7 +1179,7 @@ CODE
|
||||
# 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|
|
||||
%w(connect connect_global clear_connections connect_implicit antenna_check l2n_data device_scaling extract_devices netlist).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(*args)
|
||||
_netter.#{f}(*args)
|
||||
|
||||
@@ -68,6 +68,7 @@ module DRC
|
||||
@connect_implicit = []
|
||||
@l2n = nil
|
||||
@lnum = 0
|
||||
@device_scaling = 1.0
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
@@ -178,6 +179,19 @@ module DRC
|
||||
@engine._cmd(@l2n, :extract_devices, devex, ls)
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name device_scaling
|
||||
# @brief Specifies a dimension scale factor for the geometrical device properties
|
||||
# @synopsis device_scaling(factor)
|
||||
# Specifying a factor of 2 will make all devices being extracted as if the
|
||||
# geometries were two times larger. This feature is useful when the drawn layout
|
||||
# does not correspond to the physical dimensions.
|
||||
|
||||
def device_scaling(factor)
|
||||
@device_scaling = factor
|
||||
@l2n && @l2n.device_scaling = factor
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name clear_connections
|
||||
@@ -378,6 +392,7 @@ module DRC
|
||||
if !@l2n
|
||||
@layers = {}
|
||||
_make_data
|
||||
@l2n.device_scaling = @device_scaling
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -185,6 +185,15 @@ implied always. Sometimes cell variants will be created.
|
||||
</p><p>
|
||||
Deep mode can be cancelled with <a href="#tiles">tiles</a> or <a href="#flat">flat</a>.
|
||||
</p>
|
||||
<h2>"device_scaling" - Specifies a dimension scale factor for the geometrical device properties</h2>
|
||||
<keyword name="device_scaling"/>
|
||||
<a name="device_scaling"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>device_scaling(factor)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="/about/drc_ref_netter.xml#device_scaling">Netter#device_scaling</a> for a description of that function.
|
||||
</p>
|
||||
<h2>"diode" - Supplies the diode extractor class</h2>
|
||||
<keyword name="diode"/>
|
||||
<a name="diode"/><p>Usage:</p>
|
||||
|
||||
@@ -198,6 +198,17 @@ component.
|
||||
The implicit connections are applied on the next net extraction and cleared
|
||||
on "clear_connections".
|
||||
</p>
|
||||
<h2>"device_scaling" - Specifies a dimension scale factor for the geometrical device properties</h2>
|
||||
<keyword name="device_scaling"/>
|
||||
<a name="device_scaling"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>device_scaling(factor)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
Specifying a factor of 2 will make all devices being extracted as if the
|
||||
geometries were two times larger. This feature is useful when the drawn layout
|
||||
does not correspond to the physical dimensions.
|
||||
</p>
|
||||
<h2>"extract_devices" - Extracts devices based on the given extractor class, name and device layer selection</h2>
|
||||
<keyword name="extract_devices"/>
|
||||
<a name="extract_devices"/><p>Usage:</p>
|
||||
|
||||
@@ -124,3 +124,8 @@ TEST(10_simplification_with_align)
|
||||
run_test (_this, "ringo_simple_simplification_with_align", "ringo_for_simplification.gds");
|
||||
}
|
||||
|
||||
TEST(11_device_scaling)
|
||||
{
|
||||
run_test (_this, "ringo_simple_device_scaling", "ringo.gds");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user