Merge branch 'dev' into s8_single_port

This commit is contained in:
jcirimel 2020-11-10 03:15:44 -08:00
commit 5e2c199d38
69 changed files with 16139 additions and 11486 deletions

View File

@ -90,7 +90,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
"LVS failed for {0} with {1} errors(s)".format(self.cell_name, "LVS failed for {0} with {1} errors(s)".format(self.cell_name,
self.lvs_errors)) self.lvs_errors))
if OPTS.purge_temp: if not OPTS.keep_temp:
os.remove(tempspice) os.remove(tempspice)
os.remove(tempgds) os.remove(tempgds)
@ -112,7 +112,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
"DRC failed for {0} with {1} error(s)".format(self.cell_name, "DRC failed for {0} with {1} error(s)".format(self.cell_name,
num_errors)) num_errors))
if OPTS.purge_temp: if not OPTS.keep_temp:
os.remove(tempgds) os.remove(tempgds)
def LVS(self, final_verification=False): def LVS(self, final_verification=False):
@ -134,7 +134,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
debug.check(num_errors == 0, debug.check(num_errors == 0,
"LVS failed for {0} with {1} error(s)".format(self.cell_name, "LVS failed for {0} with {1} error(s)".format(self.cell_name,
num_errors)) num_errors))
if OPTS.purge_temp: if not OPTS.keep_temp:
os.remove(tempspice) os.remove(tempspice)
os.remove(tempgds) os.remove(tempgds)

View File

@ -5,14 +5,9 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import gdsMill
import tech
import globals
import math
import debug import debug
import datetime from tech import layer_names
from collections import defaultdict
import pdb
class lef: class lef:
""" """
@ -26,7 +21,7 @@ class lef:
# These are the layers of the obstructions # These are the layers of the obstructions
self.lef_layers = layers self.lef_layers = layers
# Round to ensure float values are divisible by 0.0025 (the manufacturing grid) # Round to ensure float values are divisible by 0.0025 (the manufacturing grid)
self.round_grid = 4; self.round_grid = 4
def lef_write(self, lef_name): def lef_write(self, lef_name):
"""Write the entire lef of the object to the file.""" """Write the entire lef of the object to the file."""
@ -65,7 +60,6 @@ class lef:
self.indent = self.indent[:-3] self.indent = self.indent[:-3]
self.lef.write("END LIBRARY\n") self.lef.write("END LIBRARY\n")
def lef_write_pin(self, name): def lef_write_pin(self, name):
pin_dir = self.get_pin_dir(name) pin_dir = self.get_pin_dir(name)
pin_type = self.get_pin_type(name) pin_type = self.get_pin_type(name)
@ -84,7 +78,7 @@ class lef:
# We could sort these together to minimize different layer sections, but meh. # We could sort these together to minimize different layer sections, but meh.
pin_list = self.get_pins(name) pin_list = self.get_pins(name)
for pin in pin_list: for pin in pin_list:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer)) self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[pin.layer]))
self.lef_write_shape(pin.rect) self.lef_write_shape(pin.rect)
# End the PORT # End the PORT
@ -99,13 +93,10 @@ class lef:
""" Write all the obstructions on each layer """ """ Write all the obstructions on each layer """
self.lef.write("{0}OBS\n".format(self.indent)) self.lef.write("{0}OBS\n".format(self.indent))
for layer in self.lef_layers: for layer in self.lef_layers:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer)) self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[layer]))
self.indent += " " self.indent += " "
# pdb.set_trace()
blockages = self.get_blockages(layer, True) blockages = self.get_blockages(layer, True)
for b in blockages: for b in blockages:
# if len(b) > 2:
# print(b)
self.lef_write_shape(b) self.lef_write_shape(b)
self.indent = self.indent[:-3] self.indent = self.indent[:-3]
self.lef.write("{0}END\n".format(self.indent)) self.lef.write("{0}END\n".format(self.indent))
@ -116,13 +107,19 @@ class lef:
self.lef.write("{0}RECT ".format(self.indent)) self.lef.write("{0}RECT ".format(self.indent))
for item in rect: for item in rect:
# print(rect) # print(rect)
self.lef.write(" {0} {1}".format(round(item[0],self.round_grid), round(item[1],self.round_grid))) self.lef.write(" {0} {1}".format(round(item[0],
self.round_grid),
round(item[1],
self.round_grid)))
self.lef.write(" ;\n") self.lef.write(" ;\n")
else: else:
""" Write a LEF polygon """ """ Write a LEF polygon """
self.lef.write("{0}POLYGON ".format(self.indent)) self.lef.write("{0}POLYGON ".format(self.indent))
for item in rect: for item in rect:
self.lef.write(" {0} {1}".format(round(item[0],self.round_grid), round(item[1],self.round_grid))) self.lef.write(" {0} {1}".format(round(item[0],
self.round_grid),
round(item[1],
self.round_grid)))
# for i in range(0,len(rect)): # for i in range(0,len(rect)):
# self.lef.write(" {0} {1}".format(round(rect[i][0],self.round_grid), round(rect[i][1],self.round_grid))) # self.lef.write(" {0} {1}".format(round(rect[i][0],self.round_grid), round(rect[i][1],self.round_grid)))
self.lef.write(" ;\n") self.lef.write(" ;\n")

View File

@ -306,7 +306,8 @@ class delay(simulation):
self.create_test_cycles() self.create_test_cycles()
# creates and opens stimulus file for writing # creates and opens stimulus file for writing
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.delay_stim_sp = "delay_stim.sp"
temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.delay_stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.sf.write("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(self.period, self.sf.write("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(self.period,
self.load, self.load,
@ -350,7 +351,8 @@ class delay(simulation):
self.check_arguments() self.check_arguments()
# creates and opens stimulus file for writing # creates and opens stimulus file for writing
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.power_stim_sp = "power_stim.sp"
temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.power_stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.sf.write("* Power stimulus for period of {0}n\n\n".format(self.period)) self.sf.write("* Power stimulus for period of {0}n\n\n".format(self.period))
self.stim = stimuli(self.sf, self.corner) self.stim = stimuli(self.sf, self.corner)
@ -616,7 +618,7 @@ class delay(simulation):
self.write_delay_stimulus() self.write_delay_stimulus()
self.stim.run_sim() self.stim.run_sim(self.delay_stim_sp)
return self.check_measurements() return self.check_measurements()
@ -772,7 +774,7 @@ class delay(simulation):
debug.info(1, "Performing leakage power simulations.") debug.info(1, "Performing leakage power simulations.")
self.write_power_stimulus(trim=False) self.write_power_stimulus(trim=False)
self.stim.run_sim() self.stim.run_sim(self.power_stim_sp)
leakage_power=parse_spice_list("timing", "leakage_power") leakage_power=parse_spice_list("timing", "leakage_power")
debug.check(leakage_power!="Failed", "Could not measure leakage power.") debug.check(leakage_power!="Failed", "Could not measure leakage power.")
debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power * 1e3)) debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power * 1e3))
@ -780,7 +782,7 @@ class delay(simulation):
# sys.exit(1) # sys.exit(1)
self.write_power_stimulus(trim=True) self.write_power_stimulus(trim=True)
self.stim.run_sim() self.stim.run_sim(self.power_stim_sp)
trim_leakage_power=parse_spice_list("timing", "leakage_power") trim_leakage_power=parse_spice_list("timing", "leakage_power")
debug.check(trim_leakage_power!="Failed", "Could not measure leakage power.") debug.check(trim_leakage_power!="Failed", "Could not measure leakage power.")
debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power * 1e3)) debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power * 1e3))

View File

@ -21,13 +21,24 @@ class functional(simulation):
for successful SRAM operation. for successful SRAM operation.
""" """
def __init__(self, sram, spfile, corner, cycles=15): def __init__(self, sram, spfile, corner=None, cycles=15, period=None, output_path=None):
super().__init__(sram, spfile, corner) super().__init__(sram, spfile, corner)
# Seed the characterizer with a constant seed for unit tests # Seed the characterizer with a constant seed for unit tests
if OPTS.is_unit_test: if OPTS.is_unit_test:
random.seed(12345) random.seed(12345)
if not corner:
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
if period:
self.period = period
if not output_path:
self.output_path = OPTS.openram_temp
else:
self.output_path = output_path
if self.write_size: if self.write_size:
self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else: else:
@ -58,15 +69,14 @@ class functional(simulation):
self.read_check = [] self.read_check = []
self.read_results = [] self.read_results = []
def run(self, feasible_period=None):
if feasible_period: # period defaults to tech.py feasible period otherwise.
self.period = feasible_period
# Generate a random sequence of reads and writes # Generate a random sequence of reads and writes
self.create_random_memory_sequence() self.create_random_memory_sequence()
# Run SPICE simulation # Write SPICE simulation
self.write_functional_stimulus() self.write_functional_stimulus()
self.stim.run_sim()
def run(self):
self.stim.run_sim(self.stim_sp)
# read dout values from SPICE simulation. If the values do not fall within the noise margins, return the error. # read dout values from SPICE simulation. If the values do not fall within the noise margins, return the error.
(success, error) = self.read_stim_results() (success, error) = self.read_stim_results()
@ -330,7 +340,8 @@ class functional(simulation):
def write_functional_stimulus(self): def write_functional_stimulus(self):
""" Writes SPICE stimulus. """ """ Writes SPICE stimulus. """
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.stim_sp = "functional_stim.sp"
temp_stim = "{0}/{1}".format(self.output_path, self.stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period)) self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period))
self.stim = stimuli(self.sf, self.corner) self.stim = stimuli(self.sf, self.corner)

View File

@ -31,19 +31,18 @@ class setup_hold():
self.set_corner(corner) self.set_corner(corner)
def set_corner(self, corner): def set_corner(self, corner):
""" Set the corner values """ """ Set the corner values """
self.corner = corner self.corner = corner
(self.process, self.vdd_voltage, self.temperature) = corner (self.process, self.vdd_voltage, self.temperature) = corner
self.gnd_voltage = 0 self.gnd_voltage = 0
def write_stimulus(self, mode, target_time, correct_value): def write_stimulus(self, mode, target_time, correct_value):
"""Creates a stimulus file for SRAM setup/hold time calculation""" """Creates a stimulus file for SRAM setup/hold time calculation"""
# creates and opens the stimulus file for writing # creates and opens the stimulus file for writing
temp_stim = OPTS.openram_temp + "stim.sp" self.stim_sp = "sh_stim.sp"
temp_stim = OPTS.openram_temp + self.stim_sp
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.stim = stimuli(self.sf, self.corner) self.stim = stimuli(self.sf, self.corner)
@ -63,7 +62,6 @@ class setup_hold():
self.write_measures(mode=mode, self.write_measures(mode=mode,
correct_value=correct_value) correct_value=correct_value)
self.stim.write_control(4 * self.period) self.stim.write_control(4 * self.period)
self.sf.close() self.sf.close()
@ -79,7 +77,6 @@ class setup_hold():
self.sf.write("\n* Global Power Supplies\n") self.sf.write("\n* Global Power Supplies\n")
self.stim.write_supply() self.stim.write_supply()
def write_data(self, mode, target_time, correct_value): def write_data(self, mode, target_time, correct_value):
"""Create the data signals for setup/hold analysis. First period is to """Create the data signals for setup/hold analysis. First period is to
initialize it to the opposite polarity. Second period is used for initialize it to the opposite polarity. Second period is used for
@ -119,8 +116,6 @@ class setup_hold():
slew=self.constrained_input_slew, slew=self.constrained_input_slew,
setup=0) setup=0)
def write_measures(self, mode, correct_value): def write_measures(self, mode, correct_value):
""" Measure statements for setup/hold with right phases. """ """ Measure statements for setup/hold with right phases. """
@ -139,7 +134,6 @@ class setup_hold():
else: else:
din_rise_or_fall = "RISE" din_rise_or_fall = "RISE"
self.sf.write("\n* Measure statements for pass/fail verification\n") self.sf.write("\n* Measure statements for pass/fail verification\n")
trig_name = "clk" trig_name = "clk"
targ_name = "dout" targ_name = "dout"
@ -168,9 +162,6 @@ class setup_hold():
trig_td=1.2 * self.period, trig_td=1.2 * self.period,
targ_td=1.2 * self.period) targ_td=1.2 * self.period)
def bidir_search(self, correct_value, mode): def bidir_search(self, correct_value, mode):
""" This will perform a bidirectional search for either setup or hold times. """ This will perform a bidirectional search for either setup or hold times.
It starts with the feasible priod and looks a half period beyond or before it It starts with the feasible priod and looks a half period beyond or before it
@ -192,13 +183,16 @@ class setup_hold():
self.write_stimulus(mode=mode, self.write_stimulus(mode=mode,
target_time=feasible_bound, target_time=feasible_bound,
correct_value=correct_value) correct_value=correct_value)
self.stim.run_sim() self.stim.run_sim(self.stim_sp)
ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time")) setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time"))
debug.info(2,"*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, correct_value,ideal_clk_to_q,setuphold_time)) debug.info(2,"*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, correct_value,ideal_clk_to_q,setuphold_time))
if type(ideal_clk_to_q)!=float or type(setuphold_time)!=float: if type(ideal_clk_to_q)!=float or type(setuphold_time)!=float:
debug.error("Initial hold time fails for data value feasible bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound,ideal_clk_to_q,setuphold_time),2) debug.error("Initial hold time fails for data value feasible bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound,
ideal_clk_to_q,
setuphold_time),
2)
if mode == "SETUP": # SETUP is clk-din, not din-clk if mode == "SETUP": # SETUP is clk-din, not din-clk
setuphold_time *= -1e9 setuphold_time *= -1e9
@ -224,8 +218,7 @@ class setup_hold():
infeasible_bound, infeasible_bound,
feasible_bound)) feasible_bound))
self.stim.run_sim(self.stim_sp)
self.stim.run_sim()
clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time")) setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time"))
if type(clk_to_q) == float and (clk_to_q < 1.1 * ideal_clk_to_q) and type(setuphold_time)==float: if type(clk_to_q) == float and (clk_to_q < 1.1 * ideal_clk_to_q) and type(setuphold_time)==float:
@ -241,7 +234,6 @@ class setup_hold():
debug.info(2, "FAIL Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q, setuphold_time)) debug.info(2, "FAIL Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q, setuphold_time))
infeasible_bound = target_time infeasible_bound = target_time
#raw_input("Press Enter to continue...")
if relative_compare(feasible_bound, infeasible_bound, error_tolerance=0.001): if relative_compare(feasible_bound, infeasible_bound, error_tolerance=0.001):
debug.info(3, "CONVERGE {0} vs {1}".format(feasible_bound, infeasible_bound)) debug.info(3, "CONVERGE {0} vs {1}".format(feasible_bound, infeasible_bound))
break break
@ -250,13 +242,11 @@ class setup_hold():
debug.info(2, "Converged on {0} time {1}.".format(mode, passing_setuphold_time)) debug.info(2, "Converged on {0} time {1}.".format(mode, passing_setuphold_time))
return passing_setuphold_time return passing_setuphold_time
def setup_LH_time(self): def setup_LH_time(self):
"""Calculates the setup time for low-to-high transition for a DFF """Calculates the setup time for low-to-high transition for a DFF
""" """
return self.bidir_search(1, "SETUP") return self.bidir_search(1, "SETUP")
def setup_HL_time(self): def setup_HL_time(self):
"""Calculates the setup time for high-to-low transition for a DFF """Calculates the setup time for high-to-low transition for a DFF
""" """
@ -272,7 +262,6 @@ class setup_hold():
""" """
return self.bidir_search(0, "HOLD") return self.bidir_search(0, "HOLD")
def analyze(self, related_slews, constrained_slews): def analyze(self, related_slews, constrained_slews):
"""main function to calculate both setup and hold time for the """main function to calculate both setup and hold time for the
DFF and returns a dictionary that contains 4 lists for both DFF and returns a dictionary that contains 4 lists for both
@ -301,10 +290,10 @@ class setup_hold():
# } # }
# return times # return times
for self.related_input_slew in related_slews: for self.related_input_slew in related_slews:
for self.constrained_input_slew in constrained_slews: for self.constrained_input_slew in constrained_slews:
debug.info(1, "Clock slew: {0} Data slew: {1}".format(self.related_input_slew,self.constrained_input_slew)) debug.info(1, "Clock slew: {0} Data slew: {1}".format(self.related_input_slew,
self.constrained_input_slew))
LH_setup_time = self.setup_LH_time() LH_setup_time = self.setup_LH_time()
debug.info(1, " Setup Time for low_to_high transition: {0}".format(LH_setup_time)) debug.info(1, " Setup Time for low_to_high transition: {0}".format(LH_setup_time))
HL_setup_time = self.setup_HL_time() HL_setup_time = self.setup_HL_time()

View File

@ -260,7 +260,7 @@ class stimuli():
# create plots for all signals # create plots for all signals
self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n") self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n")
if OPTS.debug_level>0: if OPTS.verbose_level>0:
if OPTS.spice_name in ["hspice", "xa"]: if OPTS.spice_name in ["hspice", "xa"]:
self.sf.write(".probe V(*)\n") self.sf.write(".probe V(*)\n")
else: else:
@ -285,10 +285,7 @@ class stimuli():
includes = self.device_models + [circuit] includes = self.device_models + [circuit]
for item in list(includes): for item in list(includes):
if os.path.isfile(item):
self.sf.write(".include \"{0}\"\n".format(item)) self.sf.write(".include \"{0}\"\n".format(item))
else:
debug.error("Could not find spice model: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item))
def write_supply(self): def write_supply(self):
""" Writes supply voltage statements """ """ Writes supply voltage statements """
@ -299,9 +296,9 @@ class stimuli():
self.sf.write("\n*Nodes gnd and 0 are the same global ground node in ngspice/hspice/xa. Otherwise, this source may be needed.\n") self.sf.write("\n*Nodes gnd and 0 are the same global ground node in ngspice/hspice/xa. Otherwise, this source may be needed.\n")
self.sf.write("*V{0} {0} {1} {2}\n".format(self.gnd_name, gnd_node_name, 0.0)) self.sf.write("*V{0} {0} {1} {2}\n".format(self.gnd_name, gnd_node_name, 0.0))
def run_sim(self): def run_sim(self, name):
""" Run hspice in batch mode and output rawfile to parse. """ """ Run hspice in batch mode and output rawfile to parse. """
temp_stim = "{0}stim.sp".format(OPTS.openram_temp) temp_stim = "{0}{1}".format(OPTS.openram_temp, name)
import datetime import datetime
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
debug.check(OPTS.spice_exe != "", "No spice simulator has been found.") debug.check(OPTS.spice_exe != "", "No spice simulator has been found.")

View File

@ -9,6 +9,7 @@ import os
import inspect import inspect
import globals import globals
import sys import sys
import pdb
# the debug levels: # the debug levels:
# 0 = minimum output (default) # 0 = minimum output (default)
@ -26,6 +27,9 @@ def check(check, str):
log("ERROR: file {0}: line {1}: {2}\n".format( log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str)) os.path.basename(filename), line_number, str))
if globals.OPTS.debug:
pdb.set_trace()
assert 0 assert 0
@ -37,6 +41,9 @@ def error(str, return_value=0):
log("ERROR: file {0}: line {1}: {2}\n".format( log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str)) os.path.basename(filename), line_number, str))
if globals.OPTS.debug:
pdb.set_trace()
assert return_value == 0 assert return_value == 0
@ -90,7 +97,7 @@ log.create_file = True
def info(lev, str): def info(lev, str):
from globals import OPTS from globals import OPTS
if (OPTS.debug_level >= lev): if (OPTS.verbose_level >= lev):
frm = inspect.stack()[1] frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0]) mod = inspect.getmodule(frm[0])
# classname = frm.f_globals['__name__'] # classname = frm.f_globals['__name__']

View File

@ -63,7 +63,7 @@ def parse_args():
optparse.make_option("-v", optparse.make_option("-v",
"--verbose", "--verbose",
action="count", action="count",
dest="debug_level", dest="verbose_level",
help="Increase the verbosity level"), help="Increase the verbosity level"),
optparse.make_option("-t", optparse.make_option("-t",
"--tech", "--tech",
@ -83,11 +83,16 @@ def parse_args():
action="store_false", action="store_false",
dest="analytical_delay", dest="analytical_delay",
help="Perform characterization to calculate delays (default is analytical models)"), help="Perform characterization to calculate delays (default is analytical models)"),
optparse.make_option("-k",
"--keeptemp",
action="store_true",
dest="keep_temp",
help="Keep the contents of the temp directory after a successful run"),
optparse.make_option("-d", optparse.make_option("-d",
"--dontpurge", "--debug",
action="store_false", action="store_true",
dest="purge_temp", dest="debug",
help="Don't purge the contents of the temp directory after a successful run") help="Run in debug mode to drop to pdb on failure")
# -h --help is implicit. # -h --help is implicit.
} }
@ -152,7 +157,7 @@ def check_versions():
try: try:
import coverage import coverage
OPTS.coverage = 1 OPTS.coverage = 1
except: except ModuleNotFoundError:
OPTS.coverage = 0 OPTS.coverage = 0
@ -366,7 +371,7 @@ def cleanup_paths():
We should clean up the temp directory after execution. We should clean up the temp directory after execution.
""" """
global OPTS global OPTS
if not OPTS.purge_temp: if OPTS.keep_temp:
debug.info(0, debug.info(0,
"Preserving temp directory: {}".format(OPTS.openram_temp)) "Preserving temp directory: {}".format(OPTS.openram_temp))
return return
@ -464,7 +469,7 @@ def set_default_corner():
if OPTS.nominal_corner_only: if OPTS.nominal_corner_only:
OPTS.process_corners = ["TT"] OPTS.process_corners = ["TT"]
else: else:
OPTS.process_corners = tech.spice["fet_models"].keys() OPTS.process_corners = list(tech.spice["fet_models"].keys())
if (OPTS.supply_voltages == ""): if (OPTS.supply_voltages == ""):
if OPTS.nominal_corner_only: if OPTS.nominal_corner_only:
@ -534,7 +539,7 @@ def print_time(name, now_time, last_time=None, indentation=2):
global OPTS global OPTS
# Don't print during testing # Don't print during testing
if not OPTS.is_unit_test or OPTS.debug_level > 0: if not OPTS.is_unit_test or OPTS.verbose_level > 0:
if last_time: if last_time:
time = str(round((now_time - last_time).total_seconds(), 1)) + " seconds" time = str(round((now_time - last_time).total_seconds(), 1)) + " seconds"
else: else:

View File

@ -52,7 +52,7 @@ class bitcell_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.cell) self.add_mod(self.cell)
def create_instances(self): def create_instances(self):

View File

@ -9,6 +9,7 @@ import debug
import design import design
from tech import cell_properties from tech import cell_properties
from sram_factory import factory from sram_factory import factory
from globals import OPTS
class bitcell_base_array(design.design): class bitcell_base_array(design.design):
@ -24,7 +25,7 @@ class bitcell_base_array(design.design):
self.column_offset = column_offset self.column_offset = column_offset
# Bitcell for port names only # Bitcell for port names only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.wordline_names = [[] for port in self.all_ports] self.wordline_names = [[] for port in self.all_ports]
self.all_wordline_names = [] self.all_wordline_names = []

View File

@ -51,7 +51,7 @@ class col_cap_array(bitcell_base_array):
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell)) self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """

View File

@ -44,8 +44,8 @@ class dummy_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
def create_instances(self): def create_instances(self):

View File

@ -27,7 +27,7 @@ class hierarchical_decoder(design.design):
self.pre3x8_inst = [] self.pre3x8_inst = []
self.pre4x16_inst = [] self.pre4x16_inst = []
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
self.cell_height = b.height self.cell_height = b.height
self.num_outputs = num_outputs self.num_outputs = num_outputs

View File

@ -21,7 +21,7 @@ class hierarchical_predecode(design.design):
def __init__(self, name, input_number, height=None): def __init__(self, name, input_number, height=None):
self.number_of_inputs = input_number self.number_of_inputs = input_number
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
if not height: if not height:
self.cell_height = b.height self.cell_height = b.height

View File

@ -64,7 +64,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
# This is just used for names # This is just used for names
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.bitcell_array = factory.create(module_type="replica_bitcell_array", self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.cols, cols=self.cols,

View File

@ -46,7 +46,7 @@ class bitcell_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.cell) self.add_mod(self.cell)
def create_instances(self): def create_instances(self):

View File

@ -155,7 +155,7 @@ class port_address(design.design):
# The polarity must be switched if we have a hierarchical wordline # The polarity must be switched if we have a hierarchical wordline
# to compensate for the local array inverters # to compensate for the local array inverters
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
if local_array_size > 0: if local_array_size > 0:
self.rbl_driver = factory.create(module_type="inv_dec", self.rbl_driver = factory.create(module_type="inv_dec",

View File

@ -33,7 +33,7 @@ class port_data(design.design):
self.num_spare_cols = 0 self.num_spare_cols = 0
if not bit_offsets: if not bit_offsets:
bitcell = factory.create(module_type="bitcell") bitcell = factory.create(module_type=OPTS.bitcell)
self.bit_offsets = [] self.bit_offsets = []
for i in range(self.num_cols + self.num_spare_cols): for i in range(self.num_cols + self.num_spare_cols):
self.bit_offsets.append(i * bitcell.width) self.bit_offsets.append(i * bitcell.width)
@ -191,7 +191,7 @@ class port_data(design.design):
# and mirroring happens correctly # and mirroring happens correctly
# Used for names/dimensions only # Used for names/dimensions only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
if self.port == 0: if self.port == 0:
# Append an offset on the left # Append an offset on the left
@ -270,7 +270,7 @@ class port_data(design.design):
# create arrays of bitline and bitline_bar names for read, # create arrays of bitline and bitline_bar names for read,
# write, or all ports # write, or all ports
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
self.bl_names = self.bitcell.get_all_bl_names() self.bl_names = self.bitcell.get_all_bl_names()
self.br_names = self.bitcell.get_all_br_names() self.br_names = self.bitcell.get_all_br_names()
self.wl_names = self.bitcell.get_all_wl_names() self.wl_names = self.bitcell.get_all_wl_names()

View File

@ -281,7 +281,7 @@ class replica_bitcell_array(bitcell_base_array):
self.supplies = ["vdd", "gnd"] self.supplies = ["vdd", "gnd"]
# Used for names/dimensions only # Used for names/dimensions only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
# Main array # Main array
self.bitcell_array_inst=self.add_inst(name="bitcell_array", self.bitcell_array_inst=self.add_inst(name="bitcell_array",

View File

@ -88,7 +88,7 @@ class replica_column(bitcell_base_array):
self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell) self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell)
self.add_mod(self.edge_cell) self.add_mod(self.edge_cell)
# Used for pin names only # Used for pin names only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self): def create_instances(self):
self.cell_inst = {} self.cell_inst = {}

View File

@ -43,7 +43,7 @@ class row_cap_array(bitcell_base_array):
self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell)) self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """

View File

@ -97,7 +97,7 @@ class sense_amp_array(design.design):
# This is just used for measurements, # This is just used for measurements,
# so don't add the module # so don't add the module
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
def create_sense_amp_array(self): def create_sense_amp_array(self):
self.local_insts = [] self.local_insts = []

View File

@ -59,7 +59,7 @@ class wordline_buffer_array(design.design):
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
self.wl_driver = factory.create(module_type="inv_dec", self.wl_driver = factory.create(module_type="inv_dec",
size=self.cols, size=self.cols,

View File

@ -99,7 +99,7 @@ class write_driver_array(design.design):
# This is just used for measurements, # This is just used for measurements,
# so don't add the module # so don't add the module
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
def create_write_array(self): def create_write_array(self):
self.driver_insts = [] self.driver_insts = []

View File

@ -81,7 +81,7 @@ class write_mask_and_array(design.design):
# This ensures the write mask AND array will be directly under the corresponding write driver enable wire. # This ensures the write mask AND array will be directly under the corresponding write driver enable wire.
# This is just used for measurements, so don't add the module # This is just used for measurements, so don't add the module
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
self.driver = factory.create(module_type="write_driver") self.driver = factory.create(module_type="write_driver")
if self.bitcell.width > self.driver.width: if self.bitcell.width > self.driver.width:
self.driver_spacing = self.bitcell.width self.driver_spacing = self.bitcell.width

View File

@ -80,7 +80,10 @@ class options(optparse.Values):
os.getpid()) os.getpid())
# This is the verbosity level to control debug information. 0 is none, 1 # This is the verbosity level to control debug information. 0 is none, 1
# is minimal, etc. # is minimal, etc.
debug_level = 0 verbose_level = 0
# Drop to pdb on failure?
debug = False
################### ###################
# Run-time vs accuracy options. # Run-time vs accuracy options.
@ -141,7 +144,8 @@ class options(optparse.Values):
# Route the input/output pins to the perimeter # Route the input/output pins to the perimeter
perimeter_pins = False perimeter_pins = False
purge_temp = True keep_temp = False
# These are the default modules that can be over-riden # These are the default modules that can be over-riden
bitcell_suffix = "" bitcell_suffix = ""

View File

@ -11,6 +11,7 @@ from tech import drc, layer
from vector import vector from vector import vector
from sram_factory import factory from sram_factory import factory
from tech import cell_properties as cell_props from tech import cell_properties as cell_props
from globals import OPTS
class column_mux(pgate.pgate): class column_mux(pgate.pgate):
@ -64,7 +65,7 @@ class column_mux(pgate.pgate):
self.add_pn_wells() self.add_pn_wells()
def add_ptx(self): def add_ptx(self):
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
# Adds nmos_lower,nmos_upper to the module # Adds nmos_lower,nmos_upper to the module
self.ptx_width = self.tx_size * drc("minwidth_tx") self.ptx_width = self.tx_size * drc("minwidth_tx")

View File

@ -27,7 +27,7 @@ class pinv_dec(pinv.pinv):
"creating pinv_dec structure {0} with size of {1}".format(name, "creating pinv_dec structure {0} with size of {1}".format(name,
size)) size))
if not height: if not height:
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
self.cell_height = b.height self.cell_height = b.height
else: else:
self.cell_height = height self.cell_height = height

View File

@ -26,7 +26,7 @@ class precharge(design.design):
debug.info(2, "creating precharge cell {0}".format(name)) debug.info(2, "creating precharge cell {0}".format(name))
super().__init__(name) super().__init__(name)
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
self.beta = parameter["beta"] self.beta = parameter["beta"]
self.ptx_width = self.beta * parameter["min_tx_size"] self.ptx_width = self.beta * parameter["min_tx_size"]
self.ptx_mults = 1 self.ptx_mults = 1

View File

@ -157,10 +157,17 @@ class ptx(design.design):
# self.tx_width, # self.tx_width,
# drc("minwidth_poly")) # drc("minwidth_poly"))
# TEMP FIX: Use old device names if using Calibre. # TEMP FIX: Use old device names if using Calibre.
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format("nshort" if self.tx_type == "nmos" else "pshort", self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format("nshort" if self.tx_type == "nmos" else "pshort",
self.mults, self.mults,
self.tx_width, self.tx_width,
drc("minwidth_poly")) drc("minwidth_poly"))
elif cell_props.ptx.model_is_subckt:
# sky130 requires mult parameter too
self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
else: else:
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type], self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults, self.mults,

View File

@ -33,7 +33,7 @@ class pwrite_driver(design.design):
# Width is matched to the bitcell, # Width is matched to the bitcell,
# Height will be variable # Height will be variable
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
self.width = self.bitcell.width self.width = self.bitcell.width
# Creates the netlist and layout # Creates the netlist and layout

View File

@ -25,7 +25,7 @@ class wordline_driver(design.design):
super().__init__(name) super().__init__(name)
if height is None: if height is None:
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
self.height = b.height self.height = b.height
else: else:
self.height = height self.height = height

View File

@ -26,7 +26,7 @@ class openram_test(unittest.TestCase):
if result != 0: if result != 0:
self.fail("DRC failed: {}".format(w.name)) self.fail("DRC failed: {}".format(w.name))
if OPTS.purge_temp: if not OPTS.keep_temp:
self.cleanup() self.cleanup()
def local_check(self, a, final_verification=False): def local_check(self, a, final_verification=False):
@ -49,7 +49,7 @@ class openram_test(unittest.TestCase):
if result != 0: if result != 0:
self.fail("LVS mismatch: {}".format(a.name)) self.fail("LVS mismatch: {}".format(a.name))
if OPTS.purge_temp: if not OPTS.keep_temp:
self.cleanup() self.cleanup()
def cleanup(self): def cleanup(self):

View File

@ -6,7 +6,10 @@
# All rights reserved. # All rights reserved.
# #
import datetime import datetime
import os
import debug import debug
import verify
from characterizer import functional
from globals import OPTS, print_time from globals import OPTS, print_time
@ -84,6 +87,11 @@ class sram():
gdsname = OPTS.output_path + self.s.name + ".gds" gdsname = OPTS.output_path + self.s.name + ".gds"
debug.print_raw("GDS: Writing to {0}".format(gdsname)) debug.print_raw("GDS: Writing to {0}".format(gdsname))
self.gds_write(gdsname) self.gds_write(gdsname)
verify.write_drc_script(cell_name=self.s.name,
gds_name=os.path.basename(gdsname),
extract=True,
final_verification=True,
output_path=OPTS.output_path)
print_time("GDS", datetime.datetime.now(), start_time) print_time("GDS", datetime.datetime.now(), start_time)
# Create a LEF physical model # Create a LEF physical model
@ -98,6 +106,9 @@ class sram():
spname = OPTS.output_path + self.s.name + ".sp" spname = OPTS.output_path + self.s.name + ".sp"
debug.print_raw("SP: Writing to {0}".format(spname)) debug.print_raw("SP: Writing to {0}".format(spname))
self.sp_write(spname) self.sp_write(spname)
functional(self.s,
os.path.basename(spname),
output_path=OPTS.output_path)
print_time("Spice writing", datetime.datetime.now(), start_time) print_time("Spice writing", datetime.datetime.now(), start_time)
# Save the LVS file # Save the LVS file
@ -105,11 +116,16 @@ class sram():
lvsname = OPTS.output_path + self.s.name + ".lvs.sp" lvsname = OPTS.output_path + self.s.name + ".lvs.sp"
debug.print_raw("LVS: Writing to {0}".format(lvsname)) debug.print_raw("LVS: Writing to {0}".format(lvsname))
self.lvs_write(lvsname) self.lvs_write(lvsname)
if not OPTS.netlist_only:
verify.write_lvs_script(cell_name=self.s.name,
gds_name=os.path.basename(gdsname),
sp_name=os.path.basename(lvsname),
final_verification=True,
output_path=OPTS.output_path)
print_time("LVS writing", datetime.datetime.now(), start_time) print_time("LVS writing", datetime.datetime.now(), start_time)
# Save the extracted spice file # Save the extracted spice file
if OPTS.use_pex: if OPTS.use_pex:
import verify
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
# Output the extracted design if requested # Output the extracted design if requested
pexname = OPTS.output_path + self.s.name + ".pex.sp" pexname = OPTS.output_path + self.s.name + ".pex.sp"
@ -121,6 +137,8 @@ class sram():
# Use generated spice file for characterization # Use generated spice file for characterization
sp_file = spname sp_file = spname
# Save a functional simulation file
# Characterize the design # Characterize the design
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
from characterizer import lib from characterizer import lib

View File

@ -7,6 +7,7 @@
# #
from globals import OPTS from globals import OPTS
class sram_factory: class sram_factory:
""" """
This is a factory pattern to create modules for usage in an SRAM. This is a factory pattern to create modules for usage in an SRAM.
@ -39,6 +40,11 @@ class sram_factory:
try: try:
from tech import tech_modules from tech import tech_modules
real_module_type = tech_modules[module_type] real_module_type = tech_modules[module_type]
# If we are given a list of modules, it is indexed by number of ports starting from 1
if type(real_module_type) is list:
# For now we will just index by the number of ports (except can't have 0 ports)
num_ports = OPTS.num_rw_ports + OPTS.num_r_ports + OPTS.num_w_ports
real_module_type = real_module_type[num_ports - 1]
overridden = tech_modules.is_overridden(module_type) overridden = tech_modules.is_overridden(module_type)
except ImportError: except ImportError:
# If they didn't define these, then don't use the option types. # If they didn't define these, then don't use the option types.

View File

@ -15,7 +15,6 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
#@unittest.skip("SKIPPING 05_array_test")
class array_test(openram_test): class array_test(openram_test):

View File

@ -23,7 +23,7 @@ class hierarchical_decoder_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 0
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell() globals.setup_bitcell()
@ -58,9 +58,9 @@ class hierarchical_decoder_test(openram_test):
self.local_check(a) self.local_check(a)
# Checks 3 x 4x16 and 4-input NAND decoder # Checks 3 x 4x16 and 4-input NAND decoder
debug.info(1, "Testing 4096 row sample for hierarchical_decoder") # debug.info(1, "Testing 4096 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", num_outputs=4096) # a = factory.create(module_type="hierarchical_decoder", num_outputs=4096)
self.local_check(a) # self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -15,6 +15,7 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class hierarchical_predecode2x4_test(openram_test): class hierarchical_predecode2x4_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -15,6 +15,7 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class hierarchical_predecode3x8_test(openram_test): class hierarchical_predecode3x8_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -56,8 +56,7 @@ class psram_1bank_2mux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -57,8 +57,7 @@ class psram_1bank_8mux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -56,8 +56,7 @@ class psram_1bank_nomux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -46,8 +46,7 @@ class sram_1bank_2mux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -48,8 +48,7 @@ class sram_1bank_2mux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -48,8 +48,7 @@ class sram_1bank_2mux_sparecols_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -46,8 +46,7 @@ class sram_1bank_4mux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -49,8 +49,7 @@ class sram_1bank_8mux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -49,8 +49,7 @@ class psram_1bank_nomux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -45,8 +45,7 @@ class sram_1bank_nomux_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -46,8 +46,7 @@ class sram_1bank_nomux_sparecols_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -52,8 +52,7 @@ class sram_wmask_1w_1r_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -48,8 +48,7 @@ class sram_wmask_func_test(openram_test):
tempspice = OPTS.openram_temp + "sram.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice)
f = functional(s.s, tempspice, corner)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -14,13 +14,15 @@ import globals
from globals import OPTS from globals import OPTS
import debug import debug
@unittest.skip("SKIPPING 24_lef_sram_test") @unittest.skip("SKIPPING 24_lef_sram_test")
class lef_test(openram_test): class lef_test(openram_test):
def runTest(self): def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.route_supplies=False
OPTS.check_lvsdrc=False
from sram import sram from sram import sram
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=2, c = sram_config(word_size=2,

View File

@ -14,6 +14,7 @@ import globals
from globals import OPTS from globals import OPTS
import debug import debug
class verilog_test(openram_test): class verilog_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -34,9 +34,9 @@ class hspice_pex_pinv_test(openram_test):
reload(characterizer) reload(characterizer)
# generate the pinv # generate the pinv
prev_purge_value = OPTS.purge_temp prev_keep_value = OPTS.keep_temp
# force set purge to false to save the sp file # force set purge to false to save the sp file
OPTS.purge_temp = False OPTS.keep_temp = True
debug.info(2, "Checking 1x size inverter") debug.info(2, "Checking 1x size inverter")
tx = pinv.pinv(name="pinv", size=1) tx = pinv.pinv(name="pinv", size=1)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name) tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name)
@ -52,7 +52,7 @@ class hspice_pex_pinv_test(openram_test):
# now generate its pex file # now generate its pex file
pex_file = self.run_pex(tx) pex_file = self.run_pex(tx)
OPTS.purge_temp = prev_purge_value # restore the old purge value OPTS.keep_temp = prev_keep_value # restore the old keep
# generate simulation for pex, make sure the simulation is successful # generate simulation for pex, make sure the simulation is successful
pex_delay = self.simulate_delay(test_module=pex_file, pex_delay = self.simulate_delay(test_module=pex_file,
top_level_name=tx.name) top_level_name=tx.name)
@ -77,7 +77,7 @@ class hspice_pex_pinv_test(openram_test):
sim_file = OPTS.openram_temp + "stim.sp" sim_file = OPTS.openram_temp + "stim.sp"
log_file_name = "timing" log_file_name = "timing"
test_sim = self.write_simulation(sim_file, test_module, top_level_name) test_sim = self.write_simulation(sim_file, test_module, top_level_name)
test_sim.run_sim() test_sim.run_sim("stim.sp")
delay = parse_spice_list(log_file_name, "pinv_delay") delay = parse_spice_list(log_file_name, "pinv_delay")
return delay return delay

View File

@ -33,8 +33,8 @@ class ngspice_pex_pinv_test(openram_test):
reload(characterizer) reload(characterizer)
# generate the pinv module # generate the pinv module
prev_purge_value = OPTS.purge_temp prev_keep_value = OPTS.keep_temp
OPTS.purge_temp = False # force set purge to false to save the sp file OPTS.keep_temp = True # force set keep to true to save the sp file
debug.info(2, "Checking 1x size inverter") debug.info(2, "Checking 1x size inverter")
tx = pinv.pinv(name="pinv", size=1) tx = pinv.pinv(name="pinv", size=1)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name) tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name)
@ -50,8 +50,8 @@ class ngspice_pex_pinv_test(openram_test):
# now generate its pex file # now generate its pex file
pex_file = self.run_pex(tx) pex_file = self.run_pex(tx)
# restore the old purge value # restore the old keep value
OPTS.purge_temp = prev_purge_value OPTS.keep_temp = prev_keep_value
# generate simulation for pex, make sure the simulation is successful # generate simulation for pex, make sure the simulation is successful
pex_delay = self.simulate_delay(test_module=pex_file, pex_delay = self.simulate_delay(test_module=pex_file,
top_level_name=tx.name) top_level_name=tx.name)
@ -76,7 +76,7 @@ class ngspice_pex_pinv_test(openram_test):
sim_file = OPTS.openram_temp + "stim.sp" sim_file = OPTS.openram_temp + "stim.sp"
log_file_name = "timing" log_file_name = "timing"
test_sim = self.write_simulation(sim_file, test_module, top_level_name) test_sim = self.write_simulation(sim_file, test_module, top_level_name)
test_sim.run_sim() test_sim.run_sim("stim.sp")
delay = parse_spice_list(log_file_name, "pinv_delay") delay = parse_spice_list(log_file_name, "pinv_delay")
return delay return delay

View File

@ -40,7 +40,7 @@ class openram_back_end_test(openram_test):
# specify the same verbosity for the system call # specify the same verbosity for the system call
options = "" options = ""
for i in range(OPTS.debug_level): for i in range(OPTS.verbose_level):
options += " -v" options += " -v"
if OPTS.spice_name: if OPTS.spice_name:
@ -86,7 +86,7 @@ class openram_back_end_test(openram_test):
self.assertEqual(len(re.findall('WARNING', output)), 0) self.assertEqual(len(re.findall('WARNING', output)), 0)
# now clean up the directory # now clean up the directory
if OPTS.purge_temp: if not OPTS.keep_temp:
if os.path.exists(out_path): if os.path.exists(out_path):
shutil.rmtree(out_path, ignore_errors=True) shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path), False) self.assertEqual(os.path.exists(out_path), False)

View File

@ -40,7 +40,7 @@ class openram_front_end_test(openram_test):
# specify the same verbosity for the system call # specify the same verbosity for the system call
options = "" options = ""
for i in range(OPTS.debug_level): for i in range(OPTS.verbose_level):
options += " -v" options += " -v"
if OPTS.spice_name: if OPTS.spice_name:
@ -86,7 +86,7 @@ class openram_front_end_test(openram_test):
self.assertEqual(len(re.findall('WARNING', output)), 0) self.assertEqual(len(re.findall('WARNING', output)), 0)
# now clean up the directory # now clean up the directory
if OPTS.purge_temp: if not OPTS.keep_temp:
if os.path.exists(out_path): if os.path.exists(out_path):
shutil.rmtree(out_path, ignore_errors=True) shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path), False) self.assertEqual(os.path.exists(out_path), False)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,8 @@ import sys, os, glob
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
from globals import OPTS from globals import OPTS
import debug import debug
import pdb
import traceback
class openram_test(unittest.TestCase): class openram_test(unittest.TestCase):
@ -27,7 +29,7 @@ class openram_test(unittest.TestCase):
if result != 0: if result != 0:
self.fail("DRC failed: {}".format(w.name)) self.fail("DRC failed: {}".format(w.name))
if OPTS.purge_temp: if not OPTS.keep_temp:
self.cleanup() self.cleanup()
def local_check(self, a, final_verification=False): def local_check(self, a, final_verification=False):
@ -74,7 +76,7 @@ class openram_test(unittest.TestCase):
# For debug... # For debug...
# import pdb; pdb.set_trace() # import pdb; pdb.set_trace()
if OPTS.purge_temp: if not OPTS.keep_temp:
self.cleanup() self.cleanup()
def run_pex(self, a, output=None): def run_pex(self, a, output=None):
@ -321,9 +323,7 @@ def header(filename, technology):
def debugTestRunner(post_mortem=None): def debugTestRunner(post_mortem=None):
"""unittest runner doing post mortem debugging on failing tests""" """unittest runner doing post mortem debugging on failing tests"""
import pdb if post_mortem is None and OPTS.debug:
import traceback
if post_mortem is None and not OPTS.purge_temp:
post_mortem = pdb.post_mortem post_mortem = pdb.post_mortem
class DebugTestResult(unittest.TextTestResult): class DebugTestResult(unittest.TextTestResult):

View File

@ -40,25 +40,25 @@ else:
OPTS.magic_exe = get_tool("GDS", ["magic"]) OPTS.magic_exe = get_tool("GDS", ["magic"])
if not OPTS.drc_exe: if not OPTS.drc_exe:
from .none import run_drc, print_drc_stats from .none import run_drc, print_drc_stats, write_drc_script
elif "calibre"==OPTS.drc_exe[0]: elif "calibre"==OPTS.drc_exe[0]:
from .calibre import run_drc, print_drc_stats from .calibre import run_drc, print_drc_stats, write_drc_script
elif "assura"==OPTS.drc_exe[0]: elif "assura"==OPTS.drc_exe[0]:
from .assura import run_drc, print_drc_stats from .assura import run_drc, print_drc_stats, write_drc_script
elif "magic"==OPTS.drc_exe[0]: elif "magic"==OPTS.drc_exe[0]:
from .magic import run_drc, print_drc_stats from .magic import run_drc, print_drc_stats, write_drc_script
else: else:
debug.error("Did not find a supported DRC tool." debug.error("Did not find a supported DRC tool."
+ "Disable DRC/LVS with check_lvsdrc=False to ignore.", 2) + "Disable DRC/LVS with check_lvsdrc=False to ignore.", 2)
if not OPTS.lvs_exe: if not OPTS.lvs_exe:
from .none import run_lvs, print_lvs_stats from .none import run_lvs, print_lvs_stats, write_lvs_script
elif "calibre"==OPTS.lvs_exe[0]: elif "calibre"==OPTS.lvs_exe[0]:
from .calibre import run_lvs, print_lvs_stats from .calibre import run_lvs, print_lvs_stats, write_lvs_script
elif "assura"==OPTS.lvs_exe[0]: elif "assura"==OPTS.lvs_exe[0]:
from .assura import run_lvs, print_lvs_stats from .assura import run_lvs, print_lvs_stats, write_lvs_script
elif "netgen"==OPTS.lvs_exe[0]: elif "netgen"==OPTS.lvs_exe[0]:
from .magic import run_lvs, print_lvs_stats from .magic import run_lvs, print_lvs_stats, write_lvs_script
else: else:
debug.warning("Did not find a supported LVS tool." debug.warning("Did not find a supported LVS tool."
+ "Disable DRC/LVS with check_lvsdrc=False to ignore.", 2) + "Disable DRC/LVS with check_lvsdrc=False to ignore.", 2)

View File

@ -28,7 +28,7 @@ inserted in the runset.
import os import os
import re import re
import time from run_script import *
import debug import debug
from globals import OPTS from globals import OPTS
@ -37,16 +37,11 @@ num_drc_runs = 0
num_lvs_runs = 0 num_lvs_runs = 0
num_pex_runs = 0 num_pex_runs = 0
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
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path):
from tech import drc from tech import drc
drc_rules = drc["drc_rules"] drc_rules = drc["drc_rules"]
drc_runset = OPTS.openram_temp + name + ".rsf" drc_runset = output_path + cell_name + ".rsf"
drc_log_file = "{0}{1}.log".format(OPTS.openram_temp, name) drc_log_file = "{0}{1}.log".format(OPTS.openram_temp, name)
# write the runset file # write the runset file
@ -64,8 +59,8 @@ def run_drc(name, gds_name, final_verification=False):
f.write("\n") f.write("\n")
f.write("avParameters(\n") f.write("avParameters(\n")
f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name)) f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name))
f.write(" ?cellName \"{}\"\n".format(name)) f.write(" ?cellName \"{}\"\n".format(cell_name))
f.write(" ?workingDirectory \"{}\"\n".format(OPTS.openram_temp)) f.write(" ?workingDirectory \"{}\"\n".format(output_path))
f.write(" ?rulesFile \"{}\"\n".format(drc_rules)) f.write(" ?rulesFile \"{}\"\n".format(drc_rules))
f.write(" ?set ( \"GridCheck\" )\n") f.write(" ?set ( \"GridCheck\" )\n")
f.write(" ?avrpt t\n") f.write(" ?avrpt t\n")
@ -73,12 +68,23 @@ def run_drc(name, gds_name, final_verification=False):
f.close() f.close()
# run drc # run drc
cwd = os.getcwd() run_file = output_path + "/run_drc.sh"
os.chdir(OPTS.openram_temp) f = open(run_file, "w")
cmd = "assura {0} 2> {1} 1> {2}".format(drc_runset, drc_log_file, drc_log_file) f.write("#!/bin/sh\n")
debug.info(1, cmd) f.write("assura {0} 2> {1} 1> {2}\n".format(drc_runset, drc_log_file, drc_log_file))
os.system(cmd) f.close()
os.chdir(cwd)
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 # count and report errors
errors = 0 errors = 0
@ -100,23 +106,18 @@ def run_drc(name, gds_name, final_verification=False):
return errors return errors
def run_lvs(name, gds_name, sp_name, final_verification=False): def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
"""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
from tech import drc from tech import drc
lvs_rules = drc["lvs_rules"] lvs_rules = drc["lvs_rules"]
lvs_runset = OPTS.openram_temp + name + ".rsf" lvs_runset = output_path + name + ".rsf"
# The LVS compare rules must be defined in the tech file for Assura. # The LVS compare rules must be defined in the tech file for Assura.
lvs_compare = drc["lvs_compare"] lvs_compare = drc["lvs_compare"]
# Define the must-connect names for disconnected LVS nets for Assura # Define the must-connect names for disconnected LVS nets for Assura
lvs_bindings = drc["lvs_bindings"] lvs_bindings = drc["lvs_bindings"]
lvs_log_file = "{0}{1}.log".format(OPTS.openram_temp, name) lvs_log_file = "{0}{1}.log".format(output_path, name)
# Needed when FET models are sub-circuits # Needed when FET models are sub-circuits
if drc.has_key("lvs_subcircuits"): if "lvs_subcircuits" in drc:
lvs_sub_file = drc["lvs_subcircuits"] lvs_sub_file = drc["lvs_subcircuits"]
else: else:
lvs_sub_file = "" lvs_sub_file = ""
@ -128,7 +129,7 @@ def run_lvs(name, gds_name, sp_name, final_verification=False):
f.write("avParameters(\n") f.write("avParameters(\n")
f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name)) f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name))
f.write(" ?cellName \"{}\"\n".format(name)) f.write(" ?cellName \"{}\"\n".format(name))
f.write(" ?workingDirectory \"{}\"\n".format(OPTS.openram_temp)) f.write(" ?workingDirectory \"{}\"\n".format(output_path))
f.write(" ?rulesFile \"{}\"\n".format(lvs_rules)) f.write(" ?rulesFile \"{}\"\n".format(lvs_rules))
f.write(" ?autoGrid nil\n") f.write(" ?autoGrid nil\n")
f.write(" ?avrpt t\n") f.write(" ?avrpt t\n")
@ -160,13 +161,24 @@ def run_lvs(name, gds_name, sp_name, final_verification=False):
f.write("avLVS()\n") f.write("avLVS()\n")
f.close() f.close()
# run lvs # run drc
cwd = os.getcwd() run_file = output_path + "/run_vls.sh"
os.chdir(OPTS.openram_temp) f = open(run_file, "w")
cmd = "assura {0} 2> {1} 1> {2}".format(lvs_runset, lvs_log_file, lvs_log_file) f.write("#!/bin/sh\n")
debug.info(1, cmd) f.write("assura {0} 2> {1} 1> {2}\n".format(lvs_runset, lvs_log_file, lvs_log_file))
os.system(cmd) f.close()
os.chdir(cwd)
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 errors = 0
try: try:
@ -193,9 +205,14 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
global num_pex_runs global num_pex_runs
num_pex_runs += 1 num_pex_runs += 1
def print_drc_stats(): def print_drc_stats():
debug.info(1, "DRC runs: {0}".format(num_drc_runs)) debug.info(1, "DRC runs: {0}".format(num_drc_runs))
def print_lvs_stats(): def print_lvs_stats():
debug.info(1, "LVS runs: {0}".format(num_lvs_runs)) debug.info(1, "LVS runs: {0}".format(num_lvs_runs))
def print_pex_stats(): def print_pex_stats():
debug.info(1, "PEX runs: {0}".format(num_pex_runs)) debug.info(1, "PEX runs: {0}".format(num_pex_runs))

View File

@ -30,7 +30,7 @@ num_lvs_runs = 0
num_pex_runs = 0 num_pex_runs = 0
def write_calibre_drc_script(cell_name, extract, final_verification, gds_name): def write_drc_script(cell_name, gds_name, extract, final_verification, output_path):
""" Write a Calibre runset file and script to run DRC """ """ Write a Calibre runset file and script to run DRC """
# the runset file contains all the options to run calibre # the runset file contains all the options to run calibre
from tech import drc from tech import drc
@ -38,7 +38,7 @@ def write_calibre_drc_script(cell_name, extract, final_verification, gds_name):
drc_runset = { drc_runset = {
'drcRulesFile': drc_rules, 'drcRulesFile': drc_rules,
'drcRunDir': OPTS.openram_temp, 'drcRunDir': output_path,
'drcLayoutPaths': gds_name, 'drcLayoutPaths': gds_name,
'drcLayoutPrimary': cell_name, 'drcLayoutPrimary': cell_name,
'drcLayoutSystem': 'GDSII', 'drcLayoutSystem': 'GDSII',
@ -50,17 +50,17 @@ def write_calibre_drc_script(cell_name, extract, final_verification, gds_name):
} }
# write the runset file # write the runset file
f = open(OPTS.openram_temp + "drc_runset", "w") f = open(output_path + "drc_runset", "w")
for k in sorted(iter(drc_runset.keys())): for k in sorted(iter(drc_runset.keys())):
f.write("*{0}: {1}\n".format(k, drc_runset[k])) f.write("*{0}: {1}\n".format(k, drc_runset[k]))
f.close() f.close()
# Create an auxiliary script to run calibre with the runset # Create an auxiliary script to run calibre with the runset
run_file = OPTS.openram_temp + "run_drc.sh" run_file = output_path + "run_drc.sh"
f = open(run_file, "w") f = open(run_file, "w")
f.write("#!/bin/sh\n") f.write("#!/bin/sh\n")
cmd = "{0} -gui -drc {1}drc_runset -batch".format(OPTS.drc_exe[1], cmd = "{0} -gui -drc {1}drc_runset -batch".format(OPTS.drc_exe[1],
OPTS.openram_temp) output_path)
f.write(cmd) f.write(cmd)
f.write("\n") f.write("\n")
f.close() f.close()
@ -68,14 +68,14 @@ def write_calibre_drc_script(cell_name, extract, final_verification, gds_name):
return drc_runset return drc_runset
def write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name): def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
""" Write a Calibre runset file and script to run LVS """ """ Write a Calibre runset file and script to run LVS """
from tech import drc from tech import drc
lvs_rules = drc["lvs_rules"] lvs_rules = drc["lvs_rules"]
lvs_runset = { lvs_runset = {
'lvsRulesFile': lvs_rules, 'lvsRulesFile': lvs_rules,
'lvsRunDir': OPTS.openram_temp, 'lvsRunDir': output_path,
'lvsLayoutPaths': gds_name, 'lvsLayoutPaths': gds_name,
'lvsLayoutPrimary': cell_name, 'lvsLayoutPrimary': cell_name,
'lvsSourcePath': sp_name, 'lvsSourcePath': sp_name,
@ -111,19 +111,19 @@ def write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name):
# write the runset file # write the runset file
f = open(OPTS.openram_temp + "lvs_runset", "w") f = open(output_path + "lvs_runset", "w")
for k in sorted(iter(lvs_runset.keys())): for k in sorted(iter(lvs_runset.keys())):
f.write("*{0}: {1}\n".format(k, lvs_runset[k])) f.write("*{0}: {1}\n".format(k, lvs_runset[k]))
f.close() f.close()
# Create an auxiliary script to run calibre with the runset # Create an auxiliary script to run calibre with the runset
run_file = OPTS.openram_temp + "run_lvs.sh" run_file = output_path + "run_lvs.sh"
f = open(run_file, "w") f = open(run_file, "w")
f.write("#!/bin/sh\n") f.write("#!/bin/sh\n")
PDK_DIR=os.environ.get("PDK_DIR") PDK_DIR=os.environ.get("PDK_DIR")
f.write("export PDK_DIR={}\n".format(PDK_DIR)) f.write("export PDK_DIR={}\n".format(PDK_DIR))
cmd = "{0} -gui -lvs {1}lvs_runset -batch".format(OPTS.lvs_exe[1], cmd = "{0} -gui -lvs {1}lvs_runset -batch".format(OPTS.lvs_exe[1],
OPTS.openram_temp) output_path)
f.write(cmd) f.write(cmd)
f.write("\n") f.write("\n")
f.close() f.close()
@ -132,16 +132,16 @@ def write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name):
return lvs_runset return lvs_runset
def write_calibre_pex_script(cell_name, extract, output, final_verification): def write_pex_script(cell_name, extract, output, final_verification, output_path):
""" Write a pex script that can either just extract the netlist or the netlist+parasitics """ """ Write a pex script that can either just extract the netlist or the netlist+parasitics """
if output == None: if output == None:
output = cell_name + ".pex.sp" output = cell_name + ".pex.sp"
# check if lvs report has been done # check if lvs report has been done
# if not run drc and lvs # if not run drc and lvs
if not os.path.isfile(OPTS.openram_temp + cell_name + ".lvs.report"): if not os.path.isfile(output_path + cell_name + ".lvs.report"):
gds_name = OPTS.openram_temp +"/"+ cell_name + ".gds" gds_name = output_path +"/"+ cell_name + ".gds"
sp_name = OPTS.openram_temp +"/"+ cell_name + ".sp" sp_name = output_path +"/"+ cell_name + ".sp"
run_drc(cell_name, gds_name) run_drc(cell_name, gds_name)
run_lvs(cell_name, gds_name, sp_name) run_lvs(cell_name, gds_name, sp_name)
@ -149,7 +149,7 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification):
pex_rules = drc["xrc_rules"] pex_rules = drc["xrc_rules"]
pex_runset = { pex_runset = {
'pexRulesFile': pex_rules, 'pexRulesFile': pex_rules,
'pexRunDir': OPTS.openram_temp, 'pexRunDir': output_path,
'pexLayoutPaths': cell_name + ".gds", 'pexLayoutPaths': cell_name + ".gds",
'pexLayoutPrimary': cell_name, 'pexLayoutPrimary': cell_name,
'pexSourcePath': cell_name + ".sp", 'pexSourcePath': cell_name + ".sp",
@ -162,13 +162,13 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification):
} }
# write the runset file # write the runset file
f = open(OPTS.openram_temp + "pex_runset", "w") f = open(output_path + "pex_runset", "w")
for k in sorted(iter(pex_runset.keys())): for k in sorted(iter(pex_runset.keys())):
f.write("*{0}: {1}\n".format(k, pex_runset[k])) f.write("*{0}: {1}\n".format(k, pex_runset[k]))
f.close() f.close()
# Create an auxiliary script to run calibre with the runset # Create an auxiliary script to run calibre with the runset
run_file = OPTS.openram_temp + "run_pex.sh" run_file = output_path + "run_pex.sh"
f = open(run_file, "w") f = open(run_file, "w")
f.write("#!/bin/sh\n") f.write("#!/bin/sh\n")
cmd = "{0} -gui -pex {1}pex_runset -batch".format(OPTS.pex_exe[1], cmd = "{0} -gui -pex {1}pex_runset -batch".format(OPTS.pex_exe[1],
@ -198,7 +198,7 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)):
shutil.copy(gds_name, OPTS.openram_temp) shutil.copy(gds_name, OPTS.openram_temp)
drc_runset = write_calibre_drc_script(cell_name, extract, final_verification, gds_name) drc_runset = write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp)
if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)):
shutil.copy(gds_name, OPTS.openram_temp + os.path.basename(gds_name)) shutil.copy(gds_name, OPTS.openram_temp + os.path.basename(gds_name))
@ -241,7 +241,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
global num_lvs_runs global num_lvs_runs
num_lvs_runs += 1 num_lvs_runs += 1
lvs_runset = write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name) lvs_runset = write_lvs_script(cell_name, gds_name, sp_name, final_verification, OPTS.openram_temp)
# Copy file to local dir if it isn't already # Copy file to local dir if it isn't already
if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)):
@ -328,7 +328,7 @@ def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False)
global num_pex_runs global num_pex_runs
num_pex_runs += 1 num_pex_runs += 1
write_calibre_pex_script(cell_name, True, output, final_verification) write_pex_script(cell_name, True, output, final_verification, OPTS.openram_temp)
# Copy file to local dir if it isn't already # Copy file to local dir if it isn't already
if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)):
@ -390,9 +390,14 @@ def correct_port(name, output_file_name, ref_file_name):
output_file.write(part2) output_file.write(part2)
output_file.close() output_file.close()
def print_drc_stats(): def print_drc_stats():
debug.info(1, "DRC runs: {0}".format(num_drc_runs)) debug.info(1, "DRC runs: {0}".format(num_drc_runs))
def print_lvs_stats(): def print_lvs_stats():
debug.info(1, "LVS runs: {0}".format(num_lvs_runs)) debug.info(1, "LVS runs: {0}".format(num_lvs_runs))
def print_pex_stats(): def print_pex_stats():
debug.info(1, "PEX runs: {0}".format(num_pex_runs)) debug.info(1, "PEX runs: {0}".format(num_pex_runs))

View File

@ -66,19 +66,27 @@ def filter_gds(cell_name, input_gds, output_gds):
(outfile, errfile, resultsfile) = run_script(cell_name, "filter") (outfile, errfile, resultsfile) = run_script(cell_name, "filter")
def write_magic_script(cell_name, extract=False, final_verification=False): def write_drc_script(cell_name, gds_name, extract, final_verification, output_path):
""" Write a magic script to perform DRC and optionally extraction. """ """ Write a magic script to perform DRC and optionally extraction. """
global OPTS global OPTS
run_file = OPTS.openram_temp + "run_drc.sh" # Copy .magicrc file into the directory
magic_file = OPTS.openram_tech + "tech/.magicrc"
if os.path.exists(magic_file):
shutil.copy(magic_file, output_path)
else:
debug.warning("Could not locate .magicrc file: {}".format(magic_file))
run_file = output_path + "run_drc.sh"
f = open(run_file, "w") f = open(run_file, "w")
f.write("#!/bin/sh\n") f.write("#!/bin/sh\n")
f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1])) f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1]))
f.write("gds polygon subcell true\n") f.write("gds polygon subcell true\n")
f.write("gds warning default\n") f.write("gds warning default\n")
f.write("gds flatten true\n")
f.write("gds readonly true\n") f.write("gds readonly true\n")
f.write("gds read {}.gds\n".format(cell_name)) f.write("gds read {}\n".format(gds_name))
f.write("load {}\n".format(cell_name)) f.write("load {}\n".format(cell_name))
# Flatten the cell to get rid of DRCs spanning multiple layers # Flatten the cell to get rid of DRCs spanning multiple layers
# (e.g. with routes) # (e.g. with routes)
@ -130,32 +138,6 @@ def write_magic_script(cell_name, extract=False, final_verification=False):
os.system("chmod u+x {}".format(run_file)) os.system("chmod u+x {}".format(run_file))
def write_netgen_script(cell_name):
""" Write a netgen script to perform LVS. """
global OPTS
setup_file = "setup.tcl"
full_setup_file = OPTS.openram_tech + "tech/" + setup_file
if os.path.exists(full_setup_file):
# Copy setup.tcl file into temp dir
shutil.copy(full_setup_file, OPTS.openram_temp)
else:
setup_file = 'nosetup'
run_file = OPTS.openram_temp + "run_lvs.sh"
f = open(run_file, "w")
f.write("#!/bin/sh\n")
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
f.write("readnet spice {0}.spice\n".format(cell_name))
f.write("readnet spice {0}.sp\n".format(cell_name))
f.write("lvs {{{0}.spice {0}}} {{{0}.sp {0}}} {1} {0}.lvs.report -json\n".format(cell_name, setup_file))
f.write("quit\n")
f.write("EOF\n")
f.close()
os.system("chmod u+x {}".format(run_file))
def run_drc(cell_name, gds_name, extract=True, final_verification=False): def run_drc(cell_name, gds_name, extract=True, final_verification=False):
"""Run DRC check on a cell which is implemented in gds_name.""" """Run DRC check on a cell which is implemented in gds_name."""
@ -166,14 +148,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'):
shutil.copy(gds_name, OPTS.openram_temp) shutil.copy(gds_name, OPTS.openram_temp)
# Copy .magicrc file into temp dir write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp)
magic_file = OPTS.openram_tech + "tech/.magicrc"
if os.path.exists(magic_file):
shutil.copy(magic_file, OPTS.openram_temp)
else:
debug.warning("Could not locate .magicrc file: {}".format(magic_file))
write_magic_script(cell_name, extract, final_verification)
(outfile, errfile, resultsfile) = run_script(cell_name, "drc") (outfile, errfile, resultsfile) = run_script(cell_name, "drc")
@ -213,6 +188,32 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
return errors return errors
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
""" Write a netgen script to perform LVS. """
global OPTS
setup_file = "setup.tcl"
full_setup_file = OPTS.openram_tech + "tech/" + setup_file
if os.path.exists(full_setup_file):
# Copy setup.tcl file into temp dir
shutil.copy(full_setup_file, output_path)
else:
setup_file = 'nosetup'
run_file = output_path + "/run_lvs.sh"
f = open(run_file, "w")
f.write("#!/bin/sh\n")
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
# f.write("readnet spice {0}.spice\n".format(cell_name))
# f.write("readnet spice {0}\n".format(sp_name))
f.write("lvs {{{0}.spice {0}}} {{{1} {0}}} {2} {0}.lvs.report -json\n".format(cell_name, sp_name, setup_file))
f.write("quit\n")
f.write("EOF\n")
f.close()
os.system("chmod u+x {}".format(run_file))
def run_lvs(cell_name, gds_name, sp_name, final_verification=False): def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
"""Run LVS check on a given top-level name which is """Run LVS check on a given top-level name which is
implemented in gds_name and sp_name. Final verification will implemented in gds_name and sp_name. Final verification will
@ -227,7 +228,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'):
shutil.copy(sp_name, OPTS.openram_temp) shutil.copy(sp_name, OPTS.openram_temp)
write_netgen_script(cell_name) write_lvs_script(cell_name, gds_name, sp_name, final_verification, OPTS.openram_temp)
(outfile, errfile, resultsfile) = run_script(cell_name, "lvs") (outfile, errfile, resultsfile) = run_script(cell_name, "lvs")

View File

@ -17,6 +17,10 @@ lvs_warned = False
pex_warned = False pex_warned = False
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path):
pass
def run_drc(cell_name, gds_name, extract=False, final_verification=False): def run_drc(cell_name, gds_name, extract=False, final_verification=False):
global drc_warned global drc_warned
if not drc_warned: if not drc_warned:
@ -26,6 +30,10 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
return 1 return 1
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path):
pass
def run_lvs(cell_name, gds_name, sp_name, final_verification=False): def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
global lvs_warned global lvs_warned
if not lvs_warned: if not lvs_warned:

View File

@ -13,6 +13,7 @@ import os
import debug import debug
from globals import OPTS from globals import OPTS
def run_script(cell_name, script="lvs"): def run_script(cell_name, script="lvs"):
""" Run script and create output files. """ """ Run script and create output files. """

View File

@ -103,8 +103,7 @@ power_grid = m3_stack
# GDS Layer Map # GDS Layer Map
################################################### ###################################################
# create the GDS layer map # Create the GDS layer map using internal names
# FIXME: parse the gds layer map from the cadence map?
layer = {} layer = {}
layer["active"] = (1, 0) layer["active"] = (1, 0)
layer["pwell"] = (2, 0) layer["pwell"] = (2, 0)
@ -138,6 +137,40 @@ layer["m10"] = (29, 0)
layer["text"] = (239, 0) layer["text"] = (239, 0)
layer["boundary"]= (239, 0) layer["boundary"]= (239, 0)
# Layer names for external PDKs
layer_names = {}
layer_names["active"] = "active"
layer_names["pwell"] = "pwell"
layer_names["nwell"] = "nwell"
layer_names["nimplant"]= "nimplant"
layer_names["pimplant"]= "pimplant"
layer_names["vtg"] = "vtg"
layer_names["vth"] = "vth"
layer_names["thkox"] = "thkox"
layer_names["poly"] = "poly"
layer_names["contact"] = "contact"
layer_names["m1"] = "metal1"
layer_names["via1"] = "via1"
layer_names["m2"] = "metal2"
layer_names["via2"] = "via2"
layer_names["m3"] = "metal3"
layer_names["via3"] = "via3"
layer_names["m4"] = "metal4"
layer_names["via4"] = "via4"
layer_names["m5"] = "metal5"
layer_names["via5"] = "via5"
layer_names["m6"] = "metal6"
layer_names["via6"] = "via6"
layer_names["m7"] = "metal7"
layer_names["via7"] = "via7"
layer_names["m8"] = "metal8"
layer_names["via8"] = "via8"
layer_names["m9"] = "metal9"
layer_names["via9"] = "via9"
layer_names["m10"] = "metal10"
layer_names["text"] = "text"
layer_names["boundary"]= "boundary"
################################################### ###################################################
# DRC/LVS Rules Setup # DRC/LVS Rules Setup
################################################### ###################################################
@ -240,7 +273,7 @@ drc.add_enclosure("active",
enclosure=0.005) enclosure=0.005)
# CONTACT.6 Minimum spacing of contact and gate # CONTACT.6 Minimum spacing of contact and gate
drc["active_contact_to_gate"] = 0.0375 #changed from 0.035 drc["active_contact_to_gate"]=0.0375
# CONTACT.7 Minimum spacing of contact and poly # CONTACT.7 Minimum spacing of contact and poly
drc["poly_contact_to_gate"]=0.090 drc["poly_contact_to_gate"]=0.090
@ -254,7 +287,7 @@ drc.add_enclosure("poly",
layer="contact", layer="contact",
enclosure=0.005) enclosure=0.005)
# CONTACT.6 Minimum spacing of contact and gate # CONTACT.6 Minimum spacing of contact and gate
drc["contact_to_gate"] = 0.0375 #changed from 0.035 drc["contact_to_gate"]=0.0375
# CONTACT.7 Minimum spacing of contact and poly # CONTACT.7 Minimum spacing of contact and poly
drc["contact_to_poly"]=0.090 drc["contact_to_poly"]=0.090

View File

@ -121,6 +121,26 @@ layer["m4"] = (31, 0)
layer["text"] = (63, 0) layer["text"] = (63, 0)
layer["boundary"] = (63, 0) layer["boundary"] = (63, 0)
# Layer names for external PDKs
layer_names = {}
layer_names["active"] = "active"
layer_names["pwell"] = "pwell"
layer_names["nwell"] = "nwell"
layer_names["nimplant"]= "nimplant"
layer_names["pimplant"]= "pimplant"
layer_names["poly"] = "poly"
layer_names["poly_contact"] = "poly_contact"
layer_names["active_contact"] = "active_contact"
layer_names["m1"] = "metal1"
layer_names["via1"] = "via1"
layer_names["m2"] = "metal2"
layer_names["via2"] = "via2"
layer_names["m3"] = "metal3"
layer_names["via3"] = "via3"
layer_names["m4"] = "metal4"
layer_names["text"] = "text"
layer_names["boundary"]= "boundary"
################################################### ###################################################
# DRC/LVS Rules Setup # DRC/LVS Rules Setup
################################################### ###################################################