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); 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) void Circuit::translate_circuits (const std::map<const Circuit *, Circuit *> &map)
{ {
for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) { for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) {

View File

@ -589,6 +589,15 @@ public:
*/ */
void combine_devices (); 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: private:
friend class Netlist; friend class Netlist;
friend class Net; friend class Net;

View File

@ -369,6 +369,20 @@ void Netlist::remove_circuit (Circuit *circuit)
m_circuits.erase (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) DeviceClass *Netlist::device_class_by_name (const std::string &name)
{ {
for (device_class_iterator d = begin_device_classes (); d != end_device_classes (); ++d) { 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); 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) * @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"), gsi::method ("remove_subcircuit", &db::Circuit::remove_subcircuit, gsi::arg ("subcircuit"),
"@brief Removes the given subcircuit from the circuit\n" "@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, 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" "@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" "@brief Removes the given circuit object from the netlist\n"
"After the object has been removed, it becomes invalid and cannot be used further." "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"), 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" "@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." "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 "dbNetlist.h"
#include "dbNetlistDeviceClasses.h"
#include "tlUnitTest.h" #include "tlUnitTest.h"
#include "tlString.h" #include "tlString.h"
@ -1104,3 +1105,176 @@ TEST(13_DeviceAbstract)
EXPECT_EQ (nl.begin_device_abstracts () == nl.end_device_abstracts (), true); 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 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 end
load("test_epilogue.rb") load("test_epilogue.rb")