WIP: added concept of device model.

This commit is contained in:
Matthias Koefferlein 2019-01-15 23:03:25 +01:00
parent 5962d66940
commit 4cb8982ca2
15 changed files with 444 additions and 75 deletions

View File

@ -160,7 +160,8 @@ SOURCES = \
dbSubCircuit.cc \
dbPin.cc \
dbLayoutToNetlistReader.cc \
dbLayoutToNetlistWriter.cc
dbLayoutToNetlistWriter.cc \
dbDeviceModel.cc
HEADERS = \
dbArray.h \
@ -285,7 +286,8 @@ HEADERS = \
dbPin.h \
dbSubCircuit.h \
dbLayoutToNetlistReader.h \
dbLayoutToNetlistWriter.h
dbLayoutToNetlistWriter.h \
dbDeviceModel.h
!equals(HAVE_QT, "0") {

View File

@ -330,6 +330,17 @@ void Circuit::translate_device_classes (const std::map<const DeviceClass *, Devi
}
}
void Circuit::translate_device_models (const std::map<const DeviceModel *, DeviceModel *> &map)
{
for (device_iterator i = m_devices.begin (); i != m_devices.end (); ++i) {
if (i->device_model ()) {
std::map<const DeviceModel *, DeviceModel *>::const_iterator m = map.find (i->device_model ());
tl_assert (m != map.end ());
i->set_device_model (m->second);
}
}
}
void Circuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter)
{
if (m_pin_refs.size () < pin_id + 1) {

View File

@ -620,6 +620,7 @@ private:
void translate_circuits (const std::map<const Circuit *, Circuit *> &map);
void translate_device_classes (const std::map<const DeviceClass *, DeviceClass *> &map);
void translate_device_models (const std::map<const DeviceModel *, DeviceModel *> &map);
void set_netlist (Netlist *netlist);
bool combine_parallel_devices (const db::DeviceClass &cls);
bool combine_serial_devices (const db::DeviceClass &cls);

View File

@ -31,7 +31,7 @@ namespace db
// Device class implementation
Device::Device ()
: mp_device_class (0), m_cell_index (std::numeric_limits<db::cell_index_type>::max ()), m_id (0), mp_circuit (0)
: mp_device_class (0), mp_device_model (0), m_id (0), mp_circuit (0)
{
// .. nothing yet ..
}
@ -46,13 +46,19 @@ Device::~Device ()
}
Device::Device (DeviceClass *device_class, const std::string &name)
: mp_device_class (device_class), m_name (name), m_cell_index (std::numeric_limits<db::cell_index_type>::max ()), m_id (0), mp_circuit (0)
: mp_device_class (device_class), mp_device_model (0), m_name (name), m_id (0), mp_circuit (0)
{
// .. nothing yet ..
}
Device::Device (DeviceClass *device_class, DeviceModel *device_model, const std::string &name)
: mp_device_class (device_class), mp_device_model (device_model), m_name (name), m_id (0), mp_circuit (0)
{
// .. nothing yet ..
}
Device::Device (const Device &other)
: tl::Object (other), mp_device_class (0), m_cell_index (std::numeric_limits<db::cell_index_type>::max ()), m_id (0), mp_circuit (0)
: tl::Object (other), mp_device_class (0), mp_device_model (0), m_id (0), mp_circuit (0)
{
operator= (other);
}
@ -62,10 +68,9 @@ Device &Device::operator= (const Device &other)
if (this != &other) {
m_name = other.m_name;
m_position = other.m_position;
m_cell_index = other.m_cell_index;
m_terminal_cluster_ids = other.m_terminal_cluster_ids;
m_parameters = other.m_parameters;
mp_device_class = other.mp_device_class;
mp_device_model = other.mp_device_model;
}
return *this;
}
@ -88,24 +93,6 @@ void Device::set_position (const db::DPoint &pt)
m_position = pt;
}
void Device::set_cell_index (db::cell_index_type ci)
{
m_cell_index = ci;
}
size_t Device::cluster_id_for_terminal (size_t terminal_id) const
{
return terminal_id < m_terminal_cluster_ids.size () ? m_terminal_cluster_ids [terminal_id] : 0;
}
void Device::set_cluster_id_for_terminal (size_t terminal_id, size_t cluster_id)
{
if (m_terminal_cluster_ids.size () <= terminal_id) {
m_terminal_cluster_ids.resize (terminal_id + 1, 0);
}
m_terminal_cluster_ids [terminal_id] = cluster_id;
}
void Device::set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter)
{
if (m_terminal_refs.size () < terminal_id + 1) {

View File

@ -36,6 +36,7 @@ namespace db
class Circuit;
class DeviceClass;
class DeviceModel;
/**
* @brief An actual device
@ -63,6 +64,11 @@ public:
*/
Device (DeviceClass *device_class, const std::string &name = std::string ());
/**
* @brief The constructor
*/
Device (DeviceClass *device_class, DeviceModel *device_model, const std::string &name = std::string ());
/**
* @brief Copy constructor
*/
@ -86,6 +92,29 @@ public:
return mp_device_class;
}
/**
* @brief Sets the device class
*/
void set_device_class (DeviceClass *dc)
{
mp_device_class = dc;
}
/**
* @brief Gets the device model
*/
const DeviceModel *device_model () const
{
return mp_device_model;
}
/**
* @brief Sets the device model
*/
void set_device_model (DeviceModel *dm)
{
mp_device_model = dm;
}
/**
* @brief Gets the device ID
* The ID is a unique integer which identifies the device.
@ -145,32 +174,6 @@ public:
return m_position;
}
/**
* @brief Sets the device cell index
* In the layout, a device is represented by a cell. This attribute gives the index of this
* cell.
*/
void set_cell_index (db::cell_index_type ci);
/**
* @brief Gets the device cell index
*/
db::cell_index_type cell_index () const
{
return m_cell_index;
}
/**
* @brief Gets the cluster ID for a given terminal
* This attribute connects the device terminal with a terminal cluster
*/
size_t cluster_id_for_terminal (size_t terminal_id) const;
/**
* @brief Sets the cluster ID for a given terminal
*/
void set_cluster_id_for_terminal (size_t terminal_id, size_t cluster_id);
/**
* @brief Gets the net attached to a specific terminal
* Returns 0 if no net is attached.
@ -223,11 +226,10 @@ private:
friend class Net;
DeviceClass *mp_device_class;
DeviceModel *mp_device_model;
std::string m_name;
db::DPoint m_position;
db::cell_index_type m_cell_index;
std::vector<Net::terminal_iterator> m_terminal_refs;
std::vector<size_t> m_terminal_cluster_ids;
std::vector<double> m_parameters;
size_t m_id;
Circuit *mp_circuit;
@ -237,14 +239,6 @@ private:
*/
void set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter);
/**
* @brief Sets the device class
*/
void set_device_class (DeviceClass *dc)
{
mp_device_class = dc;
}
/**
* @brief Sets the device ID
*/

View File

@ -0,0 +1,87 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dbDeviceModel.h"
#include "dbCircuit.h"
namespace db
{
// --------------------------------------------------------------------------------
// DeviceModel class implementation
DeviceModel::~DeviceModel ()
{
// .. nothing yet ..
}
DeviceModel::DeviceModel (const std::string &name)
: m_name (name), m_cell_index (std::numeric_limits<db::cell_index_type>::max ()), mp_netlist (0)
{
// .. nothing yet ..
}
DeviceModel::DeviceModel (const DeviceModel &other)
: tl::Object (other), m_cell_index (std::numeric_limits<db::cell_index_type>::max ()), mp_netlist (0)
{
operator= (other);
}
DeviceModel &DeviceModel::operator= (const DeviceModel &other)
{
if (this != &other) {
m_name = other.m_name;
m_cell_index = other.m_cell_index;
m_terminal_cluster_ids = other.m_terminal_cluster_ids;
}
return *this;
}
void DeviceModel::set_netlist (Netlist *netlist)
{
mp_netlist = netlist;
}
void DeviceModel::set_name (const std::string &n)
{
m_name = n;
}
void DeviceModel::set_cell_index (db::cell_index_type ci)
{
m_cell_index = ci;
}
size_t DeviceModel::cluster_id_for_terminal (size_t terminal_id) const
{
return terminal_id < m_terminal_cluster_ids.size () ? m_terminal_cluster_ids [terminal_id] : 0;
}
void DeviceModel::set_cluster_id_for_terminal (size_t terminal_id, size_t cluster_id)
{
if (m_terminal_cluster_ids.size () <= terminal_id) {
m_terminal_cluster_ids.resize (terminal_id + 1, 0);
}
m_terminal_cluster_ids [terminal_id] = cluster_id;
}
}

142
src/db/db/dbDeviceModel.h Normal file
View File

@ -0,0 +1,142 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HDR_dbDeviceModel
#define _HDR_dbDeviceModel
#include "dbCommon.h"
#include "dbNet.h"
#include "dbPoint.h"
#include "tlObject.h"
#include <vector>
namespace db
{
class Netlist;
/**
* @brief A device model
*
* A device model represents the geometrical properties of a device. It basically links
* to a cell and clusters for indicating the terminal geometry of the device.
*/
class DB_PUBLIC DeviceModel
: public tl::Object
{
public:
/**
* @brief The constructor
*/
DeviceModel (const std::string &name = std::string ());
/**
* @brief Copy constructor
*/
DeviceModel (const DeviceModel &other);
/**
* @brief Assignment
*/
DeviceModel &operator= (const DeviceModel &other);
/**
* @brief Destructor
*/
~DeviceModel ();
/**
* @brief Gets the netlist the device lives in (const version)
* This pointer is 0 if the device model isn't added to a netlist
*/
const Netlist *netlist () const
{
return mp_netlist;
}
/**
* @brief Gets the netlist the device lives in (non-const version)
* This pointer is 0 if the device model isn't added to a netlist
*/
Netlist *netlist ()
{
return mp_netlist;
}
/**
* @brief Sets the name
*/
void set_name (const std::string &n);
/**
* @brief Gets the name
*/
const std::string &name () const
{
return m_name;
}
/**
* @brief Sets the device cell index
* In the layout, a device is represented by a cell. This attribute gives the index of this
* cell.
*/
void set_cell_index (db::cell_index_type ci);
/**
* @brief Gets the device cell index
*/
db::cell_index_type cell_index () const
{
return m_cell_index;
}
/**
* @brief Gets the cluster ID for a given terminal
* This attribute connects the device terminal with a terminal cluster
*/
size_t cluster_id_for_terminal (size_t terminal_id) const;
/**
* @brief Sets the cluster ID for a given terminal
*/
void set_cluster_id_for_terminal (size_t terminal_id, size_t cluster_id);
private:
friend class Netlist;
std::string m_name;
db::cell_index_type m_cell_index;
std::vector<size_t> m_terminal_cluster_ids;
Netlist *mp_netlist;
/**
* @brief Sets the netlist
*/
void set_netlist (Netlist *netlist);
};
}
#endif

View File

@ -68,10 +68,18 @@ Netlist &Netlist::operator= (const Netlist &other)
m_device_classes.push_back (dc_new);
}
std::map<const DeviceModel *, DeviceModel *> dmt;
for (const_device_model_iterator dm = other.begin_device_models (); dm != other.end_device_models (); ++dm) {
DeviceModel *dm_new = new DeviceModel (*dm);
dmt [dm.operator-> ()] = dm_new;
m_device_models.push_back (dm_new);
}
std::map<const Circuit *, Circuit *> ct;
for (const_circuit_iterator i = other.begin_circuits (); i != other.end_circuits (); ++i) {
Circuit *ct_new = new Circuit (*i);
ct_new->translate_device_classes (dct);
ct_new->translate_device_models (dmt);
ct [i.operator-> ()] = ct_new;
add_circuit (ct_new);
}
@ -332,6 +340,7 @@ Netlist::const_bottom_up_circuit_iterator Netlist::end_bottom_up () const
void Netlist::clear ()
{
m_device_classes.clear ();
m_device_models.clear ();
m_circuits.clear ();
}
@ -359,6 +368,18 @@ void Netlist::remove_device_class (DeviceClass *device_class)
m_device_classes.erase (device_class);
}
void Netlist::add_device_model (DeviceModel *device_model)
{
m_device_models.push_back (device_model);
device_model->set_netlist (this);
}
void Netlist::remove_device_model (DeviceModel *device_model)
{
device_model->set_netlist (0);
m_device_models.erase (device_model);
}
void Netlist::purge_nets ()
{
for (circuit_iterator c = begin_circuits (); c != end_circuits (); ++c) {

View File

@ -26,6 +26,7 @@
#include "dbCommon.h"
#include "dbCircuit.h"
#include "dbDeviceClass.h"
#include "dbDeviceModel.h"
#include "tlVector.h"
@ -51,6 +52,9 @@ public:
typedef tl::shared_collection<DeviceClass> device_class_list;
typedef device_class_list::const_iterator const_device_class_iterator;
typedef device_class_list::iterator device_class_iterator;
typedef tl::shared_collection<DeviceModel> device_model_list;
typedef device_model_list::const_iterator const_device_model_iterator;
typedef device_model_list::iterator device_model_iterator;
typedef tl::vector<Circuit *>::const_iterator top_down_circuit_iterator;
typedef tl::vector<const Circuit *>::const_iterator const_top_down_circuit_iterator;
typedef tl::vector<Circuit *>::const_reverse_iterator bottom_up_circuit_iterator;
@ -301,6 +305,50 @@ public:
return m_device_classes.end ();
}
/**
* @brief Adds a device model to this netlist
*
* The netlist takes over ownership of the object.
*/
void add_device_model (DeviceModel *device_model);
/**
* @brief Deletes a device model from the netlist
*/
void remove_device_model (DeviceModel *device_model);
/**
* @brief Begin iterator for the device models of the netlist (non-const version)
*/
device_model_iterator begin_device_models ()
{
return m_device_models.begin ();
}
/**
* @brief End iterator for the device models of the netlist (non-const version)
*/
device_model_iterator end_device_models ()
{
return m_device_models.end ();
}
/**
* @brief Begin iterator for the device models of the netlist (const version)
*/
const_device_model_iterator begin_device_models () const
{
return m_device_models.begin ();
}
/**
* @brief End iterator for the device models of the netlist (const version)
*/
const_device_model_iterator end_device_models () const
{
return m_device_models.end ();
}
/**
* @brief Purge unused nets
*
@ -338,6 +386,7 @@ private:
circuit_list m_circuits;
device_class_list m_device_classes;
device_model_list m_device_models;
bool m_valid_topology;
int m_lock_count;
tl::vector<Circuit *> m_top_down_circuits;

View File

@ -281,12 +281,17 @@ void NetlistDeviceExtractor::push_new_devices ()
db::PropertiesRepository::properties_set ps;
std::map<DeviceCellKey, db::cell_index_type>::iterator c = m_device_cells.find (key);
std::map<DeviceCellKey, std::pair<db::cell_index_type, db::DeviceModel *> >::iterator c = m_device_cells.find (key);
if (c == m_device_cells.end ()) {
std::string cell_name = "D$" + mp_device_class->name ();
db::Cell &device_cell = mp_layout->cell (mp_layout->add_cell (cell_name.c_str ()));
c = m_device_cells.insert (std::make_pair (key, device_cell.cell_index ())).first;
db::DeviceModel *dm = new db::DeviceModel (mp_layout->cell_name (device_cell.cell_index ()));
m_netlist->add_device_model (dm);
dm->set_cell_index (device_cell.cell_index ());
c = m_device_cells.insert (std::make_pair (key, std::make_pair (device_cell.cell_index (), dm))).first;
// attach the device class ID to the cell
ps.clear ();
@ -305,6 +310,7 @@ void NetlistDeviceExtractor::push_new_devices ()
// initialize the local cluster (will not be extracted)
db::local_cluster<db::PolygonRef> *lc = cc.insert ();
lc->add_attr (pi);
dm->set_cluster_id_for_terminal (t->first, lc->id ());
// build the cell shapes and local cluster
for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) {
@ -322,14 +328,14 @@ void NetlistDeviceExtractor::push_new_devices ()
}
// make the cell index known to the device
device->set_cell_index (c->second);
device->set_device_model (c->second.second);
// Build a property set for the device ID
ps.clear ();
ps.insert (std::make_pair (m_device_id_propname_id, tl::Variant (d->first)));
db::properties_id_type pi = mp_layout->properties_repository ().properties_id (ps);
db::CellInstArrayWithProperties inst (db::CellInstArray (db::CellInst (c->second), db::Trans (disp)), pi);
db::CellInstArrayWithProperties inst (db::CellInstArray (db::CellInst (c->second.first), db::Trans (disp)), pi);
mp_layout->cell (m_cell_index).insert (inst);
}

View File

@ -513,7 +513,7 @@ private:
std::vector<unsigned int> m_layers;
error_list m_errors;
std::map<size_t, geometry_per_terminal_type> m_new_devices;
std::map<DeviceCellKey, db::cell_index_type> m_device_cells;
std::map<DeviceCellKey, std::pair<db::cell_index_type, db::DeviceModel *> > m_device_cells;
// no copying
NetlistDeviceExtractor (const NetlistDeviceExtractor &);

View File

@ -208,7 +208,6 @@ void NetlistExtractor::connect_devices (db::Circuit *circuit,
size_t tid = j->second.to<size_t> ();
device->connect_terminal (tid, net);
device->set_cluster_id_for_terminal (tid, i->id ());
}

View File

@ -134,6 +134,36 @@ Class<db::Device> decl_dbDevice ("db", "Device",
"This class has been added in version 0.26."
);
#if 0
// TODO: activate once the geometry API is opened (clusters at al.)
Class<db::DeviceModel> decl_dbDeviceModel ("db", "DeviceModel",
gsi::method ("netlist", (db::Netlist *(db::DeviceModel::*) ()) &db::DeviceModel::netlist,
"@brief Gets the netlist the device model lives in."
) +
gsi::method ("name=", &db::DeviceModel::set_name, gsi::arg ("name"),
"@brief Sets the name of the device model.\n"
"Device names are used to name a device model inside a netlist file. "
"Device names should be unique within a netlist."
) +
gsi::method ("name", &db::DeviceModel::name,
"@brief Gets the name of the device model.\n"
) +
gsi::method ("cell_index", &db::DeviceModel::cell_index,
"@brief Gets the cell index of the device model.\n"
"This is the cell that represents the device."
) +
gsi::method ("cluster_id_for_terminal", &db::DeviceModel::cluster_id_for_terminal, gsi::arg ("terminal_id"),
"@brief Gets the cluster ID for the given terminal.\n"
"The cluster ID links the terminal to geometrical shapes within the clusters of the cell (see \\cell_index)"
),
"@brief A geometrical device model\n"
"This class represents the geometrical model for the device. It links into the extracted layout "
"to a cell which holds the terminal shapes for the device.\n"
"\n"
"This class has been added in version 0.26."
);
#endif
static void subcircuit_connect_pin1 (db::SubCircuit *subcircuit, const db::Pin *pin, db::Net *net)
{
if (pin) {

View File

@ -93,12 +93,14 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters<
for (db::Circuit::const_device_iterator d = c->begin_devices (); d != c->end_devices (); ++d) {
if (device_cells_seen.find (d->cell_index ()) != device_cells_seen.end ()) {
db::cell_index_type dci = d->device_model ()->cell_index ();
if (device_cells_seen.find (dci) != device_cells_seen.end ()) {
continue;
}
db::Cell &device_cell = ly.cell (cmap.cell_mapping (d->cell_index ()));
device_cells_seen.insert (d->cell_index ());
db::Cell &device_cell = ly.cell (cmap.cell_mapping (dci));
device_cells_seen.insert (dci);
std::string ps;
const std::vector<db::DeviceParameterDefinition> &pd = d->device_class ()->parameter_definitions ();
@ -112,7 +114,7 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters<
const std::vector<db::DeviceTerminalDefinition> &td = d->device_class ()->terminal_definitions ();
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
const db::local_cluster<db::PolygonRef> &dc = clusters.clusters_per_cell (d->cell_index ()).cluster_by_id (d->cluster_id_for_terminal (t->id ()));
const db::local_cluster<db::PolygonRef> &dc = clusters.clusters_per_cell (dci).cluster_by_id (d->device_model ()->cluster_id_for_terminal (t->id ()));
for (std::map<unsigned int, unsigned int>::const_iterator m = lmap.begin (); m != lmap.end (); ++m) {
db::Shapes &target = device_cell.shapes (m->second);

View File

@ -124,7 +124,11 @@ static std::string netlist2 (const db::Circuit &c)
pins += "=";
pins += net ? net->name () : std::string ("(null)");
}
res += " D" + d->name () + ":" + pins + "\n";
res += " D" + d->name ();
if (d->device_model ()) {
res += "/" + d->device_model ()->name ();
}
res += ":" + pins + "\n";
}
for (db::Circuit::const_subcircuit_iterator s = c.begin_subcircuits (); s != c.end_subcircuits (); ++s) {
@ -497,6 +501,12 @@ TEST(4_NetlistSubcircuits)
dc->add_terminal_definition (db::DeviceTerminalDefinition ("B", ""));
nl->add_device_class (dc);
db::DeviceModel *dm = new db::DeviceModel ();
dm->set_name ("dm2");
dm->set_cell_index (42);
dm->set_cluster_id_for_terminal (0, 17);
nl->add_device_model (dm);
db::Circuit *c1 = new db::Circuit ();
c1->set_cell_index (17);
EXPECT_EQ (c1->netlist (), 0);
@ -526,8 +536,9 @@ TEST(4_NetlistSubcircuits)
EXPECT_EQ (nl->circuit_by_cell_index (41) == 0, true);
EXPECT_EQ (nl->circuit_by_cell_index (42) == c2, true);
db::Device *d = new db::Device (dc, "D");
db::Device *d = new db::Device (dc, dm, "D");
c2->add_device (d);
EXPECT_EQ (d->device_model ()->name (), "dm2");
EXPECT_EQ (refs2string (c2), "");
db::SubCircuit *sc1 = new db::SubCircuit (c2);
@ -601,7 +612,7 @@ TEST(4_NetlistSubcircuits)
" Xsc1:c2p1=n1a,c2p2=n1b\n"
" Xsc2:c2p1=n1b,c2p2=n1c\n"
"c2:c2p1=n2a,c2p2=n2b\n"
" DD:A=n2a,B=n2b\n"
" DD/dm2:A=n2a,B=n2b\n"
);
// check netlist
@ -636,7 +647,7 @@ TEST(4_NetlistSubcircuits)
" Xsc1:c2p1=n1a,c2p2=n1b\n"
" Xsc2:c2p1=n1b,c2p2=n1c\n"
"c2:c2p1=n2a,c2p2=n2b\n"
" DD:A=n2a,B=n2b\n"
" DD/dm2:A=n2a,B=n2b\n"
);
// check netlist
@ -1028,3 +1039,30 @@ TEST(12_NetlistTopology)
EXPECT_EQ (td2string (nl.get ()), "c1,c3,c2");
EXPECT_EQ (bu2string (nl.get ()), "c2,c3,c1");
}
TEST(13_DeviceModel)
{
db::Netlist nl;
db::DeviceModel *dm = new db::DeviceModel ("name");
EXPECT_EQ (dm->name (), "name");
dm->set_name ("name2");
EXPECT_EQ (dm->name (), "name2");
dm->set_cluster_id_for_terminal (1, 17);
dm->set_cluster_id_for_terminal (0, 42);
EXPECT_EQ (dm->cluster_id_for_terminal (0), size_t (42));
EXPECT_EQ (dm->cluster_id_for_terminal (1), size_t (17));
dm->set_cell_index (5);
EXPECT_EQ (dm->cell_index (), db::cell_index_type (5));
nl.add_device_model (dm);
EXPECT_EQ (dm->netlist () == &nl, true);
EXPECT_EQ (nl.begin_device_models () == nl.end_device_models (), false);
EXPECT_EQ (nl.begin_device_models ()->name (), "name2");
nl.remove_device_model (dm);
EXPECT_EQ (nl.begin_device_models () == nl.end_device_models (), true);
}