Simple DRC for CMOS processes

edited June 2013 in General
Based on the layer processing framework, layer_proc.rbm, I have written a simple DRC (only few rules are checked). All errors will be outputted in some layers with GDS number/datatype : 254/xx

However, I found it useful to avoid to use an expensive Calibre license. It is OK for small cells and very small chips, but cannot replace Calibre or other DRC tools.

Here it is my simple drc file within the layer_processing :

#
# DRC for a generic 0.18um process
#
# check 254/10 : deepnwell : width = 3.0
# check 254/11 : deepnwell : space = 5.0
# check 254/20 : nwell : width = 2.1
# check 254/21 : nwell : space = 1.4
# check 254/30 : active : width = 0.22
# check 254/31 : active : space = 0.28
# check 254/32 : nwell - ptap : space = 0.12
# check 254/33 : nwell - nactive : space = 0.43
# check 254/34 : nwell - ntap : space = 0.12
# check 254/35 : nwell - pactive : space = 0.43
# check 254/40 : poly : width = 0.18
# check 254/41 : poly : space = 0.25
# check 254/50 : nplus : width = 0.44
# check 254/51 : poly : space = 0.44
# check 254/60 : pplus : width = 0.44
# check 254/61 : pplus : space = 0.44
# check 254/63 : nplus - pplus active : space = 0.86
# check 254/70 : rpo : width = 0.44
# check 254/71 : rpo : space = 0.43
# check 254/80 : contact : width = 0.22
# check 254/81 : contact : space = 0.25
# check 254/90 : metal1 : width = 0.23
# check 254/91 : metal1 : space = 0.23
# check 254/100 : via1 : width = 0.26
# check 254/101 : via1 : space = 0.26
# check 254/102 : via1 without metal1 or metal2
# check 254/110 : metal2 : width = 0.28
# check 254/111 : metal2 : space = 0.28
# check 254/120 : via2 : width = 0.26
# check 254/121 : via2 : space = 0.26
# check 254/122 : via1 without metal2 or metal3
# check 254/130 : metal3 : width = 0.28
# check 254/131 : metal3 : space = 0.28
# check 254/140 : via3 : width = 0.26
# check 254/141 : via3 : space = 0.26
# check 254/142 : via3 without metal3 or metal4
# check 254/150 : metal4 : width = 0.28
# check 254/151 : metal4 : space = 0.28

##########################################################

# layer to be used
deepnwell = input("1/0")
nwell = input("3/0")
active = input("6/0")
poly = input("17/0")
nplus = input("25/0")
pplus = input("26/0")
rpo = input("29/0")
contact = input("30/0")
metal1 = input("31/0")
via1 = input("51/0")
metal2 = input("32/0")
via2 = input("52/0")
metal3 = input("33/0")
via3 = input("53/0")
metal4 = input("34/0")

# check 254/10 : deepnwell : width = 3.0
drc = 3.0
drc_layer = deepnwell
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/10")

# check 254/11 : deepnwell : space = 5.0
drc = 5.0
drc_layer = deepnwell
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/11")

# check 254/20 : nwell : width = 2.1
drc = 2.1
drc_layer = nwell
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/20")

# check 254/21 : nwell : space = 1.4
drc = 1.4
drc_layer = nwell
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/21")

# check 254/30 : active : width = 0.22
drc = 0.22
drc_layer = active
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/30")

# check 254/31 : active : space = 0.28
drc = 0.28
drc_layer = active
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/31")

# check 254/32 : nwell - ptap : space = 0.12
drc = 0.12
drc_layer1 = nwell
ptap = (active.and(pplus)).not(nwell)
drc_layer2 = ptap
drc_mkr = ((drc_layer1.rsize(drc/2)).round(drc/2,drc/2,20)).and((drc_layer2.rsize(drc/2)).round(drc/2,drc/2,20))
drc_mkr = drc_mkr.size(drc/2)
drc_mkr = (drc_mkr.not(drc_layer1)).not(drc_layer2)
drc_mkr.output("254/32")

# check 254/33 : nwell - nactive : space = 0.43
drc = 0.43
drc_layer1 = nwell
drc_layer2 = (active.and(nplus)).not(nwell)
drc_mkr = ((drc_layer1.rsize(drc/2)).round(drc/2,drc/2,20)).and((drc_layer2.rsize(drc/2)).round(drc/2,drc/2,20))
drc_mkr = drc_mkr.size(drc/2)
drc_mkr = (drc_mkr.not(drc_layer1)).not(drc_layer2)
drc_mkr.output("254/33")

# check 254/34 : nwell - ntap : space = 0.12
drc = 0.12
drc_layer1 = bbox.not(nwell)
ntap = (active.and(nplus)).and(nwell)
drc_layer2 = ntap
drc_mkr = ((drc_layer1.rsize(drc/2)).round(drc/2,drc/2,20)).and((drc_layer2.rsize(drc/2)).round(drc/2,drc/2,20))
drc_mkr = drc_mkr.size(drc/2)
drc_mkr = (drc_mkr.not(drc_layer1)).not(drc_layer2)
drc_mkr.output("254/34")

# check 254/35 : nwell - pactive : space = 0.43
drc = 0.43
drc_layer1 = bbox.not(nwell)
drc_layer2 = (active.and(pplus)).and(nwell)
drc_mkr = ((drc_layer1.rsize(drc/2)).round(drc/2,drc/2,20)).and((drc_layer2.rsize(drc/2)).round(drc/2,drc/2,20))
drc_mkr = drc_mkr.size(drc/2)
drc_mkr = (drc_mkr.not(drc_layer1)).not(drc_layer2)
drc_mkr.output("254/35")

# check 254/40 : poly : width = 0.18
drc = 0.18
drc_layer = poly
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/40")

# check 254/41 : poly : space = 0.25
drc = 0.25
drc_layer = poly
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/41")

# check 254/50 : nplus : width = 0.44
drc = 0.44
drc_layer = nplus
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/50")

# check 254/51 : poly : space = 0.44
drc = 0.44
drc_layer = nplus
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/51")

# check 254/60 : pplus : width = 0.44
drc = 0.44
drc_layer = pplus
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/60")

# check 254/61 : pplus : space = 0.44
drc = 0.44
drc_layer = pplus
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/61")

# check 254/63 : nplus - pplus active : space = 0.86
drc = 0.86
drc_layer1 = nplus.and(active)
drc_layer2 = pplus.and(active)
drc_mkr = ((drc_layer1.rsize(drc/2)).round(drc/2,drc/2,20)).and((drc_layer2.rsize(drc/2)).round(drc/2,drc/2,20))
drc_mkr = drc_mkr.size(drc/2)
drc_mkr = (drc_mkr.not(drc_layer1)).not(drc_layer2)
drc_mkr.output("254/63")

# check 254/70 : rpo : width = 0.44
drc = 0.44
drc_layer = rpo
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/70")

# check 254/71 : rpo : space = 0.43
drc = 0.43
drc_layer = rpo
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/71")

# check 254/80 : contact : width = 0.22
drc = 0.22
drc_layer = contact
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/80")

# check 254/81 : contact : space = 0.25
drc = 0.25
drc_layer = contact
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/81")

# check 254/90 : metal1 : width = 0.23
drc = 0.23
drc_layer = metal1
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/90")

# check 254/91 : metal1 : space = 0.23
drc = 0.23
drc_layer = metal1
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/91")

# check 254/100 : via1 : width = 0.26
drc = 0.26
drc_layer = via1
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/100")

# check 254/101 : via1 : space = 0.26
drc = 0.26
drc_layer = via1
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/101")

# check 254/102 : via1 without metal1 or metal2
drc_mkr = via1.not(metal1.and(metal2))
drc_mkr.output("254/102")

# check 254/110 : metal2 : width = 0.28
drc = 0.28
drc_layer = metal2
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/110")

# check 254/111 : metal2 : space = 0.28
drc = 0.28
drc_layer = metal1
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/111")

# check 254/120 : via2 : width = 0.26
drc = 0.26
drc_layer = via2
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/120")

# check 254/121 : via2 : space = 0.26
drc = 0.26
drc_layer = via2
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/121")

# check 254/122 : via1 without metal2 or metal3
drc_mkr = via2.not(metal2.and(metal3))
drc_mkr.output("254/122")

# check 254/130 : metal3 : width = 0.28
drc = 0.28
drc_layer = metal3
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/130")

# check 254/131 : metal3 : space = 0.28
drc = 0.28
drc_layer = metal3
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/131")

# check 254/140 : via3 : width = 0.26
drc = 0.26
drc_layer = via3
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/140")

# check 254/141 : via3 : space = 0.26
drc = 0.26
drc_layer = via3
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/141")

# check 254/142 : via3 without metal3 or metal4
drc_mkr = via3.not(metal3.and(metal4))
drc_mkr.output("254/142")

# check 254/150 : metal4 : width = 0.28
drc = 0.28
drc_layer = metal4
drc_mkr = (drc_layer.size(-drc/2)).size(drc/2)
drc_mkr = drc_layer.not(drc_mkr)
drc_mkr.output("254/150")

# check 254/151 : metal4 : space = 0.28
drc = 0.28
drc_layer = metal4
drc_mkr = (drc_layer.size(drc/2)).round(drc/2,drc/2,20)
drc_mkr = (drc_mkr.merge(1)).size(drc/2)
drc_mkr = drc_mkr.not(drc_layer)
drc_mkr.output("254/151")

Comments

  • edited November -1
    Matthias,

    To simplify this script, I have tried to modify the layer_proc.rbm to add a width command :
    example of usage : drc_mkr = metal1.width(0.26)

    So, I have added in the "class LayerProcessorLayer", the lines :
    def width(*args)
    @p.width(self, *args)
    end


    And in the "class LayerProcessor", the lines :
    # Check the width of the shapes of a layer
    def width(l, *args)
    input = l.layer_index
    drc = to_dbu(args[0])
    if (args.size == 1)
    res = tmp()
    @proc.size(@layout, @cell, input, @cell.shapes(res), -drc/2, 2, true, true, true)
    @proc.size(@layout, @cell, @proc, @cell.shapes(res), drc/2, 2, true, true, true)
    @proc.boolean(@layout, @cell, @proc, @layout, @cell, input, @cell.shapes(res),
    RBA::EdgeProcessor::mode_anotb, true, true, true)
    return LayerProcessorLayer.new(self, res, false)

    else
    raise "width method expects one size dimension value"
    end

    end

    But, I always get an error when I run it, as the width method seems not to be recognised. So, how to add this width command in the layer_proc.rbm processing ?

    Thanks,
    OkGuy
  • edited November -1

    Hi OkGuy,

    thanks for posting the script - it's a nice application for the layer processing framework.

    I don't see a reason why you modification should not work, but I don't have the full script. What exactly is the error message?

    BTW: the script also shows the limitations of the layer processor framework. It's simply not a DRC framework yet. By "yet" I mean that I am actually working on that. The DRC framework will look similar to the layer processing framework, but provide "real" DRC functionality such a width and space checks.

    Regards,

    Matthias

  • edited November -1
    Matthias,

    The error message is :
    TypeError: can't convert NoMethodError into String
    ../klayout/layer_proc.rbm:716:in 'critical'
    ../klayout/layer_proc.rbm:716:in 'rescue in run_script'
    ../klayout/layer_proc.rbm:721:in 'run_script'
    .....

    OkGuy
  • edited June 2013

    Hi OkGuy,

    that is actually not the real message. Your layer_proc.rbm is an older version which contained a bug, specifically when displaying the error. You could call that a "meta-bug" :-)

    This bug has been fixed already. You can either update your version or get the real error by replacing line 716 with

    RBA::MessageBox.critical("Script failed", $!.to_s, RBA::MessageBox.b_ok)
    

    (the change is the "to_s" after "$!").

    The resulting message should be more specific. What does it say?

    Matthias

Sign In or Register to comment.