Skip to content

2018 12 31

Matthias Köfferlein edited this page Feb 2, 2019 · 5 revisions

First functional implementation of a netlist extractor

As of today, the "dvb" branch contains a basic hierarchical netlist extraction feature. It can be used from Ruby and Python. The basic entry point is "db::LayoutToNetlist" aka "RBA::LayoutToNetlist".

Highlights are:

  • Customizable connectivity extraction with support for hierachical boolean operations.
  • Customizable device recognition and extraction. A device extractor is provided currently for three-terminal MOSFET devices.
  • Net extraction in device-less mode for net geometry extraction.
  • Hierarchical netlist extraction.
  • Netlist cleaning ("purge") and device combination.
  • Backannotation of layout to nets.
  • Net probing by location.

The current implementation is fairly tested and not performance-optimized. Advanced features are missing yet.

After all, the whole thing needs to be wrapped into a nice DSL similar to the DRC language which is a wrapper around the pretty basic RBA::Region class.

Here is a some code you can try:

Device-less extraction

The input for this sample is part of the sources:

ly = RBA::Layout::new
ly.read("testdata/algo/device_extract_l1.gds")

l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, []))

# only plain connectivity

ractive     = l2n.make_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" )

# compute the source/drain shapes and register 
# the layer (this will make it persisted)
rsd         = ractive - rpoly
l2n.register(rsd, "sd")

# Intra-layer
l2n.connect(rsd)
l2n.connect(rpoly)
l2n.connect(rdiff_cont)
l2n.connect(rpoly_cont)
l2n.connect(rmetal1)
l2n.connect(rvia1)
l2n.connect(rmetal2)

# Inter-layer
l2n.connect(rsd,        rdiff_cont)
l2n.connect(rpoly,      rpoly_cont)
l2n.connect(rpoly_cont, rmetal1)
l2n.connect(rdiff_cont, rmetal1)
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

# Perform netlist extraction 
l2n.extract_netlist

puts l2n.netlist.to_s

The output of this script is:

Circuit TRANS ($1=$1,$2=$2,$3=$3):
Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):
  XTRANS $1 ($1=$2,$2=$4,$3=IN)
  XTRANS $2 ($1=$2,$2=$5,$3=IN)
  XTRANS $3 ($1=$5,$2=OUT,$3=$2)
  XTRANS $4 ($1=$4,$2=OUT,$3=$2)
Circuit RINGO ():
  XINV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD)
  XINV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD)
  XINV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD)
  XINV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD)
  XINV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD)
  XINV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD)
  XINV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD)
  XINV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD)
  XINV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD)
  XINV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD)

Net extraction with devices:

ly = RBA::Layout::new
ly.read("testdata/algo/device_extract_l1.gds")

l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, []))

rnwell      = l2n.make_layer(         ly.layer(1, 0), "nwell" )
ractive     = l2n.make_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" )

# compute the PMOS source/drain areas and register
# these layers so they become persisted
rpactive    = ractive & rnwell
rpgate      = rpactive & rpoly
rpsd        = rpactive - rpgate
l2n.register(rpsd, "psd")

# compute the NMOS source/drain areas and register
# these layers so they become persisted
rnactive    = ractive - rnwell
rngate      = rnactive & rpoly
rnsd        = rnactive - rngate
l2n.register(rnsd, "nsd")

# PMOS transistor device extraction
pmos_ex = RBA::DeviceExtractorMOS3Transistor::new("PMOS")
l2n.extract_devices(pmos_ex, { "SD" => rpsd, "G" => rpgate, "P" => rpoly })

# NMOS transistor device extraction
nmos_ex = RBA::DeviceExtractorMOS3Transistor::new("NMOS")
l2n.extract_devices(nmos_ex, { "SD" => rnsd, "G" => rngate, "P" => rpoly })

# Define connectivity for netlist extraction

# Intra-layer
l2n.connect(rpsd)
l2n.connect(rnsd)
l2n.connect(rpoly)
l2n.connect(rdiff_cont)
l2n.connect(rpoly_cont)
l2n.connect(rmetal1)
l2n.connect(rvia1)
l2n.connect(rmetal2)

# 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(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

# Perform netlist extraction 
l2n.extract_netlist

# Simplification
l2n.netlist.purge

puts l2n.netlist.to_s

The output of this script is:

Circuit RINGO ():
  XINV2 $1 (IN=$I8,$2=FB,OUT=(null),$4=VSS,$5=VDD)
  XINV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD)
  XINV2 $3 (IN=$I19,$2=(null),OUT=$I1,$4=VSS,$5=VDD)
  XINV2 $4 (IN=$I1,$2=(null),OUT=$I2,$4=VSS,$5=VDD)
  XINV2 $5 (IN=$I2,$2=(null),OUT=$I3,$4=VSS,$5=VDD)
  XINV2 $6 (IN=$I3,$2=(null),OUT=$I4,$4=VSS,$5=VDD)
  XINV2 $7 (IN=$I4,$2=(null),OUT=$I5,$4=VSS,$5=VDD)
  XINV2 $8 (IN=$I5,$2=(null),OUT=$I6,$4=VSS,$5=VDD)
  XINV2 $9 (IN=$I6,$2=(null),OUT=$I7,$4=VSS,$5=VDD)
  XINV2 $10 (IN=$I7,$2=(null),OUT=$I8,$4=VSS,$5=VDD)
Circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5):
  DPMOS $1 (S=$2,G=IN,D=$5) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]
  DPMOS $2 (S=$5,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]
  DNMOS $3 (S=$2,G=IN,D=$4) [L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5]
  DNMOS $4 (S=$4,G=$2,D=OUT) [L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95]