mirror of https://github.com/KLayout/klayout.git
Introduced concept of device class templates
This concept allows to persist at least the standard (built-in) device classes into L2N DB files. This way device classes are persisted.
This commit is contained in:
parent
46b47ff0d9
commit
7f9da5e8de
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "dbDeviceClass.h"
|
||||
#include "dbDevice.h"
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -273,4 +274,29 @@ bool DeviceClass::equal (const db::Device &a, const db::Device &b)
|
|||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// DeviceClassTemplateBase class implementation
|
||||
|
||||
DeviceClassTemplateBase *
|
||||
DeviceClassTemplateBase::template_by_name (const std::string &name)
|
||||
{
|
||||
for (tl::Registrar<db::DeviceClassTemplateBase>::iterator i = tl::Registrar<db::DeviceClassTemplateBase>::begin (); i != tl::Registrar<db::DeviceClassTemplateBase>::end (); ++i) {
|
||||
if (i->name () == name) {
|
||||
return i.operator-> ();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DeviceClassTemplateBase *
|
||||
DeviceClassTemplateBase::is_a (const db::DeviceClass *dc)
|
||||
{
|
||||
for (tl::Registrar<db::DeviceClassTemplateBase>::iterator i = tl::Registrar<db::DeviceClassTemplateBase>::begin (); i != tl::Registrar<db::DeviceClassTemplateBase>::end (); ++i) {
|
||||
if (i->is_of (dc)) {
|
||||
return i.operator-> ();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -536,6 +536,74 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A device class template
|
||||
*
|
||||
* This is a registered class which provides a device class template.
|
||||
* The built-in classes serve as templates and registering a template
|
||||
* allows regenerating the class from an abstract description (template
|
||||
* name).
|
||||
*
|
||||
* NOTE: device classes derived from one of the built-in classes
|
||||
* cannot be distinguished from pure built-in classes. Entirely
|
||||
* customized classes are treated as "non-template based" (i.e.
|
||||
* "is_a" returns 0).
|
||||
*/
|
||||
class DB_PUBLIC DeviceClassTemplateBase
|
||||
{
|
||||
public:
|
||||
DeviceClassTemplateBase (const std::string &name)
|
||||
: m_name (name)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual ~DeviceClassTemplateBase () { }
|
||||
|
||||
const std::string &name () const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
virtual bool is_of (const db::DeviceClass *) const = 0;
|
||||
virtual DeviceClass *create () const = 0;
|
||||
|
||||
static DeviceClassTemplateBase *template_by_name (const std::string &name);
|
||||
static DeviceClassTemplateBase *is_a (const db::DeviceClass *dc);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
|
||||
DeviceClassTemplateBase (const DeviceClassTemplateBase &);
|
||||
DeviceClassTemplateBase &operator= (const DeviceClassTemplateBase &);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DB_PUBLIC_TEMPLATE device_class_template
|
||||
: public DeviceClassTemplateBase
|
||||
{
|
||||
public:
|
||||
device_class_template (const std::string &name)
|
||||
: DeviceClassTemplateBase (name)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual bool is_of (const db::DeviceClass *dc) const
|
||||
{
|
||||
return dynamic_cast<const T *> (dc) != 0;
|
||||
}
|
||||
|
||||
virtual DeviceClass *create () const
|
||||
{
|
||||
return new T ();
|
||||
}
|
||||
|
||||
private:
|
||||
device_class_template (const device_class_template &);
|
||||
device_class_template &operator= (const device_class_template &);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace l2n_std_format
|
|||
template<> DB_PUBLIC const std::string keys<false>::top_key ("top");
|
||||
template<> DB_PUBLIC const std::string keys<false>::unit_key ("unit");
|
||||
template<> DB_PUBLIC const std::string keys<false>::layer_key ("layer");
|
||||
template<> DB_PUBLIC const std::string keys<false>::class_key ("class");
|
||||
template<> DB_PUBLIC const std::string keys<false>::connect_key ("connect");
|
||||
template<> DB_PUBLIC const std::string keys<false>::global_key ("global");
|
||||
template<> DB_PUBLIC const std::string keys<false>::circuit_key ("circuit");
|
||||
|
|
@ -54,6 +55,7 @@ namespace l2n_std_format
|
|||
template<> DB_PUBLIC const std::string keys<true>::top_key ("W");
|
||||
template<> DB_PUBLIC const std::string keys<true>::unit_key ("U");
|
||||
template<> DB_PUBLIC const std::string keys<true>::layer_key ("L");
|
||||
template<> DB_PUBLIC const std::string keys<true>::class_key ("K");
|
||||
template<> DB_PUBLIC const std::string keys<true>::connect_key ("C");
|
||||
template<> DB_PUBLIC const std::string keys<true>::global_key ("G");
|
||||
template<> DB_PUBLIC const std::string keys<true>::circuit_key ("X");
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ namespace db
|
|||
* - connects the shapes of the layer with the given global
|
||||
* nets [short key: G]
|
||||
* circuit(<name> [circuit-def]) - circuit (cell) [short key: X]
|
||||
* class(<name> <template>) - a device class definition (template: RES,CAP,...) [short key: K]
|
||||
* device(<name> <class> [device-abstract-def])
|
||||
* - device abstract [short key: D]
|
||||
*
|
||||
|
|
@ -73,7 +74,7 @@ namespace db
|
|||
* circuit(<name> [circuit-def]) - subcircuit with connections [short key: X]
|
||||
*
|
||||
* [net-name]:
|
||||
* name(<net-name>) - specify net name [short key:
|
||||
* name(<net-name>) - specify net name [short key: I]
|
||||
*
|
||||
* [geometry-def]:
|
||||
*
|
||||
|
|
@ -115,6 +116,7 @@ namespace l2n_std_format
|
|||
static const std::string top_key;
|
||||
static const std::string unit_key;
|
||||
static const std::string layer_key;
|
||||
static const std::string class_key;
|
||||
static const std::string connect_key;
|
||||
static const std::string global_key;
|
||||
static const std::string circuit_key;
|
||||
|
|
|
|||
|
|
@ -206,6 +206,27 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
|
|||
delete l2n->make_layer (layer);
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::class_key) || test (lkeys::class_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::string class_name, templ_name;
|
||||
read_word_or_quoted (class_name);
|
||||
read_word_or_quoted (templ_name);
|
||||
br.done ();
|
||||
|
||||
if (l2n->netlist ()->device_class_by_name (class_name) != 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device class must be defined before being used in device")));
|
||||
}
|
||||
|
||||
db::DeviceClassTemplateBase *dct = db::DeviceClassTemplateBase::template_by_name (templ_name);
|
||||
if (! dct) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid device class template: ")) + templ_name);
|
||||
}
|
||||
|
||||
db::DeviceClass *dc = dct->create ();
|
||||
dc->set_name (class_name);
|
||||
l2n->netlist ()->add_device_class (dc);
|
||||
|
||||
} else if (test (skeys::connect_key) || test (lkeys::connect_key)) {
|
||||
|
||||
Brace br (this);
|
||||
|
|
@ -298,12 +319,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
|
|||
std::string cls;
|
||||
read_word_or_quoted (cls);
|
||||
|
||||
db::DeviceClass *dc = 0;
|
||||
for (db::Netlist::device_class_iterator i = l2n->netlist ()->begin_device_classes (); i != l2n->netlist ()->end_device_classes (); ++i) {
|
||||
if (i->name () == cls) {
|
||||
dc = i.operator-> ();
|
||||
}
|
||||
}
|
||||
db::DeviceClass *dc = l2n->netlist ()->device_class_by_name (cls);
|
||||
|
||||
// use a generic device class unless the right one is registered already.
|
||||
bool gen_dc = (dc == 0);
|
||||
|
|
|
|||
|
|
@ -164,6 +164,16 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
|
|||
|
||||
}
|
||||
|
||||
if (nl->begin_device_classes () != nl->end_device_classes () && ! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Device class section" << endl;
|
||||
for (db::Netlist::const_device_class_iterator c = nl->begin_device_classes (); c != nl->end_device_classes (); ++c) {
|
||||
db::DeviceClassTemplateBase *temp = db::DeviceClassTemplateBase::is_a (c.operator-> ());
|
||||
if (temp) {
|
||||
*mp_stream << Keys::class_key << "(" << tl::to_word_or_quoted_string (c->name ()) << " " << tl::to_word_or_quoted_string (temp->name ()) << ")" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nl->begin_device_abstracts () != nl->end_device_abstracts () && ! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Device abstracts section" << endl;
|
||||
*mp_stream << "# Device abstracts list the pin shapes of the devices." << endl;
|
||||
|
|
|
|||
|
|
@ -21,10 +21,21 @@
|
|||
*/
|
||||
|
||||
#include "dbNetlistDeviceClasses.h"
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// The built-in device class templates
|
||||
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_cap (new db::device_class_template<db::DeviceClassCapacitor> ("CAP"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_res (new db::device_class_template<db::DeviceClassResistor> ("RES"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_ind (new db::device_class_template<db::DeviceClassInductor> ("IND"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_diode (new db::device_class_template<db::DeviceClassDiode> ("DIODE"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_mos3 (new db::device_class_template<db::DeviceClassMOS3Transistor> ("MOS3"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_mos4 (new db::device_class_template<db::DeviceClassMOS4Transistor> ("MOS4"));
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// DeviceClassTwoTerminalDevice implementation
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,23 @@ static std::string bu2string (const db::Netlist *nl)
|
|||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
TEST(0_DeviceClassTemplates)
|
||||
{
|
||||
db::DeviceClassMOS3Transistor mos3;
|
||||
db::DeviceClass generic;
|
||||
|
||||
EXPECT_EQ (db::DeviceClassTemplateBase::template_by_name ("MOS3") != 0, true);
|
||||
EXPECT_EQ (db::DeviceClassTemplateBase::template_by_name ("RES") != 0, true);
|
||||
EXPECT_EQ (db::DeviceClassTemplateBase::template_by_name ("DOESNTEXIST") == 0, true);
|
||||
EXPECT_EQ (db::DeviceClassTemplateBase::template_by_name ("MOS3")->is_of (&mos3), true);
|
||||
EXPECT_EQ (db::DeviceClassTemplateBase::template_by_name ("RES")->is_of (&mos3), false);
|
||||
EXPECT_EQ (db::DeviceClassTemplateBase::is_a (&mos3) != 0, true);
|
||||
EXPECT_EQ (db::DeviceClassTemplateBase::is_a (&generic) == 0, true);
|
||||
EXPECT_EQ (db::DeviceClassTemplateBase::is_a (&mos3)->name (), "MOS3");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
TEST(1_DeviceTerminalDefinition)
|
||||
{
|
||||
db::DeviceTerminalDefinition pd;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ connect(metal2_lbl metal2)
|
|||
connect(psd diff_cont psd)
|
||||
connect(nsd diff_cont nsd)
|
||||
|
||||
# Device class section
|
||||
class(PMOS MOS3)
|
||||
class(NMOS MOS3)
|
||||
|
||||
# Device abstracts section
|
||||
# Device abstracts list the pin shapes of the devices.
|
||||
device(D$PMOS PMOS
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ connect(nsd diff_cont nsd)
|
|||
global(rbulk BULK)
|
||||
global(ptie BULK)
|
||||
|
||||
# Device class section
|
||||
class(PMOS MOS4)
|
||||
class(NMOS MOS4)
|
||||
|
||||
# Device abstracts section
|
||||
# Device abstracts list the pin shapes of the devices.
|
||||
device(D$PMOS PMOS
|
||||
|
|
|
|||
Loading…
Reference in New Issue