Cleaned up result tables to be indexed by port and measurement name. Lib has not been updated, so it crashes there.

This commit is contained in:
Hunter Nichols 2018-09-15 01:04:21 -07:00
parent 346b188372
commit ab7d3510b5
1 changed files with 40 additions and 37 deletions

View File

@ -335,8 +335,7 @@ class delay():
starting point. starting point.
""" """
debug.check(port in self.read_ports, "Characterizer requires a read port to determine a period.") debug.check(port in self.read_ports, "Characterizer requires a read port to determine a period.")
#Adding this as a sanity check for editing this function later. This function assumes period has been set previously
debug.check(self.period > 0, "Initial starting period not defined")
feasible_period = float(tech.spice["feasible_period"]) feasible_period = float(tech.spice["feasible_period"])
#feasible_period = float(2.5)#What happens if feasible starting point is wrong? #feasible_period = float(2.5)#What happens if feasible starting point is wrong?
time_out = 9 time_out = 9
@ -361,8 +360,8 @@ class delay():
break break
#Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews #Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews
feasible_delays = [results["{0}{1}".format(mname,port)] for mname in self.delay_meas_names if "delay" in mname] feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname]
feasible_slews = [results["{0}{1}".format(mname,port)] for mname in self.delay_meas_names if "slew" in mname] feasible_slews = [results[port][mname] for mname in self.delay_meas_names if "slew" in mname]
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays) delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays)
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(*feasible_slews) slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(*feasible_slews)
debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period, debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period,
@ -380,11 +379,10 @@ class delay():
Loops through all read ports determining the feasible period and collecting Loops through all read ports determining the feasible period and collecting
delay information from each port. delay information from each port.
""" """
feasible_delays = {}
self.period = float(tech.spice["feasible_period"]) self.period = float(tech.spice["feasible_period"])
#Get initial feasible period from first port #Get initial feasible delays from first port
feasible_delays.update(self.find_feasible_period_one_port(self.read_ports[0])) feasible_delays = self.find_feasible_period_one_port(self.read_ports[0])
previous_period = self.period previous_period = self.period
@ -393,7 +391,7 @@ class delay():
i = 1 i = 1
while i < len(self.read_ports): while i < len(self.read_ports):
port = self.read_ports[i] port = self.read_ports[i]
feasible_delays.update(self.find_feasible_period_one_port(port)) feasible_delays[port].update(self.find_feasible_period_one_port(port))
#Function sets the period. Restart the entire process if period changes to collect accurate delays #Function sets the period. Restart the entire process if period changes to collect accurate delays
if self.period > previous_period: if self.period > previous_period:
i = 0 i = 0
@ -403,13 +401,15 @@ class delay():
return feasible_delays return feasible_delays
def parse_values(self, values_names, mult = 1.0): def parse_values(self, values_names, port, mult = 1.0):
"""Parse multiple values in the timing output file. Optional multiplier.""" """Parse multiple values in the timing output file. Optional multiplier.
Return a dict of the input names and values. Port used for parsing file.
"""
values = [] values = []
all_values_floats = True all_values_floats = True
for vname in values_names: for vname in values_names:
#ngspice converts all measure characters to lowercase, not tested on other sims #ngspice converts all measure characters to lowercase, not tested on other sims
value = parse_spice_list("timing", vname.lower()) value = parse_spice_list("timing", "{0}{1}".format(vname.lower(), port))
#Check if any of the values fail to parse #Check if any of the values fail to parse
if type(value)!=float: if type(value)!=float:
all_values_floats = False all_values_floats = False
@ -428,7 +428,10 @@ class delay():
works on the trimmed netlist by default, so powers do not works on the trimmed netlist by default, so powers do not
include leakage of all cells. include leakage of all cells.
""" """
result = {} #Sanity Check
debug.check(self.period > 0, "Initial starting period not defined")
result = [{} for i in range(self.total_port_num)]
# Checking from not data_value to data_value # Checking from not data_value to data_value
self.write_delay_stimulus() self.write_delay_stimulus()
@ -438,27 +441,28 @@ class delay():
#Too much duplicate code here. Try reducing #Too much duplicate code here. Try reducing
for port in self.targ_read_ports: for port in self.targ_read_ports:
delay_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names] delay_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names]
delays = self.parse_values(delay_names, 1e9) # scale delays to ns delay_names = [mname for mname in self.delay_meas_names]
delays = self.parse_values(delay_names, port, 1e9) # scale delays to ns
if not self.check_valid_delays(tuple(delays.values())): if not self.check_valid_delays(tuple(delays.values())):
return (False,{}) return (False,{})
result.update(delays) result[port].update(delays)
power_names = ["{0}{1}".format(mname,port) for mname in self.power_meas_names if 'read' in mname] power_names = [mname for mname in self.power_meas_names if 'read' in mname]
powers = self.parse_values(power_names, 1e3) # scale power to mw powers = self.parse_values(power_names, port, 1e3) # scale power to mw
#Check that power parsing worked. #Check that power parsing worked.
for name, power in powers.items(): for name, power in powers.items():
if type(power)!=float: if type(power)!=float:
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad. debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad.
result.update(powers) result[port].update(powers)
for port in self.targ_write_ports: for port in self.targ_write_ports:
power_names = ["{0}{1}".format(mname,port) for mname in self.power_meas_names if 'write' in mname] power_names = [mname for mname in self.power_meas_names if 'write' in mname]
powers = self.parse_values(power_names, 1e3) # scale power to mw powers = self.parse_values(power_names, port, 1e3) # scale power to mw
#Check that power parsing worked. #Check that power parsing worked.
for name, power in powers.items(): for name, power in powers.items():
if type(power)!=float: if type(power)!=float:
debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad. debug.error("Failed to Parse Power Values:\n\t\t{0}".format(powers),1) #Printing the entire dict looks bad.
result.update(powers) result[port].update(powers)
# The delay is from the negative edge for our SRAM # The delay is from the negative edge for our SRAM
return (True,result) return (True,result)
@ -589,16 +593,16 @@ class delay():
#Check the values of target readwrite and read ports. Write ports do not produce delays in this current version #Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
for port in self.targ_read_ports: for port in self.targ_read_ports:
delay_port_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names if "delay" in mname] delay_port_names = [mname for mname in self.delay_meas_names if "delay" in mname]
for dname in delay_port_names: for dname in delay_port_names:
if not relative_compare(results[dname],feasible_delays[dname],error_tolerance=0.05): if not relative_compare(results[port][dname],feasible_delays[port][dname],error_tolerance=0.05):
debug.info(2,"Delay too big {0} vs {1}".format(results[dname],feasible_delays[dname])) debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname]))
return False return False
#key=raw_input("press return to continue") #key=raw_input("press return to continue")
#Dynamic way to build string. A bit messy though. #Dynamic way to build string. A bit messy though.
delay_str = ', '.join("{0}={1}ns".format(mname, results["{0}{1}".format(mname,port)]) for mname in self.delay_meas_names) delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names)
debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period, debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
delay_str, delay_str,
port)) port))
@ -671,9 +675,6 @@ class delay():
# 1) Find a feasible period and it's corresponding delays using the trimmed array. # 1) Find a feasible period and it's corresponding delays using the trimmed array.
feasible_delays = self.find_feasible_period() feasible_delays = self.find_feasible_period()
#Check all the delays
for k,v in feasible_delays.items():
debug.check(v>0,"Negative delay may not be possible: {0}={1}".format(k,v))
# 2) Finds the minimum period without degrading the delays by X% # 2) Finds the minimum period without degrading the delays by X%
self.set_load_slew(max(loads),max(slews)) self.set_load_slew(max(loads),max(slews))
@ -689,9 +690,9 @@ class delay():
# 4) At the minimum period, measure the delay, slew and power for all slew/load pairs. # 4) At the minimum period, measure the delay, slew and power for all slew/load pairs.
load_slew_data = self.simulate_loads_and_slews(slews, loads, leakage_offset) load_slew_data = self.simulate_loads_and_slews(slews, loads, leakage_offset)
char_data.update(load_slew_data) #char_data.update(load_slew_data)
return char_data return (char_data, load_slew_data)
def simulate_loads_and_slews(self, slews, loads, leakage_offset): def simulate_loads_and_slews(self, slews, loads, leakage_offset):
"""Simulate all specified output loads and input slews pairs of all ports""" """Simulate all specified output loads and input slews pairs of all ports"""
@ -706,12 +707,14 @@ class delay():
(success, delay_results) = self.run_delay_simulation() (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.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load))
debug.info(1, "Successful simulation on all ports. slew={0} load={1}".format(self.slew,self.load)) debug.info(1, "Successful simulation on all ports. slew={0} load={1}".format(self.slew,self.load))
for mname,value in delay_results.items(): #The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
if "power" in mname: for port in range(self.total_port_num):
# Subtract partial array leakage and add full array leakage for the power measures for mname,value in delay_results[port].items():
measure_data[mname].append(value + leakage_offset) if "power" in mname:
else: # Subtract partial array leakage and add full array leakage for the power measures
measure_data[mname].append(value) measure_data[port][mname].append(value + leakage_offset)
else:
measure_data[port][mname].append(value)
return measure_data return measure_data
def add_data(self, data, port): def add_data(self, data, port):
@ -1041,6 +1044,6 @@ class delay():
def get_empty_measure_data_dict(self): def get_empty_measure_data_dict(self):
"""Make a dict of lists for each type of delay and power measurement to append results to""" """Make a dict of lists for each type of delay and power measurement to append results to"""
measure_names = self.delay_meas_names + self.power_meas_names measure_names = self.delay_meas_names + self.power_meas_names
#Create dict of lists of size #measure_names x total_port_num. Some lists are never used. #Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
measure_data = {"{0}{1}".format(nmame,port):[] for nmame in measure_names for port in range(self.total_port_num)} measure_data = [{mname:[] for mname in measure_names} for i in range(self.total_port_num)]
return measure_data return measure_data