mirror of https://github.com/VLSIDA/OpenRAM.git
218 lines
7.1 KiB
Python
218 lines
7.1 KiB
Python
# See LICENSE for licensing information.
|
|
#
|
|
# Copyright (c) 2016-2024 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 interface for Assura. It implements completely two
|
|
functions: run_drc and run_lvs, that perform these functions in batch
|
|
mode and will return true/false if the result passes. All of the setup
|
|
(the rules, temp dirs, etc.) should be contained in this file.
|
|
Replacing with another DRC/LVS tool involves rewriting this code to
|
|
work properly. Porting to a new technology in Assura means pointing
|
|
the code to the proper DRC and LVS rule files.
|
|
|
|
LVS Notes:
|
|
|
|
For some processes the FET models are sub-circuits. Meaning, the
|
|
first letter of their SPICE instantiation begins with 'X' not 'M'.
|
|
The former confuses Assura, however, so to get these sub-circuit models
|
|
to LVS properly, an empty sub-circuit must be inserted into the
|
|
LVS SPICE netlist. The sub-circuits are pointed to using the
|
|
drc["lvs_subcircuits"] variable, and additional options must be
|
|
inserted in the runset.
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
from openram import debug
|
|
from openram.verify.run_script import *
|
|
from openram import OPTS
|
|
|
|
# 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):
|
|
from openram.tech import drc
|
|
drc_rules = drc["drc_rules"]
|
|
drc_runset = output_path + cell_name + ".rsf"
|
|
drc_log_file = "{0}{1}.log".format(OPTS.openram_temp, name)
|
|
|
|
# write the runset file
|
|
# the runset file contains all the options to run Assura
|
|
# different processes may require different options
|
|
f = open(drc_runset, "w")
|
|
f.write("avParameters(\n")
|
|
f.write(" ?flagDotShapes t\n")
|
|
f.write(" ?flagMalformed t\n")
|
|
f.write(" ?flagPathNonManhattanSeg all\n")
|
|
f.write(" ?flagPathShortSegments endOnlySmart\n")
|
|
f.write(" ?maintain45 nil\n")
|
|
f.write(" ?combineNearCollinearEdges nil\n")
|
|
f.write(")\n")
|
|
f.write("\n")
|
|
f.write("avParameters(\n")
|
|
f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name))
|
|
f.write(" ?cellName \"{}\"\n".format(cell_name))
|
|
f.write(" ?workingDirectory \"{}\"\n".format(output_path))
|
|
f.write(" ?rulesFile \"{}\"\n".format(drc_rules))
|
|
f.write(" ?set ( \"GridCheck\" )\n")
|
|
f.write(" ?avrpt t\n")
|
|
f.write(")\n")
|
|
f.close()
|
|
|
|
# run drc
|
|
run_file = output_path + "/run_drc.sh"
|
|
f = open(run_file, "w")
|
|
f.write("#!/bin/sh\n")
|
|
f.write("assura {0} 2> {1} 1> {2}\n".format(drc_runset, drc_log_file, drc_log_file))
|
|
f.close()
|
|
|
|
|
|
def run_drc(name, gds_name, final_verification=False):
|
|
"""Run DRC check on a given top-level name which is
|
|
implemented in gds_name."""
|
|
|
|
global num_drc_runs
|
|
num_drc_runs += 1
|
|
|
|
write_drc_script(name, gds_name, True, final_verification, OPTS.openram_temp)
|
|
|
|
(outfile, errfile, resultsfile) = run_script(name, "drc")
|
|
|
|
# count and report errors
|
|
errors = 0
|
|
try:
|
|
f = open(OPTS.openram_temp + name +".err", "r")
|
|
except:
|
|
debug.error("Unable to retrieve DRC results file.", 1)
|
|
results = f.readlines()
|
|
f.close()
|
|
for line in results:
|
|
if re.match("Rule No.", line):
|
|
if re.search("# INFO:", line) == None:
|
|
errors = errors + 1
|
|
debug.info(1, line)
|
|
|
|
if errors > 0:
|
|
debug.error("Errors: {}".format(errors))
|
|
|
|
return errors
|
|
|
|
|
|
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
|
|
|
|
from openram.tech import drc
|
|
lvs_rules = drc["lvs_rules"]
|
|
lvs_runset = output_path + name + ".rsf"
|
|
# The LVS compare rules must be defined in the tech file for Assura.
|
|
lvs_compare = drc["lvs_compare"]
|
|
# Define the must-connect names for disconnected LVS nets for Assura
|
|
lvs_bindings = drc["lvs_bindings"]
|
|
lvs_log_file = "{0}{1}.log".format(output_path, name)
|
|
# Needed when FET models are sub-circuits
|
|
if "lvs_subcircuits" in drc:
|
|
lvs_sub_file = drc["lvs_subcircuits"]
|
|
else:
|
|
lvs_sub_file = ""
|
|
|
|
# write the runset file
|
|
# the runset file contains all the options to run Assura
|
|
# different processes may require different options
|
|
f = open(lvs_runset, "w")
|
|
f.write("avParameters(\n")
|
|
f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name))
|
|
f.write(" ?cellName \"{}\"\n".format(name))
|
|
f.write(" ?workingDirectory \"{}\"\n".format(output_path))
|
|
f.write(" ?rulesFile \"{}\"\n".format(lvs_rules))
|
|
f.write(" ?autoGrid nil\n")
|
|
f.write(" ?avrpt t\n")
|
|
# The below options vary greatly between processes and cell-types
|
|
f.write(" ?set (\"NO_SUBC_IN_GRLOGIC\")\n")
|
|
f.write(")\n")
|
|
f.write("\n")
|
|
c = open(lvs_compare, "r")
|
|
lines = c.read()
|
|
c.close
|
|
f.write(lines)
|
|
f.write("\n")
|
|
f.write("avCompareRules(\n")
|
|
f.write(" schematic(\n")
|
|
# Needed when FET models are sub-circuits
|
|
if os.path.isfile(lvs_sub_file):
|
|
f.write(" genericDevice(emptySubckt)\n")
|
|
f.write(" netlist( spice \"{}\" )\n".format(lvs_sub_file))
|
|
f.write(" netlist( spice \"{}\" )\n".format(sp_name))
|
|
f.write(" )\n")
|
|
f.write(" layout(\n")
|
|
# Separate gnd shapes are sometimes not connected by metal, so this connects by name
|
|
# The use of this option is not recommended for final DRC
|
|
f.write(" joinNets( root \"gnd\" \"gnd*\" ) \n")
|
|
f.write(" )\n")
|
|
f.write(" bindingFile( \"{}\" )\n".format(lvs_bindings))
|
|
f.write(")\n")
|
|
f.write("\n")
|
|
f.write("avLVS()\n")
|
|
f.close()
|
|
|
|
# run drc
|
|
run_file = output_path + "/run_vls.sh"
|
|
f = open(run_file, "w")
|
|
f.write("#!/bin/sh\n")
|
|
f.write("assura {0} 2> {1} 1> {2}\n".format(lvs_runset, lvs_log_file, lvs_log_file))
|
|
f.close()
|
|
|
|
|
|
def run_lvs(name, gds_name, sp_name, final_verification=False):
|
|
"""Run LVS check on a given top-level name which is
|
|
implemented in gds_name and sp_name. """
|
|
|
|
global num_lvs_runs
|
|
num_lvs_runs += 1
|
|
|
|
write_lvs_script(name, gds_name, sp_name, final_verification, OPTS.openram_temp)
|
|
|
|
(outfile, errfile, resultsfile) = run_script(name, "drc")
|
|
|
|
errors = 0
|
|
try:
|
|
f = open(OPTS.openram_temp + name + ".csm", "r")
|
|
except:
|
|
debug.error("Unable to retrieve LVS results file.", 1)
|
|
results = f.readlines()
|
|
f.close()
|
|
for line in results:
|
|
if re.search("errors", line):
|
|
errors = errors + 1
|
|
debug.info(1, line)
|
|
elif re.search("Schematic and Layout", line):
|
|
debug.info(1, line)
|
|
|
|
return errors
|
|
|
|
|
|
def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
|
|
"""Run pex on a given top-level name which is
|
|
implemented in gds_name and sp_name. """
|
|
debug.error("PEX extraction not implemented with Assura.", -1)
|
|
|
|
global num_pex_runs
|
|
num_pex_runs += 1
|
|
|
|
|
|
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))
|