Add utility script gen_stimulus.py to help create simulations for debugging.

This commit is contained in:
Matt Guthaus 2018-02-26 08:54:35 -08:00
parent cc99025279
commit a732405836
5 changed files with 105 additions and 11 deletions

View File

@ -37,9 +37,7 @@ class delay():
# These are the member variables for a simulation # These are the member variables for a simulation
self.period = 0 self.period = 0
self.load = 0 self.set_load_slew(0,0)
self.slew = 0
self.set_corner(corner) self.set_corner(corner)
def set_corner(self,corner): def set_corner(self,corner):
@ -47,6 +45,10 @@ class delay():
self.corner = corner self.corner = corner
(self.process, self.vdd_voltage, self.temperature) = corner (self.process, self.vdd_voltage, self.temperature) = corner
def set_load_slew(self,load,slew):
""" Set the load and slew """
self.load = load
self.slew = slew
def check_arguments(self): def check_arguments(self):
"""Checks if arguments given for write_stimulus() meets requirements""" """Checks if arguments given for write_stimulus() meets requirements"""
@ -578,8 +580,9 @@ class delay():
(full_array_leakage, trim_array_leakage)=self.run_power_simulation() (full_array_leakage, trim_array_leakage)=self.run_power_simulation()
char_data["leakage_power"]=full_array_leakage char_data["leakage_power"]=full_array_leakage
for self.slew in slews: for slew in slews:
for self.load in loads: for load in loads:
self.set_load_slew(load,slew)
# 2c) Find the delay, dynamic power, and leakage power of the trimmed array. # 2c) Find the delay, dynamic power, and leakage power of the trimmed array.
(success, delay_results) = self.run_delay_simulation() (success, delay_results) = self.run_delay_simulation()
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load)) debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load))
@ -593,8 +596,7 @@ class delay():
# 3) Finds the minimum period without degrading the delays by X% # 3) Finds the minimum period without degrading the delays by X%
self.load=max(loads) self.set_load_slew(max(loads),max(slews))
self.slew=max(slews)
min_period = self.find_min_period(feasible_delay_lh, feasible_delay_hl) min_period = self.find_min_period(feasible_delay_lh, feasible_delay_hl)
debug.check(type(min_period)==float,"Couldn't find minimum period.") debug.check(type(min_period)==float,"Couldn't find minimum period.")
debug.info(1, "Min Period: {0}n with a delay of {1} / {2}".format(min_period, feasible_delay_lh, feasible_delay_hl)) debug.info(1, "Min Period: {0}n with a delay of {1} / {2}".format(min_period, feasible_delay_lh, feasible_delay_hl))
@ -710,8 +712,9 @@ class delay():
delay_hl = [] delay_hl = []
slew_lh = [] slew_lh = []
slew_hl = [] slew_hl = []
for self.slew in slews: for slew in slews:
for self.load in loads: for load in loads:
self.set_load_slew(load,slew)
bank_delay = sram.analytical_delay(self.slew,self.load) bank_delay = sram.analytical_delay(self.slew,self.load)
# Convert from ps to ns # Convert from ps to ns
delay_lh.append(bank_delay.delay/1e3) delay_lh.append(bank_delay.delay/1e3)

86
compiler/gen_stimulus.py Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env python2.7
"""
This script will generate a stimulus file for a given period, load, and slew input
for the given dimension SRAM. It is useful for debugging after an SRAM has been
created without re-running the entire process. Right now, it assumes the nominal
corner, but should probably be extended.
"""
import sys,os
import datetime
import re
import importlib
from globals import *
(OPTS, args) = parse_args()
# Override the usage
USAGE = "Usage: {} [options] <config file> <period in ns> <load in fF> <slew in ns>\nUse -h for help.\n".format(__file__)
# Check that we are left with a single configuration file as argument.
if len(args) != 4:
print(USAGE)
sys.exit(2)
# We need to get the:
# config file
config_file = args[0]
# period
period = float(args[1])
# load
load = float(args[2])
# slew
slew = float(args[3])
# These depend on arguments, so don't load them until now.
import debug
init_openram(config_file=config_file, is_unit_test=False)
OPTS.check_lvsdrc = False
# Put the temp output in the output path since it is what we want to generate!
old_openram_temp = OPTS.openram_temp
OPTS.openram_temp = OPTS.output_path
import sram
class fake_sram(sram.sram):
""" This is an SRAM that doesn't actually create itself, just computes
the sizes. """
def __init__(self, word_size, num_words, num_banks, name):
self.name = name
self.word_size = word_size
self.num_words = num_words
self.num_banks = num_banks
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
# to get the row, col, etc.
self.compute_sizes()
sram = fake_sram(OPTS.word_size, OPTS.num_words, OPTS.num_banks, OPTS.output_name)
sp_file = OPTS.output_path+OPTS.output_name + ".sp"
from characterizer import delay
import tech
# Set up the delay and set to the nominal corner
d = delay.delay(sram, sp_file, ("TT", tech.spice["nom_supply_voltage"], tech.spice["nom_temperature"]))
# Set the period
d.period = period
# Set the load of outputs and slew of inputs
d.set_load_slew(load,slew)
# Set the probe address/bit
probe_address = "1" * sram.addr_size
probe_data = sram.word_size - 1
d.set_probe(probe_address, probe_data)
d.write_delay_stimulus()
# Output info about this run
report_status()
print("Output files are:\n{0}stim.sp\n{0}sram.sp\n{0}reduced.sp".format(OPTS.output_path))
OPTS.openram_temp = old_openram_temp
# Delete temp files, remove the dir, etc.
end_openram()

View File

@ -167,6 +167,8 @@ def read_config(config_file, is_unit_test=True):
if not OPTS.output_path.endswith('/'): if not OPTS.output_path.endswith('/'):
OPTS.output_path += "/" OPTS.output_path += "/"
if not OPTS.output_path.startswith('/'):
OPTS.output_path = os.getcwd() + "/" + OPTS.output_path
debug.info(1, "Output saved in " + OPTS.output_path) debug.info(1, "Output saved in " + OPTS.output_path)
OPTS.is_unit_test=is_unit_test OPTS.is_unit_test=is_unit_test
@ -321,7 +323,6 @@ def report_status():
if not OPTS.tech_name: if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.") debug.error("Tech name must be specified in config file.")
print("Output files are " + OPTS.output_name + ".(sp|gds|v|lib|lef)")
print("Technology: {0}".format(OPTS.tech_name)) print("Technology: {0}".format(OPTS.tech_name))
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
OPTS.num_words, OPTS.num_words,

View File

@ -40,6 +40,8 @@ report_status()
import verify import verify
import sram import sram
print("Output files are " + OPTS.output_name + ".(sp|gds|v|lib|lef)")
# Keep track of running stats # Keep track of running stats
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
print_time("Start",start_time) print_time("Start",start_time)

View File

@ -35,6 +35,8 @@ class code_format_test(openram_test):
continue continue
if re.search("openram.py$", code): if re.search("openram.py$", code):
continue continue
if re.search("gen_stimulus.py$", code):
continue
errors += check_print_output(code) errors += check_print_output(code)
# fails if there are any tabs in any files # fails if there are any tabs in any files