mirror of https://github.com/KLayout/klayout.git
Custom devices for device extractor - tests in the DRC framework
This commit is contained in:
parent
510c675d21
commit
41fdd74189
|
|
@ -100,9 +100,9 @@ namespace tl
|
|||
|
||||
template<> struct type_traits<GenericDeviceExtractor> : public tl::type_traits<void>
|
||||
{
|
||||
// mark "NetlistDeviceExtractor" as not having a default ctor and no copy ctor
|
||||
// mark "NetlistDeviceExtractor" as having a default ctor and no copy ctor
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
typedef tl::false_tag has_default_constructor;
|
||||
typedef tl::true_tag has_default_constructor;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -212,7 +212,7 @@ Class<db::NetlistDeviceExtractor> decl_dbNetlistDeviceExtractor ("db", "DeviceEx
|
|||
"@brief Iterates over all errors collected in the device extractor."
|
||||
),
|
||||
"@brief The base class for all device extractors.\n"
|
||||
"This is an abstract base class for device extractors. See \\NetlistDeviceExtractor for a generic "
|
||||
"This is an abstract base class for device extractors. See \\GenericDeviceExtractor for a generic "
|
||||
"class which you can reimplement to supply your own customized device extractor. "
|
||||
"In many cases using one of the preconfigured specific device extractors may be useful already and "
|
||||
"it's not required to implement a custom one. For an example about a preconfigured device extractor see "
|
||||
|
|
|
|||
|
|
@ -438,6 +438,66 @@ TEST(10_NetlistExtractionFlat)
|
|||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
|
||||
// verify
|
||||
|
||||
{
|
||||
tl::InputStream is (output);
|
||||
tl::InputStream is_au (au);
|
||||
|
||||
if (is.read_all () != is_au.read_all ()) {
|
||||
_this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s",
|
||||
tl::absolute_file_path (output),
|
||||
tl::absolute_file_path (au)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream is (output_simplified);
|
||||
tl::InputStream is_au (au_simplified);
|
||||
|
||||
if (is.read_all () != is_au.read_all ()) {
|
||||
_this->raise (tl::sprintf ("Compare failed (simplified netlist) - see\n actual: %s\n golden: %s",
|
||||
tl::absolute_file_path (output_simplified),
|
||||
tl::absolute_file_path (au_simplified)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(11_CustomDevices)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
rs += "/testdata/drc/drcSimpleTests_11.drc";
|
||||
|
||||
std::string input = tl::testsrc ();
|
||||
input += "/testdata/drc/vdiv.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/drc/drcSimpleTests_au11a.cir";
|
||||
|
||||
std::string au_simplified = tl::testsrc ();
|
||||
au_simplified += "/testdata/drc/drcSimpleTests_au11b.cir";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.cir");
|
||||
std::string output_simplified = this->tmp_file ("tmp_simplified.cir");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
"$drc_test_target_simplified = '%s'\n"
|
||||
, input, output, output_simplified)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
|
||||
// verify
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Hierarchical extraction
|
||||
# Flat extraction
|
||||
|
||||
source($drc_test_source)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,204 @@
|
|||
|
||||
source($drc_test_source)
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
diff = input(2, 0)
|
||||
pplus = input(3, 0)
|
||||
nplus = input(4, 0)
|
||||
poly = input(5, 0)
|
||||
thickox = input(6, 0)
|
||||
polyres = input(7, 0)
|
||||
contact = input(8, 0)
|
||||
metal1 = input(9, 0)
|
||||
via = input(10, 0)
|
||||
metal2 = input(11, 0)
|
||||
|
||||
# Special layer for bulk terminals
|
||||
|
||||
bulk = make_layer
|
||||
|
||||
# Computed layers
|
||||
|
||||
poly_not_res = poly - polyres
|
||||
poly_in_res = poly & polyres
|
||||
|
||||
diff_in_nwell = diff & nwell
|
||||
pdiff = diff_in_nwell - nplus
|
||||
ntie = diff_in_nwell & nplus
|
||||
pgate = pdiff & poly_not_res
|
||||
psd = pdiff - pgate
|
||||
hv_pgate = pgate & thickox
|
||||
lv_pgate = pgate - hv_pgate
|
||||
hv_psd = psd & thickox
|
||||
lv_psd = psd - thickox
|
||||
|
||||
diff_outside_nwell = diff - nwell
|
||||
ndiff = diff_outside_nwell - pplus
|
||||
ptie = diff_outside_nwell & pplus
|
||||
ngate = ndiff & poly_not_res
|
||||
nsd = ndiff - ngate
|
||||
hv_ngate = ngate & thickox
|
||||
lv_ngate = ngate - hv_ngate
|
||||
hv_nsd = nsd & thickox
|
||||
lv_nsd = nsd - thickox
|
||||
|
||||
# Resistor device extraction
|
||||
|
||||
class CustomResistorExtraction < RBA::GenericDeviceExtractor
|
||||
|
||||
def initialize(name, sheet_rho)
|
||||
self.name = name
|
||||
@sheet_rho = sheet_rho
|
||||
end
|
||||
|
||||
def setup
|
||||
|
||||
define_layer("M", "Marker")
|
||||
define_layer("C", "Conductor")
|
||||
define_layer("R", "Resistor")
|
||||
|
||||
register_device_class (RBA::DeviceClassResistor::new);
|
||||
|
||||
end
|
||||
|
||||
def extract_devices(layer_geometry)
|
||||
|
||||
marker = layer_geometry[0]
|
||||
conductor = layer_geometry[1]
|
||||
resistor = layer_geometry[2]
|
||||
|
||||
conductor_geometry_index = 1
|
||||
|
||||
resistor_merged = resistor.merged
|
||||
|
||||
marker_edges = marker.merged.edges & resistor_merged.edges
|
||||
|
||||
resistor_merged.each do |r|
|
||||
|
||||
connection_edges = marker_edges.interacting(RBA::Region::new(r))
|
||||
|
||||
terminals = connection_edges.extended_out(1)
|
||||
|
||||
if terminals.size != 2
|
||||
error("Resistor shape does not touch marker border in exactly two places", r)
|
||||
else
|
||||
|
||||
# A = L*W
|
||||
# P = 2*(L+W)
|
||||
# -> L = p+sqrt(p*p-A)
|
||||
# -> W = p-sqrt(p*p-A)
|
||||
# (p=P/4)
|
||||
|
||||
p = 0.25 * r.perimeter
|
||||
a = r.area
|
||||
|
||||
d = Math.sqrt(p * p - a)
|
||||
l = p + d
|
||||
w = p - d
|
||||
|
||||
if w > 1e-3
|
||||
|
||||
device = create_device
|
||||
|
||||
device.set_parameter(RBA::DeviceClassResistor::PARAM_R, @sheet_rho * l / w);
|
||||
|
||||
define_terminal(device, RBA::DeviceClassResistor::TERMINAL_A, conductor_geometry_index, terminals[0]);
|
||||
define_terminal(device, RBA::DeviceClassResistor::TERMINAL_B, conductor_geometry_index, terminals[1]);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def get_connectivity(layout, layers)
|
||||
|
||||
# the layer definition is marker, conductor, resistor
|
||||
# * resistor is used for extraction
|
||||
# * conductor is used for producing the terminals
|
||||
# * marker is included because it's required for the extraction
|
||||
|
||||
marker = layers[0]
|
||||
conductor = layers[1]
|
||||
resistor = layers[2]
|
||||
|
||||
conn = RBA::Connectivity::new
|
||||
|
||||
conn.connect(resistor, resistor)
|
||||
conn.connect(conductor, resistor)
|
||||
conn.connect(marker, resistor)
|
||||
|
||||
return conn;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Resistor
|
||||
|
||||
# Assumes a sheet rho of 150 Ohm/Square
|
||||
res_ex = CustomResistorExtraction::new("RES", 150.0)
|
||||
extract_devices(res_ex, { "C" => poly_not_res, "R" => poly_in_res, "M" => polyres })
|
||||
|
||||
# PMOS transistor device extraction
|
||||
|
||||
hvpmos_ex = RBA::DeviceExtractorMOS4Transistor::new("HVPMOS")
|
||||
extract_devices(hvpmos_ex, { "SD" => psd, "G" => hv_pgate, "P" => poly_not_res, "W" => nwell })
|
||||
|
||||
lvpmos_ex = RBA::DeviceExtractorMOS4Transistor::new("LVPMOS")
|
||||
extract_devices(lvpmos_ex, { "SD" => psd, "G" => lv_pgate, "P" => poly_not_res, "W" => nwell })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
|
||||
lvnmos_ex = RBA::DeviceExtractorMOS4Transistor::new("LVNMOS")
|
||||
extract_devices(lvnmos_ex, { "SD" => nsd, "G" => lv_ngate, "P" => poly_not_res, "W" => bulk })
|
||||
|
||||
hvnmos_ex = RBA::DeviceExtractorMOS4Transistor::new("HVNMOS")
|
||||
extract_devices(hvnmos_ex, { "SD" => nsd, "G" => hv_ngate, "P" => poly_not_res, "W" => bulk })
|
||||
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
connect(contact, ntie)
|
||||
connect(contact, ptie)
|
||||
connect(nwell, ntie)
|
||||
connect(psd, contact)
|
||||
connect(nsd, contact)
|
||||
connect(poly_not_res, contact)
|
||||
connect(contact, metal1)
|
||||
connect(metal1, via)
|
||||
connect(via, metal2)
|
||||
|
||||
# Global connections
|
||||
connect_global(ptie, "BULK")
|
||||
connect_global(bulk, "BULK")
|
||||
|
||||
# Actually performs the extraction
|
||||
|
||||
netlist = l2n_data.netlist
|
||||
|
||||
# Write the netlist
|
||||
|
||||
writer = RBA::NetlistSpiceWriter::new
|
||||
|
||||
writer = RBA::NetlistSpiceWriter::new
|
||||
netlist.write($drc_test_target, writer, "VDIV netlist before simplification")
|
||||
|
||||
# Netlist simplification
|
||||
|
||||
# NOTE: use make_top_level_pins before combine_devices as the pin
|
||||
# stops the three resistors to be combined into one
|
||||
netlist.make_top_level_pins
|
||||
netlist.combine_devices
|
||||
netlist.purge
|
||||
netlist.purge_nets
|
||||
|
||||
netlist.write($drc_test_target_simplified, writer, "VDIV netlist after simplification")
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
* VDIV netlist before simplification
|
||||
|
||||
* cell TOP
|
||||
.SUBCKT TOP
|
||||
* net 1 OUT
|
||||
* net 2 GND
|
||||
* net 4 IN
|
||||
* net 7 VDD
|
||||
* device instance $1 1.025,0.335 RES
|
||||
R$1 6 1 7650
|
||||
* device instance $2 2.85,0.335 RES
|
||||
R$2 3 1 7650
|
||||
* device instance $3 4.665,0.335 RES
|
||||
R$3 3 2 2670
|
||||
* device instance $4 1.765,7.485 HVPMOS
|
||||
M$4 6 4 7 7 MHVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U
|
||||
.ENDS TOP
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
* VDIV netlist after simplification
|
||||
|
||||
* cell TOP
|
||||
* pin OUT
|
||||
* pin GND
|
||||
* pin IN
|
||||
* pin VDD
|
||||
.SUBCKT TOP 1 2 3 5
|
||||
* net 1 OUT
|
||||
* net 2 GND
|
||||
* net 3 IN
|
||||
* net 5 VDD
|
||||
* device instance $1 1.025,0.335 RES
|
||||
R$1 4 1 7650
|
||||
* device instance $2 2.85,0.335 RES
|
||||
R$2 2 1 10320
|
||||
* device instance $4 1.765,7.485 HVPMOS
|
||||
M$4 4 3 5 5 MHVPMOS L=0.25U W=1.5U AS=0.63P AD=0.63P PS=3.84U PD=3.84U
|
||||
.ENDS TOP
|
||||
Binary file not shown.
Loading…
Reference in New Issue