-
Notifications
You must be signed in to change notification settings - Fork 211
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:
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 ), "poly" ) # GDS #1 -> poly
rcont = l2n.make_polygon_layer( ly.layer(2, 0 ), "cont" ) # GDS #2 -> contact (poly or diff)
rmetal1 = l2n.make_polygon_layer( ly.layer(3, 0 ), "metal1" ) # GDS #3 -> metal 1
rmetal1_lbl = l2n.make_text_layer( ly.layer(103,0 ), "metal1_lbl" ) # GDS #103 -> metal 1 labels
rvia1 = l2n.make_polygon_layer( ly.layer(4, 0 ), "via1" ) # GDS #4 -> via 1
rmetal2 = l2n.make_polygon_layer( ly.layer(5, 0 ), "metal2" ) # GDS #5 -> metal 2
rmetal2_lbl = l2n.make_text_layer( ly.layer(105,0 ), "metal2_lbl" ) # GDS #105 -> metal 2 labels
rvia2 = l2n.make_polygon_layer( ly.layer(6, 0 ), "via2" ) # GDS #6 -> via 2
rmetal3 = l2n.make_polygon_layer( ly.layer(7, 0 ), "metal3" ) # GDS #7 -> metal 3
rmetal3_lbl = l2n.make_text_layer( ly.layer(107,0 ), "metal3_lbl" ) # GDS #107 -> metal 3 labels
rvia3 = l2n.make_polygon_layer( ly.layer(8, 0 ), "via3" ) # GDS #8 -> via 3
rmetal4 = l2n.make_polygon_layer( ly.layer(9, 0 ), "metal4" ) # GDS #9 -> metal 4
rmetal4_lbl = l2n.make_text_layer( ly.layer(109,0 ), "metal4_lbl" ) # GDS #109 -> metal 4 labels
rvia4 = l2n.make_polygon_layer( ly.layer(10, 0 ), "via4" ) # GDS #10 -> via 4
rmetal5 = l2n.make_polygon_layer( ly.layer(11, 0 ), "metal5" ) # GDS #11 -> metal 5
rmetal5_lbl = l2n.make_text_layer( ly.layer(111,0 ), "metal5_lbl" ) # 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
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 layer as "W" input (well). When connecting this layer to the global "BULK" net, the "B" (bulk) 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. The p-tie-down diode will also connect to the "BULK" global net. The n diode will connect to the n-well area. n-well is included in the net extraction like a conductive layer.
ly = RBA::Layout::new
ly.read(File.join("testdata", "algo", "device_extract_l3.gds"))
l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, []))
rbulk = l2n.make_polygon_layer( ly.layer , "bulk" )
rnwell = l2n.make_polygon_layer( ly.layer(1, 0), "nwell" )
ractive = l2n.make_polygon_layer( ly.layer(2, 0), "active" )
rpoly = l2n.make_polygon_layer( ly.layer(3, 0), "poly" )
rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1), "poly_lbl" )
rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0), "diff_cont" )
rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0), "poly_cont" )
rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" )
rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1), "metal1_lbl" )
rvia1 = l2n.make_polygon_layer( ly.layer(7, 0), "via1" )
rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0), "metal2" )
rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1), "metal2_lbl" )
rpplus = l2n.make_polygon_layer( ly.layer(10, 0), "pplus" )
rnplus = l2n.make_polygon_layer( ly.layer(11, 0), "nplus" )
ractive_in_nwell = ractive & rnwell
rpactive = ractive_in_nwell & rpplus
rntie = ractive_in_nwell & rnplus
rpgate = rpactive & rpoly
rpsd = rpactive - rpgate
l2n.register(rntie, "ntie")
l2n.register(rpsd, "psd")
ractive_outside_nwell = ractive - rnwell
rnactive = ractive_outside_nwell & rnplus
rptie = ractive_outside_nwell & rpplus
rngate = rnactive & rpoly
rnsd = rnactive - rngate
l2n.register(rptie, "ptie")
l2n.register(rnsd, "nsd")
# 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
The output of this script is:
Circuit RINGO ():
XINV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=OSC,$7=VDD)
XINV2PAIR $2 (BULK='BULK,VSS',$2=$I22,$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD)
XINV2PAIR $3 (BULK='BULK,VSS',$2=$I23,$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD)
XINV2PAIR $4 (BULK='BULK,VSS',$2=$I24,$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD)
XINV2PAIR $5 (BULK='BULK,VSS',$2=$I25,$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD)
Circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1):
XINV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)
XINV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)
Circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):
DPMOS $1 (S=$3,G=IN,D=VDD,B=$1) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]
DPMOS $2 (S=VDD,G=$3,D=OUT,B=$1) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]
DNMOS $3 (S=$3,G=IN,D=VSS,B=BULK) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]
DNMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]
XTRANS $1 ($1=$3,$2=VSS,$3=IN)
XTRANS $2 ($1=$3,$2=VDD,$3=IN)
XTRANS $3 ($1=VDD,$2=OUT,$3=$3)
XTRANS $4 ($1=VSS,$2=OUT,$3=$3)
Circuit TRANS ($1=$1,$2=$2,$3=$3):
With two additional steps, the netlist can be simplified and top-level pins are added:
l2n.netlist.purge
l2n.netlist.make_top_level_pins
puts l2n.netlist.to_s
This cleaned netlist lacks the empty "TRANS" subcircuits which are left over from transistor cells - they are propagated because the n-Well layer differentiates them into PMOS and NMOS transistors. The cleaned netlist looks like this:
Circuit RINGO (FB=FB,VDD=VDD,'BULK,VSS'='BULK,VSS'):
XINV2PAIR $1 (BULK='BULK,VSS',$2=FB,$3=VDD,$4='BULK,VSS',$5=$I7,$6=(null),$7=VDD)
XINV2PAIR $2 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=FB,$6=$I13,$7=VDD)
XINV2PAIR $3 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I13,$6=$I5,$7=VDD)
XINV2PAIR $4 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I5,$6=$I6,$7=VDD)
XINV2PAIR $5 (BULK='BULK,VSS',$2=(null),$3=VDD,$4='BULK,VSS',$5=$I6,$6=$I7,$7=VDD)
Circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1):
XINV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK)
XINV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK)
Circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK):
DPMOS $1 (S=$3,G=IN,D=VDD,B=$1) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]
DPMOS $2 (S=VDD,G=$3,D=OUT,B=$1) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]
DNMOS $3 (S=$3,G=IN,D=VSS,B=BULK) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]
DNMOS $4 (S=VSS,G=$3,D=OUT,B=BULK) [L=0.25,W=0.95,AS=0.26125,AD=0.49875]