diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index bfc6ca603..1c86b2e91 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -483,6 +483,14 @@ void Netlist::combine_devices () } } +void Netlist::simplify () +{ + make_top_level_pins (); + purge (); + combine_devices (); + purge_nets (); +} + static std::string net2string (const db::Net *net) { return net ? tl::to_word_or_quoted_string (net->expanded_name ()) : "(null)"; diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index a932cc8a6..d145083cf 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -452,6 +452,11 @@ public: */ void purge (); + /** + * @brief Convenience method: simplify (purge, combine devices, ...) + */ + void simplify (); + /** * @brief Combine devices * diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 1799448a1..08c2a190e 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1397,6 +1397,10 @@ Class decl_dbNetlist ("db", "Netlist", "Floating nets can be created as effect of reconnections of devices or pins. " "This method will eliminate all nets that make less than two connections." ) + + gsi::method ("simplify", &db::Netlist::simplify, + "@brief Convience method that combines the simplification.\n" + "This method is a convenience method that runs \\make_top_level_pins, \\purge, \\combine_devices and \\purge_nets." + ) + gsi::method_ext ("read", &read_netlist, gsi::arg ("file"), gsi::arg ("reader"), "@brief Writes the netlist to the given file using the given reader object to parse the file\n" "See \\NetlistSpiceReader for an example for a parser. " @@ -1873,7 +1877,7 @@ Class db_NetlistSpiceReader (db_NetlistReader, "db", "Ne gsi::constructor ("new", &new_spice_reader, "@brief Creates a new reader.\n" ) + - gsi::constructor ("new", &new_spice_reader2, + gsi::constructor ("new", &new_spice_reader2, gsi::arg ("delegate"), "@brief Creates a new reader with a delegate.\n" ), "@brief Implements a netlist Reader for the SPICE format.\n" diff --git a/testdata/ruby/dbNetlistReaderTests.rb b/testdata/ruby/dbNetlistReaderTests.rb new file mode 100644 index 000000000..1eb80fdf8 --- /dev/null +++ b/testdata/ruby/dbNetlistReaderTests.rb @@ -0,0 +1,143 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2019 Matthias Koefferlein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +# For analysis +module RBA + class Netlist + attr_accessor :description + end +end + +class MyDelegate < RBA::NetlistSpiceReaderDelegate + + def start(netlist) + netlist.description = "Read by MyDelegate" + end + + def finish(netlist) + netlist.description = "Read by MyDelegate (sucessfully)" + end + + def wants_subcircuit(name) + name == "HVNMOS" || name == "HVPMOS" + end + + def element(circuit, el, name, model, value, nets, params) + + if el != "X" + return super + end + + if nets.size != 4 + error("Subcircuit #{model} needs four nodes") + end + + cls = circuit.netlist.device_class_by_name(model) + if ! cls + cls = RBA::DeviceClassMOS4Transistor::new + cls.name = model + circuit.netlist.add(cls) + end + + device = circuit.create_device(cls, name) + + [ "S", "G", "D", "B" ].each_with_index do |t,index| + device.connect_terminal(t, nets[index]) + end + params.each do |p,value| + device.set_parameter(p, value * 1.5) + end + + end + +end + +class DBNetlistReaderTests_TestClass < TestBase + + def test_1_Basic + + nl = RBA::Netlist::new + + input = File.join($ut_testsrc, "testdata", "algo", "nreader6.cir") + + mydelegate = MyDelegate::new + reader = RBA::NetlistSpiceReader::new(mydelegate) + # the delegate is kept by the SPICE writer .. + mydelegate = nil + GC.start + nl.read(input, reader) + + assert_equal(nl.description, "Read by MyDelegate (sucessfully)") + + assert_equal(nl.to_s, <<"END") +circuit SUBCKT ($1=$1,$2=A,$3=VDD,$4=Z,$5=gnd,$6=gnd$1); + device HVPMOS $1 (S=VDD,G=$3,D=Z,B=$1) (L=0.3,W=1.5,AS=0.27,AD=0.27,PS=3.24,PD=3.24); + device HVPMOS $2 (S=VDD,G=A,D=$3,B=$1) (L=0.3,W=1.5,AS=0.27,AD=0.27,PS=3.24,PD=3.24); + device HVNMOS $3 (S=gnd,G=$3,D=gnd,B=gnd$1) (L=1.695,W=3.18,AS=0,AD=0,PS=9,PD=9); + device HVNMOS $4 (S=gnd,G=$3,D=Z,B=gnd$1) (L=0.6,W=0.6,AS=0.285,AD=0.285,PS=1.74,PD=1.74); + device HVNMOS $5 (S=gnd,G=A,D=$3,B=gnd$1) (L=0.6,W=0.6,AS=0.285,AD=0.285,PS=2.64,PD=2.64); + device RES $1 (A=A,B=Z) (R=100000,L=0,W=0,A=0,P=0); +end; +circuit .TOP (); + subcircuit SUBCKT SUBCKT ($1=(null),$2=(null),$3=(null),$4=(null),$5=VSS,$6=VSS); +end; +END + + end + + def test_2_WithError + + nl = RBA::Netlist::new + + input = File.join($ut_testsrc, "testdata", "algo", "nreader6.cir") + + mydelegate = MyDelegate::new + + def mydelegate.element(circuit, el, name, model, value, nets, params) + self.error("Nothing implemented") + end + + reader = RBA::NetlistSpiceReader::new(mydelegate) + # the delegate is kept by the SPICE writer .. + mydelegate = nil + GC.start + + msg = "no error happened!" + begin + nl.read(input, reader) + rescue Exception => ex + msg = ex.message + end + assert_equal(msg.sub(input, ""), "Nothing implemented in , line 22 in Netlist::read") + + assert_equal(nl.description, "Read by MyDelegate") + + end + +end + +load("test_epilogue.rb") + +