mirror of https://github.com/KLayout/klayout.git
WIP: LVSDB reader/writer fixes
This commit is contained in:
parent
ea8320dcf8
commit
834dcc7474
|
|
@ -495,19 +495,25 @@ void
|
|||
LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutToNetlist * /*l2n*/, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
unsigned int netid = (unsigned int) read_int ();
|
||||
br.done ();
|
||||
|
||||
const db::Pin &pin = circuit->add_pin (name);
|
||||
|
||||
db::Net *net = id2net [netid];
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net ID: ")) + tl::to_string (netid));
|
||||
if (br) {
|
||||
|
||||
unsigned int netid = (unsigned int) read_int ();
|
||||
db::Net *net = id2net [netid];
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net ID: ")) + tl::to_string (netid));
|
||||
}
|
||||
|
||||
circuit->connect_pin (pin.id (), net);
|
||||
|
||||
}
|
||||
|
||||
circuit->connect_pin (pin.id (), net);
|
||||
br.done ();
|
||||
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
@ -616,18 +622,23 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
|
|||
Brace br2 (this);
|
||||
std::string tname;
|
||||
read_word_or_quoted (tname);
|
||||
unsigned int netid = (unsigned int) read_int ();
|
||||
br2.done ();
|
||||
|
||||
size_t tid = terminal_id (dm.second, tname);
|
||||
max_tid = std::max (max_tid, tid + 1);
|
||||
|
||||
db::Net *net = id2net [netid];
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net ID: ")) + tl::to_string (netid));
|
||||
if (br2) {
|
||||
|
||||
unsigned int netid = (unsigned int) read_int ();
|
||||
db::Net *net = id2net [netid];
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net ID: ")) + tl::to_string (netid));
|
||||
}
|
||||
|
||||
device->connect_terminal (tid, net);
|
||||
|
||||
}
|
||||
|
||||
device->connect_terminal (tid, net);
|
||||
br2.done ();
|
||||
|
||||
} else if (test (skeys::param_key) || test (lkeys::param_key)) {
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,8 @@ void std_writer_impl<Keys>::write (const db::Netlist *netlist, const db::LayoutT
|
|||
const db::Net *net = circuit.net_for_pin (p->id ());
|
||||
if (net) {
|
||||
*mp_stream << indent << indent1 << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << (*net2id) [net] << ")" << endl;
|
||||
} else {
|
||||
*mp_stream << indent << indent1 << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << ")" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -530,6 +532,8 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist * /*l2n*/, const db
|
|||
const db::Net *net = device.net_for_terminal (i->id ());
|
||||
if (net) {
|
||||
*mp_stream << indent << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << net2id [net] << ")" << endl;
|
||||
} else {
|
||||
*mp_stream << indent << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,18 +162,24 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref
|
|||
|
||||
Brace br (this);
|
||||
|
||||
std::string name_a, name_b;
|
||||
read_word_or_quoted (name_a);
|
||||
read_word_or_quoted (name_b);
|
||||
std::pair<std::string, bool> non_a, non_b;
|
||||
non_a = read_non_string ();
|
||||
non_b = read_non_string ();
|
||||
|
||||
const db::Circuit *circuit_a = xref->netlist_a ()->circuit_by_name (name_a);
|
||||
if (! circuit_a) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid circuit name: ")) + name_a);
|
||||
const db::Circuit *circuit_a = 0;
|
||||
if (non_a.second) {
|
||||
circuit_a = xref->netlist_a ()->circuit_by_name (non_a.first);
|
||||
if (! circuit_a) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid circuit name: ")) + non_a.first);
|
||||
}
|
||||
}
|
||||
|
||||
const db::Circuit *circuit_b = xref->netlist_b ()->circuit_by_name (name_b);
|
||||
if (! circuit_b) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid circuit name: ")) + name_b);
|
||||
const db::Circuit *circuit_b = 0;
|
||||
if (non_b.second) {
|
||||
circuit_b = xref->netlist_b ()->circuit_by_name (non_b.first);
|
||||
if (! circuit_b) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid circuit name: ")) + non_b.first);
|
||||
}
|
||||
}
|
||||
|
||||
xref->gen_begin_circuit (circuit_a, circuit_b);
|
||||
|
|
|
|||
|
|
@ -257,3 +257,199 @@ TEST(1_BasicFlow)
|
|||
compare_lvsdbs (_this, path2, au_path);
|
||||
}
|
||||
|
||||
|
||||
TEST(2_FlowWithErrors)
|
||||
{
|
||||
db::Layout ly;
|
||||
db::LayerMap lmap;
|
||||
|
||||
unsigned int nwell = define_layer (ly, lmap, 1);
|
||||
unsigned int active = define_layer (ly, lmap, 2);
|
||||
unsigned int pplus = define_layer (ly, lmap, 10);
|
||||
unsigned int nplus = define_layer (ly, lmap, 11);
|
||||
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, "lvs_test_1.gds");
|
||||
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly, options);
|
||||
}
|
||||
|
||||
db::Cell &tc = ly.cell (*ly.begin_top_down ());
|
||||
db::LayoutVsSchematic lvs (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
|
||||
|
||||
std::auto_ptr<db::Region> rbulk (lvs.make_layer ("bulk"));
|
||||
std::auto_ptr<db::Region> rnwell (lvs.make_layer (nwell, "nwell"));
|
||||
std::auto_ptr<db::Region> ractive (lvs.make_layer (active, "active"));
|
||||
std::auto_ptr<db::Region> rpplus (lvs.make_layer (pplus, "pplus"));
|
||||
std::auto_ptr<db::Region> rnplus (lvs.make_layer (nplus, "nplus"));
|
||||
std::auto_ptr<db::Region> rpoly (lvs.make_polygon_layer (poly, "poly"));
|
||||
std::auto_ptr<db::Region> rpoly_lbl (lvs.make_text_layer (poly_lbl, "poly_lbl"));
|
||||
std::auto_ptr<db::Region> rdiff_cont (lvs.make_polygon_layer (diff_cont, "diff_cont"));
|
||||
std::auto_ptr<db::Region> rpoly_cont (lvs.make_polygon_layer (poly_cont, "poly_cont"));
|
||||
std::auto_ptr<db::Region> rmetal1 (lvs.make_polygon_layer (metal1, "metal1"));
|
||||
std::auto_ptr<db::Region> rmetal1_lbl (lvs.make_text_layer (metal1_lbl, "metal1_lbl"));
|
||||
std::auto_ptr<db::Region> rvia1 (lvs.make_polygon_layer (via1, "via1"));
|
||||
std::auto_ptr<db::Region> rmetal2 (lvs.make_polygon_layer (metal2, "metal2"));
|
||||
std::auto_ptr<db::Region> rmetal2_lbl (lvs.make_text_layer (metal2_lbl, "metal2_lbl"));
|
||||
|
||||
// derived regions
|
||||
|
||||
db::Region ractive_in_nwell = *ractive & *rnwell;
|
||||
db::Region rpactive = ractive_in_nwell & *rpplus;
|
||||
db::Region rntie = ractive_in_nwell & *rnplus;
|
||||
db::Region rpgate = rpactive & *rpoly;
|
||||
db::Region rpsd = rpactive - rpgate;
|
||||
|
||||
db::Region ractive_outside_nwell = *ractive - *rnwell;
|
||||
db::Region rnactive = ractive_outside_nwell & *rnplus;
|
||||
db::Region rptie = ractive_outside_nwell & *rpplus;
|
||||
db::Region rngate = rnactive & *rpoly;
|
||||
db::Region rnsd = rnactive - rngate;
|
||||
|
||||
// return the computed layers into the original layout and write it for debugging purposes
|
||||
|
||||
unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate
|
||||
unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain
|
||||
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion
|
||||
unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion
|
||||
unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie
|
||||
unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie
|
||||
|
||||
rpgate.insert_into (&ly, tc.cell_index (), lgate);
|
||||
rngate.insert_into (&ly, tc.cell_index (), lgate);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lptie);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lntie);
|
||||
|
||||
db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS");
|
||||
db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS");
|
||||
|
||||
// device extraction
|
||||
|
||||
db::NetlistDeviceExtractor::input_layers dl;
|
||||
|
||||
dl["SD"] = &rpsd;
|
||||
dl["G"] = &rpgate;
|
||||
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
|
||||
dl["W"] = rnwell.get ();
|
||||
lvs.extract_devices (pmos_ex, dl);
|
||||
|
||||
dl["SD"] = &rnsd;
|
||||
dl["G"] = &rngate;
|
||||
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
|
||||
dl["W"] = rbulk.get ();
|
||||
lvs.extract_devices (nmos_ex, dl);
|
||||
|
||||
// net extraction
|
||||
|
||||
lvs.register_layer (rpsd, "psd");
|
||||
lvs.register_layer (rnsd, "nsd");
|
||||
lvs.register_layer (rptie, "ptie");
|
||||
lvs.register_layer (rntie, "ntie");
|
||||
|
||||
// Intra-layer
|
||||
lvs.connect (rpsd);
|
||||
lvs.connect (rnsd);
|
||||
lvs.connect (*rnwell);
|
||||
lvs.connect (*rpoly);
|
||||
lvs.connect (*rdiff_cont);
|
||||
lvs.connect (*rpoly_cont);
|
||||
lvs.connect (*rmetal1);
|
||||
lvs.connect (*rvia1);
|
||||
lvs.connect (*rmetal2);
|
||||
lvs.connect (rptie);
|
||||
lvs.connect (rntie);
|
||||
// Inter-layer
|
||||
lvs.connect (rpsd, *rdiff_cont);
|
||||
lvs.connect (rnsd, *rdiff_cont);
|
||||
lvs.connect (*rpoly, *rpoly_cont);
|
||||
lvs.connect (*rpoly_cont, *rmetal1);
|
||||
lvs.connect (*rdiff_cont, *rmetal1);
|
||||
lvs.connect (*rdiff_cont, rptie);
|
||||
lvs.connect (*rdiff_cont, rntie);
|
||||
lvs.connect (*rnwell, rntie);
|
||||
lvs.connect (*rmetal1, *rvia1);
|
||||
lvs.connect (*rvia1, *rmetal2);
|
||||
lvs.connect (*rpoly, *rpoly_lbl); // attaches labels
|
||||
lvs.connect (*rmetal1, *rmetal1_lbl); // attaches labels
|
||||
lvs.connect (*rmetal2, *rmetal2_lbl); // attaches labels
|
||||
// Global
|
||||
lvs.connect_global (rptie, "BULK");
|
||||
lvs.connect_global (*rbulk, "BULK");
|
||||
|
||||
// create some mess - we have to keep references to the layers to make them not disappear
|
||||
rmetal1_lbl.reset (0);
|
||||
rmetal2_lbl.reset (0);
|
||||
rpoly_lbl.reset (0);
|
||||
|
||||
lvs.extract_netlist ();
|
||||
|
||||
// doesn't do anything here, but we test that this does not destroy anything:
|
||||
lvs.netlist ()->combine_devices ();
|
||||
|
||||
// make pins for named nets of top-level circuits - this way they are not purged
|
||||
lvs.netlist ()->make_top_level_pins ();
|
||||
lvs.netlist ()->purge ();
|
||||
|
||||
// read the reference netlist
|
||||
{
|
||||
db::NetlistSpiceReader reader;
|
||||
|
||||
std::string fn (tl::testsrc ());
|
||||
fn = tl::combine_path (fn, "testdata");
|
||||
fn = tl::combine_path (fn, "algo");
|
||||
fn = tl::combine_path (fn, "lvs_test_2.spi");
|
||||
|
||||
std::auto_ptr<db::Netlist> netlist (new db::Netlist ());
|
||||
tl::InputStream stream (fn);
|
||||
reader.read (stream, *netlist);
|
||||
lvs.set_reference_netlist (netlist.release ());
|
||||
}
|
||||
|
||||
// perform the compare
|
||||
{
|
||||
db::NetlistComparer comparer;
|
||||
lvs.compare_netlists (&comparer);
|
||||
}
|
||||
|
||||
// save and compare
|
||||
|
||||
std::string path = tmp_file ("tmp_lvstest2.lvsdb");
|
||||
lvs.save (path, false);
|
||||
|
||||
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "lvs_test2_au.lvsdb");
|
||||
|
||||
compare_lvsdbs (_this, path, au_path);
|
||||
|
||||
// load, save and compare
|
||||
|
||||
db::LayoutVsSchematic lvs2;
|
||||
|
||||
std::string path2 = tmp_file ("tmp_lvstest2b.lvsdb");
|
||||
lvs2.load (path);
|
||||
lvs2.save (path2, false);
|
||||
|
||||
compare_lvsdbs (_this, path2, au_path);
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,70 @@
|
|||
* Test netlist
|
||||
|
||||
* cell RINGO
|
||||
* pin FB
|
||||
* pin OSC
|
||||
* pin VDD
|
||||
* pin BULK,VSS
|
||||
.SUBCKT RINGO 1 2 3 4
|
||||
* net 1 FB
|
||||
* net 2 OSC
|
||||
* net 3 VDD
|
||||
* net 4 BULK,VSS
|
||||
* cell instance $1 r0 *1 19.42,-0.8
|
||||
X$1 4 3 4 1 6 2 3 INV2PAIR
|
||||
* cell instance $2 r0 *1 -1.7,-0.8
|
||||
X$2 4 3 4 1 1 5 3 INV2PAIR
|
||||
* cell instance $3 r0 *1 3.58,-0.8
|
||||
X$3 4 3 4 101 5 8 3 INV2PAIR
|
||||
* cell instance $4 r0 *1 8.86,-0.8
|
||||
X$4 4 3 4 102 8 7 3 INV2PAIR
|
||||
* cell instance $5 r0 *1 14.14,-0.8
|
||||
X$5 4 3 4 103 7 6 3 INV2PAIR
|
||||
.ENDS RINGO
|
||||
|
||||
* cell INV2PAIR
|
||||
* pin BULK
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
.SUBCKT INV2PAIR 1 2 3 4 5 6 7
|
||||
* net 1 BULK
|
||||
* cell instance $2 r0 *1 4.34,0.8
|
||||
X$2 7 4 6 3 2 1 INV2
|
||||
.ENDS INV2PAIR
|
||||
|
||||
* cell INV2PAIRX
|
||||
* pin BULK
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
* pin
|
||||
.SUBCKT INV2PAIRX 1 2 3 4 5 6 7
|
||||
* net 1 BULK
|
||||
* cell instance $2 r0 *1 4.34,0.8
|
||||
X$2 7 4 6 3 2 1 INV2
|
||||
.ENDS INV2PAIR
|
||||
|
||||
* cell INV2
|
||||
* pin
|
||||
* pin IN
|
||||
* pin OUT
|
||||
* pin VSS
|
||||
* pin VDD
|
||||
* pin BULK
|
||||
.SUBCKT INV2 1 2 3 4 5 6
|
||||
* net 2 IN
|
||||
* net 3 OUT
|
||||
* net 4 VSS
|
||||
* net 5 VDD
|
||||
* net 6 BULK
|
||||
* device instance $1 -0.4,3.2 PMOS
|
||||
M$1 3 2 5 1 PMOS L=0.25U W=3.5U AS=1.4P AD=1.4P PS=6.85U PD=6.85U
|
||||
* device instance $3 -0.4,-0.4 NMOS
|
||||
M$3 3 2 4 6 NMOS L=0.25U W=3.5U AS=1.4P AD=1.4P PS=6.85U PD=6.85U
|
||||
.ENDS INV2
|
||||
Loading…
Reference in New Issue