OpenRAM/compiler/verify/assura.py

218 lines
7.1 KiB
Python
Raw Permalink Normal View History

# See LICENSE for licensing information.
#
2024-01-03 23:32:44 +01:00
# Copyright (c) 2016-2024 Regents of the University of California and The Board
2019-06-14 17:43:41 +02:00
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
2017-11-15 21:07:10 +01:00
"""
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.
2017-11-15 21:07:10 +01:00
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
2022-11-27 22:01:20 +01:00
from openram import debug
from openram.verify.run_script import *
from openram import OPTS
2017-11-15 21:07:10 +01:00
# Keep track of statistics
num_drc_runs = 0
num_lvs_runs = 0
num_pex_runs = 0
2020-11-03 15:29:17 +01:00
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path):
2022-11-27 22:01:20 +01:00
from openram.tech import drc
2017-11-15 21:07:10 +01:00
drc_rules = drc["drc_rules"]
drc_runset = output_path + cell_name + ".rsf"
drc_log_file = "{0}{1}.log".format(OPTS.openram_temp, name)
2017-11-15 21:07:10 +01:00
# 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))
2017-11-15 21:07:10 +01:00
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()
2022-07-22 18:52:38 +02:00
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)
2017-11-15 21:07:10 +01:00
(outfile, errfile, resultsfile) = run_script(name, "drc")
2022-07-22 18:52:38 +02:00
2017-11-15 21:07:10 +01:00
# count and report errors
errors = 0
try:
f = open(OPTS.openram_temp + name +".err", "r")
2017-11-15 21:07:10 +01:00
except:
debug.error("Unable to retrieve DRC results file.", 1)
2017-11-15 21:07:10 +01:00
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)
2017-11-15 21:07:10 +01:00
if errors > 0:
debug.error("Errors: {}".format(errors))
2017-11-15 21:07:10 +01:00
return errors
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
2020-11-03 15:29:17 +01:00
2022-11-27 22:01:20 +01:00
from openram.tech import drc
2017-11-15 21:07:10 +01:00
lvs_rules = drc["lvs_rules"]
lvs_runset = output_path + name + ".rsf"
# The LVS compare rules must be defined in the tech file for Assura.
2017-11-15 21:07:10 +01:00
lvs_compare = drc["lvs_compare"]
# Define the must-connect names for disconnected LVS nets for Assura
2017-11-15 21:07:10 +01:00
lvs_bindings = drc["lvs_bindings"]
lvs_log_file = "{0}{1}.log".format(output_path, name)
2017-11-15 21:07:10 +01:00
# Needed when FET models are sub-circuits
if "lvs_subcircuits" in drc:
2017-11-15 21:07:10 +01:00
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))
2017-11-15 21:07:10 +01:00
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()
2022-07-22 18:52:38 +02:00
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)
2017-11-15 21:07:10 +01:00
(outfile, errfile, resultsfile) = run_script(name, "drc")
2022-07-22 18:52:38 +02:00
2017-11-15 21:07:10 +01:00
errors = 0
try:
f = open(OPTS.openram_temp + name + ".csm", "r")
2017-11-15 21:07:10 +01:00
except:
debug.error("Unable to retrieve LVS results file.", 1)
2017-11-15 21:07:10 +01:00
results = f.readlines()
f.close()
for line in results:
if re.search("errors", line):
errors = errors + 1
debug.info(1, line)
2017-11-15 21:07:10 +01:00
elif re.search("Schematic and Layout", line):
debug.info(1, line)
2017-11-15 21:07:10 +01:00
return errors
2019-02-24 19:49:35 +01:00
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
2020-11-03 15:29:17 +01:00
2022-07-22 18:52:38 +02:00
def print_drc_stats():
debug.info(1, "DRC runs: {0}".format(num_drc_runs))
2022-07-22 18:52:38 +02:00
def print_lvs_stats():
debug.info(1, "LVS runs: {0}".format(num_lvs_runs))
2022-07-22 18:52:38 +02:00
def print_pex_stats():
debug.info(1, "PEX runs: {0}".format(num_pex_runs))