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:
Matthias Koefferlein 2019-04-23 19:44:07 +02:00
parent 46b47ff0d9
commit 7f9da5e8de
10 changed files with 167 additions and 7 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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");

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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