Added option to allow specific load/slew combinations in config file.

This commit is contained in:
Hunter Nichols 2021-02-24 16:43:34 -08:00
parent 2ce802612b
commit b5516865f1
4 changed files with 78 additions and 58 deletions

View File

@ -1058,7 +1058,7 @@ class delay(simulation):
self.create_measurement_names()
self.create_measurement_objects()
def analyze(self, probe_address, probe_data, slews, loads):
def analyze(self, probe_address, probe_data, load_slews):
"""
Main function to characterize an SRAM for a table. Computes both delay and power characterization.
"""
@ -1066,7 +1066,11 @@ class delay(simulation):
# Dict to hold all characterization values
char_sram_data = {}
self.analysis_init(probe_address, probe_data)
loads = []
slews = []
for load,slew in load_slews:
loads.append(load)
slews.append(slew)
self.load=max(loads)
self.slew=max(slews)
@ -1086,7 +1090,7 @@ class delay(simulation):
leakage_offset = full_array_leakage - trim_array_leakage
# 4) At the minimum period, measure the delay, slew and power for all slew/load pairs.
self.period = min_period
char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset)
char_port_data = self.simulate_loads_and_slews(load_slews, leakage_offset)
# FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate.
self.alter_lh_char_data(char_port_data)
@ -1101,28 +1105,27 @@ class delay(simulation):
char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl']
char_port_data[port]['slew_lh'] = char_port_data[port]['slew_hl']
def simulate_loads_and_slews(self, slews, loads, leakage_offset):
def simulate_loads_and_slews(self, load_slews, leakage_offset):
"""Simulate all specified output loads and input slews pairs of all ports"""
measure_data = self.get_empty_measure_data_dict()
# Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_ports
for slew in slews:
for load in loads:
self.set_load_slew(load, slew)
# Find the delay, dynamic power, and leakage power of the trimmed array.
(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.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew, self.load))
# The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
for port in self.all_ports:
for mname, value in delay_results[port].items():
if "power" in mname:
# Subtract partial array leakage and add full array leakage for the power measures
measure_data[port][mname].append(value + leakage_offset)
else:
measure_data[port][mname].append(value)
for load, slew in load_slews:
self.set_load_slew(load, slew)
# Find the delay, dynamic power, and leakage power of the trimmed array.
(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.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew, self.load))
# The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
for port in self.all_ports:
for mname, value in delay_results[port].items():
if "power" in mname:
# Subtract partial array leakage and add full array leakage for the power measures
measure_data[port][mname].append(value + leakage_offset)
else:
measure_data[port][mname].append(value)
return measure_data
def calculate_inverse_address(self):

View File

@ -44,16 +44,32 @@ class lib:
def prepare_tables(self):
""" Determine the load/slews if they aren't specified in the config file. """
# These are the parameters to determine the table sizes
self.load_scales = np.array(OPTS.load_scales)
self.load = tech.spice["dff_in_cap"]
self.loads = self.load_scales * self.load
if OPTS.use_specified_load_slew == None:
self.load_scales = np.array(OPTS.load_scales)
self.load = tech.spice["dff_in_cap"]
self.loads = self.load_scales * self.load
self.slew_scales = np.array(OPTS.slew_scales)
self.slew = tech.spice["rise_time"]
self.slews = self.slew_scales * self.slew
self.load_slews = []
for slew in self.slews:
for load in self.loads:
self.load_slews.append((load, slew))
else:
debug.warning("Using the option \"use_specified_load_slew\" will make load slew,data in lib file inaccurate.")
self.load_slews = OPTS.use_specified_load_slew
self.loads = []
self.slews = []
for load,slew in self.load_slews:
self.loads.append(load)
self.slews.append(slew)
self.loads = np.array(self.loads)
self.slews = np.array(self.slews)
debug.info(1, "Slews: {0}".format(self.slews))
debug.info(1, "Loads: {0}".format(self.loads))
self.slew_scales = np.array(OPTS.slew_scales)
self.slew = tech.spice["rise_time"]
self.slews = self.slew_scales * self.slew
debug.info(1, "Slews: {0}".format(self.slews))
debug.info(1, "self.load_slews : {0}".format(self.load_slews))
def create_corners(self):
""" Create corners for characterization. """
# Get the corners from the options file
@ -607,7 +623,7 @@ class lib:
import math
m = model(self.sram, self.sp_file, self.corner)
char_results = m.get_lib_values(self.slews,self.loads)
char_results = m.get_lib_values(self.load_slews)
else:
self.d = delay(self.sram, self.sp_file, self.corner)
@ -616,7 +632,7 @@ class lib:
else:
probe_address = "0" + "1" * (self.sram.addr_size - 1)
probe_data = self.sram.word_size - 1
char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
char_results = self.d.analyze(probe_address, probe_data, self.load_slews)
self.char_sram_results, self.char_port_results = char_results
def compute_setup_hold(self):
@ -625,7 +641,7 @@ class lib:
if not hasattr(self,"sh"):
self.sh = setup_hold(self.corner)
if self.use_model:
self.times = self.sh.analytical_setuphold(self.slews,self.loads)
self.times = self.sh.analytical_setuphold(self.slews,self.slews)
else:
self.times = self.sh.analyze(self.slews,self.slews)

View File

@ -47,7 +47,7 @@ class regression_model(simulation):
super().__init__(sram, spfile, corner)
self.set_corner(corner)
def get_lib_values(self, slews, loads):
def get_lib_values(self, load_slews):
"""
A model and prediction is created for each output needed for the LIB
"""
@ -71,33 +71,32 @@ class regression_model(simulation):
port_data = self.get_empty_measure_data_dict()
debug.info(1, 'Slew, Load, Port, Delay(ns), Slew(ns)')
max_delay = 0.0
for slew in slews:
for load in loads:
# List returned with value order being delay, power, leakage, slew
sram_vals = self.get_predictions(model_inputs+[slew, load], models)
# Delay is only calculated on a single port and replicated for now.
for port in self.all_ports:
port_data[port]['delay_lh'].append(sram_vals['delay_lh'])
port_data[port]['delay_hl'].append(sram_vals['delay_hl'])
port_data[port]['slew_lh'].append(sram_vals['slew_lh'])
port_data[port]['slew_hl'].append(sram_vals['slew_hl'])
for load, slew in load_slews:
# List returned with value order being delay, power, leakage, slew
sram_vals = self.get_predictions(model_inputs+[slew, load], models)
# Delay is only calculated on a single port and replicated for now.
for port in self.all_ports:
port_data[port]['delay_lh'].append(sram_vals['delay_lh'])
port_data[port]['delay_hl'].append(sram_vals['delay_hl'])
port_data[port]['slew_lh'].append(sram_vals['slew_lh'])
port_data[port]['slew_hl'].append(sram_vals['slew_hl'])
port_data[port]['write1_power'].append(sram_vals['write1_power'])
port_data[port]['write0_power'].append(sram_vals['write0_power'])
port_data[port]['read1_power'].append(sram_vals['read1_power'])
port_data[port]['read0_power'].append(sram_vals['read0_power'])
# Disabled power not modeled. Copied from other power predictions
port_data[port]['disabled_write1_power'].append(sram_vals['write1_power'])
port_data[port]['disabled_write0_power'].append(sram_vals['write0_power'])
port_data[port]['disabled_read1_power'].append(sram_vals['read1_power'])
port_data[port]['disabled_read0_power'].append(sram_vals['read0_power'])
port_data[port]['write1_power'].append(sram_vals['write1_power'])
port_data[port]['write0_power'].append(sram_vals['write0_power'])
port_data[port]['read1_power'].append(sram_vals['read1_power'])
port_data[port]['read0_power'].append(sram_vals['read0_power'])
# Disabled power not modeled. Copied from other power predictions
port_data[port]['disabled_write1_power'].append(sram_vals['write1_power'])
port_data[port]['disabled_write0_power'].append(sram_vals['write0_power'])
port_data[port]['disabled_read1_power'].append(sram_vals['read1_power'])
port_data[port]['disabled_read0_power'].append(sram_vals['read0_power'])
debug.info(1, '{}, {}, {}, {}, {}'.format(slew,
load,
port,
sram_vals['delay_lh'],
sram_vals['slew_lh']))
debug.info(1, '{}, {}, {}, {}, {}'.format(slew,
load,
port,
sram_vals['delay_lh'],
sram_vals['slew_lh']))
# Estimate the period as double the delay with margin
period_margin = 0.1
sram_data = {"min_period": sram_vals['delay_lh'] * 2,

View File

@ -87,6 +87,8 @@ class options(optparse.Values):
use_specified_corners = None
# Allows specification of model data
sim_data_path = None
# A list of load/slew tuples
use_specified_load_slew = None
###################
# Run-time vs accuracy options.