WIP: standard device classes, added GSI binding plus tests.

This commit is contained in:
Matthias Koefferlein 2018-12-29 23:48:31 +01:00
parent 44b5b2742e
commit c571535e55
5 changed files with 567 additions and 1 deletions

View File

@ -147,7 +147,9 @@ SOURCES = \
gsiDeclDbNetlist.cc \
dbNetlistDeviceClasses.cc \
dbNetlistDeviceExtractor.cc \
dbNetlistExtractor.cc
dbNetlistExtractor.cc \
gsiDeclDbNetlistDeviceClasses.cc \
gsiDeclDbNetlistDeviceExtractor.cc
HEADERS = \
dbArray.h \

View File

@ -0,0 +1,232 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#include "gsiDecl.h"
#include "dbNetlistDeviceClasses.h"
namespace gsi
{
// TODO: move this to gsiMethods.h
template <class R>
class ConstantValueGetter
: public StaticMethodBase
{
public:
ConstantValueGetter (const std::string &name, const R &v, const std::string &doc)
: StaticMethodBase (name, doc, true), m_v (v)
{
}
void initialize ()
{
this->clear ();
// Note: a constant must not return a reference to an existing object, hence "set_return_new":
this->template set_return_new<R> ();
}
virtual MethodBase *clone () const
{
return new ConstantValueGetter (*this);
}
virtual void call (void *, SerialArgs &, SerialArgs &ret) const
{
mark_called ();
ret.write<R> (m_v);
}
private:
R m_v;
};
template <class R>
Methods
constant (const std::string &name, const R &v, const std::string &doc = std::string ())
{
return Methods (new ConstantValueGetter <R> (name, v, doc));
}
extern Class<db::DeviceClass> decl_dbDeviceClass;
Class<db::DeviceClassResistor> decl_dbDeviceClassResistor (decl_dbDeviceClass, "db", "DeviceClassResistor",
gsi::constant ("TERMINAL_A", db::DeviceClassResistor::terminal_id_A,
"@brief A constant giving the terminal ID for terminal A"
) +
gsi::constant ("TERMINAL_B", db::DeviceClassResistor::terminal_id_B,
"@brief A constant giving the terminal ID for terminal B"
) +
gsi::constant ("PARAM_R", db::DeviceClassResistor::param_id_R,
"@brief A constant giving the parameter ID for parameter R"
),
"@brief A device class for a resistor.\n"
"This class can be used to describe resistors. Resistors are defined by their combination behavior and "
"the basic parameter 'R' which is the resistance in Ohm.\n"
"\n"
"A resistor has two terminals, A and B.\n"
"\n"
"This class has been introduced in version 0.26."
);
Class<db::DeviceClassCapacitor> decl_dbDeviceClassCapacitor (decl_dbDeviceClass, "db", "DeviceClassCapacitor",
gsi::constant ("TERMINAL_A", db::DeviceClassCapacitor::terminal_id_A,
"@brief A constant giving the terminal ID for terminal A"
) +
gsi::constant ("TERMINAL_B", db::DeviceClassCapacitor::terminal_id_B,
"@brief A constant giving the terminal ID for terminal B"
) +
gsi::constant ("PARAM_C", db::DeviceClassCapacitor::param_id_C,
"@brief A constant giving the parameter ID for parameter C"
),
"@brief A device class for a capacitor.\n"
"This class can be used to describe capacitors. Capacitors are defined by their combination behavior and "
"the basic parameter 'C' which is the capacitance in Farad.\n"
"\n"
"A capacitor has two terminals, A and B.\n"
"\n"
"This class has been introduced in version 0.26."
);
Class<db::DeviceClassInductor> decl_dbDeviceClassInductor (decl_dbDeviceClass, "db", "DeviceClassInductor",
gsi::constant ("TERMINAL_A", db::DeviceClassInductor::terminal_id_A,
"@brief A constant giving the terminal ID for terminal A"
) +
gsi::constant ("TERMINAL_B", db::DeviceClassInductor::terminal_id_B,
"@brief A constant giving the terminal ID for terminal B"
) +
gsi::constant ("PARAM_L", db::DeviceClassInductor::param_id_L,
"@brief A constant giving the parameter ID for parameter L"
),
"@brief A device class for an inductor.\n"
"This class can be used to describe inductors. Inductors are defined by their combination behavior and "
"the basic parameter 'L' which is the inductance in Henry.\n"
"\n"
"An inductor has two terminals, A and B.\n"
"\n"
"This class has been introduced in version 0.26."
);
Class<db::DeviceClassDiode> decl_dbDeviceClassDiode (decl_dbDeviceClass, "db", "DeviceClassDiode",
gsi::constant ("TERMINAL_A", db::DeviceClassDiode::terminal_id_A,
"@brief A constant giving the terminal ID for terminal A"
) +
gsi::constant ("TERMINAL_C", db::DeviceClassDiode::terminal_id_C,
"@brief A constant giving the terminal ID for terminal C"
) +
gsi::constant ("PARAM_A", db::DeviceClassDiode::param_id_A,
"@brief A constant giving the parameter ID for parameter A"
),
"@brief A device class for a diode.\n"
"This class can be used to describe diodes. Diodes are defined by their combination behavior and "
"the basic parameter 'A' which is their area in square micrometers.\n"
"\n"
"Diodes only combine when parallel and in the same direction. In this case, their areas are added."
"\n"
"An inductor has two terminals, A (anode) and C (cathode).\n"
"\n"
"This class has been introduced in version 0.26."
);
Class<db::DeviceClassMOS3Transistor> decl_dbDeviceClassMOS3Transistor (decl_dbDeviceClass, "db", "DeviceClassMOS3Transistor",
gsi::constant ("TERMINAL_S", db::DeviceClassMOS3Transistor::terminal_id_S,
"@brief A constant giving the terminal ID for terminal S"
) +
gsi::constant ("TERMINAL_D", db::DeviceClassMOS3Transistor::terminal_id_D,
"@brief A constant giving the terminal ID for terminal D"
) +
gsi::constant ("TERMINAL_G", db::DeviceClassMOS3Transistor::terminal_id_G,
"@brief A constant giving the terminal ID for terminal G"
) +
gsi::constant ("PARAM_L", db::DeviceClassMOS3Transistor::param_id_L,
"@brief A constant giving the parameter ID for parameter L"
) +
gsi::constant ("PARAM_W", db::DeviceClassMOS3Transistor::param_id_W,
"@brief A constant giving the parameter ID for parameter W"
) +
gsi::constant ("PARAM_AS", db::DeviceClassMOS3Transistor::param_id_AS,
"@brief A constant giving the parameter ID for parameter AS"
) +
gsi::constant ("PARAM_AD", db::DeviceClassMOS3Transistor::param_id_AD,
"@brief A constant giving the parameter ID for parameter AD"
),
"@brief A device class for a 3-terminal MOS transistor.\n"
"This class can be used to describe MOS transistors without a bulk terminal. "
"A device class for a MOS transistor with a bulk terminal is \\DeviceClassMOS4Transistor. "
"MOS transistors are defined by their combination behavior and the basic parameters.\n"
"\n"
"The parameters are L, W, AS and AD for the gate length and width in micrometers and source and drain area "
"in square micrometers.\n"
"\n"
"The terminals are S, G and D for source, gate and drain.\n"
"\n"
"MOS transistors combine in parallel mode, when both gate lengths are identical and "
"their gates are connected (source and drain can be swapped). In this case, their widths and source and drain "
"areas are added.\n"
"\n"
"This class has been introduced in version 0.26."
);
Class<db::DeviceClassMOS4Transistor> decl_dbDeviceClassMOS4Transistor (decl_dbDeviceClass, "db", "DeviceClassMOS4Transistor",
gsi::constant ("TERMINAL_S", db::DeviceClassMOS4Transistor::terminal_id_S,
"@brief A constant giving the terminal ID for terminal S"
) +
gsi::constant ("TERMINAL_D", db::DeviceClassMOS4Transistor::terminal_id_D,
"@brief A constant giving the terminal ID for terminal D"
) +
gsi::constant ("TERMINAL_G", db::DeviceClassMOS4Transistor::terminal_id_G,
"@brief A constant giving the terminal ID for terminal G"
) +
gsi::constant ("TERMINAL_B", db::DeviceClassMOS4Transistor::terminal_id_B,
"@brief A constant giving the terminal ID for terminal B"
) +
gsi::constant ("PARAM_L", db::DeviceClassMOS4Transistor::param_id_L,
"@brief A constant giving the parameter ID for parameter L"
) +
gsi::constant ("PARAM_W", db::DeviceClassMOS4Transistor::param_id_W,
"@brief A constant giving the parameter ID for parameter W"
) +
gsi::constant ("PARAM_AS", db::DeviceClassMOS4Transistor::param_id_AS,
"@brief A constant giving the parameter ID for parameter AS"
) +
gsi::constant ("PARAM_AD", db::DeviceClassMOS4Transistor::param_id_AD,
"@brief A constant giving the parameter ID for parameter AD"
),
"@brief A device class for a 4-terminal MOS transistor.\n"
"This class can be used to describe MOS transistors with a bulk terminal. "
"A device class for a MOS transistor without a bulk terminal is \\DeviceClassMOS3Transistor. "
"MOS transistors are defined by their combination behavior and the basic parameters.\n"
"\n"
"The parameters are L, W, AS and AD for the gate length and width in micrometers and source and drain area "
"in square micrometers.\n"
"\n"
"The terminals are S, G, D and B for source, gate, drain and bulk.\n"
"\n"
"MOS transistors combine in parallel mode, when both gate lengths are identical and "
"their gates and bulk terminals are connected (source and drain can be swapped). In this case, their widths and source and drain "
"areas are added.\n"
"\n"
"This class has been introduced in version 0.26."
);
}

View File

@ -110,6 +110,7 @@ RUBYTEST (dbLayoutDiff, "dbLayoutDiff.rb")
RUBYTEST (dbLayoutQuery, "dbLayoutQuery.rb")
RUBYTEST (dbMatrix, "dbMatrix.rb")
RUBYTEST (dbNetlist, "dbNetlist.rb")
RUBYTEST (dbNetlistDeviceClasses, "dbNetlistDeviceClasses.rb")
RUBYTEST (dbPathTest, "dbPathTest.rb")
RUBYTEST (dbPCells, "dbPCells.rb")
RUBYTEST (dbPointTest, "dbPointTest.rb")

331
testdata/ruby/dbNetlistDeviceClasses.rb vendored Normal file
View File

@ -0,0 +1,331 @@
# encoding: UTF-8
# KLayout Layout Viewer
# Copyright (C) 2006-2018 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")
class DBNetlist_TestClass < TestBase
def test_1_Resistors
cls = RBA::DeviceClassResistor::new
nl = RBA::Netlist::new
nl.add(cls)
circuit = RBA::Circuit::new
nl.add(circuit)
r1 = circuit.create_device(cls, "r1")
r1.set_parameter(RBA::DeviceClassResistor::PARAM_R, 1.0)
r2 = circuit.create_device(cls, "r2")
r2.set_parameter("R", 3.0)
pin_a = circuit.create_pin ("A")
pin_b = circuit.create_pin ("B")
n1 = circuit.create_net("n1")
circuit.connect_pin(pin_a, n1)
r1.connect_terminal(RBA::DeviceClassResistor::TERMINAL_A, n1)
n2 = circuit.create_net("n2")
r1.connect_terminal(RBA::DeviceClassResistor::TERMINAL_B, n2)
r2.connect_terminal(RBA::DeviceClassResistor::TERMINAL_A, n2)
n3 = circuit.create_net("n3")
r2.connect_terminal(RBA::DeviceClassResistor::TERMINAL_B, n3)
circuit.connect_pin(pin_b, n3)
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n3):
D r1 (A=n1,B=n2) [R=1]
D r2 (A=n2,B=n3) [R=3]
END
nl.combine_devices
nl.purge
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n3):
D r1 (A=n1,B=n3) [R=4]
END
end
def test_2_Capacitors
cls = RBA::DeviceClassCapacitor::new
nl = RBA::Netlist::new
nl.add(cls)
circuit = RBA::Circuit::new
nl.add(circuit)
c1 = circuit.create_device(cls, "c1")
c1.set_parameter(RBA::DeviceClassCapacitor::PARAM_C, 2.0)
c2 = circuit.create_device(cls, "c2")
c2.set_parameter("C", 3.0)
pin_a = circuit.create_pin ("A")
pin_b = circuit.create_pin ("B")
n1 = circuit.create_net("n1")
circuit.connect_pin(pin_a, n1)
c1.connect_terminal(RBA::DeviceClassCapacitor::TERMINAL_A, n1)
n2 = circuit.create_net("n2")
c1.connect_terminal(RBA::DeviceClassCapacitor::TERMINAL_B, n2)
c2.connect_terminal(RBA::DeviceClassCapacitor::TERMINAL_A, n2)
n3 = circuit.create_net("n3")
c2.connect_terminal(RBA::DeviceClassCapacitor::TERMINAL_B, n3)
circuit.connect_pin(pin_b, n3)
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n3):
D c1 (A=n1,B=n2) [C=2]
D c2 (A=n2,B=n3) [C=3]
END
nl.combine_devices
nl.purge
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n3):
D c1 (A=n1,B=n3) [C=1.2]
END
end
def test_3_Inductors
cls = RBA::DeviceClassInductor::new
nl = RBA::Netlist::new
nl.add(cls)
circuit = RBA::Circuit::new
nl.add(circuit)
l1 = circuit.create_device(cls, "l1")
l1.set_parameter(RBA::DeviceClassInductor::PARAM_L, 1.0)
l2 = circuit.create_device(cls, "l2")
l2.set_parameter("L", 3.0)
pin_a = circuit.create_pin ("A")
pin_b = circuit.create_pin ("B")
n1 = circuit.create_net("n1")
circuit.connect_pin(pin_a, n1)
l1.connect_terminal(RBA::DeviceClassInductor::TERMINAL_A, n1)
n2 = circuit.create_net("n2")
l1.connect_terminal(RBA::DeviceClassInductor::TERMINAL_B, n2)
l2.connect_terminal(RBA::DeviceClassInductor::TERMINAL_A, n2)
n3 = circuit.create_net("n3")
l2.connect_terminal(RBA::DeviceClassInductor::TERMINAL_B, n3)
circuit.connect_pin(pin_b, n3)
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n3):
D l1 (A=n1,B=n2) [L=1]
D l2 (A=n2,B=n3) [L=3]
END
nl.combine_devices
nl.purge
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n3):
D l1 (A=n1,B=n3) [L=4]
END
end
def test_4_Diodes
cls = RBA::DeviceClassDiode::new
nl = RBA::Netlist::new
nl.add(cls)
circuit = RBA::Circuit::new
nl.add(circuit)
d1 = circuit.create_device(cls, "d1")
d1.set_parameter(RBA::DeviceClassDiode::PARAM_A, 1.0)
d2 = circuit.create_device(cls, "d2")
d2.set_parameter("A", 3.0)
pin_a = circuit.create_pin ("A")
pin_b = circuit.create_pin ("B")
n1 = circuit.create_net("n1")
circuit.connect_pin(pin_a, n1)
d1.connect_terminal(RBA::DeviceClassDiode::TERMINAL_A, n1)
d2.connect_terminal(RBA::DeviceClassDiode::TERMINAL_A, n1)
n2 = circuit.create_net("n2")
d1.connect_terminal(RBA::DeviceClassDiode::TERMINAL_C, n2)
d2.connect_terminal(RBA::DeviceClassDiode::TERMINAL_C, n2)
circuit.connect_pin(pin_b, n2)
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n2):
D d1 (A=n1,C=n2) [A=1]
D d2 (A=n1,C=n2) [A=3]
END
nl.combine_devices
nl.purge
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n2):
D d1 (A=n1,C=n2) [A=4]
END
end
def test_5_MOS3
cls = RBA::DeviceClassMOS3Transistor::new
nl = RBA::Netlist::new
nl.add(cls)
circuit = RBA::Circuit::new
nl.add(circuit)
d1 = circuit.create_device(cls, "d1")
d1.set_parameter(RBA::DeviceClassMOS3Transistor::PARAM_L, 1.0)
d1.set_parameter(RBA::DeviceClassMOS3Transistor::PARAM_W, 2.0)
d1.set_parameter(RBA::DeviceClassMOS3Transistor::PARAM_AS, 3.0)
d1.set_parameter(RBA::DeviceClassMOS3Transistor::PARAM_AD, 4.0)
d2 = circuit.create_device(cls, "d2")
d2.set_parameter("L", 1.0)
d2.set_parameter("W", 3.0)
d2.set_parameter("AS", 4.0)
d2.set_parameter("AD", 5.0)
pin_a = circuit.create_pin ("A")
pin_b = circuit.create_pin ("B")
pin_c = circuit.create_pin ("C")
n1 = circuit.create_net("n1")
circuit.connect_pin(pin_a, n1)
d1.connect_terminal(RBA::DeviceClassMOS3Transistor::TERMINAL_S, n1)
d2.connect_terminal(RBA::DeviceClassMOS3Transistor::TERMINAL_S, n1)
n2 = circuit.create_net("n2")
circuit.connect_pin(pin_b, n2)
d1.connect_terminal(RBA::DeviceClassMOS3Transistor::TERMINAL_D, n2)
d2.connect_terminal(RBA::DeviceClassMOS3Transistor::TERMINAL_D, n2)
n3 = circuit.create_net("n3")
circuit.connect_pin(pin_c, n3)
d1.connect_terminal(RBA::DeviceClassMOS3Transistor::TERMINAL_G, n3)
d2.connect_terminal(RBA::DeviceClassMOS3Transistor::TERMINAL_G, n3)
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n2,C=n3):
D d1 (S=n1,G=n3,D=n2) [L=1,W=2,AS=3,AD=4]
D d2 (S=n1,G=n3,D=n2) [L=1,W=3,AS=4,AD=5]
END
nl.combine_devices
nl.purge
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n2,C=n3):
D d1 (S=n1,G=n3,D=n2) [L=1,W=5,AS=7,AD=9]
END
end
def test_6_MOS4
cls = RBA::DeviceClassMOS4Transistor::new
nl = RBA::Netlist::new
nl.add(cls)
circuit = RBA::Circuit::new
nl.add(circuit)
d1 = circuit.create_device(cls, "d1")
d1.set_parameter(RBA::DeviceClassMOS4Transistor::PARAM_L, 1.0)
d1.set_parameter(RBA::DeviceClassMOS4Transistor::PARAM_W, 2.0)
d1.set_parameter(RBA::DeviceClassMOS4Transistor::PARAM_AS, 3.0)
d1.set_parameter(RBA::DeviceClassMOS4Transistor::PARAM_AD, 4.0)
d2 = circuit.create_device(cls, "d2")
d2.set_parameter("L", 1.0)
d2.set_parameter("W", 3.0)
d2.set_parameter("AS", 4.0)
d2.set_parameter("AD", 5.0)
pin_a = circuit.create_pin ("A")
pin_b = circuit.create_pin ("B")
pin_c = circuit.create_pin ("C")
pin_d = circuit.create_pin ("D")
n1 = circuit.create_net("n1")
circuit.connect_pin(pin_a, n1)
d1.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_S, n1)
d2.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_S, n1)
n2 = circuit.create_net("n2")
circuit.connect_pin(pin_b, n2)
d1.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_D, n2)
d2.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_D, n2)
n3 = circuit.create_net("n3")
circuit.connect_pin(pin_c, n3)
d1.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_G, n3)
d2.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_G, n3)
n4 = circuit.create_net("n4")
circuit.connect_pin(pin_d, n4)
d1.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_B, n4)
d2.connect_terminal(RBA::DeviceClassMOS4Transistor::TERMINAL_B, n4)
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n2,C=n3,D=n4):
D d1 (S=n1,G=n3,D=n2,B=n4) [L=1,W=2,AS=3,AD=4]
D d2 (S=n1,G=n3,D=n2,B=n4) [L=1,W=3,AS=4,AD=5]
END
nl.combine_devices
nl.purge
assert_equal(nl.to_s, <<END)
Circuit (A=n1,B=n2,C=n3,D=n4):
D d1 (S=n1,G=n3,D=n2,B=n4) [L=1,W=5,AS=7,AD=9]
END
end
end
load("test_epilogue.rb")