Added persistency of the netlist object properties into L2N/LVSDB files

This commit is contained in:
Matthias Koefferlein 2019-11-13 00:06:29 +01:00
parent d060147713
commit 876487edde
11 changed files with 186 additions and 34 deletions

View File

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

View File

@ -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)
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -72,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;
@ -82,11 +91,6 @@ private:
{
m_id = id;
}
void set_name (const std::string &name)
{
m_name = name;
}
};
}

View File

@ -1125,7 +1125,7 @@ static void circuit_disconnect_pin1 (db::Circuit *c, const db::Pin *pin)
}
Class<db::Circuit> decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
gsi::method ("create_pin", &db::Circuit::add_pin, gsi::arg ("name"),
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 "

View File

@ -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,30 @@ 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);
}
TEST(2_ReaderWithGlobalNets)
{
db::LayoutToNetlist l2n;
@ -278,7 +302,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 +359,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 +418,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);

View File

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