From f3d1c6edc33757ab1cc1f2b3cf6c63a9a55433be Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 15 Sep 2021 11:33:39 -0700 Subject: [PATCH] klayout DRC/LVS working --- compiler/verify/klayout.py | 263 ++++++++++++++ technology/freepdk45/tech/freepdk45.lydrc | 161 +++------ technology/freepdk45/tech/freepdk45.lylvs | 406 +++++++++++++++++++++- 3 files changed, 707 insertions(+), 123 deletions(-) create mode 100644 compiler/verify/klayout.py diff --git a/compiler/verify/klayout.py b/compiler/verify/klayout.py new file mode 100644 index 00000000..808c66a7 --- /dev/null +++ b/compiler/verify/klayout.py @@ -0,0 +1,263 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +""" +This is a DRC/LVS/PEX interface file for klayout. + +""" + + +import os +import re +import shutil +import debug +from globals import OPTS +from run_script import * + +# Keep track of statistics +num_drc_runs = 0 +num_lvs_runs = 0 +num_pex_runs = 0 + + +def write_drc_script(cell_name, gds_name, extract, final_verification, output_path, sp_name=None): + """ + Write a klayout script to perform DRC and optionally extraction. + """ + global OPTS + + # DRC: + # klayout -b -r drc_FreePDK45.lydrc -rd input=sram_8_256_freepdk45.gds -rd topcell=sram_8_256_freepdk45 -rd output=drc_FreePDK45.lyrdb + + # Copy .lydrc file into the output directory + drc_file = OPTS.openram_tech + "tech/{}.lydrc".format(OPTS.tech_name) + if os.path.exists(drc_file): + shutil.copy(drc_file, output_path) + else: + debug.warning("Could not locate file: {}".format(drc_file)) + + # Create an auxiliary script to run calibre with the runset + run_file = output_path + "run_drc.sh" + f = open(run_file, "w") + f.write("#!/bin/sh\n") + cmd = "{0} -b -r {1} -rd input={2} -rd topcell={3} -rd output={3}.drc.report".format(OPTS.drc_exe[1], + drc_file, + gds_name, + cell_name) + + f.write(cmd) + f.write("\n") + f.close() + os.system("chmod u+x {}".format(run_file)) + + +def run_drc(cell_name, gds_name, sp_name=None, extract=True, final_verification=False): + """Run DRC check on a cell which is implemented in gds_name.""" + + global num_drc_runs + num_drc_runs += 1 + + write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp, sp_name=sp_name) + + (outfile, errfile, resultsfile) = run_script(cell_name, "drc") + + # Check the result for these lines in the summary: + # Total DRC errors found: 0 + # The count is shown in this format: + # Cell replica_cell_6t has 3 error tiles. + # Cell tri_gate_array has 8 error tiles. + # etc. + try: + f = open(resultsfile, "r") + except FileNotFoundError: + debug.error("Unable to load DRC results file from {}. Is klayout set up?".format(resultsfile), 1) + breakpoint() + results = f.readlines() + f.close() + errors=len([x for x in results if "" in x]) + + # always display this summary + result_str = "DRC Errors {0}\t{1}".format(cell_name, errors) + if errors > 0: + debug.warning(result_str) + else: + debug.info(1, result_str) + + return errors + + +def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, output_path=None): + """ Write a klayout script to perform LVS. """ + + # LVS: + # klayout -b -rd input=sram_32_2048_freepdk45.gds -rd report=my_report.lyrdb -rd schematic=sram_32_2048_freepdk45.sp -rd target_netlist=sram_32_2048_freepdk45_extracted.cir -r lvs_freepdk45.lvs + + global OPTS + + if not output_path: + output_path = OPTS.openram_temp + + # Copy .lylvs file into the output directory + lvs_file = OPTS.openram_tech + "tech/{}.lylvs".format(OPTS.tech_name) + if os.path.exists(lvs_file): + shutil.copy(lvs_file, output_path) + else: + debug.warning("Could not locate file: {}".format(lvs_file)) + + run_file = output_path + "/run_lvs.sh" + f = open(run_file, "w") + f.write("#!/bin/sh\n") + cmd = "{0} -b -r {1} -rd input={2} -rd report={4}.lvs.report -rd schematic={3} -rd target_netlist={4}.spice".format(OPTS.lvs_exe[1], + lvs_file, + gds_name, + sp_name, + cell_name) + f.write(cmd) + f.write("\n") + f.close() + os.system("chmod u+x {}".format(run_file)) + + +def run_lvs(cell_name, gds_name, sp_name, final_verification=False, output_path=None): + """Run LVS check on a given top-level name which is + implemented in gds_name and sp_name. Final verification will + ensure that there are no remaining virtual conections. """ + + global num_lvs_runs + num_lvs_runs += 1 + + if not output_path: + output_path = OPTS.openram_temp + + write_lvs_script(cell_name, gds_name, sp_name, final_verification) + + (outfile, errfile, resultsfile) = run_script(cell_name, "lvs") + + # check the result for these lines in the summary: + try: + f = open(outfile, "r") + except FileNotFoundError: + debug.error("Unable to load LVS results from {}".format(outfile), 1) + + results = f.readlines() + f.close() + # Look for CONGRATULATIONS or ERROR + congrats = len([x for x in results if "CONGRATULATIONS" in x]) + total_errors = len([x for x in results if "ERROR" in x]) + + if total_errors>0: + debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name, resultsfile)) + elif congrats>0: + debug.info(1, "{0}\tLVS matches".format(cell_name)) + else: + debug.info(1, "{0}\tNo LVS result".format(cell_name)) + total_errors += 1 + + return total_errors + + +def run_pex(name, gds_name, sp_name, output=None, final_verification=False, output_path=None): + """Run pex on a given top-level name which is + implemented in gds_name and sp_name. """ + + debug.error("PEX not implemented", -1) + + global num_pex_runs + num_pex_runs += 1 + + if not output_path: + output_path = OPTS.openram_temp + + os.chdir(output_path) + + if not output_path: + output_path = OPTS.openram_temp + + if output == None: + output = name + ".pex.netlist" + + # check if lvs report has been done + # if not run drc and lvs + if not os.path.isfile(name + ".lvs.report"): + run_drc(name, gds_name) + run_lvs(name, gds_name, sp_name) + + # # pex_fix did run the pex using a script while dev orignial method + # # use batch mode. + # # the dev old code using batch mode does not run and is split into functions + # pex_runset = write_script_pex_rule(gds_name, name, sp_name, output) + + # errfile = "{0}{1}.pex.err".format(output_path, name) + # outfile = "{0}{1}.pex.out".format(output_path, name) + + # script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset, + # errfile, + # outfile) + # cmd = script_cmd + # debug.info(2, cmd) + # os.system(cmd) + + # # rename technology models + # pex_nelist = open(output, 'r') + # s = pex_nelist.read() + # pex_nelist.close() + # s = s.replace('pfet', 'p') + # s = s.replace('nfet', 'n') + # f = open(output, 'w') + # f.write(s) + # f.close() + + # # also check the output file + # f = open(outfile, "r") + # results = f.readlines() + # f.close() + # out_errors = find_error(results) + # debug.check(os.path.isfile(output), "Couldn't find PEX extracted output.") + + # correct_port(name, output, sp_name) + return out_errors + + +def write_batch_pex_rule(gds_name, name, sp_name, output): + """ + """ + # write the runset file + file = OPTS.openram_temp + "pex_runset" + f = open(file, "w") + + f.close() + return file + + +def write_script_pex_rule(gds_name, cell_name, sp_name, output): + global OPTS + run_file = OPTS.openram_temp + "run_pex.sh" + f = open(run_file, "w") + f.write("#!/bin/sh\n") + f.write('export OPENRAM_TECH="{}"\n'.format(os.environ['OPENRAM_TECH'])) + f.write('echo "$(date): Starting PEX using Klayout {}"\n'.format(OPTS.drc_exe[1])) + + f.write("retcode=$?\n") + f.write("mv {0}.spice {1}\n".format(cell_name, output)) + f.write('echo "$(date): Finished PEX using Klayout {}"\n'.format(OPTS.drc_exe[1])) + f.write("exit $retcode\n") + + f.close() + os.system("chmod u+x {}".format(run_file)) + return run_file + + +def print_drc_stats(): + debug.info(1, "DRC runs: {0}".format(num_drc_runs)) + + +def print_lvs_stats(): + debug.info(1, "LVS runs: {0}".format(num_lvs_runs)) + + +def print_pex_stats(): + debug.info(1, "PEX runs: {0}".format(num_pex_runs)) diff --git a/technology/freepdk45/tech/freepdk45.lydrc b/technology/freepdk45/tech/freepdk45.lydrc index 1d719e33..87025bc7 100644 --- a/technology/freepdk45/tech/freepdk45.lydrc +++ b/technology/freepdk45/tech/freepdk45.lydrc @@ -14,12 +14,11 @@ tools_menu.drc.end dsl drc-dsl-xml - -# -# DRC for FreePDK45 according to : + # +# DRC for FreePDK45 according to : # https://www.eda.ncsu.edu/wiki/FreePDK45:RuleDevel # https://www.eda.ncsu.edu/wiki/FreePDK45:Contents -# +# ########################################################################################## tstart = Time.now @@ -42,15 +41,14 @@ end ############### OFFGRID = true ANTENNA = true -DRC = true # KLAYOUT setup ######################## # Use a tile size of 1mm -# tiles(100.um) +tiles(1000.um) # Use a tile border of 10 micron: -# tile_borders(1.um) -# no_borders +tile_borders(1.um) +#no_borders # Hierachical deep @@ -66,37 +64,30 @@ pwell = polygons(2, 0) nwell = polygons(3, 0) nplus = polygons(4, 0) pplus = polygons(5, 0) -vtg = polygons(6, 0) -vth = polygons(7, 0) -thkox = polygons(8, 0) +vtg = polygons(6, 0) +vth = polygons(7, 0) +thkox = polygons(8, 0) poly = polygons(9, 0) cont = polygons(10, 0) -metal1 = polygons(11, 0) -via1 = polygons(12, 0) -metal2 = polygons(13, 0) -via2 = polygons(14, 0) -metal3 = polygons(15, 0) -via3 = polygons(16, 0) -metal4 = polygons(17, 0) -via4 = polygons(18, 0) -metal5 = polygons(19, 0) -via5 = polygons(20, 0) -metal6 = polygons(21, 0) -via6 = polygons(22, 0) -metal7 = polygons(23, 0) -via7 = polygons(24, 0) -metal8 = polygons(25, 0) -via8 = polygons(26, 0) -metal9 = polygons(27, 0) -via9 = polygons(28, 0) -metal10 = polygons(29, 0) - -# Computed layers -well = nwell.or(pwell) -gate = poly & active -implant = nplus.or(pplus) - -if DRC +metal1 = polygons(11, 0) +via1 = polygons(12, 0) +metal2 = polygons(13, 0) +via2 = polygons(14, 0) +metal3 = polygons(15, 0) +via3 = polygons(16, 0) +metal4 = polygons(17, 0) +via4 = polygons(18, 0) +metal5 = polygons(19, 0) +via5 = polygons(20, 0) +metal6 = polygons(21, 0) +via6 = polygons(22, 0) +metal7 = polygons(23, 0) +via7 = polygons(24, 0) +metal8 = polygons(25, 0) +via8 = polygons(26, 0) +metal9 = polygons(27, 0) +via9 = polygons(28, 0) +metal10 = polygons(29, 0) # DRC section ######################## @@ -108,6 +99,7 @@ def classify_by_width(layer, *dimensions) end # Wells +well = nwell + pwell nwell.and(pwell).output("WELL.1", "WELL.1 : nwell/pwell must not overlap") # the rule "WELL.2 : Minimum spacing of well at different potential : 225nm" was not coded : see : https://www.klayout.de/forum/discussion/comment/6021 nwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of nwell at same potential : 135nm") @@ -115,14 +107,13 @@ pwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of pwe well.separation(well, 200.nm, euclidian).output("WELL.4", "WELL.4 : Minimum width of nwell/pwell : 200nm") vtg.not(well).output("VT.1","VT.1 : Vtg adjust layers must coincide with well") vth.not(well).output("VT.1","VT.1 : Vth adjust layers must coincide with well") - + # Poly +gate = poly & active poly.width(50.nm, euclidian).output("POLY.1", "POLY.1 : Minimum width of poly : 50nm") -poly_sep_active = poly.separation(active, 140.nm, projection) -if poly_sep_active.polygons? - poly_sep_active.polygons.without_area(0).output("POLY.2", "POLY.2 : Minimum spacing of poly AND active: 140nm") +if poly.separation(active, 140.nm, projection).polygons? + poly.separation(active, 140.nm, projection).polygons.without_area(0).output("POLY.2", "POLY.2 : Minimum spacing of poly AND active: 140nm") end -poly_sep_active.forget poly.enclosing(gate, 55.nm, projection).polygons.without_area(0).output("POLY.3", "POLY.3 : Minimum poly extension beyond active : 55nm") active.enclosing(gate, 70.nm, projection).polygons.without_area(0).output("POLY.4", "POLY.4 : Minimum enclosure of active around gate : 70nm") poly.not(active).separation(active, 50.nm, projection).polygons.without_area(0).output("POLY.5", "POLY.5 : Minimum spacing of field poly to active: 50nm") @@ -135,17 +126,17 @@ well.enclosing(active, 55.nm, euclidian).output("ACTIVE.3", "ACTIVE.3 : Minimum active.not(well).output("ACTIVE.4", "ACTIVE.4 : active must be inside nwell or pwell") # Implant +implant = nplus + pplus implant.separation(gate, 70.nm, projection).polygons.without_area(0).output("IMPLANT.1", "IMPLANT.1 : Minimum spacing of nimplant/ pimplant to channel : 70nm") implant.separation(cont, 25.nm, projection).polygons.without_area(0).output("IMPLANT.2", "IMPLANT.1 : Minimum spacing of nimplant/ pimplant to contact : 25nm") implant.width(45.nm, euclidian).output("IMPLANT.3", "IMPLANT.3 : Minimum width of nimplant/ pimplant : 45nm") implant.space(45.nm, euclidian).output("IMPLANT.4", "IMPLANT.4 : Minimum spacing of nimplant/ pimplant : 45nm") nplus.and(pplus).output("IMPLANT.5", "IMPLANT.5 : Nimplant and pimplant must not overlap") -implant.forget # Contact cont.edges.without_length(65.nm).output("CONTACT.1", "CONTACT.1 : Minimum/Maximum width of contact : 65nm") cont.space(75.nm, euclidian).output("CONTACT.2", "CONTACT.2 : Minimum spacing of contact : 75nm") -cont.not(active).not(poly).not(metal1).output("CONTACT.3", "CONTACT.3 : contact must be inside active or poly or metal1") +cont.not(active + poly + metal1).output("CONTACT.3", "CONTACT.3 : contact must be inside active or poly or metal1") active.enclosing(cont, 5.nm, euclidian).output("CONTACT.4", "CONTACT.4 : Minimum enclosure of active around contact : 5nm") poly.enclosing(cont, 5.nm, euclidian).output("CONTACT.5", "CONTACT.5 : Minimum enclosure of poly around contact : 5nm") cont.separation(poly, 35.nm, euclidian).output("CONTACT.6", "CONTACT.6 : Minimum spacing of contact and poly : 35nm") @@ -155,21 +146,16 @@ metal1.width(65.nm, euclidian).output("METAL1.1", "METAL1.1 : Minimum width of m metal1.space(65.nm, euclidian).output("METAL1.2", "METAL1.2 : Minimum spacing of metal1 : 65nm") cont_edges_with_less_enclosure = metal1.enclosing(cont, 35.nm, projection).second_edges error_corners = cont_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) -cont_edges_with_less_enclosure.forget cont.interacting(error_corners.polygons(1.dbu)).output("METAL1.3", "METAL1.3 : Minimum enclosure around contact on two opposite sides : 35nm") -error_corners.forget via1_edges_with_less_enclosure = metal1.enclosing(via1, 35.nm, projection).second_edges error_corners = via1_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) -via1_edges_with_less_enclosure.forget via1.interacting(error_corners.polygons(1.dbu)).output("METAL1.4", "METAL1.4 : Minimum enclosure around via1 on two opposite sides : 35nm") -error_corners.forget metal1_gt90, metal1_gt270, metal1_gt500, metal1_gt900, metal1_gt1500 = classify_by_width(metal1, 90.nm, 270.nm, 500.nm, 900.nm, 1500.nm) metal1_gt90.edges.with_length(300.nm,nil).space(90.nm,euclidian).output("METAL1.5", "METAL1.5 : Minimum spacing of metal1 wider than 90 nm and longer than 300 nm : 90nm") metal1_gt270.edges.with_length(900.nm,nil).space(270.nm,euclidian).output("METAL1.6", "METAL1.6 : Minimum spacing of metal1 wider than 270 nm and longer than 900 nm : 270nm") metal1_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL1.7", "METAL1.7 : Minimum spacing of metal1 wider than 500 nm and longer than 1.8 um : 500nm") metal1_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL1.8", "METAL1.8 : Minimum spacing of metal1 wider than 900 nm and longer than 2.7 um : 900nm") metal1_gt1500.edges.with_length(4.um,nil).space(1500.nm,euclidian).output("METAL1.9", "METAL1.9 : Minimum spacing of metal1 wider than 1500 nm and longer than 4.0 um : 1500nm") -[ metal1_gt90, metal1_gt270, metal1_gt500, metal1_gt900, metal1_gt1500 ].each { |l| l.forget } # Via1 via1.edges.without_length(65.nm).output("VIA1.1", "VIA1.1 : Minimum/Maximum width of via1 : 65nm") @@ -182,21 +168,16 @@ metal2.width(70.nm, euclidian).output("METAL2.1", "METAL2.1 : Minimum width of metal2.space(70.nm, euclidian).output("METAL2.2", "METAL2.2 : Minimum spacing of intermediate metal2 : 70nm") via1_edges_with_less_enclosure = metal2.enclosing(via1, 35.nm, projection).second_edges error_corners = via1_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) -via1_edges_with_less_enclosure.forget via1.interacting(error_corners.polygons(1.dbu)).output("METAL2.3", "METAL2.3 : Minimum enclosure around via1 on two opposite sides : 35nm") -error_corners.forget via2_edges_with_less_enclosure = metal2.enclosing(via2, 35.nm, projection).second_edges error_corners = via2_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) -via2_edges_with_less_enclosure.forget via2.interacting(error_corners.polygons(1.dbu)).output("METAL2.4", "METAL2.4 : Minimum enclosure around via2 on two opposite sides : 35nm") -error_corners.forget metal2_gt90, metal2_gt270, metal2_gt500, metal2_gt900, metal2_gt1500 = classify_by_width(metal2, 90.nm, 270.nm, 500.nm, 900.nm, 1500.nm) metal2_gt90.edges.with_length(300.nm,nil).space(90.nm,euclidian).output("METAL2.5", "METAL2.5 : Minimum spacing of intermediate metal2 wider than 90 nm and longer than 300 nm : 90nm") metal2_gt270.edges.with_length(900.nm,nil).space(270.nm,euclidian).output("METAL2.6", "METAL2.6 : Minimum spacing of intermediate metal2 wider than 270 nm and longer than 900 nm : 270nm") metal2_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL2.7", "METAL2.7 : Minimum spacing of intermediate metal2 wider than 500 nm and longer than 1.8 um : 500nm") metal2_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL2.8", "METAL2.8 : Minimum spacing of intermediate metal2 wider than 900 nm and longer than 2.7 um : 900nm") metal2_gt1500.edges.with_length(4.um,nil).space(1500.nm,euclidian).output("METAL2.9", "METAL2.9 : Minimum spacing of intermediate metal2 wider than 1500 nm and longer than 4.0 um : 1500nm") -[ metal2_gt90, metal2_gt270, metal2_gt500, metal2_gt900, metal2_gt1500 ].each { |l| l.forget } # via2 via2.edges.without_length(70.nm).output("VIA2.1", "VIA2.1 : Minimum/Maximum width of via2 : 70nm") @@ -209,21 +190,16 @@ metal3.width(70.nm, euclidian).output("METAL3.1", "METAL3.1 : Minimum width of metal3.space(70.nm, euclidian).output("METAL3.2", "METAL3.2 : Minimum spacing of intermediate metal3 : 70nm") via2_edges_with_less_enclosure = metal3.enclosing(via2, 35.nm, projection).second_edges error_corners = via2_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) -via2_edges_with_less_enclosure.forget via2.interacting(error_corners.polygons(1.dbu)).output("METAL3.3", "METAL3.3 : Minimum enclosure around via2 on two opposite sides : 35nm") -error_corners.forget via3_edges_with_less_enclosure = metal3.enclosing(via3, 35.nm, projection).second_edges error_corners = via3_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) -via3_edges_with_less_enclosure.forget via3.interacting(error_corners.polygons(1.dbu)).output("METAL3.4", "METAL3.4 : Minimum enclosure around via3 on two opposite sides : 35nm") -error_corners.forget metal3_gt90, metal3_gt270, metal3_gt500, metal3_gt900, metal3_gt1500 = classify_by_width(metal3, 90.nm, 270.nm, 500.nm, 900.nm, 1500.nm) metal3_gt90.edges.with_length(300.nm,nil).space(90.nm,euclidian).output("METAL3.5", "METAL3.5 : Minimum spacing of intermediate metal3 wider than 90 nm and longer than 300 nm : 90nm") metal3_gt270.edges.with_length(900.nm,nil).space(270.nm,euclidian).output("METAL3.6", "METAL3.6 : Minimum spacing of intermediate metal3 wider than 270 nm and longer than 900 nm : 270nm") metal3_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL3.7", "METAL3.7 : Minimum spacing of intermediate metal3 wider than 500 nm and longer than 1.8 um : 500nm") metal3_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL3.8", "METAL3.8 : Minimum spacing of intermediate metal3 wider than 900 nm and longer than 2.7 um : 900nm") metal3_gt1500.edges.with_length(4.um,nil).space(1500.nm,euclidian).output("METAL3.9", "METAL3.9 : Minimum spacing of intermediate metal3 wider than 1500 nm and longer than 4.0 um : 1500nm") -[ metal3_gt90, metal3_gt270, metal3_gt500, metal3_gt900, metal3_gt1500 ].each { |l| l.forget } # via3 via3.edges.without_length(70.nm).output("VIA3.1", "VIA3.1 : Minimum/Maximum width of via3 : 70nm") @@ -238,7 +214,6 @@ metal4_gt270, metal4_gt500, metal4_gt900 = classify_by_width(metal4, 270.nm, 500 metal4_gt270.edges.with_length(900.nm,nil).space(270.nm,euclidian).output("METAL4.6", "METAL4.6 : Minimum spacing of semi-global metal4 wider than 270 nm and longer than 900 nm : 270nm") metal4_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL4.7", "METAL4.7 : Minimum spacing of semi-global metal4 wider than 500 nm and longer than 1.8 um : 500nm") metal4_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL4.8", "METAL4.8 : Minimum spacing of semi-global meta4l wider than 900 nm and longer than 2.7 um : 900nm") -[ metal4_gt270, metal4_gt500, metal4_gt900 ].each { |l| l.forget } # via4 via4.edges.without_length(140.nm).output("VIA4.1", "VIA4.1 : Minimum/Maximum width of via4 : 140nm") @@ -253,7 +228,6 @@ metal5_gt270, metal5_gt500, metal5_gt900 = classify_by_width(metal5, 270.nm, 500 metal5_gt270.edges.with_length(900.nm,nil).space(270.nm,euclidian).output("METAL5.6", "METAL5.6 : Minimum spacing of semi-global metal5 wider than 270 nm and longer than 900 nm : 270nm") metal5_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL5.7", "METAL5.7 : Minimum spacing of semi-global metal5 wider than 500 nm and longer than 1.8 um : 500nm") metal5_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL5.8", "METAL5.8 : Minimum spacing of semi-global meta5l wider than 900 nm and longer than 2.7 um : 900nm") -[ metal5_gt270, metal5_gt500, metal5_gt900 ].each { |l| l.forget } # via5 via5.edges.without_length(140.nm).output("VIA5.1", "VIA5.1 : Minimum/Maximum width of via5 : 140nm") @@ -268,7 +242,6 @@ metal6_gt270, metal6_gt500, metal6_gt900 = classify_by_width(metal6, 270.nm, 500 metal6_gt270.edges.with_length(900.nm,nil).space(270.nm,euclidian).output("METAL6.6", "METAL6.6 : Minimum spacing of semi-global metal6 wider than 270 nm and longer than 900 nm : 270nm") metal6_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL6.7", "METAL6.7 : Minimum spacing of semi-global metal6 wider than 500 nm and longer than 1.8 um : 500nm") metal6_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL6.8", "METAL6.8 : Minimum spacing of semi-global metal6 wider than 900 nm and longer than 2.7 um : 900nm") -[ metal6_gt270, metal6_gt500, metal6_gt900 ].each { |l| l.forget } # via6 via6.edges.without_length(140.nm).output("VIA6.1", "VIA6.1 : Minimum/Maximum width of via6 : 140nm") @@ -283,7 +256,6 @@ metal7_gt500, metal7_gt900, metal7_gt1500 = classify_by_width(metal7, 500.nm, 90 metal7_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL7.7", "METAL7.7 : Minimum spacing of thin global metal7 wider than 500 nm and longer than 1.8 um : 500nm") metal7_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL7.8", "METAL7.8 : Minimum spacing of thin global metal7 wider than 900 nm and longer than 2.7 um : 900nm") metal7_gt1500.edges.with_length(4.um,nil).space(1500.nm,euclidian).output("METAL7.9", "METAL7.9 : Minimum spacing of thin global meta7l wider than 1500 nm and longer than 4.0 um : 1500nm") -[ metal7_gt500, metal7_gt900, metal7_gt1500 ].each { |l| l.forget } # via7 via7.edges.without_length(400.nm).output("VIA6.1", "VIA6.1 : Minimum/Maximum width of via7 : 400nm") @@ -298,7 +270,6 @@ metal8_gt500, metal8_gt900, metal8_gt1500 = classify_by_width(metal8, 500.nm, 90 metal8_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL8.7", "METAL8.7 : Minimum spacing of thin global metal8 wider than 500 nm and longer than 1.8 um : 500nm") metal8_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL8.8", "METAL8.8 : Minimum spacing of thin global metal8 wider than 900 nm and longer than 2.7 um : 900nm") metal8_gt1500.edges.with_length(4.um,nil).space(1500.nm,euclidian).output("METAL8.9", "METAL8.9 : Minimum spacing of thin global metal8 wider than 1500 nm and longer than 4.0 um : 1500nm") -[ metal8_gt500, metal8_gt900, metal8_gt1500 ].each { |l| l.forget } # via8 via8.edges.without_length(400.nm).output("VIA8.1", "VIA8.1 : Minimum/Maximum width of via8 : 400nm") @@ -313,7 +284,6 @@ metal9_gt500, metal9_gt900, metal9_gt1500 = classify_by_width(metal9, 500.nm, 90 metal9_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL9.7", "METAL9.7 : Minimum spacing of global metal9 wider than 500 nm and longer than 1.8 um : 500nm") metal9_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL9.8", "METAL9.8 : Minimum spacing of global metal9 wider than 900 nm and longer than 2.7 um : 900nm") metal9_gt1500.edges.with_length(4.um,nil).space(1500.nm,euclidian).output("METAL9.9", "METAL9.9 : Minimum spacing of global metal9 wider than 1500 nm and longer than 4.0 um : 1500nm") -[ metal9_gt500, metal9_gt900, metal9_gt1500 ].each { |l| l.forget } # via9 via9.edges.without_length(800.nm).output("VIA9.1", "VIA9.1 : Minimum/Maximum width of via9 : 800nm") @@ -328,9 +298,7 @@ metal10_gt500, metal10_gt900, metal10_gt1500 = classify_by_width(metal10, 500.nm metal10_gt500.edges.with_length(1.8.um,nil).space(500.nm,euclidian).output("METAL10.7", "METAL10.7 : Minimum spacing of global metal10 wider than 500 nm and longer than 1.8 um : 500nm") metal10_gt900.edges.with_length(2.7.um,nil).space(900.nm,euclidian).output("METAL10.8", "METAL10.8 : Minimum spacing of global metal10 wider than 900 nm and longer than 2.7 um : 900nm") metal10_gt1500.edges.with_length(4.um,nil).space(1500.nm,euclidian).output("METAL10.9", "METAL10.9 : Minimum spacing of global metal10 wider than 1500 nm and longer than 4.0 um : 1500nm") -[ metal10_gt500, metal10_gt900, metal10_gt1500 ].each { |l| l.forget } -end # ONGRID also defined in : @@ -354,70 +322,46 @@ end if ANTENNA info("ANTENNA section") -diode = nplus & active - nwell # diode recognition layer - -# build connction of poly+gate to metal1 +# build connections of poly+gate to metals connect(gate, poly) connect(poly, cont) -connect(diode, cont) connect(cont, metal1) - -antenna_check(gate, metal1, 300.0, diode).output("METAL1_ANTENNA", "METAL1_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal2 connect(metal1, via1) connect(via1, metal2) - -antenna_check(gate, metal2, 300.0, diode).output("METAL2_ANTENNA", "METAL2_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal3 connect(metal2, via2) connect(via2, metal3) - -antenna_check(gate, metal3, 300.0, diode).output("METAL3_ANTENNA", "METAL3_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal4 connect(metal3, via3) connect(via3, metal4) - -antenna_check(gate, metal4, 300.0, diode).output("METAL4_ANTENNA", "METAL4_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal5 connect(metal4, via4) connect(via4, metal5) - -antenna_check(gate, metal5, 300.0, diode).output("METAL5_ANTENNA", "METAL5_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal6 connect(metal5, via5) connect(via5, metal6) - -antenna_check(gate, metal6, 300.0, diode).output("METAL6_ANTENNA", "METAL6_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal7 connect(metal6, via6) connect(via6, metal7) - -antenna_check(gate, metal7, 300.0, diode).output("METAL7_ANTENNA", "METAL7_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal8 connect(metal7, via7) connect(via7, metal8) - -antenna_check(gate, metal8, 300.0, diode).output("METAL8_ANTENNA", "METAL8_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal9 connect(metal8, via8) connect(via8, metal9) - -antenna_check(gate, metal9, 300.0, diode).output("METAL9_ANTENNA", "METAL9_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") - -# build connction of poly+gate to metal10 connect(metal9, via9) connect(via9, metal10) +diode = nplus & active - nwell # diode recognition layer +connect(diode, cont) + +# runs an antenna checks for each metal with a ratio of 300 +antenna_check(gate, metal1, 300.0, diode).output("METAL1_ANTENNA", "METAL1_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +antenna_check(gate, metal2, 300.0, diode).output("METAL2_ANTENNA", "METAL2_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +antenna_check(gate, metal3, 300.0, diode).output("METAL3_ANTENNA", "METAL3_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +antenna_check(gate, metal4, 300.0, diode).output("METAL4_ANTENNA", "METAL4_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +antenna_check(gate, metal5, 300.0, diode).output("METAL5_ANTENNA", "METAL5_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +antenna_check(gate, metal6, 300.0, diode).output("METAL6_ANTENNA", "METAL6_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +antenna_check(gate, metal7, 300.0, diode).output("METAL7_ANTENNA", "METAL7_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +antenna_check(gate, metal8, 300.0, diode).output("METAL8_ANTENNA", "METAL8_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +antenna_check(gate, metal9, 300.0, diode).output("METAL9_ANTENNA", "METAL9_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") antenna_check(gate, metal10, 300.0, diode).output("METAL10_ANTENNA", "METAL10_ANTENNA : Ratio of Maximum Allowed (Field poly area or Metal Layer Area) to transistor gate area : 300:1") +# this will remove all connections made +clear_connections end # time spent for the DRC @@ -425,6 +369,5 @@ time = Time.now hours = ((time - tstart)/3600).to_i minutes = ((time - tstart)/60 - hours * 60).to_i seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i -$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" - +$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index c9107e45..c8dfccef 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -26,7 +26,7 @@ if $input end if $report - report_lvs($report) + report($report) else report_lvs("lvs_report.lvsdb") end @@ -34,7 +34,7 @@ end if $schematic #reference netlist schematic($schematic) -else +else # schematic("sram_8_256_freepdk45.sp") schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp")) end @@ -50,7 +50,7 @@ spice_with_comments = false if $target_netlist target_netlist($target_netlist) else - # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.") + # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.") target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), write_spice(spice_with_net_names, spice_with_comments), "Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") end @@ -136,7 +136,7 @@ lv_ngate = ngate - vtg - thkox gv_ngate = ngate & vtg - vth - thkox hv_ngate = ngate - vtg - vth & thkox -cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0") { +cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0", "replica_cell_1rw", "replica_bitcell_array") { # PMOS transistor device extraction extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) @@ -210,16 +210,286 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") connect_global(bulk, "BULK") -#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) -# connect_explicit(pat, [ "NWELL", "vdd" ]) -# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) -#end +for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) + connect_explicit(pat, [ "NWELL", "vdd" ]) + connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +end + +for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* + FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) + connect_explicit(pat, [ "NWELL", "VDD" ]) + connect_explicit(pat, [ "BULK", "VSS" ]) +end -#for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* -# FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) -# connect_explicit(pat, [ "NWELL", "VDD" ]) -# connect_explicit(pat, [ "BULK", "VSS" ]) -#end +# NangateOpenCellLibrary Digital gates VDD VSS implicit connection due to lack of taps insides the cells +connect_implicit("AND2_X1" , "VDD") +connect_implicit("AND2_X1" , "VSS") +connect_implicit("AND2_X2" , "VDD") +connect_implicit("AND2_X2" , "VSS") +connect_implicit("AND2_X4" , "VDD") +connect_implicit("AND2_X4" , "VSS") +connect_implicit("AND3_X1" , "VDD") +connect_implicit("AND3_X1" , "VSS") +connect_implicit("AND3_X2" , "VDD") +connect_implicit("AND3_X2" , "VSS") +connect_implicit("AND3_X4" , "VDD") +connect_implicit("AND3_X4" , "VSS") +connect_implicit("AND4_X1" , "VDD") +connect_implicit("AND4_X1" , "VSS") +connect_implicit("AND4_X2" , "VDD") +connect_implicit("AND4_X2" , "VSS") +connect_implicit("AND4_X4" , "VDD") +connect_implicit("AND4_X4" , "VSS") +connect_implicit("ANTENNA_X1" , "VDD") +connect_implicit("ANTENNA_X1" , "VSS") +connect_implicit("AOI211_X1" , "VDD") +connect_implicit("AOI211_X1" , "VSS") +connect_implicit("AOI211_X2" , "VDD") +connect_implicit("AOI211_X2" , "VSS") +connect_implicit("AOI211_X4" , "VDD") +connect_implicit("AOI211_X4" , "VSS") +connect_implicit("AOI21_X1" , "VDD") +connect_implicit("AOI21_X1" , "VSS") +connect_implicit("AOI21_X2" , "VDD") +connect_implicit("AOI21_X2" , "VSS") +connect_implicit("AOI21_X4" , "VDD") +connect_implicit("AOI21_X4" , "VSS") +connect_implicit("AOI221_X1" , "VDD") +connect_implicit("AOI221_X1" , "VSS") +connect_implicit("AOI221_X2" , "VDD") +connect_implicit("AOI221_X2" , "VSS") +connect_implicit("AOI221_X4" , "VDD") +connect_implicit("AOI221_X4" , "VSS") +connect_implicit("AOI222_X1" , "VDD") +connect_implicit("AOI222_X1" , "VSS") +connect_implicit("AOI222_X2" , "VDD") +connect_implicit("AOI222_X2" , "VSS") +connect_implicit("AOI222_X4" , "VDD") +connect_implicit("AOI222_X4" , "VSS") +connect_implicit("AOI22_X1" , "VDD") +connect_implicit("AOI22_X1" , "VSS") +connect_implicit("AOI22_X2" , "VDD") +connect_implicit("AOI22_X2" , "VSS") +connect_implicit("AOI22_X4" , "VDD") +connect_implicit("AOI22_X4" , "VSS") +connect_implicit("BUF_X1" , "VDD") +connect_implicit("BUF_X1" , "VSS") +connect_implicit("BUF_X16" , "VDD") +connect_implicit("BUF_X16" , "VSS") +connect_implicit("BUF_X2" , "VDD") +connect_implicit("BUF_X2" , "VSS") +connect_implicit("BUF_X32" , "VDD") +connect_implicit("BUF_X32" , "VSS") +connect_implicit("BUF_X4" , "VDD") +connect_implicit("BUF_X4" , "VSS") +connect_implicit("BUF_X8" , "VDD") +connect_implicit("BUF_X8" , "VSS") +connect_implicit("CLKBUF_X1" , "VDD") +connect_implicit("CLKBUF_X1" , "VSS") +connect_implicit("CLKBUF_X2" , "VDD") +connect_implicit("CLKBUF_X2" , "VSS") +connect_implicit("CLKBUF_X3" , "VDD") +connect_implicit("CLKBUF_X3" , "VSS") +connect_implicit("CLKGATETST_X1" , "VDD") +connect_implicit("CLKGATETST_X1" , "VSS") +connect_implicit("CLKGATETST_X2" , "VDD") +connect_implicit("CLKGATETST_X2" , "VSS") +connect_implicit("CLKGATETST_X4" , "VDD") +connect_implicit("CLKGATETST_X4" , "VSS") +connect_implicit("CLKGATETST_X8" , "VDD") +connect_implicit("CLKGATETST_X8" , "VSS") +connect_implicit("CLKGATE_X1" , "VDD") +connect_implicit("CLKGATE_X1" , "VSS") +connect_implicit("CLKGATE_X2" , "VDD") +connect_implicit("CLKGATE_X2" , "VSS") +connect_implicit("CLKGATE_X4" , "VDD") +connect_implicit("CLKGATE_X4" , "VSS") +connect_implicit("CLKGATE_X8" , "VDD") +connect_implicit("CLKGATE_X8" , "VSS") +connect_implicit("DFFRS_X1" , "VDD") +connect_implicit("DFFRS_X1" , "VSS") +connect_implicit("DFFRS_X2" , "VDD") +connect_implicit("DFFRS_X2" , "VSS") +connect_implicit("DFFR_X1" , "VDD") +connect_implicit("DFFR_X1" , "VSS") +connect_implicit("DFFR_X2" , "VDD") +connect_implicit("DFFR_X2" , "VSS") +connect_implicit("DFFS_X1" , "VDD") +connect_implicit("DFFS_X1" , "VSS") +connect_implicit("DFFS_X2" , "VDD") +connect_implicit("DFFS_X2" , "VSS") +connect_implicit("DFF_X1" , "VDD") +connect_implicit("DFF_X1" , "VSS") +connect_implicit("DFF_X2" , "VDD") +connect_implicit("DFF_X2" , "VSS") +connect_implicit("DLH_X1" , "VDD") +connect_implicit("DLH_X1" , "VSS") +connect_implicit("DLH_X2" , "VDD") +connect_implicit("DLH_X2" , "VSS") +connect_implicit("DLL_X1" , "VDD") +connect_implicit("DLL_X1" , "VSS") +connect_implicit("DLL_X2" , "VDD") +connect_implicit("DLL_X2" , "VSS") +connect_implicit("FA_X1" , "VDD") +connect_implicit("FA_X1" , "VSS") +connect_implicit("FILLCELL_X1" , "VDD") +connect_implicit("FILLCELL_X1" , "VSS") +connect_implicit("FILLCELL_X16" , "VDD") +connect_implicit("FILLCELL_X16" , "VSS") +connect_implicit("FILLCELL_X2" , "VDD") +connect_implicit("FILLCELL_X2" , "VSS") +connect_implicit("FILLCELL_X32" , "VDD") +connect_implicit("FILLCELL_X32" , "VSS") +connect_implicit("FILLCELL_X4" , "VDD") +connect_implicit("FILLCELL_X4" , "VSS") +connect_implicit("FILLCELL_X8" , "VDD") +connect_implicit("FILLCELL_X8" , "VSS") +connect_implicit("HA_X1" , "VDD") +connect_implicit("HA_X1" , "VSS") +connect_implicit("INV_X1" , "VDD") +connect_implicit("INV_X1" , "VSS") +connect_implicit("INV_X16" , "VDD") +connect_implicit("INV_X16" , "VSS") +connect_implicit("INV_X2" , "VDD") +connect_implicit("INV_X2" , "VSS") +connect_implicit("INV_X32" , "VDD") +connect_implicit("INV_X32" , "VSS") +connect_implicit("INV_X4" , "VDD") +connect_implicit("INV_X4" , "VSS") +connect_implicit("INV_X8" , "VDD") +connect_implicit("INV_X8" , "VSS") +connect_implicit("LOGIC0_X1" , "VDD") +connect_implicit("LOGIC0_X1" , "VSS") +connect_implicit("LOGIC1_X1" , "VDD") +connect_implicit("LOGIC1_X1" , "VSS") +connect_implicit("MUX2_X1" , "VDD") +connect_implicit("MUX2_X1" , "VSS") +connect_implicit("MUX2_X2" , "VDD") +connect_implicit("MUX2_X2" , "VSS") +connect_implicit("NAND2_X1" , "VDD") +connect_implicit("NAND2_X1" , "VSS") +connect_implicit("NAND2_X2" , "VDD") +connect_implicit("NAND2_X2" , "VSS") +connect_implicit("NAND2_X4" , "VDD") +connect_implicit("NAND2_X4" , "VSS") +connect_implicit("NAND3_X1" , "VDD") +connect_implicit("NAND3_X1" , "VSS") +connect_implicit("NAND3_X2" , "VDD") +connect_implicit("NAND3_X2" , "VSS") +connect_implicit("NAND3_X4" , "VDD") +connect_implicit("NAND3_X4" , "VSS") +connect_implicit("NAND4_X1" , "VDD") +connect_implicit("NAND4_X1" , "VSS") +connect_implicit("NAND4_X2" , "VDD") +connect_implicit("NAND4_X2" , "VSS") +connect_implicit("NAND4_X4" , "VDD") +connect_implicit("NAND4_X4" , "VSS") +connect_implicit("NOR2_X1" , "VDD") +connect_implicit("NOR2_X1" , "VSS") +connect_implicit("NOR2_X2" , "VDD") +connect_implicit("NOR2_X2" , "VSS") +connect_implicit("NOR2_X4" , "VDD") +connect_implicit("NOR2_X4" , "VSS") +connect_implicit("NOR3_X1" , "VDD") +connect_implicit("NOR3_X1" , "VSS") +connect_implicit("NOR3_X2" , "VDD") +connect_implicit("NOR3_X2" , "VSS") +connect_implicit("NOR3_X4" , "VDD") +connect_implicit("NOR3_X4" , "VSS") +connect_implicit("NOR4_X1" , "VDD") +connect_implicit("NOR4_X1" , "VSS") +connect_implicit("NOR4_X2" , "VDD") +connect_implicit("NOR4_X2" , "VSS") +connect_implicit("NOR4_X4" , "VDD") +connect_implicit("NOR4_X4" , "VSS") +connect_implicit("OAI211_X1" , "VDD") +connect_implicit("OAI211_X1" , "VSS") +connect_implicit("OAI211_X2" , "VDD") +connect_implicit("OAI211_X2" , "VSS") +connect_implicit("OAI211_X4" , "VDD") +connect_implicit("OAI211_X4" , "VSS") +connect_implicit("OAI21_X1" , "VDD") +connect_implicit("OAI21_X1" , "VSS") +connect_implicit("OAI21_X2" , "VDD") +connect_implicit("OAI21_X2" , "VSS") +connect_implicit("OAI21_X4" , "VDD") +connect_implicit("OAI21_X4" , "VSS") +connect_implicit("OAI221_X1" , "VDD") +connect_implicit("OAI221_X1" , "VSS") +connect_implicit("OAI221_X2" , "VDD") +connect_implicit("OAI221_X2" , "VSS") +connect_implicit("OAI221_X4" , "VDD") +connect_implicit("OAI221_X4" , "VSS") +connect_implicit("OAI222_X1" , "VDD") +connect_implicit("OAI222_X1" , "VSS") +connect_implicit("OAI222_X2" , "VDD") +connect_implicit("OAI222_X2" , "VSS") +connect_implicit("OAI222_X4" , "VDD") +connect_implicit("OAI222_X4" , "VSS") +connect_implicit("OAI22_X1" , "VDD") +connect_implicit("OAI22_X1" , "VSS") +connect_implicit("OAI22_X2" , "VDD") +connect_implicit("OAI22_X2" , "VSS") +connect_implicit("OAI22_X4" , "VDD") +connect_implicit("OAI22_X4" , "VSS") +connect_implicit("OAI33_X1" , "VDD") +connect_implicit("OAI33_X1" , "VSS") +connect_implicit("OR2_X1" , "VDD") +connect_implicit("OR2_X1" , "VSS") +connect_implicit("OR2_X2" , "VDD") +connect_implicit("OR2_X2" , "VSS") +connect_implicit("OR2_X4" , "VDD") +connect_implicit("OR2_X4" , "VSS") +connect_implicit("OR3_X1" , "VDD") +connect_implicit("OR3_X1" , "VSS") +connect_implicit("OR3_X2" , "VDD") +connect_implicit("OR3_X2" , "VSS") +connect_implicit("OR3_X4" , "VDD") +connect_implicit("OR3_X4" , "VSS") +connect_implicit("OR4_X1" , "VDD") +connect_implicit("OR4_X1" , "VSS") +connect_implicit("OR4_X2" , "VDD") +connect_implicit("OR4_X2" , "VSS") +connect_implicit("OR4_X4" , "VDD") +connect_implicit("OR4_X4" , "VSS") +connect_implicit("SDFFRS_X1" , "VDD") +connect_implicit("SDFFRS_X1" , "VSS") +connect_implicit("SDFFRS_X2" , "VDD") +connect_implicit("SDFFRS_X2" , "VSS") +connect_implicit("SDFFR_X1" , "VDD") +connect_implicit("SDFFR_X1" , "VSS") +connect_implicit("SDFFR_X2" , "VDD") +connect_implicit("SDFFR_X2" , "VSS") +connect_implicit("SDFFS_X1" , "VDD") +connect_implicit("SDFFS_X1" , "VSS") +connect_implicit("SDFFS_X2" , "VDD") +connect_implicit("SDFFS_X2" , "VSS") +connect_implicit("SDFF_X1" , "VDD") +connect_implicit("SDFF_X1" , "VSS") +connect_implicit("SDFF_X2" , "VDD") +connect_implicit("SDFF_X2" , "VSS") +connect_implicit("TBUF_X1" , "VDD") +connect_implicit("TBUF_X1" , "VSS") +connect_implicit("TBUF_X16" , "VDD") +connect_implicit("TBUF_X16" , "VSS") +connect_implicit("TBUF_X2" , "VDD") +connect_implicit("TBUF_X2" , "VSS") +connect_implicit("TBUF_X4" , "VDD") +connect_implicit("TBUF_X4" , "VSS") +connect_implicit("TBUF_X8" , "VDD") +connect_implicit("TBUF_X8" , "VSS") +connect_implicit("TINV_X1" , "VDD") +connect_implicit("TINV_X1" , "VSS") +connect_implicit("TLAT_X1" , "VDD") +connect_implicit("TLAT_X1" , "VSS") +connect_implicit("XNOR2_X1" , "VDD") +connect_implicit("XNOR2_X1" , "VSS") +connect_implicit("XNOR2_X2" , "VDD") +connect_implicit("XNOR2_X2" , "VSS") +connect_implicit("XOR2_X1" , "VDD") +connect_implicit("XOR2_X1" , "VSS") +connect_implicit("XOR2_X2" , "VDD") +connect_implicit("XOR2_X2" , "VSS") # Actually performs the extraction netlist # ... not really required @@ -248,13 +518,121 @@ tolerance("NMOS_GVT", "L", :absolute => 1.nm, :relative => 0.001) tolerance("NMOS_HVT", "W", :absolute => 1.nm, :relative => 0.001) tolerance("NMOS_HVT", "L", :absolute => 1.nm, :relative => 0.001) +# NangateOpenCellLibrary Digital gates input equivalence : +equivalent_pins("AND2_X1", "A1", "A2") +equivalent_pins("AND2_X2", "A1", "A2") +equivalent_pins("AND2_X4", "A1", "A2") +equivalent_pins("AND3_X1", "A1", "A2", "A3") +equivalent_pins("AND3_X2", "A1", "A2", "A3") +equivalent_pins("AND3_X4", "A1", "A2", "A3") +equivalent_pins("AND4_X1", "A1", "A2", "A3", "A4") +equivalent_pins("AND4_X2", "A1", "A2", "A3", "A4") +equivalent_pins("AND4_X4", "A1", "A2", "A3", "A4") +equivalent_pins("NAND2_X1", "A1", "A2") +equivalent_pins("NAND2_X2", "A1", "A2") +equivalent_pins("NAND2_X4", "A1", "A2") +equivalent_pins("NAND3_X1", "A1", "A2", "A3") +equivalent_pins("NAND3_X2", "A1", "A2", "A3") +equivalent_pins("NAND3_X4", "A1", "A2", "A3") +equivalent_pins("NAND4_X1", "A1", "A2", "A3", "A4") +equivalent_pins("NAND4_X2", "A1", "A2", "A3", "A4") +equivalent_pins("NAND4_X4", "A1", "A2", "A3", "A4") +equivalent_pins("OR2_X1", "A1", "A2") +equivalent_pins("OR2_X2", "A1", "A2") +equivalent_pins("OR2_X4", "A1", "A2") +equivalent_pins("OR3_X1", "A1", "A2", "A3") +equivalent_pins("OR3_X2", "A1", "A2", "A3") +equivalent_pins("OR3_X4", "A1", "A2", "A3") +equivalent_pins("OR4_X1", "A1", "A2", "A3", "A4") +equivalent_pins("OR4_X2", "A1", "A2", "A3", "A4") +equivalent_pins("OR4_X4", "A1", "A2", "A3", "A4") +equivalent_pins("NOR2_X1", "A1", "A2") +equivalent_pins("NOR2_X2", "A1", "A2") +equivalent_pins("NOR2_X4", "A1", "A2") +equivalent_pins("NOR3_X1", "A1", "A2", "A3") +equivalent_pins("NOR3_X2", "A1", "A2", "A3") +equivalent_pins("NOR3_X4", "A1", "A2", "A3") +equivalent_pins("NOR4_X1", "A1", "A2", "A3", "A4") +equivalent_pins("NOR4_X2", "A1", "A2", "A3", "A4") +equivalent_pins("NOR4_X4", "A1", "A2", "A3", "A4") +equivalent_pins("XOR2_X1", "A", "B") +equivalent_pins("XOR2_X2", "A", "B") +equivalent_pins("XNOR2_X1", "A", "B") +equivalent_pins("XNOR2_X2", "A", "B") + +equivalent_pins("AOI211_X1","A","B") +equivalent_pins("AOI211_X1","C1","C2") +equivalent_pins("AOI211_X2","A","B") +equivalent_pins("AOI211_X2","C1","C2") +equivalent_pins("AOI211_X4","A","B") +equivalent_pins("AOI211_X4","C1","C2") +equivalent_pins("AOI21_X1","B1","B2") +equivalent_pins("AOI21_X2","B1","B2") +equivalent_pins("AOI21_X4","B1","B2") +equivalent_pins("AOI221_X1","B1","B2") +equivalent_pins("AOI221_X1","C1","C2") +equivalent_pins("AOI221_X2","B1","B2") +equivalent_pins("AOI221_X2","C1","C2") +equivalent_pins("AOI221_X4","B1","B2") +equivalent_pins("AOI221_X4","C1","C2") +equivalent_pins("AOI222_X1","A1","A2") +equivalent_pins("AOI222_X1","B1","B2") +equivalent_pins("AOI222_X1","C1","C2") +equivalent_pins("AOI222_X2","A1","A2") +equivalent_pins("AOI222_X2","B1","B2") +equivalent_pins("AOI222_X2","C1","C2") +equivalent_pins("AOI222_X4","A1","A2") +equivalent_pins("AOI222_X4","B1","B2") +equivalent_pins("AOI222_X4","C1","C2") +equivalent_pins("AOI22_X1","A1","A2") +equivalent_pins("AOI22_X1","B1","B2") +equivalent_pins("AOI22_X2","A1","A2") +equivalent_pins("AOI22_X2","B1","B2") +equivalent_pins("AOI22_X4","A1","A2") +equivalent_pins("AOI22_X4","B1","B2") + +equivalent_pins("OAI211_X1","A","B") +equivalent_pins("OAI211_X1","C1","C2") +equivalent_pins("OAI211_X2","A","B") +equivalent_pins("OAI211_X2","C1","C2") +equivalent_pins("OAI211_X4","A","B") +equivalent_pins("OAI211_X4","C1","C2") +equivalent_pins("OAI21_X1","B1","B2") +equivalent_pins("OAI21_X2","B1","B2") +equivalent_pins("OAI21_X4","B1","B2") +equivalent_pins("OAI221_X1","B1","B2") +equivalent_pins("OAI221_X1","C1","C2") +equivalent_pins("OAI221_X2","B1","B2") +equivalent_pins("OAI221_X2","C1","C2") +equivalent_pins("OAI221_X4","B1","B2") +equivalent_pins("OAI221_X4","C1","C2") +equivalent_pins("OAI222_X1","A1","A2") +equivalent_pins("OAI222_X1","B1","B2") +equivalent_pins("OAI222_X1","C1","C2") +equivalent_pins("OAI222_X2","A1","A2") +equivalent_pins("OAI222_X2","B1","B2") +equivalent_pins("OAI222_X2","C1","C2") +equivalent_pins("OAI222_X4","A1","A2") +equivalent_pins("OAI222_X4","B1","B2") +equivalent_pins("OAI222_X4","C1","C2") +equivalent_pins("OAI22_X1","A1","A2") +equivalent_pins("OAI22_X1","B1","B2") +equivalent_pins("OAI22_X2","A1","A2") +equivalent_pins("OAI22_X2","B1","B2") +equivalent_pins("OAI22_X4","A1","A2") +equivalent_pins("OAI22_X4","B1","B2") +equivalent_pins("OAI33_X1","A1","A2","A3") +equivalent_pins("OAI33_X1","B1","B2","B3") + +equivalent_pins("HA_X1","A","B") + #max_res(1000000) #min_caps(1e-15) max_branch_complexity(65536) max_depth(16) -if ! compare +if ! compare #raise "ERROR : Netlists don't match" puts "ERROR : Netlists don't match" else