WIP: speedup LVS 'align' by flattening top-down

This commit is contained in:
Matthias Koefferlein 2019-10-21 22:14:36 +02:00
parent f0635589f7
commit 36ee1efe16
5 changed files with 61 additions and 17 deletions

View File

@ -380,6 +380,30 @@ void Netlist::purge_circuit (Circuit *circuit)
remove_circuit (circuit);
}
void Netlist::flatten_circuits (const std::vector<Circuit *> &circuits)
{
if (circuits.empty ()) {
return;
}
std::set<Circuit *> circuits_set (circuits.begin (), circuits.end ());
std::vector<Circuit *> to_flatten;
to_flatten.reserve (circuits.size ());
// Before flatten, we sort top-down. This optimizes for the case of flattening away
// some hierarchy above a certain circuit.
for (top_down_circuit_iterator c = begin_top_down (); c != end_top_down (); ++c) {
if (circuits_set.find (c.operator-> ()) != circuits_set.end ()) {
to_flatten.push_back (c.operator-> ());
}
}
for (std::vector<Circuit *>::const_iterator c = to_flatten.begin (); c != to_flatten.end (); ++c) {
flatten_circuit (*c);
}
}
void Netlist::flatten_circuit (Circuit *circuit)
{
tl_assert (circuit != 0);

View File

@ -174,6 +174,12 @@ public:
*/
void flatten_circuit (Circuit *circuit);
/**
* @brief Flattens the given circuits
* This is basically equivalent to calling flatten on all given circuits, but more efficient.
*/
void flatten_circuits (const std::vector<Circuit *> &circuits);
/**
* @brief Flattens the netlist
*/

View File

@ -1345,7 +1345,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<tl::weak_ptr<db::Circuit> > circuits_to_flatten;
std::vector<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 ())) {
@ -1353,11 +1353,7 @@ static void flatten_circuit_by_name (db::Netlist *nl, const std::string &name_pa
}
}
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 ());
}
}
nl->flatten_circuits (circuits_to_flatten);
}
static void blank_circuit_by_name (db::Netlist *nl, const std::string &name_pattern)
@ -1399,6 +1395,12 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
"@brief Flattens all circuits of the netlist\n"
"After calling this method, only the top circuits will remain."
) +
gsi::method ("flatten_circuits", &db::Netlist::flatten_circuits,
"@brief Flattens all given circuits of the netlist\n"
"This method is equivalent to calling \\flatten_circuit for all given circuits, but more efficient.\n"
"\n"
"This method has been introduced in version 0.26.1"
) +
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 "

View File

@ -137,14 +137,15 @@ module LVS
# flatten layout cells for which there is no corresponding schematic circuit
unmatched_a.each do |c|
@engine.info("Flatten layout cell (no schematic): #{c.name}")
nl[0].flatten_circuit(c)
end
nl[0].flatten_circuits(unmatched_a)
# flatten schematic circuits for which there is no corresponding layout cell
comparer.unmatched_circuits_b(*nl).each do |c|
unmatched_b = comparer.unmatched_circuits_b(*nl)
unmatched_b.each do |c|
@engine.info("Flatten schematic circuit (no layout): #{c.name}")
nl[1].flatten_circuit(c)
end
nl[1].flatten_circuits(unmatched_b)
end

View File

@ -841,25 +841,36 @@ end;
END
nl3 = nl2.dup
nl2.flatten_circuit(nl2.circuit_by_name("PTRANS"))
nl2.flatten_circuit(nl2.circuit_by_name("NTRANS"))
nl3.flatten_circuit(nl3.circuit_by_name("NTRANS"))
nl3.flatten_circuit(nl3.circuit_by_name("PTRANS"))
assert_equal(nl2.to_s, <<"END")
assert_equal(nl3.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);
device NMOS $2 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
device NMOS $3 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
device PMOS $4 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);
end;
END
nl3.flatten_circuit("{N,P}TRANS")
assert_equal(nl3.to_s, nl2.to_s)
nl4 = nl2.dup
nl4.flatten_circuit("{P,N}TRANS")
assert_equal(nl4.to_s, nl3.to_s)
nl4 = nl2.dup
nl4.flatten_circuits([ nl4.circuit_by_name("PTRANS"), nl4.circuit_by_name("NTRANS") ])
assert_equal(nl4.to_s, nl3.to_s)
nl2 = nl.dup
nl2.flatten_circuit("*") # smoke test
assert_equal(nl2.to_s, "")
nl2 = nl.dup
cc = []
nl2.each_circuit { |c| cc << c }
nl2.flatten_circuits(cc)
assert_equal(nl2.to_s, "")
end
def test_12_BlankAndPurgeCircuits