WIP: first implementation - needs testing.

This commit is contained in:
Matthias Koefferlein 2019-11-23 01:20:22 +01:00
parent 2757b22da6
commit d5506a176a
8 changed files with 227 additions and 65 deletions

View File

@ -105,6 +105,14 @@ Circuit &Circuit::operator= (const Circuit &other)
m_cell_index = other.m_cell_index;
m_pins = other.m_pins;
m_pin_by_id.clear ();
for (pin_list::iterator p = m_pins.begin (); p != m_pins.end (); ++p) {
if (m_pin_by_id.size () <= p->id ()) {
m_pin_by_id.resize (p->id () + 1, pin_list::iterator ());
}
m_pin_by_id [p->id ()] = p;
}
std::map<const Device *, Device *> device_table;
for (const_device_iterator i = other.begin_devices (); i != other.end_devices (); ++i) {
Device *d = new Device (*i);
@ -157,17 +165,22 @@ void Circuit::set_netlist (Netlist *netlist)
const Pin *Circuit::pin_by_id (size_t id) const
{
if (id >= m_pins.size ()) {
if (id >= m_pin_by_id.size ()) {
return 0;
} else {
return &m_pins [id];
pin_list::iterator pi = m_pin_by_id [id];
if (pi == pin_list::iterator ()) {
return 0;
} else {
return pi.operator-> ();
}
}
}
void Circuit::rename_pin (size_t id, const std::string &name)
{
if (id < m_pins.size ()) {
m_pins [id].set_name (name);
if (id < m_pin_by_id.size () && m_pin_by_id [id] != pin_list::iterator ()) {
m_pin_by_id [id]->set_name (name);
}
}
@ -207,6 +220,7 @@ void Circuit::clear ()
{
m_name.clear ();
m_pins.clear ();
m_pin_by_id.clear ();
m_devices.clear ();
m_nets.clear ();
m_subcircuits.clear ();
@ -290,22 +304,33 @@ Circuit::const_child_circuit_iterator Circuit::end_parents () const
void Circuit::clear_pins ()
{
m_pins.clear ();
m_pin_by_id.clear ();
}
const Pin &Circuit::add_pin (const Pin &pin)
{
m_pins.push_back (pin);
m_pins.back ().set_id (m_pins.size () - 1);
m_pins.back ().set_id (m_pin_by_id.size ());
m_pin_by_id.push_back (--m_pins.end ());
return m_pins.back ();
}
const Pin &Circuit::add_pin (const std::string &name)
{
m_pins.push_back (Pin (name));
m_pins.back ().set_id (m_pins.size () - 1);
m_pins.back ().set_id (m_pin_by_id.size ());
m_pin_by_id.push_back (--m_pins.end ());
return m_pins.back ();
}
void Circuit::remove_pin (size_t id)
{
if (id < m_pin_by_id.size () && m_pin_by_id [id] != pin_list::iterator ()) {
m_pins.erase (m_pin_by_id [id]);
m_pin_by_id [id] = pin_list::iterator ();
}
}
void Circuit::add_net (Net *net)
{
m_nets.push_back (net);
@ -554,13 +579,38 @@ void Circuit::purge_nets ()
{
std::vector<db::Net *> nets_to_be_purged;
for (net_iterator n = begin_nets (); n != end_nets (); ++n) {
if (n->is_floating ()) {
if (n->is_passive ()) {
nets_to_be_purged.push_back (n.operator-> ());
}
}
std::set<size_t> pins_to_delete;
for (std::vector<db::Net *>::const_iterator n = nets_to_be_purged.begin (); n != nets_to_be_purged.end (); ++n) {
for (db::Net::pin_iterator p = (*n)->begin_pins (); p != (*n)->end_pins (); ++p) {
pins_to_delete.insert (p->pin_id ());
}
delete *n;
}
// remove the pin references of the pins we're going to delete
for (refs_iterator r = begin_refs (); r != end_refs (); ++r) {
db::SubCircuit *subcircuit = r.operator-> ();
for (std::set<size_t>::const_iterator p = pins_to_delete.begin (); p != pins_to_delete.end (); ++p) {
db::Net *net = subcircuit->net_for_pin (*p);
for (db::Net::subcircuit_pin_iterator sp = net->begin_subcircuit_pins (); sp != net->end_subcircuit_pins (); ++sp) {
if (sp->pin_id () == *p && sp->subcircuit () == subcircuit) {
net->erase_subcircuit_pin (sp);
break;
}
}
}
}
// and actually remove those pins
for (std::set<size_t>::const_iterator p = pins_to_delete.begin (); p != pins_to_delete.end (); ++p) {
remove_pin (*p);
}
}
/**

View File

@ -89,7 +89,7 @@ class DB_PUBLIC Circuit
: public db::NetlistObject, public gsi::ObjectBase
{
public:
typedef tl::vector<Pin> pin_list;
typedef std::list<Pin> pin_list;
typedef pin_list::const_iterator const_pin_iterator;
typedef pin_list::iterator pin_iterator;
typedef tl::shared_collection<Device> device_list;
@ -330,6 +330,11 @@ public:
*/
const Pin &add_pin (const Pin &pin);
/**
* @brief Removes the pin with the given ID
*/
void remove_pin (size_t id);
/**
* @brief Begin iterator for the pins of the circuit (non-const version)
*/
@ -751,6 +756,7 @@ private:
db::cell_index_type m_cell_index;
net_list m_nets;
pin_list m_pins;
std::vector<pin_list::iterator> m_pin_by_id;
device_list m_devices;
subcircuit_list m_subcircuits;
Netlist *mp_netlist;

View File

@ -472,7 +472,7 @@ void Netlist::remove_device_abstract (DeviceAbstract *device_abstract)
void Netlist::purge_nets ()
{
for (circuit_iterator c = begin_circuits (); c != end_circuits (); ++c) {
for (bottom_up_circuit_iterator c = begin_bottom_up (); c != end_bottom_up (); ++c) {
c->purge_nets ();
}
}

View File

@ -1131,6 +1131,11 @@ Class<db::Circuit> decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
"to the outside through such a pin. The pin is added after all existing "
"pins. For more details see the \\Pin class."
) +
gsi::method ("remove_pin", &db::Circuit::remove_pin, gsi::arg ("id"),
"@brief Removes the pin with the given ID from the circuit\n"
"\n"
"This method has been introduced in version 0.26.2.\n"
) +
gsi::iterator ("each_child", (db::Circuit::child_circuit_iterator (db::Circuit::*) ()) &db::Circuit::begin_children, (db::Circuit::child_circuit_iterator (db::Circuit::*) ()) &db::Circuit::end_children,
"@brief Iterates over the child circuits of this circuit\n"
"Child circuits are the ones that are referenced from this circuit via subcircuits."

View File

@ -2573,3 +2573,134 @@ TEST(12_FloatingSubcircuitExtraction)
);
}
TEST(13_RemoveDummyPins)
{
db::Layout ly;
db::LayerMap lmap;
unsigned int nwell = define_layer (ly, lmap, 1);
unsigned int active = define_layer (ly, lmap, 2);
unsigned int poly = define_layer (ly, lmap, 3);
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
unsigned int diff_cont = define_layer (ly, lmap, 4);
unsigned int poly_cont = define_layer (ly, lmap, 5);
unsigned int metal1 = define_layer (ly, lmap, 6);
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
unsigned int via1 = define_layer (ly, lmap, 7);
unsigned int metal2 = define_layer (ly, lmap, 8);
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
{
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
std::string fn (tl::testsrc ());
fn = tl::combine_path (fn, "testdata");
fn = tl::combine_path (fn, "algo");
fn = tl::combine_path (fn, "issue-425.gds");
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly, options);
}
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::DeepShapeStore dss;
dss.set_text_enlargement (1);
dss.set_text_property_name (tl::Variant ("LABEL"));
// original layers
db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss);
db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss);
db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss);
db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss);
db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss);
db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss);
db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss);
db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss);
db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss);
db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss);
db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss);
// derived regions
db::Region rpactive = ractive & rnwell;
db::Region rpgate = rpactive & rpoly;
db::Region rpsd = rpactive - rpgate;
db::Region rnactive = ractive - rnwell;
db::Region rngate = rnactive & rpoly;
db::Region rnsd = rnactive - rngate;
// perform the extraction
db::Netlist nl;
db::hier_clusters<db::PolygonRef> cl;
db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS");
db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS");
db::NetlistDeviceExtractor::input_layers dl;
dl["SD"] = &rpsd;
dl["G"] = &rpgate;
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
pmos_ex.extract (dss, 0, dl, nl, cl);
dl["SD"] = &rnsd;
dl["G"] = &rngate;
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
nmos_ex.extract (dss, 0, dl, nl, cl);
// perform the net extraction
db::Connectivity conn;
// Intra-layer
conn.connect (rpsd);
conn.connect (rnsd);
conn.connect (rpoly);
conn.connect (rdiff_cont);
conn.connect (rpoly_cont);
conn.connect (rmetal1);
conn.connect (rvia1);
conn.connect (rmetal2);
// Inter-layer
conn.connect (rpsd, rdiff_cont);
conn.connect (rnsd, rdiff_cont);
conn.connect (rpoly, rpoly_cont);
conn.connect (rpoly_cont, rmetal1);
conn.connect (rdiff_cont, rmetal1);
conn.connect (rmetal1, rvia1);
conn.connect (rvia1, rmetal2);
conn.connect (rpoly, rpoly_lbl); // attaches labels
conn.connect (rmetal1, rmetal1_lbl); // attaches labels
conn.connect (rmetal2, rmetal2_lbl); // attaches labels
// extract the nets
db::NetlistExtractor net_ex;
net_ex.set_include_floating_subcircuits (true);
net_ex.extract_nets (dss, 0, conn, nl, cl);
nl.simplify ();
// compare netlist as string
CHECKPOINT ();
db::compare_netlist (_this, nl,
"circuit RINGO (FB=FB,VSS=VSS,VDD=VDD);\n"
" subcircuit INV2 $1 (IN=FB,OUT=$I25,$3=VSS,$4=VDD);\n"
" subcircuit INV2 $2 (IN=$I25,OUT=$I1,$3=VSS,$4=VDD);\n"
" subcircuit INV2 $3 (IN=$I1,OUT=$I2,$3=VSS,$4=VDD);\n"
" subcircuit INV2 $4 (IN=$I2,OUT=$I3,$3=VSS,$4=VDD);\n"
"end;\n"
"circuit INV2 (IN=IN,OUT=OUT,$3=$4,$4=$5);\n"
" device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
" device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
"end;\n"
);
}

View File

@ -360,6 +360,17 @@ TEST(3_CircuitBasic)
EXPECT_EQ (c2.pin_by_id (0)->name (), "p1");
EXPECT_EQ (c2.pin_by_id (1)->name (), "p2");
EXPECT_EQ (c2.pin_by_id (2), 0);
c2.remove_pin (1);
EXPECT_EQ (c2.pin_by_id (0)->name (), "p1");
EXPECT_EQ (c2.pin_by_id (1), 0);
EXPECT_EQ (c2.pin_by_id (2), 0);
db::Pin p3 = c2.add_pin ("p3");
EXPECT_EQ (c2.pin_by_id (0)->name (), "p1");
EXPECT_EQ (c2.pin_by_id (1), 0);
EXPECT_EQ (c2.pin_by_id (2)->name (), "p3");
EXPECT_EQ (c2.pin_by_id (3), 0);
}
TEST(4_CircuitDevices)

View File

@ -1,85 +1,29 @@
* cell INVCHAIN
.SUBCKT INVCHAIN
* cell instance $1 r0 *1 -1.5,-0.8
X$1 9 7 8 6 9 5 1 5 3 2 13 14 INV3
* cell instance $2 r0 *1 2.6,-0.8
X$2 8 11 9 10 8 11 2 12 2 12 5 4 13 14 INV2
* cell instance $3 m90 *1 7.4,0
X$3 14 13 11 12 4 4 10 10 INV
.ENDS INVCHAIN
* cell INV3
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
.SUBCKT INV3 1 2 3 4 5 6 7 8 9 10 11 12
* cell instance $1 r0 *1 4.8,0.8
X$1 12 11 3 10 8 6 1 5 INV
* cell instance $2 r0 *1 1.5,0.8
X$2 12 11 4 7 9 9 2 2 INV
* cell instance $3 m90 *1 2.3,0.8
X$3 12 11 2 9 7 7 4 4 INV
.ENDS INV3
* cell INV2
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
.SUBCKT INV2 1 2 3 4 5 6 7 8 9 10 11 12 13 14
* cell instance $1 m90 *1 1.5,0.8
X$1 14 13 3 11 9 7 1 5 INV
* cell instance $2 r0 *1 4,0.8
X$2 14 13 4 12 10 8 2 6 INV
.ENDS INV2
* cell INV
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
.SUBCKT INV 1 2 3 4 5 6 7 8
* cell instance $1 r0 *1 0,0
X$1 4 1 3 TRANS
* cell instance $2 r0 *1 0,2.8
X$2 4 2 3 TRANS
* device instance $1 r0 *1 0,2.8 PMOS
M$1 4 3 2 4 PMOS L=0.25U W=0.95U AS=0.79325P AD=0.26125P PS=3.57U PD=1.5U
* device instance $2 r0 *1 0.8,2.8 PMOS
M$2 2 7 5 2 PMOS L=0.25U W=0.95U AS=0.26125P AD=0.03325P PS=1.5U PD=1.97U
* device instance $3 r0 *1 0,0 NMOS
M$3 4 3 1 4 NMOS L=0.25U W=0.95U AS=0.79325P AD=0.26125P PS=3.57U PD=1.5U
* device instance $4 r0 *1 0.8,0 NMOS
M$4 1 8 6 1 NMOS L=0.25U W=0.95U AS=0.26125P AD=0.03325P PS=1.5U PD=1.97U
.ENDS INV
* cell TRANS
* pin
* pin
* pin
.SUBCKT TRANS 1 2 3
.ENDS TRANS

View File

@ -170,6 +170,21 @@ class DBNetlist_TestClass < TestBase
c.each_pin { |p| names << p.name }
assert_equal(names, [ "A", "B" ])
assert_equal(c.pin_by_id(0) == nil, false)
assert_equal(c.pin_by_id(1) == nil, false)
assert_equal(c.pin_by_id(0).name, "A")
assert_equal(c.pin_by_id(1).name, "B")
c.remove_pin(0)
names = []
c.each_pin { |p| names << p.name }
assert_equal(names, [ "B" ])
assert_equal(c.pin_by_id(0) == nil, true)
assert_equal(c.pin_by_id(1) == nil, false)
assert_equal(c.pin_by_id(1).name, "B")
end
def test_4_Device