mirror of https://github.com/KLayout/klayout.git
Merge pull request #409 from KLayout/netlist_properties
Netlist properties
This commit is contained in:
commit
b6869e4deb
|
|
@ -183,7 +183,8 @@ SOURCES = \
|
|||
dbLayoutVsSchematicFormatDefs.cc \
|
||||
dbLayoutVsSchematic.cc \
|
||||
gsiDeclDbNetlistCrossReference.cc \
|
||||
gsiDeclDbLayoutVsSchematic.cc
|
||||
gsiDeclDbLayoutVsSchematic.cc \
|
||||
dbNetlistObject.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
@ -329,7 +330,8 @@ HEADERS = \
|
|||
dbLayoutVsSchematicWriter.h \
|
||||
dbLayoutVsSchematicReader.h \
|
||||
dbLayoutVsSchematicFormatDefs.h \
|
||||
dbLayoutVsSchematic.h
|
||||
dbLayoutVsSchematic.h \
|
||||
dbNetlistObject.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace db
|
|||
// Circuit class implementation
|
||||
|
||||
Circuit::Circuit ()
|
||||
: m_dont_purge (false), m_cell_index (0), mp_netlist (0),
|
||||
: db::NetlistObject (), gsi::ObjectBase (), m_dont_purge (false), m_cell_index (0), mp_netlist (0),
|
||||
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
|
||||
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
|
||||
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
|
||||
|
|
@ -48,7 +48,7 @@ Circuit::Circuit ()
|
|||
}
|
||||
|
||||
Circuit::Circuit (const db::Layout &layout, db::cell_index_type ci)
|
||||
: m_name (layout.cell_name (ci)), m_dont_purge (false), m_cell_index (ci), mp_netlist (0),
|
||||
: db::NetlistObject (), gsi::ObjectBase (), m_name (layout.cell_name (ci)), m_dont_purge (false), m_cell_index (ci), mp_netlist (0),
|
||||
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
|
||||
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
|
||||
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
|
||||
|
|
@ -65,7 +65,7 @@ Circuit::Circuit (const db::Layout &layout, db::cell_index_type ci)
|
|||
}
|
||||
|
||||
Circuit::Circuit (const Circuit &other)
|
||||
: gsi::ObjectBase (other), tl::Object (other), m_dont_purge (false), m_cell_index (0), mp_netlist (0),
|
||||
: db::NetlistObject (other), gsi::ObjectBase (other), m_dont_purge (false), m_cell_index (0), mp_netlist (0),
|
||||
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
|
||||
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
|
||||
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
|
||||
|
|
@ -95,6 +95,8 @@ Circuit &Circuit::operator= (const Circuit &other)
|
|||
{
|
||||
if (this != &other) {
|
||||
|
||||
db::NetlistObject::operator= (other);
|
||||
|
||||
clear ();
|
||||
|
||||
m_name = other.m_name;
|
||||
|
|
@ -290,6 +292,13 @@ void Circuit::clear_pins ()
|
|||
m_pins.clear ();
|
||||
}
|
||||
|
||||
const Pin &Circuit::add_pin (const Pin &pin)
|
||||
{
|
||||
m_pins.push_back (pin);
|
||||
m_pins.back ().set_id (m_pins.size () - 1);
|
||||
return m_pins.back ();
|
||||
}
|
||||
|
||||
const Pin &Circuit::add_pin (const std::string &name)
|
||||
{
|
||||
m_pins.push_back (Pin (name));
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public:
|
|||
* devices.
|
||||
*/
|
||||
class DB_PUBLIC Circuit
|
||||
: public gsi::ObjectBase, public tl::Object
|
||||
: public db::NetlistObject, public gsi::ObjectBase
|
||||
{
|
||||
public:
|
||||
typedef tl::vector<Pin> pin_list;
|
||||
|
|
@ -324,6 +324,12 @@ public:
|
|||
*/
|
||||
const Pin &add_pin (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Adds a pin to this circuit
|
||||
* This version uses the given pin as the template.
|
||||
*/
|
||||
const Pin &add_pin (const Pin &pin);
|
||||
|
||||
/**
|
||||
* @brief Begin iterator for the pins of the circuit (non-const version)
|
||||
*/
|
||||
|
|
@ -353,6 +359,14 @@ public:
|
|||
*/
|
||||
const Pin *pin_by_id (size_t id) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the pin by ID (the ID is basically the index) - non-const version
|
||||
*/
|
||||
Pin *pin_by_id (size_t id)
|
||||
{
|
||||
return const_cast<Pin *> (((const db::Circuit *) this)->pin_by_id (id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the pin by name
|
||||
*
|
||||
|
|
@ -361,6 +375,14 @@ public:
|
|||
*/
|
||||
const Pin *pin_by_name (const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the pin by name - non-const version
|
||||
*/
|
||||
Pin *pin_by_name (const std::string &name)
|
||||
{
|
||||
return const_cast<Pin *> (((const db::Circuit *) this)->pin_by_name (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Begin iterator for the pins of the circuit (const version)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace db
|
|||
// Device class implementation
|
||||
|
||||
Device::Device ()
|
||||
: mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0)
|
||||
: db::NetlistObject (), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -46,19 +46,19 @@ Device::~Device ()
|
|||
}
|
||||
|
||||
Device::Device (DeviceClass *device_class, const std::string &name)
|
||||
: mp_device_class (device_class), mp_device_abstract (0), m_name (name), m_id (0), mp_circuit (0)
|
||||
: db::NetlistObject (), mp_device_class (device_class), mp_device_abstract (0), m_name (name), m_id (0), mp_circuit (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Device::Device (DeviceClass *device_class, DeviceAbstract *device_abstract, const std::string &name)
|
||||
: mp_device_class (device_class), mp_device_abstract (device_abstract), m_name (name), m_id (0), mp_circuit (0)
|
||||
: db::NetlistObject (), mp_device_class (device_class), mp_device_abstract (device_abstract), m_name (name), m_id (0), mp_circuit (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Device::Device (const Device &other)
|
||||
: tl::Object (other), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0)
|
||||
: db::NetlistObject (other), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
@ -66,6 +66,7 @@ Device::Device (const Device &other)
|
|||
Device &Device::operator= (const Device &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
db::NetlistObject::operator= (other);
|
||||
m_name = other.m_name;
|
||||
m_trans = other.m_trans;
|
||||
m_parameters = other.m_parameters;
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ struct DeviceAbstractRef
|
|||
* a specific device class.
|
||||
*/
|
||||
class DB_PUBLIC Device
|
||||
: public tl::Object
|
||||
: public db::NetlistObject
|
||||
{
|
||||
public:
|
||||
typedef std::vector<std::pair<size_t, size_t> > global_connections;
|
||||
|
|
|
|||
|
|
@ -814,11 +814,20 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &
|
|||
db::properties_id_type
|
||||
LayoutToNetlist::make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const
|
||||
{
|
||||
if (! netname_prop.is_nil ()) {
|
||||
if (! netname_prop.is_nil () || net.begin_properties () != net.end_properties ()) {
|
||||
|
||||
db::property_names_id_type name_propnameid = ly.properties_repository ().prop_name_id (netname_prop);
|
||||
db::PropertiesRepository::properties_set propset;
|
||||
propset.insert (std::make_pair (name_propnameid, tl::Variant (net.expanded_name ())));
|
||||
|
||||
// add the user properties too (TODO: make this configurable?)
|
||||
for (db::Net::property_iterator p = net.begin_properties (); p != net.end_properties (); ++p) {
|
||||
db::property_names_id_type key_propnameid = ly.properties_repository ().prop_name_id (p->first);
|
||||
propset.insert (std::make_pair (key_propnameid, p->second));
|
||||
}
|
||||
|
||||
if (! netname_prop.is_nil ()) {
|
||||
db::property_names_id_type name_propnameid = ly.properties_repository ().prop_name_id (netname_prop);
|
||||
propset.insert (std::make_pair (name_propnameid, tl::Variant (net.expanded_name ())));
|
||||
}
|
||||
|
||||
return ly.properties_repository ().properties_id (propset);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string LongKeys::circuit_key ("circuit");
|
||||
DB_PUBLIC std::string LongKeys::net_key ("net");
|
||||
DB_PUBLIC std::string LongKeys::name_key ("name");
|
||||
DB_PUBLIC std::string LongKeys::property_key ("property");
|
||||
DB_PUBLIC std::string LongKeys::device_key ("device");
|
||||
DB_PUBLIC std::string LongKeys::polygon_key ("polygon");
|
||||
DB_PUBLIC std::string LongKeys::rect_key ("rect");
|
||||
|
|
@ -55,7 +56,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string LongKeys::scale_key ("scale");
|
||||
DB_PUBLIC std::string LongKeys::pin_key ("pin");
|
||||
|
||||
// A, B, C, D, E, G, I, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
|
||||
// A, B, C, D, E, F, G, I, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
|
||||
DB_PUBLIC std::string ShortKeys::version_key ("V");
|
||||
DB_PUBLIC std::string ShortKeys::description_key ("B");
|
||||
DB_PUBLIC std::string ShortKeys::top_key ("W");
|
||||
|
|
@ -67,6 +68,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string ShortKeys::circuit_key ("X");
|
||||
DB_PUBLIC std::string ShortKeys::net_key ("N");
|
||||
DB_PUBLIC std::string ShortKeys::name_key ("I");
|
||||
DB_PUBLIC std::string ShortKeys::property_key ("F");
|
||||
DB_PUBLIC std::string ShortKeys::device_key ("D");
|
||||
DB_PUBLIC std::string ShortKeys::polygon_key ("Q");
|
||||
DB_PUBLIC std::string ShortKeys::rect_key ("R");
|
||||
|
|
|
|||
|
|
@ -66,7 +66,9 @@ namespace db
|
|||
*
|
||||
* [boundary-def]
|
||||
*
|
||||
* net(<id> [name]? [geometry-def]*)
|
||||
* [property-def]*
|
||||
*
|
||||
* net(<id> [name]? [property-def]* [geometry-def]*)
|
||||
* - net geometry [short key: N]
|
||||
* A net declaration shall be there also if no geometry
|
||||
* is present. The ID is a numerical shortcut for the net.
|
||||
|
|
@ -103,6 +105,14 @@ namespace db
|
|||
*
|
||||
* name(<name>) - specify net name [short key: I]
|
||||
*
|
||||
* [property-def]:
|
||||
*
|
||||
* property(<prop-name> <prop-value>)
|
||||
* - specifies a property value/key pair [short key: F]
|
||||
* prop-name and prop-value are variant specifications
|
||||
* in klayout notation: #x is an integer, ##y a floating-point
|
||||
* value, a word or quoted literal is a string.
|
||||
*
|
||||
* [geometry-def]:
|
||||
*
|
||||
* polygon(<layer> [coord] ...) - defines a polygon [short key: Q]
|
||||
|
|
@ -123,24 +133,26 @@ namespace db
|
|||
*
|
||||
* [device-def]:
|
||||
*
|
||||
* [trans-def] - location of the device [short key Y]
|
||||
* [property-def]* - user properties
|
||||
* [trans-def] - location of the device
|
||||
* must be before terminal
|
||||
* param(<name> <value>) - defines a parameter [short key E]
|
||||
* param(<name> <value>) - defines a parameter [short key: E]
|
||||
* terminal(<terminal-name> <net-id>)
|
||||
* - specifies connection of the terminal with
|
||||
* a net (short key: T)
|
||||
*
|
||||
* [subcircuit-def]:
|
||||
*
|
||||
* [trans-def] - location of the subcircuit [short key Y]
|
||||
* [property-def]* - user properties
|
||||
* [trans-def] - location of the subcircuit
|
||||
* pin(<pin-id> <net-id>) - specifies connection of the pin with a net [short key: P]
|
||||
*
|
||||
* [trans-def]:
|
||||
*
|
||||
* location(<x> <y>) - location of the instance [short key Y]
|
||||
* rotation(<angle>) - rotation angle (in degree, default is 0) [short key O]
|
||||
* mirror - if specified, the instance is mirrored before rotation [short key M]
|
||||
* scale(<mag>) - magnification (default is 1) [short key S]
|
||||
* location(<x> <y>) - location of the instance [short key: Y]
|
||||
* rotation(<angle>) - rotation angle (in degree, default is 0) [short key: O]
|
||||
* mirror - if specified, the instance is mirrored before rotation [short key: M]
|
||||
* scale(<mag>) - magnification (default is 1) [short key: S]
|
||||
*/
|
||||
|
||||
namespace l2n_std_format
|
||||
|
|
@ -160,6 +172,7 @@ namespace l2n_std_format
|
|||
static std::string circuit_key;
|
||||
static std::string net_key;
|
||||
static std::string name_key;
|
||||
static std::string property_key;
|
||||
static std::string device_key;
|
||||
static std::string subcircuit_key;
|
||||
static std::string polygon_key;
|
||||
|
|
@ -191,6 +204,7 @@ namespace l2n_std_format
|
|||
static std::string circuit_key;
|
||||
static std::string net_key;
|
||||
static std::string name_key;
|
||||
static std::string property_key;
|
||||
static std::string device_key;
|
||||
static std::string subcircuit_key;
|
||||
static std::string polygon_key;
|
||||
|
|
|
|||
|
|
@ -305,7 +305,9 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
|
|||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::rect_key) || test (lkeys::rect_key)) {
|
||||
if (test (skeys::property_key) || test (lkeys::property_key)) {
|
||||
read_property (circuit);
|
||||
} else if (test (skeys::rect_key) || test (lkeys::rect_key)) {
|
||||
circuit->set_boundary (db::DPolygon (dbu * read_rect ()));
|
||||
} else if (test (skeys::polygon_key) || test (lkeys::polygon_key)) {
|
||||
circuit->set_boundary (read_polygon ().transformed (dbu));
|
||||
|
|
@ -423,6 +425,22 @@ LayoutToNetlistStandardReader::read_point ()
|
|||
return m_ref;
|
||||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_property (db::NetlistObject *obj)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
tl::Variant k, v;
|
||||
m_ex.read (k);
|
||||
m_ex.read (v);
|
||||
|
||||
if (obj) {
|
||||
obj->set_property (k, v);
|
||||
}
|
||||
|
||||
br.done ();
|
||||
}
|
||||
|
||||
std::pair<unsigned int, db::PolygonRef>
|
||||
LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n)
|
||||
{
|
||||
|
|
@ -502,14 +520,18 @@ LayoutToNetlistStandardReader::read_polygon ()
|
|||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_geometries (Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell)
|
||||
LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell)
|
||||
{
|
||||
m_ref = db::Point ();
|
||||
|
||||
while (br) {
|
||||
std::pair<unsigned int, db::PolygonRef> pr = read_geometry (l2n);
|
||||
lc.add (pr.second, pr.first);
|
||||
cell.shapes (pr.first).insert (pr.second);
|
||||
if (test (skeys::property_key) || test (lkeys::property_key)) {
|
||||
read_property (obj);
|
||||
} else {
|
||||
std::pair<unsigned int, db::PolygonRef> pr = read_geometry (l2n);
|
||||
lc.add (pr.second, pr.first);
|
||||
cell.shapes (pr.first).insert (pr.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -540,7 +562,7 @@ LayoutToNetlistStandardReader::read_net (db::Netlist * /*netlist*/, db::LayoutTo
|
|||
net->set_cluster_id (lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
read_geometries (br, l2n, lc, cell);
|
||||
read_geometries (net, br, l2n, lc, cell);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -552,21 +574,28 @@ LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutTo
|
|||
{
|
||||
Brace br (this);
|
||||
|
||||
std::string name;
|
||||
db::Net *net = 0;
|
||||
|
||||
db::Pin pin;
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::name_key) || test (lkeys::name_key)) {
|
||||
|
||||
if (!name.empty ()) {
|
||||
if (! pin.name ().empty ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Duplicate pin name")));
|
||||
}
|
||||
|
||||
Brace br_name (this);
|
||||
read_word_or_quoted (name);
|
||||
std::string n;
|
||||
read_word_or_quoted (n);
|
||||
pin.set_name (n);
|
||||
br_name.done ();
|
||||
|
||||
} else if (test (skeys::property_key) || test (lkeys::property_key)) {
|
||||
|
||||
read_property (&pin);
|
||||
|
||||
} else {
|
||||
|
||||
if (net) {
|
||||
|
|
@ -583,9 +612,9 @@ LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutTo
|
|||
|
||||
}
|
||||
|
||||
const db::Pin &pin = circuit->add_pin (name);
|
||||
size_t pin_id = circuit->add_pin (pin).id ();
|
||||
if (net) {
|
||||
circuit->connect_pin (pin.id (), net);
|
||||
circuit->connect_pin (pin_id, net);
|
||||
}
|
||||
|
||||
br.done ();
|
||||
|
|
@ -657,6 +686,10 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
|
|||
|
||||
// .. nothing yet ..
|
||||
|
||||
} else if (test (skeys::property_key) || test (lkeys::property_key)) {
|
||||
|
||||
read_property (device.get ());
|
||||
|
||||
} else if (test (skeys::device_key) || test (lkeys::device_key)) {
|
||||
|
||||
std::string n;
|
||||
|
|
@ -900,6 +933,10 @@ LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::Layout
|
|||
|
||||
// .. nothing yet ..
|
||||
|
||||
} else if (test (skeys::property_key) || test (lkeys::property_key)) {
|
||||
|
||||
read_property (subcircuit.get ());
|
||||
|
||||
} else if (test (skeys::pin_key) || test (lkeys::pin_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
|
|
@ -989,7 +1026,7 @@ LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n,
|
|||
dm->set_cluster_id_for_terminal (tid, lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ());
|
||||
read_geometries (br, l2n, lc, cell);
|
||||
read_geometries (0, br, l2n, lc, cell);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,9 +140,10 @@ protected:
|
|||
bool read_trans_part (db::DCplxTrans &tr);
|
||||
void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceAbstract *dm, db::DeviceClass *dc);
|
||||
std::pair<unsigned int, db::PolygonRef> read_geometry (db::LayoutToNetlist *l2n);
|
||||
void read_property (db::NetlistObject *obj);
|
||||
db::Polygon read_polygon ();
|
||||
db::Box read_rect ();
|
||||
void read_geometries (Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell);
|
||||
void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell);
|
||||
db::Point read_point ();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -278,6 +278,13 @@ void std_writer_impl<Keys>::write (const db::Netlist *netlist, const db::LayoutT
|
|||
|
||||
}
|
||||
|
||||
for (db::NetlistObject::property_iterator p = circuit.begin_properties (); p != circuit.end_properties (); ++p) {
|
||||
if (p == circuit.begin_properties() && ! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent << indent1 << "# Properties" << endl;
|
||||
}
|
||||
*mp_stream << indent << indent1 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
|
||||
}
|
||||
|
||||
std::map<const db::Net *, unsigned int> net2id_local;
|
||||
std::map<const db::Net *, unsigned int> *net2id = &net2id_local;
|
||||
if (net2id_per_circuit) {
|
||||
|
|
@ -416,12 +423,19 @@ void std_writer_impl<Keys>::write (const db::Netlist *netlist, const db::LayoutT
|
|||
} else {
|
||||
|
||||
if (! any) {
|
||||
|
||||
*mp_stream << indent << indent1 << Keys::net_key << "(" << id;
|
||||
if (! net.name ().empty ()) {
|
||||
*mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")";
|
||||
}
|
||||
*mp_stream << endl;
|
||||
|
||||
for (db::NetlistObject::property_iterator p = net.begin_properties (); p != net.end_properties (); ++p) {
|
||||
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
|
||||
}
|
||||
|
||||
any = true;
|
||||
|
||||
}
|
||||
|
||||
*mp_stream << indent << indent2;
|
||||
|
|
@ -449,7 +463,15 @@ void std_writer_impl<Keys>::write (const db::Netlist *netlist, const db::LayoutT
|
|||
if (! net.name ().empty ()) {
|
||||
*mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")";
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
if (net.begin_properties () != net.end_properties ()) {
|
||||
*mp_stream << endl;
|
||||
for (db::NetlistObject::property_iterator p = net.begin_properties (); p != net.end_properties (); ++p) {
|
||||
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
|
||||
}
|
||||
*mp_stream << indent << ")" << endl;
|
||||
} else {
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -470,12 +492,16 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Sub
|
|||
}
|
||||
|
||||
// each pin in one line for more than a few pins
|
||||
bool separate_lines = (subcircuit.circuit_ref ()->pin_count () > 1);
|
||||
bool separate_lines = (subcircuit.circuit_ref ()->pin_count () > 1) || subcircuit.begin_properties () != subcircuit.end_properties ();
|
||||
|
||||
if (separate_lines) {
|
||||
*mp_stream << endl;
|
||||
}
|
||||
|
||||
for (db::NetlistObject::property_iterator p = subcircuit.begin_properties (); p != subcircuit.end_properties (); ++p) {
|
||||
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
|
||||
}
|
||||
|
||||
for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p) {
|
||||
const db::Net *net = subcircuit.net_for_pin (p->id ());
|
||||
if (net) {
|
||||
|
|
@ -614,6 +640,10 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist * /*l2n*/, const db
|
|||
*mp_stream << indent << indent2 << Keys::name_key << "(" << tl::to_word_or_quoted_string (device.name ()) << ")" << endl;
|
||||
}
|
||||
|
||||
for (db::NetlistObject::property_iterator p = device.begin_properties (); p != device.end_properties (); ++p) {
|
||||
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
|
||||
}
|
||||
|
||||
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
*mp_stream << indent << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::sprintf ("%.12g", device.parameter_value (i->id ())) << ")" << endl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,19 +155,19 @@ const Pin *NetSubcircuitPinRef::pin () const
|
|||
// Net class implementation
|
||||
|
||||
Net::Net ()
|
||||
: m_cluster_id (0), mp_circuit (0)
|
||||
: NetlistObject (), m_cluster_id (0), mp_circuit (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Net::Net (const std::string &name)
|
||||
: m_cluster_id (0), mp_circuit (0)
|
||||
: NetlistObject (), m_cluster_id (0), mp_circuit (0)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
Net::Net (const Net &other)
|
||||
: tl::Object (other), m_cluster_id (0), mp_circuit (0)
|
||||
: NetlistObject (other), m_cluster_id (0), mp_circuit (0)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
@ -176,6 +176,8 @@ Net &Net::operator= (const Net &other)
|
|||
{
|
||||
if (this != &other) {
|
||||
|
||||
db::NetlistObject::operator= (other);
|
||||
|
||||
clear ();
|
||||
|
||||
m_name = other.m_name;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#define _HDR_dbNet
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbNetlistObject.h"
|
||||
|
||||
#include "tlObject.h"
|
||||
|
||||
|
|
@ -360,7 +361,7 @@ private:
|
|||
* A net connects terminals of devices and pins or circuits
|
||||
*/
|
||||
class DB_PUBLIC Net
|
||||
: public tl::Object
|
||||
: public db::NetlistObject
|
||||
{
|
||||
public:
|
||||
typedef std::list<NetTerminalRef> terminal_list;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
/*
|
||||
|
||||
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 "dbNetlistObject.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
NetlistObject::NetlistObject ()
|
||||
: tl::Object (), mp_properties (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
NetlistObject::NetlistObject (const db::NetlistObject &other)
|
||||
: tl::Object (other), mp_properties (0)
|
||||
{
|
||||
if (other.mp_properties) {
|
||||
mp_properties = new std::map<tl::Variant, tl::Variant> (*other.mp_properties);
|
||||
}
|
||||
}
|
||||
|
||||
NetlistObject::~NetlistObject ()
|
||||
{
|
||||
delete mp_properties;
|
||||
mp_properties = 0;
|
||||
}
|
||||
|
||||
NetlistObject &NetlistObject::operator= (const NetlistObject &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
|
||||
tl::Object::operator= (other);
|
||||
|
||||
delete mp_properties;
|
||||
mp_properties = 0;
|
||||
|
||||
if (other.mp_properties) {
|
||||
mp_properties = new std::map<tl::Variant, tl::Variant> (*other.mp_properties);
|
||||
}
|
||||
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
tl::Variant NetlistObject::property (const tl::Variant &key) const
|
||||
{
|
||||
if (! mp_properties) {
|
||||
return tl::Variant ();
|
||||
}
|
||||
|
||||
std::map<tl::Variant, tl::Variant>::const_iterator i = mp_properties->find (key);
|
||||
if (i == mp_properties->end ()) {
|
||||
return tl::Variant ();
|
||||
} else {
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetlistObject::set_property (const tl::Variant &key, const tl::Variant &value)
|
||||
{
|
||||
if (value.is_nil ()) {
|
||||
|
||||
if (mp_properties) {
|
||||
mp_properties->erase (key);
|
||||
if (mp_properties->empty ()) {
|
||||
delete mp_properties;
|
||||
mp_properties = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (! mp_properties) {
|
||||
mp_properties = new std::map<tl::Variant, tl::Variant> ();
|
||||
}
|
||||
(*mp_properties) [key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static NetlistObject::property_table empty_properties;
|
||||
|
||||
NetlistObject::property_iterator
|
||||
NetlistObject::begin_properties () const
|
||||
{
|
||||
return mp_properties ? mp_properties->begin () : empty_properties.begin ();
|
||||
}
|
||||
|
||||
NetlistObject::property_iterator
|
||||
NetlistObject::end_properties () const
|
||||
{
|
||||
return mp_properties ? mp_properties->end () : empty_properties.end ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
|
||||
/*
|
||||
|
||||
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_dbNetlistObject
|
||||
#define _HDR_dbNetlistObject
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "tlObject.h"
|
||||
#include "tlVariant.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A base class for a objects in the netlist
|
||||
*/
|
||||
class DB_PUBLIC NetlistObject
|
||||
: public tl::Object
|
||||
{
|
||||
public:
|
||||
typedef std::map<tl::Variant, tl::Variant> property_table;
|
||||
typedef property_table::const_iterator property_iterator;
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
NetlistObject ();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
NetlistObject (const db::NetlistObject &object);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~NetlistObject ();
|
||||
|
||||
/**
|
||||
* @brief Assignment
|
||||
*/
|
||||
NetlistObject &operator= (const NetlistObject &other);
|
||||
|
||||
/**
|
||||
* @brief Gets the property value for a given key
|
||||
* Returns nil if there is no property for the given key.
|
||||
*/
|
||||
tl::Variant property (const tl::Variant &key) const;
|
||||
|
||||
/**
|
||||
* @brief Sets the property value for a given key
|
||||
* Set the value to nil to clear a specific key
|
||||
*/
|
||||
void set_property (const tl::Variant &key, const tl::Variant &value);
|
||||
|
||||
/**
|
||||
* @brief Iterator for the netlist properties (begin)
|
||||
*/
|
||||
property_iterator begin_properties () const;
|
||||
|
||||
/**
|
||||
* @brief Iterator for the netlist properties (end)
|
||||
*/
|
||||
property_iterator end_properties () const;
|
||||
|
||||
private:
|
||||
property_table *mp_properties;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -30,13 +30,13 @@ namespace db
|
|||
// Pin class implementation
|
||||
|
||||
Pin::Pin ()
|
||||
: m_id (0)
|
||||
: db::NetlistObject (), m_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Pin::Pin (const std::string &name)
|
||||
: m_name (name), m_id (0)
|
||||
: db::NetlistObject (), m_name (name), m_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#define _HDR_dbPin
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbNetlistObject.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -36,6 +37,7 @@ namespace db
|
|||
* A pin is some place other nets can connect to a circuit.
|
||||
*/
|
||||
class DB_PUBLIC Pin
|
||||
: public db::NetlistObject
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
|
@ -70,6 +72,15 @@ public:
|
|||
return m_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the name of the pin
|
||||
* CAUTION: don't use this method on pins stored inside a netlist.
|
||||
*/
|
||||
void set_name (const std::string &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Circuit;
|
||||
|
||||
|
|
@ -80,11 +91,6 @@ private:
|
|||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
void set_name (const std::string &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace db
|
|||
// SubCircuit class implementation
|
||||
|
||||
SubCircuit::SubCircuit ()
|
||||
: m_id (0), mp_circuit (0)
|
||||
: db::NetlistObject (), m_id (0), mp_circuit (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -45,13 +45,13 @@ SubCircuit::~SubCircuit()
|
|||
}
|
||||
|
||||
SubCircuit::SubCircuit (Circuit *circuit, const std::string &name)
|
||||
: m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0)
|
||||
: db::NetlistObject (), m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0)
|
||||
{
|
||||
set_circuit_ref (circuit);
|
||||
}
|
||||
|
||||
SubCircuit::SubCircuit (const SubCircuit &other)
|
||||
: tl::Object (other), m_id (0), mp_circuit (0)
|
||||
: db::NetlistObject (other), m_id (0), mp_circuit (0)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
@ -59,6 +59,7 @@ SubCircuit::SubCircuit (const SubCircuit &other)
|
|||
SubCircuit &SubCircuit::operator= (const SubCircuit &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
db::NetlistObject::operator= (other);
|
||||
m_name = other.m_name;
|
||||
m_trans = other.m_trans;
|
||||
set_circuit_ref (const_cast<Circuit *> (other.circuit_ref ()));
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class Circuit;
|
|||
* This class essentially is a reference to another circuit
|
||||
*/
|
||||
class DB_PUBLIC SubCircuit
|
||||
: public tl::Object
|
||||
: public db::NetlistObject
|
||||
{
|
||||
public:
|
||||
typedef tl::vector<const Net *> connected_net_list;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,33 @@
|
|||
namespace gsi
|
||||
{
|
||||
|
||||
Class<db::Pin> decl_dbPin ("db", "Pin",
|
||||
static std::vector<tl::Variant> property_keys (const db::NetlistObject *object)
|
||||
{
|
||||
std::vector<tl::Variant> v;
|
||||
for (db::NetlistObject::property_iterator p = object->begin_properties (); p != object->end_properties (); ++p) {
|
||||
v.push_back (p->first);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
Class<db::NetlistObject> decl_dbNetlistObject ("db", "NetlistObject",
|
||||
gsi::method ("property", &db::NetlistObject::property, gsi::arg ("key"),
|
||||
"@brief Gets the property value for the given key or nil if there is no value with this key."
|
||||
) +
|
||||
gsi::method ("set_property", &db::NetlistObject::set_property, gsi::arg ("key"), gsi::arg ("value"),
|
||||
"@brief Sets the property value for the given key.\n"
|
||||
"Use a nil value to erase the property with this key."
|
||||
) +
|
||||
gsi::method_ext ("property_keys", &property_keys,
|
||||
"@brief Gets the keys for the properties stored in this object."
|
||||
),
|
||||
"@brief The base class for some netlist objects.\n"
|
||||
"The main purpose of this class is to supply user properties for netlist objects.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.26.2"
|
||||
);
|
||||
|
||||
Class<db::Pin> decl_dbPin (decl_dbNetlistObject, "db", "Pin",
|
||||
gsi::method ("id", &db::Pin::id,
|
||||
"@brief Gets the ID of the pin.\n"
|
||||
) +
|
||||
|
|
@ -225,7 +251,7 @@ static void add_other_abstracts (db::Device *device, const db::DeviceAbstractRef
|
|||
device->other_abstracts ().push_back (ref);
|
||||
}
|
||||
|
||||
Class<db::Device> decl_dbDevice ("db", "Device",
|
||||
Class<db::Device> decl_dbDevice (decl_dbNetlistObject, "db", "Device",
|
||||
gsi::method ("device_class", &db::Device::device_class,
|
||||
"@brief Gets the device class the device belongs to.\n"
|
||||
) +
|
||||
|
|
@ -397,7 +423,7 @@ static void subcircuit_disconnect_pin1 (db::SubCircuit *subcircuit, const db::Pi
|
|||
}
|
||||
}
|
||||
|
||||
Class<db::SubCircuit> decl_dbSubCircuit ("db", "SubCircuit",
|
||||
Class<db::SubCircuit> decl_dbSubCircuit (decl_dbNetlistObject, "db", "SubCircuit",
|
||||
gsi::method ("circuit_ref", (const db::Circuit *(db::SubCircuit::*) () const) &db::SubCircuit::circuit_ref,
|
||||
"@brief Gets the circuit referenced by the subcircuit.\n"
|
||||
) +
|
||||
|
|
@ -516,7 +542,7 @@ Class<db::NetSubcircuitPinRef> decl_dbNetSubcircuitPinRef ("db", "NetSubcircuitP
|
|||
"This class has been added in version 0.26."
|
||||
);
|
||||
|
||||
Class<db::Net> decl_dbNet ("db", "Net",
|
||||
Class<db::Net> decl_dbNet (decl_dbNetlistObject, "db", "Net",
|
||||
gsi::method ("circuit", (db::Circuit *(db::Net::*) ()) &db::Net::circuit,
|
||||
"@brief Gets the circuit the net lives in."
|
||||
) +
|
||||
|
|
@ -1098,8 +1124,8 @@ static void circuit_disconnect_pin1 (db::Circuit *c, const db::Pin *pin)
|
|||
}
|
||||
}
|
||||
|
||||
Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
|
||||
gsi::method ("create_pin", &db::Circuit::add_pin, gsi::arg ("name"),
|
||||
Class<db::Circuit> decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
|
||||
gsi::method ("create_pin", (const db::Pin &(db::Circuit::*) (const std::string &)) &db::Circuit::add_pin, gsi::arg ("name"),
|
||||
"@brief Creates a new \\Pin object inside the circuit\n"
|
||||
"This object will describe a pin of the circuit. A circuit connects "
|
||||
"to the outside through such a pin. The pin is added after all existing "
|
||||
|
|
@ -1147,11 +1173,11 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
|
|||
"@brief Gets the net object for a given name.\n"
|
||||
"If the ID is not a valid net name, nil is returned."
|
||||
) +
|
||||
gsi::method ("pin_by_id", &db::Circuit::pin_by_id, gsi::arg ("id"),
|
||||
gsi::method ("pin_by_id", (db::Pin *(db::Circuit::*) (size_t)) &db::Circuit::pin_by_id, gsi::arg ("id"),
|
||||
"@brief Gets the \\Pin object corresponding to a specific ID\n"
|
||||
"If the ID is not a valid pin ID, nil is returned."
|
||||
) +
|
||||
gsi::method ("pin_by_name", &db::Circuit::pin_by_name, gsi::arg ("name"),
|
||||
gsi::method ("pin_by_name", (db::Pin *(db::Circuit::*) (const std::string &)) &db::Circuit::pin_by_name, gsi::arg ("name"),
|
||||
"@brief Gets the \\Pin object corresponding to a specific name\n"
|
||||
"If the ID is not a valid pin name, nil is returned."
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ TEST(1b_ReaderBasicShort)
|
|||
|
||||
// verify against the input
|
||||
|
||||
std::string path = tmp_file ("tmp_l2nreader_2.txt");
|
||||
std::string path = tmp_file ("tmp.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, true);
|
||||
|
|
@ -266,6 +266,60 @@ TEST(1b_ReaderBasicShort)
|
|||
compare_text_files (path, au_path);
|
||||
}
|
||||
|
||||
TEST(1c_ReaderBasicShortWithProps)
|
||||
{
|
||||
db::LayoutToNetlist l2n;
|
||||
|
||||
std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_p.txt");
|
||||
tl::InputStream is_in (in_path);
|
||||
|
||||
db::LayoutToNetlistStandardReader reader (is_in);
|
||||
reader.read (&l2n);
|
||||
|
||||
// verify against the input
|
||||
|
||||
std::string path = tmp_file ("tmp.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, true);
|
||||
writer.write (&l2n);
|
||||
}
|
||||
|
||||
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_p.txt");
|
||||
|
||||
compare_text_files (path, au_path);
|
||||
|
||||
{
|
||||
db::Layout ly2;
|
||||
ly2.dbu (l2n.internal_layout ()->dbu ());
|
||||
db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP"));
|
||||
|
||||
std::map<unsigned int, const db::Region *> lmap;
|
||||
lmap [ly2.insert_layer (db::LayerProperties (3, 0))] = l2n.layer_by_name ("poly");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (3, 1))] = l2n.layer_by_name ("poly_lbl");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (4, 0))] = l2n.layer_by_name ("diff_cont");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (5, 0))] = l2n.layer_by_name ("poly_cont");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (6, 0))] = l2n.layer_by_name ("metal1");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (6, 1))] = l2n.layer_by_name ("metal1_lbl");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (7, 0))] = l2n.layer_by_name ("via1");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (8, 0))] = l2n.layer_by_name ("metal2");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (8, 1))] = l2n.layer_by_name ("metal2_lbl");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = l2n.layer_by_name ("psd");
|
||||
lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = l2n.layer_by_name ("nsd");
|
||||
|
||||
db::CellMapping cm = l2n.cell_mapping_into (ly2, top2);
|
||||
|
||||
l2n.build_all_nets (cm, ly2, lmap, "NET_", tl::Variant (), db::LayoutToNetlist::BNH_Disconnected, 0, "DEVICE_");
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au = tl::combine_path (au, "testdata");
|
||||
au = tl::combine_path (au, "algo");
|
||||
au = tl::combine_path (au, "l2n_writer_au_p.oas");
|
||||
|
||||
db::compare_layouts (_this, ly2, au, db::WriteOAS);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(2_ReaderWithGlobalNets)
|
||||
{
|
||||
db::LayoutToNetlist l2n;
|
||||
|
|
@ -278,7 +332,7 @@ TEST(2_ReaderWithGlobalNets)
|
|||
|
||||
// verify against the input
|
||||
|
||||
std::string path = tmp_file ("tmp_l2nreader_2.txt");
|
||||
std::string path = tmp_file ("tmp.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, false);
|
||||
|
|
@ -335,7 +389,7 @@ TEST(3_ReaderAbsoluteCoordinates)
|
|||
|
||||
// verify against the input
|
||||
|
||||
std::string path = tmp_file ("tmp_l2nreader_2.txt");
|
||||
std::string path = tmp_file ("tmp.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, false);
|
||||
|
|
@ -394,7 +448,7 @@ TEST(4_ReaderCombinedDevices)
|
|||
|
||||
// verify against the input
|
||||
|
||||
std::string path = tmp_file ("tmp_l2nreader_4.txt");
|
||||
std::string path = tmp_file ("tmp.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, false);
|
||||
|
|
|
|||
|
|
@ -217,6 +217,33 @@ TEST(1_WriterBasic)
|
|||
|
||||
db::compare_layouts (_this, ly2, au);
|
||||
}
|
||||
|
||||
l2n.netlist ()->begin_circuits ()->set_property (17, 42);
|
||||
l2n.netlist ()->begin_circuits ()->set_property ("a_float", 0.5);
|
||||
l2n.netlist ()->begin_circuits ()->set_property ("a_\"non_quoted\"_string", "s");
|
||||
|
||||
l2n.netlist ()->begin_circuits ()->begin_nets ()->set_property (17, 142);
|
||||
l2n.netlist ()->begin_circuits ()->begin_nets ()->set_property ("a_float", 10.5);
|
||||
l2n.netlist ()->begin_circuits ()->begin_nets ()->set_property ("a_\"non_quoted\"_string", "1s");
|
||||
|
||||
l2n.netlist ()->circuit_by_name ("INV2")->begin_devices ()->set_property (17, 242);
|
||||
l2n.netlist ()->circuit_by_name ("INV2")->begin_devices ()->set_property ("a_float", 20.5);
|
||||
l2n.netlist ()->circuit_by_name ("INV2")->begin_devices ()->set_property ("a_\"non_quoted\"_string", "2s");
|
||||
|
||||
l2n.netlist ()->circuit_by_name ("RINGO")->begin_subcircuits ()->set_property (17, 342);
|
||||
l2n.netlist ()->circuit_by_name ("RINGO")->begin_subcircuits ()->set_property ("a_float", 30.5);
|
||||
l2n.netlist ()->circuit_by_name ("RINGO")->begin_subcircuits ()->set_property ("a_\"non_quoted\"_string", "3s");
|
||||
|
||||
path = tmp_file ("tmp_l2nwriter_1p.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, true);
|
||||
writer.write (&l2n);
|
||||
}
|
||||
|
||||
au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_p.txt");
|
||||
|
||||
compare_text_files (path, au_path);
|
||||
}
|
||||
|
||||
TEST(2_WriterWithGlobalNets)
|
||||
|
|
|
|||
|
|
@ -344,8 +344,16 @@ TEST(3_CircuitBasic)
|
|||
EXPECT_EQ (c.pin_by_name ("p1")->name (), "p1");
|
||||
EXPECT_EQ (c.pin_by_name ("doesnt_exist") == 0, true);
|
||||
EXPECT_EQ (c.pin_by_name ("p2")->name (), "p2");
|
||||
EXPECT_EQ (c.pin_by_id (0)->begin_properties () == c.pin_by_id (0)->end_properties (), true);
|
||||
|
||||
EXPECT_EQ (c.pin_by_id (0)->property (17).to_string (), "nil");
|
||||
c.pin_by_id (0)->set_property (17, 42);
|
||||
EXPECT_EQ (c.pin_by_id (0)->begin_properties () == c.pin_by_id (0)->end_properties (), false);
|
||||
EXPECT_EQ (c.pin_by_id (0)->begin_properties ()->second.to_string (), "42");
|
||||
EXPECT_EQ (c.pin_by_id (0)->property (17).to_string (), "42");
|
||||
|
||||
db::Circuit c2 = c;
|
||||
EXPECT_EQ (c2.pin_by_id (0)->property (17).to_string (), "42");
|
||||
EXPECT_EQ (c2.name (), "name");
|
||||
EXPECT_EQ (pins2string (c), "p1#0,p2#1");
|
||||
|
||||
|
|
@ -1419,3 +1427,90 @@ TEST(22_BlankCircuit)
|
|||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(23_NetlistObject)
|
||||
{
|
||||
db::NetlistObject nlo;
|
||||
nlo.set_property (1, "hello");
|
||||
EXPECT_EQ (nlo.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (nlo.property (1).to_string (), "hello");
|
||||
nlo.set_property ("key", 42);
|
||||
EXPECT_EQ (nlo.property ("key").to_string (), "42");
|
||||
nlo.set_property ("key", tl::Variant ());
|
||||
EXPECT_EQ (nlo.property ("key").to_string (), "nil");
|
||||
|
||||
db::Net net ("net_name");
|
||||
net.set_property (1, "hello");
|
||||
EXPECT_EQ (net.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (net.property (1).to_string (), "hello");
|
||||
|
||||
db::Net net2 (net);
|
||||
EXPECT_EQ (net.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (net.property (1).to_string (), "hello");
|
||||
|
||||
db::Net net3;
|
||||
EXPECT_EQ (net3.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (net3.property (1).to_string (), "nil");
|
||||
net3 = net2;
|
||||
EXPECT_EQ (net3.property (1).to_string (), "hello");
|
||||
|
||||
db::SubCircuit sc;
|
||||
sc.set_property (1, "hello");
|
||||
EXPECT_EQ (sc.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (sc.property (1).to_string (), "hello");
|
||||
|
||||
db::SubCircuit sc2 (sc);
|
||||
EXPECT_EQ (sc.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (sc.property (1).to_string (), "hello");
|
||||
|
||||
db::SubCircuit sc3;
|
||||
EXPECT_EQ (sc3.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (sc3.property (1).to_string (), "nil");
|
||||
sc3 = sc2;
|
||||
EXPECT_EQ (sc3.property (1).to_string (), "hello");
|
||||
|
||||
db::Device dev;
|
||||
dev.set_property (1, "hello");
|
||||
EXPECT_EQ (dev.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (dev.property (1).to_string (), "hello");
|
||||
|
||||
db::Device dev2 (dev);
|
||||
EXPECT_EQ (dev.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (dev.property (1).to_string (), "hello");
|
||||
|
||||
db::Device dev3;
|
||||
EXPECT_EQ (dev3.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (dev3.property (1).to_string (), "nil");
|
||||
dev3 = dev2;
|
||||
EXPECT_EQ (dev3.property (1).to_string (), "hello");
|
||||
|
||||
db::Circuit circuit;
|
||||
circuit.set_property (1, "hello");
|
||||
EXPECT_EQ (circuit.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (circuit.property (1).to_string (), "hello");
|
||||
|
||||
db::Circuit circuit2 (circuit);
|
||||
EXPECT_EQ (circuit.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (circuit.property (1).to_string (), "hello");
|
||||
|
||||
db::Circuit circuit3;
|
||||
EXPECT_EQ (circuit3.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (circuit3.property (1).to_string (), "nil");
|
||||
circuit3 = circuit2;
|
||||
EXPECT_EQ (circuit3.property (1).to_string (), "hello");
|
||||
|
||||
db::Pin pin ("pin_name");
|
||||
pin.set_property (1, "hello");
|
||||
EXPECT_EQ (pin.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (pin.property (1).to_string (), "hello");
|
||||
|
||||
db::Pin pin2 (pin);
|
||||
EXPECT_EQ (pin.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (pin.property (1).to_string (), "hello");
|
||||
|
||||
db::Pin pin3;
|
||||
EXPECT_EQ (pin3.property ("key").to_string (), "nil");
|
||||
EXPECT_EQ (pin3.property (1).to_string (), "nil");
|
||||
pin3 = pin2;
|
||||
EXPECT_EQ (pin3.property (1).to_string (), "hello");
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -25,6 +25,24 @@ load("test_prologue.rb")
|
|||
|
||||
class DBNetlist_TestClass < TestBase
|
||||
|
||||
def test_0_NetlistObject
|
||||
|
||||
nlo = RBA::NetlistObject::new
|
||||
assert_equal(nlo.property(17), nil)
|
||||
assert_equal(nlo.property_keys.inspect, "[]")
|
||||
nlo.set_property(17, 42)
|
||||
assert_equal(nlo.property_keys.inspect, "[17]")
|
||||
assert_equal(nlo.property(17), 42)
|
||||
|
||||
nlo2 = nlo.dup
|
||||
assert_equal(nlo2.property(17), 42)
|
||||
nlo.set_property(17, nil)
|
||||
assert_equal(nlo.property_keys.inspect, "[]")
|
||||
assert_equal(nlo.property(17), nil)
|
||||
assert_equal(nlo2.property(17), 42)
|
||||
|
||||
end
|
||||
|
||||
def test_1_NetlistBasicCircuit
|
||||
|
||||
nl = RBA::Netlist::new
|
||||
|
|
@ -141,6 +159,10 @@ class DBNetlist_TestClass < TestBase
|
|||
p1 = c.create_pin("A")
|
||||
p2 = c.create_pin("B")
|
||||
|
||||
assert_equal(p1.property(17), nil)
|
||||
p1.set_property(17, 42)
|
||||
assert_equal(p1.property(17), 42)
|
||||
|
||||
assert_equal(p1.id, 0)
|
||||
assert_equal(p2.id, 1)
|
||||
|
||||
|
|
@ -188,6 +210,10 @@ class DBNetlist_TestClass < TestBase
|
|||
assert_equal(c.device_by_id(2).inspect, "nil")
|
||||
assert_equal(c.device_by_name("doesnt_exist").inspect, "nil")
|
||||
|
||||
assert_equal(d1.property(17), nil)
|
||||
d1.set_property(17, 42)
|
||||
assert_equal(d1.property(17), 42)
|
||||
|
||||
d2 = c.create_device(dc)
|
||||
assert_equal(d2.device_class.id, dc.id)
|
||||
assert_equal(d2.device_class.object_id, dc.object_id) # by virtue of Ruby-to-C++ object mapping
|
||||
|
|
@ -215,6 +241,10 @@ class DBNetlist_TestClass < TestBase
|
|||
|
||||
net = c.create_net("NET")
|
||||
|
||||
assert_equal(net.property(17), nil)
|
||||
net.set_property(17, 42)
|
||||
assert_equal(net.property(17), 42)
|
||||
|
||||
assert_equal(net.is_floating?, true)
|
||||
assert_equal(net.is_internal?, false)
|
||||
assert_equal(net.terminal_count, 0)
|
||||
|
|
@ -370,6 +400,10 @@ class DBNetlist_TestClass < TestBase
|
|||
assert_equal(c.subcircuit_by_id(2).inspect, "nil")
|
||||
assert_equal(c.subcircuit_by_name("doesnt_exist").inspect, "nil")
|
||||
|
||||
assert_equal(sc1.property(17), nil)
|
||||
sc1.set_property(17, 42)
|
||||
assert_equal(sc1.property(17), 42)
|
||||
|
||||
refs = []
|
||||
cc.each_ref { |r| refs << r.name }
|
||||
assert_equal(refs.join(","), "SC1")
|
||||
|
|
@ -564,6 +598,10 @@ class DBNetlist_TestClass < TestBase
|
|||
c.cell_index = 42
|
||||
assert_equal(c.cell_index, 42)
|
||||
|
||||
assert_equal(c.property(17), nil)
|
||||
c.set_property(17, 42)
|
||||
assert_equal(c.property(17), 42)
|
||||
|
||||
pina1 = c.create_pin("A1")
|
||||
pina2 = c.create_pin("A2")
|
||||
pinb1 = c.create_pin("B1")
|
||||
|
|
@ -581,6 +619,11 @@ class DBNetlist_TestClass < TestBase
|
|||
assert_equal(c.pin_by_id(17).inspect, "nil")
|
||||
assert_equal(c.pin_by_name("DOESNOTEXIST").inspect, "nil")
|
||||
|
||||
assert_equal(c.pin_by_id(0).property(17), nil)
|
||||
c.pin_by_id(0).set_property(17, 42)
|
||||
assert_equal(c.pin_by_id(0).property(17), 42)
|
||||
assert_equal(c.pin_by_name("A1").property(17), 42)
|
||||
|
||||
names = []
|
||||
c.each_pin { |p| names << p.name }
|
||||
assert_equal(names, [ "A1", "A2", "B1", "B2" ])
|
||||
|
|
|
|||
Loading…
Reference in New Issue