mirror of https://github.com/VLSIDA/OpenRAM.git
Added similar interface to linear regression as elmore
This commit is contained in:
parent
0adcf8935f
commit
25544c3974
|
|
@ -510,7 +510,7 @@ class delay(simulation):
|
|||
elif delay_obj.meta_str == sram_op.READ_ONE:
|
||||
meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]]
|
||||
else:
|
||||
debug.error("Unrecognised delay Index={}".format(delay_obj.meta_str),1)
|
||||
debug.error("Unrecognized delay Index={}".format(delay_obj.meta_str),1)
|
||||
|
||||
# These measurements have there time further delayed to the neg. edge of the clock.
|
||||
if delay_obj.meta_add_delay:
|
||||
|
|
@ -1270,80 +1270,6 @@ class delay(simulation):
|
|||
# Add test cycle of read/write port pair. One port could have been used already, but the other has not.
|
||||
self.gen_test_cycles_one_port(cur_read_port, cur_write_port)
|
||||
|
||||
def analytical_delay(self, slews, loads):
|
||||
"""
|
||||
Return the analytical model results for the SRAM.
|
||||
"""
|
||||
if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0:
|
||||
debug.warning("In analytical mode, all ports have the timing of the first read port.")
|
||||
|
||||
# Probe set to 0th bit, does not matter for analytical delay.
|
||||
self.set_probe('0' * self.addr_size, 0)
|
||||
self.create_graph()
|
||||
self.set_internal_spice_names()
|
||||
self.create_measurement_names()
|
||||
|
||||
port = self.read_ports[0]
|
||||
self.graph.get_all_paths('{}{}'.format("clk", port),
|
||||
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
||||
|
||||
# Select the path with the bitline (bl)
|
||||
bl_name, br_name = self.get_bl_name(self.graph.all_paths, port)
|
||||
bl_path = [path for path in self.graph.all_paths if bl_name in path][0]
|
||||
|
||||
# Set delay/power for slews and loads
|
||||
port_data = self.get_empty_measure_data_dict()
|
||||
power = self.analytical_power(slews, loads)
|
||||
debug.info(1, 'Slew, Load, Delay(ns), Slew(ns)')
|
||||
max_delay = 0.0
|
||||
for slew in slews:
|
||||
for load in loads:
|
||||
# Calculate delay based on slew and load
|
||||
path_delays = self.graph.get_timing(bl_path, self.corner, slew, load)
|
||||
|
||||
total_delay = self.sum_delays(path_delays)
|
||||
max_delay = max(max_delay, total_delay.delay)
|
||||
debug.info(1,
|
||||
'{}, {}, {}, {}'.format(slew,
|
||||
load,
|
||||
total_delay.delay / 1e3,
|
||||
total_delay.slew / 1e3))
|
||||
|
||||
# Delay is only calculated on a single port and replicated for now.
|
||||
for port in self.all_ports:
|
||||
for mname in self.delay_meas_names + self.power_meas_names:
|
||||
if "power" in mname:
|
||||
port_data[port][mname].append(power.dynamic)
|
||||
elif "delay" in mname and port in self.read_ports:
|
||||
port_data[port][mname].append(total_delay.delay / 1e3)
|
||||
elif "slew" in mname and port in self.read_ports:
|
||||
port_data[port][mname].append(total_delay.slew / 1e3)
|
||||
else:
|
||||
debug.error("Measurement name not recognized: {}".format(mname), 1)
|
||||
|
||||
# Estimate the period as double the delay with margin
|
||||
period_margin = 0.1
|
||||
sram_data = {"min_period": (max_delay / 1e3) * 2 * period_margin,
|
||||
"leakage_power": power.leakage}
|
||||
|
||||
debug.info(2, "SRAM Data:\n{}".format(sram_data))
|
||||
debug.info(2, "Port Data:\n{}".format(port_data))
|
||||
|
||||
return (sram_data, port_data)
|
||||
|
||||
def analytical_power(self, slews, loads):
|
||||
"""Get the dynamic and leakage power from the SRAM"""
|
||||
|
||||
# slews unused, only last load is used
|
||||
load = loads[-1]
|
||||
power = self.sram.analytical_power(self.corner, load)
|
||||
# convert from nW to mW
|
||||
power.dynamic /= 1e6
|
||||
power.leakage /= 1e6
|
||||
debug.info(1, "Dynamic Power: {0} mW".format(power.dynamic))
|
||||
debug.info(1, "Leakage Power: {0} mW".format(power.leakage))
|
||||
return power
|
||||
|
||||
def gen_data(self):
|
||||
""" Generates the PWL data inputs for a simulation timing test. """
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class elmore(simulation):
|
|||
self.create_signal_names()
|
||||
self.add_graph_exclusions()
|
||||
|
||||
def analytical_delay(self, slews, loads):
|
||||
def get_lib_values(self, slews, loads):
|
||||
"""
|
||||
Return the analytical model results for the SRAM.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -591,20 +591,10 @@ class lib:
|
|||
else:
|
||||
debug.error("{} model not recognized. See options.py for available models.".format(OPTS.model_name))
|
||||
import math
|
||||
#FIXME: ML models only designed for delay. Cannot produce all values for Lib
|
||||
m = model()
|
||||
#temp_wpr = 2.0 #OPTS not working right now
|
||||
log_num_words = math.log(OPTS.num_words, 2)
|
||||
debug.info(1, "OPTS.words_per_row={}".format(OPTS.words_per_row))
|
||||
model_inputs = [log_num_words,
|
||||
OPTS.word_size,
|
||||
OPTS.words_per_row,
|
||||
self.sram.width * self.sram.height]
|
||||
char_results = m.get_predictions(model_inputs)
|
||||
|
||||
#self.d = elmore(self.sram, self.sp_file, self.corner)
|
||||
# char_results = self.d.analytical_delay(self.slews,self.loads)
|
||||
# self.char_sram_results, self.char_port_results = char_results
|
||||
|
||||
m = model(self.sram, self.sp_file, self.corner)
|
||||
char_results = m.get_lib_values(self.slews,self.loads)
|
||||
|
||||
else:
|
||||
self.d = delay(self.sram, self.sp_file, self.corner)
|
||||
if (self.sram.num_spare_rows == 0):
|
||||
|
|
@ -613,7 +603,7 @@ class lib:
|
|||
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)
|
||||
self.char_sram_results, self.char_port_results = char_results
|
||||
self.char_sram_results, self.char_port_results = char_results
|
||||
|
||||
def compute_setup_hold(self):
|
||||
""" Do the analysis if we haven't characterized a FF yet """
|
||||
|
|
|
|||
|
|
@ -6,32 +6,100 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
|
||||
import os
|
||||
from sklearn.linear_model import LinearRegression
|
||||
from .analytical_util import *
|
||||
from .simulation import simulation
|
||||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
import os
|
||||
from sklearn.linear_model import LinearRegression
|
||||
import math
|
||||
|
||||
relative_data_path = "/sim_data"
|
||||
delay_data_filename = "data.csv"
|
||||
power_data_filename = "power_data.csv"
|
||||
data_fnames = ["delay_data.csv",
|
||||
"power_data.csv",
|
||||
"leakage_data.csv",
|
||||
"slew_data.csv"]
|
||||
tech_path = os.environ.get('OPENRAM_TECH')
|
||||
data_dir = tech_path+'/'+OPTS.tech_name+relative_data_path
|
||||
data_paths = [data_dir +'/'+fname for fname in data_fnames]
|
||||
|
||||
class linear_regression():
|
||||
class linear_regression(simulation):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, sram, spfile, corner):
|
||||
super().__init__(sram, spfile, corner)
|
||||
self.set_corner(corner)
|
||||
self.create_signal_names()
|
||||
self.add_graph_exclusions()
|
||||
self.delay_model = None
|
||||
self.slew_model = None
|
||||
self.power_model = None
|
||||
self.leakage_model = None
|
||||
|
||||
def get_lib_values(self, slews, loads):
|
||||
"""
|
||||
A model and prediction is created for each output needed for the LIB
|
||||
"""
|
||||
|
||||
log_num_words = math.log(OPTS.num_words, 2)
|
||||
debug.info(1, "OPTS.words_per_row={}".format(OPTS.words_per_row))
|
||||
model_inputs = [log_num_words,
|
||||
OPTS.word_size,
|
||||
OPTS.words_per_row,
|
||||
self.sram.width * self.sram.height]
|
||||
|
||||
# List returned with value order being delay, power, leakage, slew
|
||||
# FIXME: make order less hard coded
|
||||
sram_vals = self.get_predictions(model_inputs)
|
||||
|
||||
self.create_measurement_names()
|
||||
|
||||
|
||||
# Set delay/power for slews and loads
|
||||
port_data = self.get_empty_measure_data_dict()
|
||||
debug.info(1, 'Slew, Load, Delay(ns), Slew(ns)')
|
||||
max_delay = 0.0
|
||||
for slew in slews:
|
||||
for load in loads:
|
||||
# Calculate delay based on slew and load
|
||||
debug.info(1,
|
||||
'{}, {}, {}, {}'.format(slew,
|
||||
load,
|
||||
total_delay.delay / 1e3,
|
||||
total_delay.slew / 1e3))
|
||||
|
||||
# Delay is only calculated on a single port and replicated for now.
|
||||
for port in self.all_ports:
|
||||
for mname in self.delay_meas_names + self.power_meas_names:
|
||||
#FIXME: fix magic for indexing the data
|
||||
if "power" in mname:
|
||||
port_data[port][mname].append(sram_vals[1])
|
||||
elif "delay" in mname and port in self.read_ports:
|
||||
port_data[port][mname].append(sram_vals[0])
|
||||
elif "slew" in mname and port in self.read_ports:
|
||||
port_data[port][mname].append(sram_vals[3])
|
||||
else:
|
||||
debug.error("Measurement name not recognized: {}".format(mname), 1)
|
||||
|
||||
# Estimate the period as double the delay with margin
|
||||
period_margin = 0.1
|
||||
sram_data = {"min_period": sram_vals[0] * 2,
|
||||
"leakage_power": sram_vals[2]}
|
||||
|
||||
debug.info(2, "SRAM Data:\n{}".format(sram_data))
|
||||
debug.info(2, "Port Data:\n{}".format(port_data))
|
||||
|
||||
return (sram_data, port_data)
|
||||
|
||||
def get_predictions(self, model_inputs):
|
||||
"""
|
||||
Generate a model and prediction for LIB output
|
||||
"""
|
||||
|
||||
delay_file_path = data_dir +'/'+delay_data_filename
|
||||
power_file_path = data_dir +'/'+power_data_filename
|
||||
scaled_inputs = np.asarray([scale_input_datapoint(model_inputs, delay_file_path)])
|
||||
scaled_inputs = np.asarray([scale_input_datapoint(model_inputs, data_paths[0])])
|
||||
|
||||
predictions = []
|
||||
for path, model in zip([delay_file_path, power_file_path], [self.delay_model, self.power_model]):
|
||||
for path in data_paths:
|
||||
features, labels = get_scaled_data(path)
|
||||
model = self.generate_model(features, labels)
|
||||
scaled_pred = self.model_prediction(model, scaled_inputs)
|
||||
|
|
|
|||
Loading…
Reference in New Issue