diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index e2d7e1d2..88f0de9e 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -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): diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 8668d3cd..65e13465 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -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) diff --git a/compiler/characterizer/regression_model.py b/compiler/characterizer/regression_model.py index 912da6fb..c77671e5 100644 --- a/compiler/characterizer/regression_model.py +++ b/compiler/characterizer/regression_model.py @@ -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, diff --git a/compiler/options.py b/compiler/options.py index 4c04cdb0..a9212b01 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -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.