Netlist: flatten subcircuits, circuits

This commit is contained in:
Matthias Koefferlein 2019-04-06 23:36:08 +02:00
parent 18ee59023e
commit df2bd5e80a
7 changed files with 354 additions and 0 deletions

View File

@ -317,6 +317,87 @@ void Circuit::unregister_ref (SubCircuit *r)
m_refs.erase (r);
}
void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
{
const db::Circuit *c = subcircuit->circuit_ref ();
// copy the nets, produce a net map
std::map<const db::Net *, db::Net *> net2net;
for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) {
// TODO: cannot join pins through subcircuits currently
tl_assert (n->pin_count () <= 1);
db::Net *outside_net = 0;
if (n->pin_count () > 0) {
size_t pin_id = n->begin_pins ()->pin_id ();
outside_net = subcircuit->net_for_pin (pin_id);
} else {
outside_net = new db::Net ();
if (! n->name ().empty ()) {
outside_net->set_name (subcircuit->expanded_name () + "." + n->name ());
}
add_net (outside_net);
}
net2net.insert (std::make_pair (n.operator-> (), outside_net));
}
// copy the devices
for (db::Circuit::const_device_iterator d = c->begin_devices (); d != c->end_devices (); ++d) {
db::Device *device = new db::Device (*d);
if (! d->name ().empty ()) {
device->set_name (subcircuit->expanded_name () + "." + d->name ());
}
add_device (device);
const std::vector<db::DeviceTerminalDefinition> &td = d->device_class ()->terminal_definitions ();
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
const db::Net *tnet = d->net_for_terminal (t->id ());
if (tnet) {
std::map<const db::Net *, db::Net *>::const_iterator n2n = net2net.find (tnet);
tl_assert (n2n != net2net.end ());
device->connect_terminal (t->id (), n2n->second);
}
}
}
// copy the subcircuits
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
db::SubCircuit *new_subcircuit = new db::SubCircuit (*sc);
if (! new_subcircuit->name ().empty ()) {
new_subcircuit->set_name (subcircuit->expanded_name () + "." + new_subcircuit->name ());
}
add_subcircuit (new_subcircuit);
const db::Circuit *cr = sc->circuit_ref ();
for (db::Circuit::const_pin_iterator p = cr->begin_pins (); p != cr->end_pins (); ++p) {
const db::Net *pnet = sc->net_for_pin (p->id ());
if (pnet) {
std::map<const db::Net *, db::Net *>::const_iterator n2n = net2net.find (pnet);
tl_assert (n2n != net2net.end ());
new_subcircuit->connect_pin (p->id (), n2n->second);
}
}
}
remove_subcircuit (subcircuit);
}
void Circuit::translate_circuits (const std::map<const Circuit *, Circuit *> &map)
{
for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) {

View File

@ -589,6 +589,15 @@ public:
*/
void combine_devices ();
/**
* @brief Flattens the given subcircuit
*
* The subcircuit is resolved into the parent circuit and finally removed.
* Net, device and subcircuit names are decorated with the subcircuit's name
* if required.
*/
void flatten_subcircuit (SubCircuit *subcircuit);
private:
friend class Netlist;
friend class Net;

View File

@ -369,6 +369,20 @@ void Netlist::remove_circuit (Circuit *circuit)
m_circuits.erase (circuit);
}
void Netlist::flatten_circuit (Circuit *circuit)
{
std::vector<db::SubCircuit *> refs;
for (db::Circuit::refs_iterator sc = circuit->begin_refs (); sc != circuit->end_refs (); ++sc) {
refs.push_back (sc.operator-> ());
}
for (std::vector<db::SubCircuit *>::const_iterator r = refs.begin (); r != refs.end (); ++r) {
(*r)->circuit ()->flatten_subcircuit (*r);
}
remove_circuit (circuit);
}
DeviceClass *Netlist::device_class_by_name (const std::string &name)
{
for (device_class_iterator d = begin_device_classes (); d != end_device_classes (); ++d) {

View File

@ -138,6 +138,12 @@ public:
*/
void remove_circuit (Circuit *circuit);
/**
* @brief Flattens the given circuit
* All subcircuit references are replaced by the content of this circuit.
*/
void flatten_circuit (Circuit *circuit);
/**
* @brief Begin iterator for the circuits of the netlist (non-const version)
*/

View File

@ -956,6 +956,11 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
gsi::method ("remove_subcircuit", &db::Circuit::remove_subcircuit, gsi::arg ("subcircuit"),
"@brief Removes the given subcircuit from the circuit\n"
) +
gsi::method ("flatten_subcircuit", &db::Circuit::flatten_subcircuit, gsi::arg ("subcircuit"),
"@brief Flattens a subcircuit\n"
"This method will substitute the given subcircuit by it's contents. The subcircuit is removed "
"after this."
) +
gsi::iterator ("each_subcircuit", (db::Circuit::subcircuit_iterator (db::Circuit::*) ()) &db::Circuit::begin_subcircuits, (db::Circuit::subcircuit_iterator (db::Circuit::*) ()) &db::Circuit::end_subcircuits,
"@brief Iterates over the subcircuits of the circuit"
) +
@ -1084,6 +1089,11 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
"@brief Removes the given circuit object from the netlist\n"
"After the object has been removed, it becomes invalid and cannot be used further."
) +
gsi::method ("flatten_circuit", &db::Netlist::flatten_circuit, gsi::arg ("circuit"),
"@brief Flattens a subcircuit\n"
"This method will substitute all instances (subcircuits) of the given circuit by it's "
"contents. After this, the circuit is removed."
) +
gsi::method ("circuit_by_cell_index", (db::Circuit *(db::Netlist::*) (db::cell_index_type)) &db::Netlist::circuit_by_cell_index, gsi::arg ("cell_index"),
"@brief Gets the circuit object for a given cell index.\n"
"If the cell index is not valid or no circuit is registered with this index, nil is returned."

View File

@ -22,6 +22,7 @@
#include "dbNetlist.h"
#include "dbNetlistDeviceClasses.h"
#include "tlUnitTest.h"
#include "tlString.h"
@ -1104,3 +1105,176 @@ TEST(13_DeviceAbstract)
EXPECT_EQ (nl.begin_device_abstracts () == nl.end_device_abstracts (), true);
}
TEST(20_FlattenSubCircuit)
{
db::Netlist nl;
db::DeviceClass *dc;
dc = new db::DeviceClassMOS3Transistor ();
dc->set_name ("NMOS");
nl.add_device_class (dc);
dc = new db::DeviceClassMOS3Transistor ();
dc->set_name ("PMOS");
nl.add_device_class (dc);
nl.from_string (
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
"end;\n"
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
" device PMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
"end;\n"
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
" device NMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
"end;\n"
);
db::Netlist nl2;
nl2 = nl;
db::Circuit *inv2 = nl2.circuit_by_name ("INV2");
inv2->flatten_subcircuit (inv2->subcircuit_by_name ("SC1"));
EXPECT_EQ (nl2.to_string (),
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
" device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
"end;\n"
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
);
nl2.flatten_circuit (nl2.circuit_by_name ("PTRANS"));
nl2.flatten_circuit (nl2.circuit_by_name ("NTRANS"));
EXPECT_EQ (nl2.to_string (),
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
" device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
" device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
" device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
" device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
);
}
TEST(21_FlattenSubCircuit2)
{
db::Netlist nl;
db::DeviceClass *dc;
dc = new db::DeviceClassMOS3Transistor ();
dc->set_name ("NMOS");
nl.add_device_class (dc);
dc = new db::DeviceClassMOS3Transistor ();
dc->set_name ("PMOS");
nl.add_device_class (dc);
nl.from_string (
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
" subcircuit INV2 INV2_SC1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
" subcircuit INV2 INV2_SC2 (IN=FB,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n"
"end;\n"
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
"end;\n"
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
" device PMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
"end;\n"
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
" device NMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);\n"
"end;\n"
);
db::Netlist nl2;
nl2 = nl;
db::Circuit *inv2 = nl2.circuit_by_name ("RINGO");
inv2->flatten_subcircuit (inv2->subcircuit_by_name ("INV2_SC1"));
EXPECT_EQ (nl2.to_string (),
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
" subcircuit INV2 INV2_SC2 (IN=FB,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n"
" subcircuit PTRANS INV2_SC1.SC1 ($1=VDD,$2=FB,$3=$I8);\n"
" subcircuit NTRANS INV2_SC1.SC2 ($1=VSS,$2=FB,$3=$I8);\n"
" subcircuit PTRANS INV2_SC1.SC3 ($1=VDD,$2=OSC,$3=FB);\n"
" subcircuit NTRANS INV2_SC1.SC4 ($1=VSS,$2=OSC,$3=FB);\n"
"end;\n"
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
"end;\n"
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
);
inv2->flatten_subcircuit (inv2->subcircuit_by_name ("INV2_SC2"));
EXPECT_EQ (nl2.to_string (),
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
" subcircuit PTRANS INV2_SC1.SC1 ($1=VDD,$2=FB,$3=$I8);\n"
" subcircuit NTRANS INV2_SC1.SC2 ($1=VSS,$2=FB,$3=$I8);\n"
" subcircuit PTRANS INV2_SC1.SC3 ($1=VDD,$2=OSC,$3=FB);\n"
" subcircuit NTRANS INV2_SC1.SC4 ($1=VSS,$2=OSC,$3=FB);\n"
" subcircuit PTRANS INV2_SC2.SC1 ($1=VDD,$2=(null),$3=FB);\n"
" subcircuit NTRANS INV2_SC2.SC2 ($1=VSS,$2=(null),$3=FB);\n"
" subcircuit PTRANS INV2_SC2.SC3 ($1=VDD,$2=$I8,$3=(null));\n"
" subcircuit NTRANS INV2_SC2.SC4 ($1=VSS,$2=$I8,$3=(null));\n"
"end;\n"
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n"
" subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n"
" subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n"
" subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);\n"
" subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);\n"
"end;\n"
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
);
nl2 = nl;
nl2.flatten_circuit (nl2.circuit_by_name ("INV2"));
EXPECT_EQ (nl2.to_string (),
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
" subcircuit PTRANS INV2_SC1.SC1 ($1=VDD,$2=FB,$3=$I8);\n"
" subcircuit NTRANS INV2_SC1.SC2 ($1=VSS,$2=FB,$3=$I8);\n"
" subcircuit PTRANS INV2_SC1.SC3 ($1=VDD,$2=OSC,$3=FB);\n"
" subcircuit NTRANS INV2_SC1.SC4 ($1=VSS,$2=OSC,$3=FB);\n"
" subcircuit PTRANS INV2_SC2.SC1 ($1=VDD,$2=(null),$3=FB);\n"
" subcircuit NTRANS INV2_SC2.SC2 ($1=VSS,$2=(null),$3=FB);\n"
" subcircuit PTRANS INV2_SC2.SC3 ($1=VDD,$2=$I8,$3=(null));\n"
" subcircuit NTRANS INV2_SC2.SC4 ($1=VSS,$2=$I8,$3=(null));\n"
"end;\n"
"circuit PTRANS ($1=$1,$2=$2,$3=$3);\n"
" device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
"circuit NTRANS ($1=$1,$2=$2,$3=$3);\n"
" device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
);
}

View File

@ -714,6 +714,66 @@ END
end
def test_11_FlattenCircuits
nl = RBA::Netlist::new
dc = RBA::DeviceClassMOS3Transistor::new
dc.name = "NMOS"
nl.add(dc)
dc = RBA::DeviceClassMOS3Transistor::new
dc.name = "PMOS"
nl.add(dc)
nl.from_s(<<"END")
circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);
subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);
subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);
subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);
subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);
end;
circuit PTRANS ($1=$1,$2=$2,$3=$3);
device PMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);
end;
circuit NTRANS ($1=$1,$2=$2,$3=$3);
device NMOS $1 (S=$1,D=$2,G=$3) (L=0.25,W=0.95);
end;
END
nl2 = nl.dup
inv2 = nl2.circuit_by_name("INV2")
inv2.flatten_subcircuit(inv2.subcircuit_by_name("SC1"))
assert_equal(nl2.to_s, <<"END")
circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);
device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);
subcircuit PTRANS SC3 ($1=$5,$2=OUT,$3=$2);
subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$2);
end;
circuit PTRANS ($1=$1,$2=$2,$3=$3);
device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
end;
circuit NTRANS ($1=$1,$2=$2,$3=$3);
device NMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
end;
END
nl2.flatten_circuit(nl2.circuit_by_name("PTRANS"))
nl2.flatten_circuit(nl2.circuit_by_name("NTRANS"))
assert_equal(nl2.to_s, <<"END")
circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);
device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
end;
END
end
end
load("test_epilogue.rb")