mirror of https://github.com/KLayout/klayout.git
Created 2019 01 07 (markdown)
parent
cf6964d484
commit
8276167015
|
|
@ -0,0 +1,206 @@
|
|||
# 2019-01-07
|
||||
|
||||
The latest version (dvb branch) is fairly stable and has been tested on a medium-size SoC thoroughly. Here are some numbers: Extraction of all nets takes ~1hr/7GB memory. With the net tracer, the extraction of the VSS net alone was taking 5hrs and 10GB of memory. The VSS net alone has about 30M shapes. After taking the shapes of all nets and outputting them to an OASIS file, the original layout was reproduced (with the exception of a few text marker shapes). This means that all nets are captured and no shape is lost. The VSS net from this extracted netlist is XOR-identical to the one delived by the net tracer.
|
||||
|
||||
This was a pure backend extraction without devices.
|
||||
|
||||
The script used for this extraction was similar to this one:
|
||||
|
||||
```ruby
|
||||
top_cell = nil
|
||||
|
||||
prefix = "xout"
|
||||
|
||||
ly = RBA::Layout::new
|
||||
ly.read("layout.oas")
|
||||
tc = ly.top_cell
|
||||
|
||||
l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, tc, []))
|
||||
|
||||
# only plain connectivity
|
||||
|
||||
puts "Making layers ..."
|
||||
|
||||
rpoly = l2n.make_polygon_layer( ly.layer(1, 0 ) ) # GDS #1 -> poly
|
||||
rcont = l2n.make_polygon_layer( ly.layer(2, 0 ) ) # GDS #2 -> contact (poly or diff)
|
||||
rmetal1 = l2n.make_polygon_layer( ly.layer(3, 0 ) ) # GDS #3 -> metal 1
|
||||
rmetal1_lbl = l2n.make_text_layer( ly.layer(103,0 ) ) # GDS #103 -> metal 1 labels
|
||||
rvia1 = l2n.make_polygon_layer( ly.layer(4, 0 ) ) # GDS #4 -> via 1
|
||||
rmetal2 = l2n.make_polygon_layer( ly.layer(5, 0 ) ) # GDS #5 -> metal 2
|
||||
rmetal2_lbl = l2n.make_text_layer( ly.layer(105,0 ) ) # GDS #105 -> metal 2 labels
|
||||
rvia2 = l2n.make_polygon_layer( ly.layer(6, 0 ) ) # GDS #6 -> via 2
|
||||
rmetal3 = l2n.make_polygon_layer( ly.layer(7, 0 ) ) # GDS #7 -> metal 3
|
||||
rmetal3_lbl = l2n.make_text_layer( ly.layer(107,0 ) ) # GDS #107 -> metal 3 labels
|
||||
rvia3 = l2n.make_polygon_layer( ly.layer(8, 0 ) ) # GDS #8 -> via 3
|
||||
rmetal4 = l2n.make_polygon_layer( ly.layer(9, 0 ) ) # GDS #9 -> metal 4
|
||||
rmetal4_lbl = l2n.make_text_layer( ly.layer(109,0 ) ) # GDS #109 -> metal 4 labels
|
||||
rvia4 = l2n.make_polygon_layer( ly.layer(10, 0 ) ) # GDS #10 -> via 4
|
||||
rmetal5 = l2n.make_polygon_layer( ly.layer(11, 0 ) ) # GDS #11 -> metal 5
|
||||
rmetal5_lbl = l2n.make_text_layer( ly.layer(111,0 ) ) # GDS #111 -> metal 5 labels
|
||||
|
||||
puts "Connecting ..."
|
||||
|
||||
# Intra-layer
|
||||
l2n.connect(rpoly)
|
||||
l2n.connect(rcont)
|
||||
l2n.connect(rmetal1)
|
||||
l2n.connect(rvia1)
|
||||
l2n.connect(rmetal2)
|
||||
l2n.connect(rvia2)
|
||||
l2n.connect(rmetal3)
|
||||
l2n.connect(rvia3)
|
||||
l2n.connect(rmetal4)
|
||||
l2n.connect(rvia4)
|
||||
l2n.connect(rmetal5)
|
||||
|
||||
# Inter-layer
|
||||
l2n.connect(rpoly, rcont)
|
||||
l2n.connect(rcont, rmetal1)
|
||||
l2n.connect(rmetal1, rvia1)
|
||||
l2n.connect(rvia1, rmetal2)
|
||||
l2n.connect(rmetal2, rvia2)
|
||||
l2n.connect(rvia2, rmetal3)
|
||||
l2n.connect(rmetal3, rvia3)
|
||||
l2n.connect(rvia3, rmetal4)
|
||||
l2n.connect(rmetal4, rvia4)
|
||||
l2n.connect(rvia4, rmetal5)
|
||||
l2n.connect(rmetal1, rmetal1_lbl) # attaches labels
|
||||
l2n.connect(rmetal2, rmetal2_lbl) # attaches labels
|
||||
l2n.connect(rmetal3, rmetal3_lbl) # attaches labels
|
||||
l2n.connect(rmetal4, rmetal4_lbl) # attaches labels
|
||||
l2n.connect(rmetal5, rmetal5_lbl) # attaches labels
|
||||
|
||||
puts "Running netlist extraction ..."
|
||||
|
||||
# Perform netlist extraction
|
||||
l2n.extract_netlist
|
||||
|
||||
out = {
|
||||
1 => rpoly,
|
||||
2 => rcont,
|
||||
3 => rmetal1,
|
||||
103 => rmetal1_lbl,
|
||||
4 => rvia1,
|
||||
5 => rmetal2,
|
||||
105 => rmetal2_lbl,
|
||||
6 => rvia2,
|
||||
7 => rmetal3,
|
||||
107 => rmetal3_lbl,
|
||||
8 => rvia3,
|
||||
9 => rmetal4,
|
||||
109 => rmetal4_lbl,
|
||||
10 => rvia4,
|
||||
11 => rmetal5,
|
||||
111 => rmetal5_lbl
|
||||
}
|
||||
|
||||
# write an annotated layout - all nets are put into
|
||||
# cells called "NET_" + net name. The nets are output
|
||||
# hierarchically where the circuits are put into cells
|
||||
# called "CIRCUIT_" + circuit name
|
||||
|
||||
ly2 = RBA::Layout::new
|
||||
top2 = ly2.create_cell(net.expanded_name)
|
||||
|
||||
lmap = {}
|
||||
out.each do |ln,r|
|
||||
lmap[ly2.layer(ln, 0)] = r
|
||||
end
|
||||
l2n.build_all_nets(l2n.cell_mapping_into(ly2, top2), ly2, lmap, "NET_", "CIRCUIT_")
|
||||
|
||||
ly2.write("#{prefix}_all.oas.gz")
|
||||
ly2._destroy
|
||||
```
|
||||
|
||||
## Support for extracting four-terminal MOS devices and global nets
|
||||
|
||||
Four-terminal devices with a bulk connection require the concept of global nets. A specific
|
||||
global net represents the bulk (p-body) of the wafer. n-type transistors will have their bulk terminal
|
||||
connected to this virtual net. Such a net is represented by a global net. Global nets are inherited by
|
||||
parent circuits automatically. Global nets can be included in a connectivity specification with
|
||||
"connect_global". A MOS4 device extractor emits bulk terminal shapes as copies of the gate shape to
|
||||
a specified layer. When connecting this layer to the global "BULK" net, the B terminal of the
|
||||
MOS4 devices will be connected to this global net.
|
||||
|
||||
Here is code for such an extraction. It also recognizes tie-down diodes for substrate and well connections:
|
||||
|
||||
```ruby
|
||||
ly = RBA::Layout::new
|
||||
ly.read(File.join($ut_testsrc, "testdata", "algo", "device_extract_l3.gds"))
|
||||
|
||||
l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, []))
|
||||
|
||||
rbulk = l2n.make_polygon_layer( ly.layer )
|
||||
rnwell = l2n.make_polygon_layer( ly.layer(1, 0) )
|
||||
ractive = l2n.make_polygon_layer( ly.layer(2, 0) )
|
||||
rpoly = l2n.make_polygon_layer( ly.layer(3, 0) )
|
||||
rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) )
|
||||
rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) )
|
||||
rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) )
|
||||
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) )
|
||||
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) )
|
||||
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) )
|
||||
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) )
|
||||
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) )
|
||||
rpplus = l2n.make_polygon_layer( ly.layer(10, 0) )
|
||||
rnplus = l2n.make_polygon_layer( ly.layer(11, 0) )
|
||||
|
||||
ractive_in_nwell = ractive & rnwell
|
||||
rpactive = ractive_in_nwell & rpplus
|
||||
rntie = ractive_in_nwell & rnplus
|
||||
rpgate = rpactive & rpoly
|
||||
rpsd = rpactive - rpgate
|
||||
|
||||
ractive_outside_nwell = ractive - rnwell
|
||||
rnactive = ractive_outside_nwell & rnplus
|
||||
rptie = ractive_outside_nwell & rpplus
|
||||
rngate = rnactive & rpoly
|
||||
rnsd = rnactive - rngate
|
||||
|
||||
# PMOS transistor device extraction
|
||||
pmos_ex = RBA::DeviceExtractorMOS4Transistor::new("PMOS")
|
||||
l2n.extract_devices(pmos_ex, { "SD" => rpsd, "G" => rpgate, "P" => rpoly, "W" => rnwell })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
nmos_ex = RBA::DeviceExtractorMOS4Transistor::new("NMOS")
|
||||
l2n.extract_devices(nmos_ex, { "SD" => rnsd, "G" => rngate, "P" => rpoly, "W" => rbulk })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Intra-layer
|
||||
l2n.connect(rpsd)
|
||||
l2n.connect(rnsd)
|
||||
l2n.connect(rnwell)
|
||||
l2n.connect(rpoly)
|
||||
l2n.connect(rdiff_cont)
|
||||
l2n.connect(rpoly_cont)
|
||||
l2n.connect(rmetal1)
|
||||
l2n.connect(rvia1)
|
||||
l2n.connect(rmetal2)
|
||||
l2n.connect(rptie)
|
||||
l2n.connect(rntie)
|
||||
|
||||
# Inter-layer
|
||||
l2n.connect(rpsd, rdiff_cont)
|
||||
l2n.connect(rnsd, rdiff_cont)
|
||||
l2n.connect(rpoly, rpoly_cont)
|
||||
l2n.connect(rpoly_cont, rmetal1)
|
||||
l2n.connect(rdiff_cont, rmetal1)
|
||||
l2n.connect(rdiff_cont, rntie)
|
||||
l2n.connect(rdiff_cont, rptie)
|
||||
l2n.connect(rnwell, rntie)
|
||||
l2n.connect(rmetal1, rvia1)
|
||||
l2n.connect(rvia1, rmetal2)
|
||||
l2n.connect(rpoly, rpoly_lbl) # attaches labels
|
||||
l2n.connect(rmetal1, rmetal1_lbl) # attaches labels
|
||||
l2n.connect(rmetal2, rmetal2_lbl) # attaches labels
|
||||
|
||||
# Global connections
|
||||
l2n.connect_global(rptie, "BULK")
|
||||
l2n.connect_global(rbulk, "BULK")
|
||||
|
||||
# Perform netlist extraction
|
||||
l2n.extract_netlist
|
||||
|
||||
puts l2n.netlist.to_s
|
||||
```
|
||||
Loading…
Reference in New Issue