diff --git a/compiler/characterizer/model_check.py b/compiler/characterizer/model_check.py index 94b200bc..03d7982a 100644 --- a/compiler/characterizer/model_check.py +++ b/compiler/characterizer/model_check.py @@ -21,6 +21,11 @@ class model_check(delay): def __init__(self, sram, spfile, corner): delay.__init__(self,sram,spfile,corner) self.period = tech.spice["feasible_period"] + self.create_data_names() + + def create_data_names(self): + self.wl_meas_name, self.wl_model_name = "wl_measures", "wl_model" + self.sae_meas_name, self.sae_model_name = "sae_measures", "sae_model" def create_measurement_names(self): """Create measurement names. The names themselves currently define the type of measurement""" @@ -40,6 +45,16 @@ class model_check(delay): self.rbl_en_signal_names = ["Xsram.Xcontrol0.gated_clk_bar", "Xsram.Xcontrol0.Xand2_rbl_in.zb_int", "Xsram.Xcontrol0.rbl_in", "Xsram.Xcontrol0.Xreplica_bitline.Xdelay_chain.dout_1", "Xsram.Xcontrol0.Xreplica_bitline.delayed_en"] self.sae_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.bl0_0", "Xsram.Xcontrol0.pre_s_en", "Xsram.Xcontrol0.Xbuf_s_en.zb_int", "Xsram.s_en0"] + def get_all_signal_names(self): + """Returns all signals names as a dict indexed by hardcoded names. Useful for writing the head of the CSV.""" + name_dict = {} + #Signal names are more descriptive than the measurement names, first value trimmed to match size of measurements names. + name_dict[self.wl_meas_name] = self.wl_signal_names[1:] + name_dict[self.wl_model_name] = name_dict["wl_measures"] #model uses same names as measured. + name_dict[self.sae_meas_name] = self.rbl_en_signal_names[1:]+self.sae_signal_names[1:] + name_dict[self.sae_model_name] = name_dict["sae_measures"] + return name_dict + def create_measurement_objects(self): """Create the measurements used for read and write ports""" self.create_wordline_measurement_objects() @@ -181,10 +196,10 @@ class model_check(delay): def min_max_normalization(self, value_list): """Re-scales input values on a range from 0-1 where min(list)=0, max(list)=1""" scaled_values = [] - min_val = min(value_list) - min_max_diff = max(value_list) - min_val + min_max_diff = max(value_list) - min(value_list) + average = sum(value_list)/len(value_list) for value in value_list: - scaled_values.append((value-min_val)/(min_max_diff)) + scaled_values.append((value-average)/(min_max_diff)) return scaled_values def calculate_error_l2_norm(self, list_a, list_b): @@ -193,6 +208,15 @@ class model_check(delay): for val_a, val_b in zip(list_a, list_b): error_list.append((val_a-val_b)**2) return error_list + + def compare_measured_and_model(self, measured_vals, model_vals): + """First scales both inputs into similar ranges and then compares the error between both.""" + scaled_meas = self.min_max_normalization(measured_vals) + debug.info(1, "Scaled measurements:\n{}".format(scaled_meas)) + scaled_model = self.min_max_normalization(model_vals) + debug.info(1, "Scaled model:\n{}".format(scaled_model)) + errors = self.calculate_error_l2_norm(scaled_meas, scaled_model) + debug.info(1, "Errors:\n{}\n".format(errors)) def analyze(self, probe_address, probe_data, slews, loads): """Measures entire delay path along the wordline and sense amp enable and compare it to the model delays.""" @@ -200,6 +224,7 @@ class model_check(delay): self.load=max(loads) self.slew=max(slews) self.create_measurement_objects() + data_dict = {} read_port = self.read_ports[0] #only test the first read port self.targ_read_ports = [read_port] @@ -216,14 +241,18 @@ class model_check(delay): debug.info(1,"SAE model delays:\n\t {}".format(sae_model_delays)) debug.info(1,"Measured SAE slews:\n\t {}".format(sae_slews[read_port])) - scaled_wl_meas = self.min_max_normalization(wl_delays[read_port]) - debug.info(1, "Scaled wordline delays:\n{}".format(scaled_wl_meas)) - scaled_wl_model = self.min_max_normalization(wl_model_delays) - debug.info(1, "Scaled wordline model:\n{}".format(scaled_wl_model)) - errors = self.calculate_error_l2_norm(scaled_wl_meas, scaled_wl_model) - debug.info(1, "Model errors:\n{}".format(errors)) + data_dict[self.wl_meas_name] = wl_delays[read_port] + data_dict[self.wl_model_name] = wl_model_delays + data_dict[self.sae_meas_name] = sae_delays[read_port] + data_dict[self.sae_model_name] = sae_model_delays - return wl_delays, sae_delays + #Some evaluations of the model and measured values + debug.info(1, "Comparing wordline measurements and model.") + self.compare_measured_and_model(wl_delays[read_port], wl_model_delays) + debug.info(1, "Comparing SAE measurements and model") + self.compare_measured_and_model(sae_delays[read_port], sae_model_delays) + + return data_dict diff --git a/compiler/tests/28_delay_model_test.py b/compiler/tests/28_delay_model_test.py index 8f9154e0..a02a42e9 100755 --- a/compiler/tests/28_delay_model_test.py +++ b/compiler/tests/28_delay_model_test.py @@ -25,10 +25,11 @@ class delay_model_test(openram_test): from importlib import reload import characterizer reload(characterizer) + from characterizer import model_check from sram import sram from sram_config import sram_config - c = sram_config(word_size=1, + c = sram_config(word_size=4, num_words=16, num_banks=1) c.words_per_row=1 @@ -48,7 +49,7 @@ class delay_model_test(openram_test): import tech loads = [tech.spice["msflop_in_cap"]*4] slews = [tech.spice["rise_time"]*2] - wl_data, sae_data = mc.analyze(probe_address, probe_data, slews, loads) + sram_data = mc.analyze(probe_address, probe_data, slews, loads) #Combine info about port into all data #debug.info(1,"Data:\n{}".format(wl_data))