mirror of https://github.com/KLayout/klayout.git
WIP: first implementation - needs testing.
This commit is contained in:
parent
2757b22da6
commit
d5506a176a
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue