diff --git a/compiler/characterizer/model_check.py b/compiler/characterizer/model_check.py index a12117d3..94b200bc 100644 --- a/compiler/characterizer/model_check.py +++ b/compiler/characterizer/model_check.py @@ -164,6 +164,36 @@ class model_check(delay): """Get model delays based on port. Currently assumes single RW port.""" return self.sram.control_logic_rw.get_wl_sen_delays() + def scale_delays(self, delay_list): + """Takes in a list of measured delays and convert it to simple units to easily compare to model values.""" + converted_values = [] + #Calculate average + total = 0 + for meas_value in delay_list: + total+=meas_value + average = total/len(delay_list) + + #Convert values + for meas_value in delay_list: + converted_values.append(meas_value/average) + return converted_values + + 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 + for value in value_list: + scaled_values.append((value-min_val)/(min_max_diff)) + return scaled_values + + def calculate_error_l2_norm(self, list_a, list_b): + """Calculates error between two lists using the l2 norm""" + error_list = [] + for val_a, val_b in zip(list_a, list_b): + error_list.append((val_a-val_b)**2) + return error_list + 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.""" self.set_probe(probe_address, probe_data) @@ -186,6 +216,13 @@ 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)) + return wl_delays, sae_delays diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 26735870..8be7152c 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -49,9 +49,7 @@ class timing_sram_test(openram_test): data, port_data = d.analyze(probe_address, probe_data, slews, loads) #Combine info about port into all data data.update(port_data[0]) - - print(data) - + if OPTS.tech_name == "freepdk45": golden_data = {'delay_hl': [0.2011], 'delay_lh': [0.2011], diff --git a/compiler/tests/28_delay_model_test.py b/compiler/tests/28_delay_model_test.py index 74ad22f3..8f9154e0 100755 --- a/compiler/tests/28_delay_model_test.py +++ b/compiler/tests/28_delay_model_test.py @@ -18,6 +18,8 @@ class delay_model_test(openram_test): OPTS.spice_name="hspice" OPTS.analytical_delay = False OPTS.netlist_only = True + OPTS.trim_netlist = False + debug.info(1, "Trimming disabled for this test. Simulation could be slow.") # This is a hack to reload the characterizer __init__ with the spice version from importlib import reload diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index 6b2a7dcf..74d97960 100755 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -62,6 +62,7 @@ class openram_test(unittest.TestCase): delay_obj.set_load_slew(load, slew) delay_obj.set_probe(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1)) test_port = delay_obj.read_ports[0] #Only test one port, assumes other ports have similar period. + delay_obj.create_measurement_objects() delay_obj.find_feasible_period_one_port(test_port) return delay_obj.period