mirror of https://github.com/KLayout/klayout.git
WIP: added circuit blankout.
This commit is contained in:
parent
fb8a64b0e1
commit
5ce8dd2684
|
|
@ -23,6 +23,8 @@
|
|||
#include "dbCircuit.h"
|
||||
#include "dbNetlist.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
|
|
@ -30,7 +32,7 @@ namespace db
|
|||
// Circuit class implementation
|
||||
|
||||
Circuit::Circuit ()
|
||||
: m_cell_index (0), mp_netlist (0),
|
||||
: m_dont_purge (false), m_cell_index (0), mp_netlist (0),
|
||||
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
|
||||
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
|
||||
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
|
||||
|
|
@ -45,7 +47,7 @@ Circuit::Circuit ()
|
|||
}
|
||||
|
||||
Circuit::Circuit (const Circuit &other)
|
||||
: gsi::ObjectBase (other), tl::Object (other), m_cell_index (0), mp_netlist (0),
|
||||
: gsi::ObjectBase (other), tl::Object (other), m_dont_purge (false), m_cell_index (0), mp_netlist (0),
|
||||
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
|
||||
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
|
||||
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
|
||||
|
|
@ -80,6 +82,7 @@ Circuit &Circuit::operator= (const Circuit &other)
|
|||
clear ();
|
||||
|
||||
m_name = other.m_name;
|
||||
m_dont_purge = other.m_dont_purge;
|
||||
m_cell_index = other.m_cell_index;
|
||||
m_pins = other.m_pins;
|
||||
|
||||
|
|
@ -191,6 +194,11 @@ void Circuit::set_name (const std::string &name)
|
|||
}
|
||||
}
|
||||
|
||||
void Circuit::set_dont_purge (bool dp)
|
||||
{
|
||||
m_dont_purge = dp;
|
||||
}
|
||||
|
||||
void Circuit::set_cell_index (const db::cell_index_type ci)
|
||||
{
|
||||
m_cell_index = ci;
|
||||
|
|
@ -436,6 +444,35 @@ void Circuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter)
|
|||
m_pin_refs [pin_id] = iter;
|
||||
}
|
||||
|
||||
void Circuit::blank ()
|
||||
{
|
||||
tl_assert (netlist () != 0);
|
||||
|
||||
std::set<db::Circuit *> cs;
|
||||
for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) {
|
||||
cs.insert (i->circuit_ref ());
|
||||
}
|
||||
|
||||
// weak pointers are good because deleting a subcircuit might delete others ahead in
|
||||
// this list:
|
||||
std::list<tl::weak_ptr<db::Circuit> > called_circuits;
|
||||
for (std::set<db::Circuit *>::const_iterator c = cs.begin (); c != cs.end (); ++c) {
|
||||
called_circuits.push_back (*c);
|
||||
}
|
||||
|
||||
m_nets.clear ();
|
||||
m_subcircuits.clear ();
|
||||
m_devices.clear ();
|
||||
|
||||
for (std::list<tl::weak_ptr<db::Circuit> >::iterator c = called_circuits.begin (); c != called_circuits.end (); ++c) {
|
||||
if (c->get () && ! (*c)->has_refs ()) {
|
||||
netlist ()->purge_circuit (c->get ());
|
||||
}
|
||||
}
|
||||
|
||||
set_dont_purge (true);
|
||||
}
|
||||
|
||||
const Net *Circuit::net_for_pin (size_t pin_id) const
|
||||
{
|
||||
if (pin_id < m_pin_refs.size ()) {
|
||||
|
|
|
|||
|
|
@ -164,6 +164,20 @@ public:
|
|||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets or resets the "don't purge" flag
|
||||
* This flag will prevent "purge" from deleting this circuit. It is set by "blank".
|
||||
*/
|
||||
void set_dont_purge (bool dp);
|
||||
|
||||
/**
|
||||
* @brief Gets or resets the "don't purge" flag
|
||||
*/
|
||||
bool dont_purge () const
|
||||
{
|
||||
return m_dont_purge;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The index of the circuit in the netlist
|
||||
* CAUTION: this attribute is used for internal purposes and may not be valid always.
|
||||
|
|
@ -215,6 +229,23 @@ public:
|
|||
return m_refs.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the references to this circuit (end, const version)
|
||||
* This iterator will deliver all subcircuits referencing this circuit
|
||||
*/
|
||||
const_refs_iterator end_refs () const
|
||||
{
|
||||
return m_refs.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the circuit has references
|
||||
*/
|
||||
bool has_refs () const
|
||||
{
|
||||
return begin_refs () != end_refs ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the child circuits iterator (begin)
|
||||
* The child circuits are the circuits referenced by all subcircuits
|
||||
|
|
@ -261,15 +292,6 @@ public:
|
|||
*/
|
||||
const_parent_circuit_iterator end_parents () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the references to this circuit (end, const version)
|
||||
* This iterator will deliver all subcircuits referencing this circuit
|
||||
*/
|
||||
const_refs_iterator end_refs () const
|
||||
{
|
||||
return m_refs.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears the pins
|
||||
*/
|
||||
|
|
@ -658,6 +680,16 @@ public:
|
|||
*/
|
||||
void flatten_subcircuit (SubCircuit *subcircuit);
|
||||
|
||||
/**
|
||||
* @brief Blanks out the circuit
|
||||
*
|
||||
* This will remove all innards of the circuit (nets, devices, subcircuits)
|
||||
* and circuits which will itself are not longer be called after this.
|
||||
* This operation will eventually leave a blackbox model of the circuit
|
||||
* containing only pins.
|
||||
*/
|
||||
void blank ();
|
||||
|
||||
private:
|
||||
friend class Netlist;
|
||||
friend class Net;
|
||||
|
|
@ -665,6 +697,7 @@ private:
|
|||
friend class Device;
|
||||
|
||||
std::string m_name;
|
||||
bool m_dont_purge;
|
||||
db::cell_index_type m_cell_index;
|
||||
net_list m_nets;
|
||||
pin_list m_pins;
|
||||
|
|
|
|||
|
|
@ -373,6 +373,12 @@ void Netlist::remove_circuit (Circuit *circuit)
|
|||
m_circuits.erase (circuit);
|
||||
}
|
||||
|
||||
void Netlist::purge_circuit (Circuit *circuit)
|
||||
{
|
||||
circuit->blank ();
|
||||
remove_circuit (circuit);
|
||||
}
|
||||
|
||||
void Netlist::flatten_circuit (Circuit *circuit)
|
||||
{
|
||||
tl_assert (circuit != 0);
|
||||
|
|
@ -463,7 +469,7 @@ void Netlist::purge ()
|
|||
Circuit *circuit = c.operator-> ();
|
||||
|
||||
circuit->purge_nets ();
|
||||
if (circuit->begin_nets () == circuit->end_nets ()) {
|
||||
if (circuit->begin_nets () == circuit->end_nets () && ! circuit->dont_purge ()) {
|
||||
|
||||
// No nets left: delete the subcircuits that refer to us and finally delete the circuit
|
||||
while (circuit->begin_refs () != circuit->end_refs ()) {
|
||||
|
|
@ -563,13 +569,17 @@ std::string Netlist::to_string () const
|
|||
std::string ps;
|
||||
const db::SubCircuit &subcircuit = *sc;
|
||||
const db::Circuit *circuit = sc->circuit_ref ();
|
||||
for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) {
|
||||
if (p != circuit->begin_pins ()) {
|
||||
ps += ",";
|
||||
if (circuit) {
|
||||
for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) {
|
||||
if (p != circuit->begin_pins ()) {
|
||||
ps += ",";
|
||||
}
|
||||
ps += pin2string (*p) + "=" + net2string (subcircuit.net_for_pin (p->id ()));
|
||||
}
|
||||
ps += pin2string (*p) + "=" + net2string (subcircuit.net_for_pin (p->id ()));
|
||||
res += std::string (" subcircuit ") + tl::to_word_or_quoted_string (circuit->name ()) + " " + subcircuit2string (*sc) + " (" + ps + ");\n";
|
||||
} else {
|
||||
res += std::string (" subcircuit (null);\n");
|
||||
}
|
||||
res += std::string (" subcircuit ") + tl::to_word_or_quoted_string (circuit->name ()) + " " + subcircuit2string (*sc) + " (" + ps + ");\n";
|
||||
}
|
||||
|
||||
res += std::string ("end;\n");
|
||||
|
|
|
|||
|
|
@ -138,6 +138,14 @@ public:
|
|||
*/
|
||||
void remove_circuit (Circuit *circuit);
|
||||
|
||||
/**
|
||||
* @brief Purges a circuit from the netlist
|
||||
* In contrast to "delete", this method will
|
||||
* also remove subcircuits unless called
|
||||
* otherwise.
|
||||
*/
|
||||
void purge_circuit (Circuit *circuit);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of circuits
|
||||
*/
|
||||
|
|
@ -449,6 +457,9 @@ public:
|
|||
*
|
||||
* This method will purge all nets which return "floating". Circuits which don't have any
|
||||
* nets (or only floating ones) and removed. Their subcircuits are disconnected.
|
||||
*
|
||||
* This method respects the circuit's "dont_purge" flag and will not purge them if this
|
||||
* flag is set.
|
||||
*/
|
||||
void purge ();
|
||||
|
||||
|
|
|
|||
|
|
@ -1081,6 +1081,10 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
|
|||
"@brief Iterates over the parent circuits of this circuit\n"
|
||||
"Child circuits are the ones that are referencing this circuit via subcircuits."
|
||||
) +
|
||||
gsi::method ("has_refs", &db::Circuit::has_refs,
|
||||
"@brief Returns a value indicating whether the circuit has references\n"
|
||||
"A circuit has references if there is at least one subcircuit referring to it."
|
||||
) +
|
||||
gsi::iterator ("each_ref", (db::Circuit::refs_iterator (db::Circuit::*) ()) &db::Circuit::begin_refs, (db::Circuit::refs_iterator (db::Circuit::*) ()) &db::Circuit::end_refs,
|
||||
"@brief Iterates over the subcircuit objects referencing this circuit\n"
|
||||
) +
|
||||
|
|
@ -1170,6 +1174,14 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
|
|||
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"
|
||||
) +
|
||||
gsi::method ("blank", &db::Circuit::blank,
|
||||
"@brief Blanks out the circuit\n"
|
||||
"This method will remove all the innards of the circuit and just leave the pins. "
|
||||
"The pins won't be connected to inside nets anymore, but the circuit can still be "
|
||||
"called by subcircuit references. "
|
||||
"This method will eventually create a 'circuit abstract' (or black box). It will "
|
||||
"set the \\dont_purge flag to mark this circuit as 'intentionally empty'."
|
||||
) +
|
||||
gsi::method ("netlist", (db::Netlist *(db::Circuit::*) ()) &db::Circuit::netlist,
|
||||
"@brief Gets the netlist object the circuit lives in"
|
||||
) +
|
||||
|
|
@ -1179,6 +1191,14 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
|
|||
gsi::method ("name", &db::Circuit::name,
|
||||
"@brief Gets the name of the circuit"
|
||||
) +
|
||||
gsi::method ("dont_purge", &db::Circuit::dont_purge,
|
||||
"@brief Gets a value indicating whether the circuit can be purged on \\Netlist#purge.\n"
|
||||
) +
|
||||
gsi::method ("dont_purge=", &db::Circuit::set_dont_purge, gsi::arg ("f"),
|
||||
"@brief Sets a value indicating whether the circuit can be purged on \\Netlist#purge.\n"
|
||||
"If this attribute is set to true, \\Netlist#purge will never delete this circuit.\n"
|
||||
"This flag therefore marks this circuit as 'precious'."
|
||||
) +
|
||||
gsi::method ("cell_index=", &db::Circuit::set_cell_index, gsi::arg ("cell_index"),
|
||||
"@brief Sets the cell index\n"
|
||||
"The cell index relates a circuit with a cell from a layout. It's intended to "
|
||||
|
|
@ -1287,7 +1307,7 @@ static void read_netlist (db::Netlist *nl, const std::string &file, db::NetlistR
|
|||
|
||||
static void flatten_circuit_by_name (db::Netlist *nl, const std::string &name_pattern)
|
||||
{
|
||||
std::list<db::Circuit *> circuits_to_flatten;
|
||||
std::list<tl::weak_ptr<db::Circuit> > circuits_to_flatten;
|
||||
tl::GlobPattern pat (name_pattern);
|
||||
for (db::Netlist::circuit_iterator c = nl->begin_circuits (); c != nl->end_circuits (); ++c) {
|
||||
if (pat.match (c->name ())) {
|
||||
|
|
@ -1295,8 +1315,27 @@ static void flatten_circuit_by_name (db::Netlist *nl, const std::string &name_pa
|
|||
}
|
||||
}
|
||||
|
||||
for (std::list<db::Circuit *>::const_iterator c = circuits_to_flatten.begin (); c != circuits_to_flatten.end (); ++c) {
|
||||
nl->flatten_circuit (*c);
|
||||
for (std::list<tl::weak_ptr<db::Circuit> >::iterator c = circuits_to_flatten.begin (); c != circuits_to_flatten.end (); ++c) {
|
||||
if (c->get ()) {
|
||||
nl->flatten_circuit (c->get ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blank_circuit_by_name (db::Netlist *nl, const std::string &name_pattern)
|
||||
{
|
||||
std::list<tl::weak_ptr<db::Circuit> > circuits_to_blank;
|
||||
tl::GlobPattern pat (name_pattern);
|
||||
for (db::Netlist::circuit_iterator c = nl->begin_circuits (); c != nl->end_circuits (); ++c) {
|
||||
if (pat.match (c->name ())) {
|
||||
circuits_to_blank.push_back (c.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
for (std::list<tl::weak_ptr<db::Circuit> >::iterator c = circuits_to_blank.begin (); c != circuits_to_blank.end (); ++c) {
|
||||
if (c->get ()) {
|
||||
(*c)->blank ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1308,7 +1347,15 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
) +
|
||||
gsi::method ("remove", &db::Netlist::remove_circuit, gsi::arg ("circuit"),
|
||||
"@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 circuit has been removed, the object becomes invalid and cannot be used further. "
|
||||
"A circuit with references (see \\has_refs) should not be removed as the "
|
||||
"subcircuits calling it would afterwards point to nothing."
|
||||
) +
|
||||
gsi::method ("purge_circuit", &db::Netlist::purge_circuit, gsi::arg ("circuit"),
|
||||
"@brief Removes the given circuit object and all child circuits which are not used otherwise from the netlist\n"
|
||||
"After the circuit has been removed, the object becomes invalid and cannot be used further. "
|
||||
"A circuit with references (see \\has_refs) should not be removed as the "
|
||||
"subcircuits calling it would afterwards point to nothing."
|
||||
) +
|
||||
gsi::method ("flatten_circuit", &db::Netlist::flatten_circuit, gsi::arg ("circuit"),
|
||||
"@brief Flattens a subcircuit\n"
|
||||
|
|
@ -1318,9 +1365,19 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
gsi::method_ext ("flatten_circuit", &flatten_circuit_by_name, gsi::arg ("pattern"),
|
||||
"@brief Flattens circuits matching a certain pattern\n"
|
||||
"This method will substitute all instances (subcircuits) of all circuits with names matching the given name pattern. "
|
||||
"The name pattern is a glob expression. For example, 'flatten_circuit(\"np*\")' will flatten all circuits witt names "
|
||||
"The name pattern is a glob expression. For example, 'flatten_circuit(\"np*\")' will flatten all circuits with names "
|
||||
"starting with 'np'."
|
||||
) +
|
||||
gsi::method_ext ("blank_circuit", &blank_circuit_by_name, gsi::arg ("pattern"),
|
||||
"@brief Blanks circuits matching a certain pattern\n"
|
||||
"This method will erase everything from inside the circuits matching the given pattern. It will only leave pins which are "
|
||||
"not connected to any net. Hence, this method forms 'abstract' or black-box circuits which can be instantiated through "
|
||||
"subcircuits like the former ones, but are empty shells.\n"
|
||||
"The name pattern is a glob expression. For example, 'flatten_circuit(\"np*\")' will blank out all circuits with names "
|
||||
"starting with 'np'.\n"
|
||||
"\n"
|
||||
"For more details see \\Circuit#blank which is the corresponding method on the actual object."
|
||||
) +
|
||||
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."
|
||||
|
|
@ -1390,7 +1447,9 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
gsi::method ("purge", &db::Netlist::purge,
|
||||
"@brief Purge unused nets, circuits and subcircuits.\n"
|
||||
"This method will purge all nets which return \\floating == true. Circuits which don't have any "
|
||||
"nets (or only floating ones) and removed. Their subcircuits are disconnected."
|
||||
"nets (or only floating ones) and removed. Their subcircuits are disconnected.\n"
|
||||
"This method respects the \\Circuit#dont_purge attribute and will never delete circuits "
|
||||
"with this flag set."
|
||||
) +
|
||||
gsi::method ("purge_nets", &db::Netlist::purge_nets,
|
||||
"@brief Purges floating nets.\n"
|
||||
|
|
|
|||
|
|
@ -1297,3 +1297,103 @@ TEST(21_FlattenSubCircuit2)
|
|||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(22_BlankCircuit)
|
||||
{
|
||||
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 *circuit = nl2.circuit_by_name ("INV2");
|
||||
nl2.purge_circuit (circuit);
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
"circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n"
|
||||
" subcircuit (null);\n"
|
||||
" subcircuit (null);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
nl2 = nl;
|
||||
circuit = nl2.circuit_by_name ("INV2");
|
||||
EXPECT_EQ (circuit->dont_purge (), false);
|
||||
circuit->blank ();
|
||||
EXPECT_EQ (circuit->dont_purge (), true);
|
||||
|
||||
EXPECT_EQ (nl2.to_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=(null),$2=(null),OUT=(null),$4=(null),$5=(null));\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// purge won't delete INV2
|
||||
nl2.purge ();
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
"circuit RINGO (IN=(null),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=(null),$2=(null),OUT=(null),$4=(null),$5=(null));\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
circuit->set_dont_purge (false);
|
||||
|
||||
// now it will ...
|
||||
nl2.purge ();
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
""
|
||||
);
|
||||
|
||||
nl2 = nl;
|
||||
circuit = nl2.circuit_by_name ("RINGO");
|
||||
nl2.purge_circuit (circuit);
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
""
|
||||
);
|
||||
|
||||
nl2 = nl;
|
||||
circuit = nl2.circuit_by_name ("RINGO");
|
||||
circuit->blank ();
|
||||
|
||||
EXPECT_EQ (nl2.to_string (),
|
||||
"circuit RINGO (IN=(null),OSC=(null),VSS=(null),VDD=(null));\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
<p>
|
||||
Netlist tweaks can also be applied to the schematic netlist. For example to flatten away
|
||||
a model subcircuit called "NMOS", use this expression:
|
||||
a model subcircuit called "NMOS", use this <class_doc href="Netlist#flatten_circuit"/>:
|
||||
</p>
|
||||
|
||||
<pre>schematic.flatten_circuit("NMOS")</pre>
|
||||
|
|
@ -110,6 +110,46 @@
|
|||
|
||||
<pre>netlist.flatten_circuit("CIRCUIT_NAME")</pre>
|
||||
|
||||
<p>
|
||||
The argument to "flatten_circuit" is a glob pattern (shell-like).
|
||||
For example, "NMOS*" will flatten all circuits starting with "NMOS".
|
||||
</p>
|
||||
|
||||
<h2>Black boxing (circuit abstraction)</h2>
|
||||
|
||||
<p>
|
||||
Circuit abstraction is a technique to reduce the verification overhead.
|
||||
At an early stage it might be useful to replace a cell by a simplified version or
|
||||
by a raw pin frame. The circuits extracted from such cells is basically empty or
|
||||
are intentionally simplified. But as long as there is something inside the
|
||||
cell which the parent circuit connects to, pins will be generated. These
|
||||
pins then can be thought of as the circuit's abstraction.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A useful method in this context is the "blank_circuit" method. It clears
|
||||
a circuit's innards and leaves only the pins. You can use this method to
|
||||
ensure abstracts in both the layout netlist and the schematic. After this,
|
||||
the compare algorithm will identify both circuits as identical, provided
|
||||
they feature the same number of pins.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To wipe out the innards of a circuit, use the <class_doc href="Netlist#blank_circuit"/> method:
|
||||
</p>
|
||||
|
||||
<pre>netlist.blank_circuit("CIRCUIT_NAME")
|
||||
schematic.blank_circuit("CIRCUIT_NAME")</pre>
|
||||
|
||||
<p>
|
||||
The argument to "blank_circuit" is a glob pattern (shell-like).
|
||||
For example, "MEMORY*" will blank out all circuits starting with "MEMORY".
|
||||
</p>
|
||||
|
||||
<p><b>NOTE:</b> Use "blank_circuit" before "purge" or "simplify" (see below). This method
|
||||
sets a flag (<class_doc href="Circuit#dont_purge"/>) which prevents purging of abstract
|
||||
circuits.</p>
|
||||
|
||||
<h2>Purging (elimination of redundancy)</h2>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ class DBNetlist_TestClass < TestBase
|
|||
assert_equal(nl.circuit_by_name("DOESNOTEXIST").inspect, "nil")
|
||||
|
||||
cc = RBA::Circuit::new
|
||||
assert_equal(cc.dont_purge, false)
|
||||
cc.dont_purge = true
|
||||
assert_equal(cc.dont_purge, true)
|
||||
|
||||
nl.add(cc)
|
||||
cc.name = "ABC"
|
||||
|
||||
|
|
@ -845,6 +849,98 @@ END
|
|||
nl3.flatten_circuit("{N,P}TRANS")
|
||||
assert_equal(nl3.to_s, nl2.to_s)
|
||||
|
||||
nl2 = nl.dup
|
||||
nl2.flatten_circuit("*") # smoke test
|
||||
assert_equal(nl2.to_s, "")
|
||||
|
||||
end
|
||||
|
||||
def test_12_BlankAndPurgeCircuits
|
||||
|
||||
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 RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);
|
||||
subcircuit INV2 INV2_SC1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 INV2_SC2 (IN=FB,$2=(null),OUT=$I8,$4=VSS,$5=VDD);
|
||||
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
|
||||
circuit = nl2.circuit_by_name("INV2")
|
||||
nl2.purge_circuit(circuit)
|
||||
|
||||
assert_equal(nl2.to_s, <<"END")
|
||||
circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);
|
||||
subcircuit (null);
|
||||
subcircuit (null);
|
||||
end;
|
||||
END
|
||||
|
||||
nl2 = nl.dup
|
||||
circuit = nl2.circuit_by_name("INV2")
|
||||
circuit.blank
|
||||
|
||||
assert_equal(nl2.to_s, <<"END")
|
||||
circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);
|
||||
subcircuit INV2 INV2_SC1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);
|
||||
subcircuit INV2 INV2_SC2 (IN=FB,$2=(null),OUT=$I8,$4=VSS,$5=VDD);
|
||||
end;
|
||||
circuit INV2 (IN=(null),$2=(null),OUT=(null),$4=(null),$5=(null));
|
||||
end;
|
||||
END
|
||||
|
||||
nl2 = nl.dup
|
||||
circuit = nl2.circuit_by_name("RINGO")
|
||||
nl2.purge_circuit(circuit)
|
||||
|
||||
assert_equal(nl2.to_s, "")
|
||||
|
||||
nl2 = nl.dup
|
||||
circuit = nl2.circuit_by_name("RINGO")
|
||||
circuit.blank
|
||||
|
||||
assert_equal(nl2.to_s, <<"END")
|
||||
circuit RINGO (IN=(null),OSC=(null),VSS=(null),VDD=(null));
|
||||
end;
|
||||
END
|
||||
|
||||
nl2 = nl.dup
|
||||
nl2.blank_circuit("*")
|
||||
|
||||
assert_equal(nl2.to_s, <<"END")
|
||||
circuit RINGO (IN=(null),OSC=(null),VSS=(null),VDD=(null));
|
||||
end;
|
||||
END
|
||||
|
||||
nl2 = nl.dup
|
||||
nl2.blank_circuit("RINGO")
|
||||
|
||||
assert_equal(nl2.to_s, <<"END")
|
||||
circuit RINGO (IN=(null),OSC=(null),VSS=(null),VDD=(null));
|
||||
end;
|
||||
END
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue