WIP, doc update, tests

This commit is contained in:
Matthias Koefferlein 2026-06-13 23:34:14 +02:00
parent 759df81026
commit 5f45fbdc6a
6 changed files with 203 additions and 0 deletions

View File

@ -249,6 +249,7 @@ void NetlistSpiceWriterDelegate::write_device_profile (const db::Device &dev, co
}
if (! direct_value.is_nil ()) {
os << " ";
write_parameter_value (os, direct_value, 1.0);
}

View File

@ -350,6 +350,19 @@ Class<db::DeviceClass::SpiceProfile> decl_dbDeviceClassSpiceProfile ("db", "Devi
"The terminal order is a list of terminal names that specifies which device terminal to tie to the "
"nets given in the SPICE statement. The list items must be strings corresponding to valid terminal "
"names of the device."
"\n"
"Note, that the terminal order attribute is a copy. In order to manipulate it, you need "
"to change the copy and put it back again:\n"
"\n"
"@code\n"
"# adds a new terminal 'B' to the terminal order of the default SPICE profile of a device class:\n"
"cls = ... # some device class\n"
"sp = cls.spice_profile('')\n"
"term = sp.terminal_order\n"
"term.append('B')\n"
"sp.terminal_order = term\n"
"cls.set_spice_profile('', sp)\n"
"@/code\n"
) +
gsi::method_ext ("terminal_order=", &set_terminal_order,
"@brief Sets the terminal order to use for this device.\n"
@ -391,6 +404,19 @@ Class<db::DeviceClass::SpiceProfile> decl_dbDeviceClassSpiceProfile ("db", "Devi
"device or the default value is used if the parameter is a declared one.\n"
"An empty expression string is equal to \"nil\", so you can drop a parameter\n"
"by mapping the name to an empty string, e.g. '\"M\": \"\"' (drops \"M\").\n"
"\n"
"Note, that the incoming parameter hash is a copy. In order to manipulate it, you "
"need get and set it:\n"
"\n"
"@code\n"
"# adds a new incoming parameter called 'P' to a device classes default SPICE profile:\n"
"cls = ... # some device class\n"
"sp = cls.spice_profile('')\n"
"par = sp.incoming_parameters\n"
"par['P'] = 'P*2.0'\n"
"sp.incoming_parameters = par\n"
"cls.set_spice_profile('', sp)\n"
"@/code\n"
) +
gsi::method_ext ("incoming_parameters=", &set_incoming_parameters,
"@brief Sets the mapping of incoming parameters from SPICE files\n"
@ -419,6 +445,16 @@ Class<db::DeviceClass::SpiceProfile> decl_dbDeviceClassSpiceProfile ("db", "Devi
"how the value of the parameter is computed from device parameters.\n"
"\"_\" is the value of the same SPICE parameter. This is useful for generating\n"
"catch-all rules, such as '\"*\": \"_\"' (copy all parameters).\n"
"\n"
"@code\n"
"# adds a new outgoing parameter called 'P' to a device classes default SPICE profile:\n"
"cls = ... # some device class\n"
"sp = cls.spice_profile('')\n"
"par = sp.outgoing_parameters\n"
"par['P'] = 'P*2.0'\n"
"sp.outgoing_parameters = par\n"
"cls.set_spice_profile('', sp)\n"
"@/code\n"
) +
gsi::method_ext ("outgoing_parameters=", &set_outgoing_parameters,
"@brief Sets the mapping tables for outgoing parameters\n"

View File

@ -247,6 +247,7 @@ TEST(25_blackbox)
TEST(26_enableWandL)
{
run_test (_this, "enable_wl1", "resistor.gds");
run_test (_this, "enable_wl1b", "resistor.gds");
run_test (_this, "enable_wl2", "resistor.gds");
run_test (_this, "enable_wl3", "resistor.gds");
}

11
testdata/lvs/enable_wl1b.cir vendored Normal file
View File

@ -0,0 +1,11 @@
* Extracted by KLayout
* cell Rre
* pin gnd!
* pin vdd!
.SUBCKT Rre 1 2
* net 1 gnd!
* net 2 vdd!
* device instance $1 r0 *1 8.43,1.51 RR1
R$1 1 2 10 RR1 L=6U W=0.6U
.ENDS Rre

36
testdata/lvs/enable_wl1b.lvs vendored Normal file
View File

@ -0,0 +1,36 @@
source($lvs_test_source)
report_lvs($lvs_test_target_lvsdb, true)
target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
schematic("resistor.cir")
deep
contact = input(15, 0)
metal1 = input(16, 0)
metal1_ver = input(16, 5)
metal1_lbl = labels(16, 3)
res = metal1 & metal1_ver
metal1_not_res = metal1 - metal1_ver
dc = extract_devices(resistor("RR1", 1), { "R" => res , "C" => metal1_not_res})
dc.enable_parameter("W", true)
dc.enable_parameter("L", true)
sp = dc.spice_profile("")
sp.outgoing_parameters = {
"R" => "", # drop
"W" => "W",
"L" => "L",
"$" => "R" # direct value
}
dc.set_spice_profile("", sp)
connect(contact, metal1_not_res)
connect(metal1_not_res, metal1_lbl)
align
netlist.make_top_level_pins(false)
netlist.simplify
compare

118
testdata/lvs/enable_wl1b.lvsdb vendored Normal file
View File

@ -0,0 +1,118 @@
#%lvsdb-klayout
# Layout
layout(
top(Rre)
unit(0.001)
# Layer section
# This section lists the mask layers (drawing or derived) and their connections.
# Mask layers
layer(l3 '15/0')
layer(l4 '16/3')
layer(l1)
# Mask layer connectivity
connect(l3 l3 l1)
connect(l4 l1)
connect(l1 l3 l4 l1)
# Device class section
class(RR1 RES
param(L 1 0)
param(W 1 0)
)
# Device abstracts section
# Device abstracts list the pin shapes of the devices.
device(D$RR1 RR1
terminal(A
rect(l1 (-3160 -300) (160 600))
)
terminal(B
rect(l1 (3000 -300) (160 600))
)
)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(Rre
# Circuit boundary
rect((5270 1210) (6320 600))
# Nets with their geometries
net(1 name('gnd!')
rect(l3 (5295 1230) (120 560))
text(l4 'gnd!' (-60 -60))
rect(l1 (-70 -505) (125 570))
rect(l1 (-140 -585) (160 600))
)
net(2 name('vdd!')
rect(l3 (11455 1240) (120 540))
text(l4 'vdd!' (-65 -60))
rect(l1 (-65 -495) (125 560))
rect(l1 (-140 -575) (160 600))
)
# Outgoing pins and their connections to nets
pin(1 name('gnd!'))
pin(2 name('vdd!'))
# Devices and their connections
device(1 D$RR1
location(8430 1510)
param(R 10)
param(L 6)
param(W 0.6)
param(A 3.6)
param(P 13.2)
terminal(A 1)
terminal(B 2)
)
)
)
# Reference netlist
reference(
# Device class section
class(RR1 RES)
# Circuit section
# Circuits are the hierarchical building blocks of the netlist.
circuit(RRE
# Nets
net(1 name('VDD!'))
net(2 name('GND!'))
# Devices and their connections
device(1 RR1
name(R0)
param(R 10)
param(L 6)
param(W 0.6)
param(A 0)
param(P 0)
terminal(A 1)
terminal(B 2)
)
)
)
# Cross reference
xref(
circuit(Rre RRE match
xref(
net(1 2 match)
net(2 1 match)
pin(0 () match)
pin(1 () match)
device(1 1 match)
)
)
)