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_cell_index = other.m_cell_index;
m_pins = other.m_pins; 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; std::map<const Device *, Device *> device_table;
for (const_device_iterator i = other.begin_devices (); i != other.end_devices (); ++i) { for (const_device_iterator i = other.begin_devices (); i != other.end_devices (); ++i) {
Device *d = new Device (*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 const Pin *Circuit::pin_by_id (size_t id) const
{ {
if (id >= m_pins.size ()) { if (id >= m_pin_by_id.size ()) {
return 0; return 0;
} else { } 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) void Circuit::rename_pin (size_t id, const std::string &name)
{ {
if (id < m_pins.size ()) { if (id < m_pin_by_id.size () && m_pin_by_id [id] != pin_list::iterator ()) {
m_pins [id].set_name (name); m_pin_by_id [id]->set_name (name);
} }
} }
@ -207,6 +220,7 @@ void Circuit::clear ()
{ {
m_name.clear (); m_name.clear ();
m_pins.clear (); m_pins.clear ();
m_pin_by_id.clear ();
m_devices.clear (); m_devices.clear ();
m_nets.clear (); m_nets.clear ();
m_subcircuits.clear (); m_subcircuits.clear ();
@ -290,22 +304,33 @@ Circuit::const_child_circuit_iterator Circuit::end_parents () const
void Circuit::clear_pins () void Circuit::clear_pins ()
{ {
m_pins.clear (); m_pins.clear ();
m_pin_by_id.clear ();
} }
const Pin &Circuit::add_pin (const Pin &pin) const Pin &Circuit::add_pin (const Pin &pin)
{ {
m_pins.push_back (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 (); return m_pins.back ();
} }
const Pin &Circuit::add_pin (const std::string &name) const Pin &Circuit::add_pin (const std::string &name)
{ {
m_pins.push_back (Pin (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 (); 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) void Circuit::add_net (Net *net)
{ {
m_nets.push_back (net); m_nets.push_back (net);
@ -554,13 +579,38 @@ void Circuit::purge_nets ()
{ {
std::vector<db::Net *> nets_to_be_purged; std::vector<db::Net *> nets_to_be_purged;
for (net_iterator n = begin_nets (); n != end_nets (); ++n) { 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-> ()); 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 (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; 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 db::NetlistObject, public gsi::ObjectBase
{ {
public: public:
typedef tl::vector<Pin> pin_list; typedef std::list<Pin> pin_list;
typedef pin_list::const_iterator const_pin_iterator; typedef pin_list::const_iterator const_pin_iterator;
typedef pin_list::iterator pin_iterator; typedef pin_list::iterator pin_iterator;
typedef tl::shared_collection<Device> device_list; typedef tl::shared_collection<Device> device_list;
@ -330,6 +330,11 @@ public:
*/ */
const Pin &add_pin (const Pin &pin); 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) * @brief Begin iterator for the pins of the circuit (non-const version)
*/ */
@ -751,6 +756,7 @@ private:
db::cell_index_type m_cell_index; db::cell_index_type m_cell_index;
net_list m_nets; net_list m_nets;
pin_list m_pins; pin_list m_pins;
std::vector<pin_list::iterator> m_pin_by_id;
device_list m_devices; device_list m_devices;
subcircuit_list m_subcircuits; subcircuit_list m_subcircuits;
Netlist *mp_netlist; Netlist *mp_netlist;

View File

@ -472,7 +472,7 @@ void Netlist::remove_device_abstract (DeviceAbstract *device_abstract)
void Netlist::purge_nets () 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 (); 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 " "to the outside through such a pin. The pin is added after all existing "
"pins. For more details see the \\Pin class." "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, 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" "@brief Iterates over the child circuits of this circuit\n"
"Child circuits are the ones that are referenced from this circuit via subcircuits." "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 (0)->name (), "p1");
EXPECT_EQ (c2.pin_by_id (1)->name (), "p2"); EXPECT_EQ (c2.pin_by_id (1)->name (), "p2");
EXPECT_EQ (c2.pin_by_id (2), 0); 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) TEST(4_CircuitDevices)

View File

@ -1,85 +1,29 @@
* cell INVCHAIN * cell INVCHAIN
.SUBCKT 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 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 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 X$3 14 13 11 12 4 4 10 10 INV
.ENDS INVCHAIN .ENDS INVCHAIN
* cell INV3 * 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 .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 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 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 X$3 12 11 2 9 7 7 4 4 INV
.ENDS INV3 .ENDS INV3
* cell INV2 * 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 .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 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 X$2 14 13 4 12 10 8 2 6 INV
.ENDS INV2 .ENDS INV2
* cell INV * cell INV
* pin
* pin
* pin
* pin
* pin
* pin
* pin
* pin
.SUBCKT INV 1 2 3 4 5 6 7 8 .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 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 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 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 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 .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 } c.each_pin { |p| names << p.name }
assert_equal(names, [ "A", "B" ]) 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 end
def test_4_Device def test_4_Device