mirror of https://github.com/VLSIDA/OpenRAM.git
Improved on some hard coded values which determine the measurements.
This commit is contained in:
parent
cfe15d48a4
commit
346b188372
|
|
@ -48,8 +48,8 @@ class delay():
|
||||||
self.set_corner(corner)
|
self.set_corner(corner)
|
||||||
self.create_port_names()
|
self.create_port_names()
|
||||||
|
|
||||||
#Create global measure names. May be an input at some point. Altering the name here will not affect functionality.
|
#Create global measure names. May be an input at some point.
|
||||||
#Removing names will cause program to crash. TODO: This caused me to hardcode indices, fix this to be more dynamic/readable.
|
#Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
|
||||||
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
||||||
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
|
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
|
||||||
|
|
||||||
|
|
@ -209,81 +209,91 @@ class delay():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Trigger on the clk of the appropriate cycle
|
# Trigger on the clk of the appropriate cycle
|
||||||
trig_name = "clk"
|
trig_clk_name = trig_name = "clk"
|
||||||
#Target name should be an input to the function or a member variable. That way, the ports can be singled out for testing
|
#Target name should be an input to the function or a member variable. That way, the ports can be singled out for testing
|
||||||
targ_name = "{0}".format("DOUT{0}[{1}]".format(port,self.probe_data))
|
targ_name = "{0}".format("DOUT{0}[{1}]".format(port,self.probe_data))
|
||||||
trig_val = targ_val = 0.5 * self.vdd_voltage
|
trig_val = targ_val = 0.5 * self.vdd_voltage
|
||||||
|
trig_delay_val = targ_delay_val = 0.5 * self.vdd_voltage
|
||||||
|
trig_slew_low = 0.1 * self.vdd_voltage
|
||||||
|
targ_slew_high = 0.9 * self.vdd_voltage
|
||||||
|
trig_dir = "FALL"
|
||||||
|
targ_dir = "RISE"
|
||||||
|
trig_td = targ_td = 0
|
||||||
|
parse_error = False
|
||||||
|
|
||||||
# Delay the target to measure after the negative edge
|
# Delay the target to measure after the negative edge
|
||||||
self.stim.gen_meas_delay(meas_name="{0}{1}".format(self.delay_meas_names[1], port),
|
for dname in self.delay_meas_names:
|
||||||
trig_name=trig_name,
|
if 'delay' in dname:
|
||||||
targ_name=targ_name,
|
trig_dir="RISE"
|
||||||
trig_val=trig_val,
|
trig_val = trig_delay_val
|
||||||
targ_val=targ_val,
|
targ_val = targ_val
|
||||||
trig_dir="RISE",
|
trig_name = trig_clk_name
|
||||||
targ_dir="FALL",
|
if 'lh' in dname:
|
||||||
trig_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]],
|
targ_dir="RISE"
|
||||||
targ_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]])
|
else:
|
||||||
|
targ_dir="FALL"
|
||||||
self.stim.gen_meas_delay(meas_name="{0}{1}".format(self.delay_meas_names[0], port),
|
|
||||||
trig_name=trig_name,
|
elif 'slew' in dname:
|
||||||
targ_name=targ_name,
|
trig_name = targ_name
|
||||||
trig_val=trig_val,
|
if 'lh' in dname:
|
||||||
targ_val=targ_val,
|
trig_val = trig_slew_low
|
||||||
trig_dir="RISE",
|
targ_val = targ_slew_high
|
||||||
targ_dir="RISE",
|
targ_dir = trig_dir = "RISE"
|
||||||
trig_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]],
|
else:
|
||||||
targ_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]])
|
trig_val = targ_slew_high
|
||||||
|
targ_val = trig_slew_low
|
||||||
self.stim.gen_meas_delay(meas_name="{0}{1}".format(self.delay_meas_names[3], port),
|
targ_dir = trig_dir = "FALL"
|
||||||
trig_name=targ_name,
|
else:
|
||||||
targ_name=targ_name,
|
debug.error(1, "Measure command {0} not recognized".format(dname))
|
||||||
trig_val=0.9*self.vdd_voltage,
|
|
||||||
targ_val=0.1*self.vdd_voltage,
|
if 'lh' in dname:
|
||||||
trig_dir="FALL",
|
trig_td = targ_td = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
|
||||||
targ_dir="FALL",
|
elif 'hl' in dname:
|
||||||
trig_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]],
|
trig_td = targ_td = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
|
||||||
targ_td=self.cycle_times[self.measure_cycles["read0_{0}".format(port)]])
|
else:
|
||||||
|
debug.error(1, "Measure command {0} does not contain direction (lh/hl)".format(dname))
|
||||||
self.stim.gen_meas_delay(meas_name="{0}{1}".format(self.delay_meas_names[2], port),
|
|
||||||
trig_name=targ_name,
|
self.stim.gen_meas_delay(meas_name="{0}{1}".format(dname, port),
|
||||||
targ_name=targ_name,
|
trig_name=trig_name,
|
||||||
trig_val=0.1*self.vdd_voltage,
|
targ_name=targ_name,
|
||||||
targ_val=0.9*self.vdd_voltage,
|
trig_val=trig_val,
|
||||||
trig_dir="RISE",
|
targ_val=targ_val,
|
||||||
targ_dir="RISE",
|
trig_dir=trig_dir,
|
||||||
trig_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]],
|
targ_dir=targ_dir,
|
||||||
targ_td=self.cycle_times[self.measure_cycles["read1_{0}".format(port)]])
|
trig_td=trig_td,
|
||||||
|
targ_td=targ_td)
|
||||||
|
|
||||||
# add measure statements for power
|
# add measure statements for power
|
||||||
t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
|
for pname in self.power_meas_names:
|
||||||
t_final = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]+1]
|
if "read" not in pname:
|
||||||
self.stim.gen_meas_power(meas_name="{0}{1}".format(self.power_meas_names[0], port),
|
continue
|
||||||
t_initial=t_initial,
|
t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]]
|
||||||
t_final=t_final)
|
t_final = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]+1]
|
||||||
|
if '1' in pname:
|
||||||
t_initial = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
|
t_initial = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]]
|
||||||
t_final = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]+1]
|
t_final = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]+1]
|
||||||
self.stim.gen_meas_power(meas_name="{0}{1}".format(self.power_meas_names[1], port),
|
|
||||||
t_initial=t_initial,
|
|
||||||
t_final=t_final)
|
|
||||||
|
|
||||||
|
self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
|
||||||
|
t_initial=t_initial,
|
||||||
|
t_final=t_final)
|
||||||
|
|
||||||
def write_delay_measures_write_port(self, port):
|
def write_delay_measures_write_port(self, port):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the power results for a write port.
|
Write the measure statements to quantify the power results for a write port.
|
||||||
"""
|
"""
|
||||||
# add measure statements for power
|
# add measure statements for power
|
||||||
t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]]
|
for pname in self.power_meas_names:
|
||||||
t_final = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]+1]
|
if "write" not in pname:
|
||||||
self.stim.gen_meas_power(meas_name="{0}{1}".format(self.power_meas_names[2], port),
|
continue
|
||||||
t_initial=t_initial,
|
t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]]
|
||||||
t_final=t_final)
|
t_final = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]+1]
|
||||||
|
if '1' in pname:
|
||||||
t_initial = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]]
|
t_initial = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]]
|
||||||
t_final = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]+1]
|
t_final = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]+1]
|
||||||
self.stim.gen_meas_power(meas_name="{0}{1}".format(self.power_meas_names[3], port),
|
|
||||||
t_initial=t_initial,
|
self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port),
|
||||||
t_final=t_final)
|
t_initial=t_initial,
|
||||||
|
t_final=t_final)
|
||||||
|
|
||||||
def write_delay_measures(self):
|
def write_delay_measures(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -351,10 +361,10 @@ 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_delay_measures = [results["{0}{1}".format(mname,port)] for mname in self.delay_meas_names]
|
feasible_delays = [results["{0}{1}".format(mname,port)] 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]
|
||||||
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(feasible_delay_measures[0], feasible_delay_measures[1])
|
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays)
|
||||||
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(feasible_delay_measures[2], feasible_delay_measures[3])
|
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,
|
||||||
delay_str,
|
delay_str,
|
||||||
slew_str,
|
slew_str,
|
||||||
|
|
@ -363,19 +373,18 @@ class delay():
|
||||||
if success:
|
if success:
|
||||||
debug.info(1, "Found feasible_period: {0}ns".format(feasible_period))
|
debug.info(1, "Found feasible_period: {0}ns".format(feasible_period))
|
||||||
self.period = feasible_period
|
self.period = feasible_period
|
||||||
return (feasible_delay_measures[0], feasible_delay_measures[1])
|
return results
|
||||||
|
|
||||||
def find_feasible_period(self):
|
def find_feasible_period(self):
|
||||||
"""
|
"""
|
||||||
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_lh = {}
|
feasible_delays = {}
|
||||||
feasible_delays_hl = {}
|
|
||||||
self.period = float(tech.spice["feasible_period"])
|
self.period = float(tech.spice["feasible_period"])
|
||||||
|
|
||||||
#Get initial feasible period from first port
|
#Get initial feasible period from first port
|
||||||
(feasible_delays_lh[0], feasible_delays_hl[0]) = self.find_feasible_period_one_port(self.read_ports[0])
|
feasible_delays.update(self.find_feasible_period_one_port(self.read_ports[0]))
|
||||||
previous_period = self.period
|
previous_period = self.period
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -384,14 +393,14 @@ 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_lh[port], feasible_delays_hl[port]) = self.find_feasible_period_one_port(port)
|
feasible_delays.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
|
||||||
else:
|
else:
|
||||||
i+=1
|
i+=1
|
||||||
previous_period = self.period
|
previous_period = self.period
|
||||||
return (feasible_delays_lh, feasible_delays_hl)
|
return feasible_delays
|
||||||
|
|
||||||
|
|
||||||
def parse_values(self, values_names, mult = 1.0):
|
def parse_values(self, values_names, mult = 1.0):
|
||||||
|
|
@ -430,11 +439,11 @@ class delay():
|
||||||
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
|
delays = self.parse_values(delay_names, 1e9) # scale delays to ns
|
||||||
if not self.check_valid_delays((delays[delay_names[0]],delays[delay_names[1]],delays[delay_names[2]],delays[delay_names[3]])):
|
if not self.check_valid_delays(tuple(delays.values())):
|
||||||
return (False,{})
|
return (False,{})
|
||||||
result.update(delays)
|
result.update(delays)
|
||||||
|
|
||||||
power_names = ["{0}{1}".format(mname,port) for mname in self.power_meas_names[:2]]
|
power_names = ["{0}{1}".format(mname,port) 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, 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():
|
||||||
|
|
@ -443,7 +452,7 @@ class delay():
|
||||||
result.update(powers)
|
result.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[2:]]
|
power_names = ["{0}{1}".format(mname,port) 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, 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():
|
||||||
|
|
@ -508,7 +517,7 @@ class delay():
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def find_min_period(self, feasible_delays_lh, feasible_delays_hl):
|
def find_min_period(self, feasible_delays):
|
||||||
"""
|
"""
|
||||||
Determine the minimum period for all ports.
|
Determine the minimum period for all ports.
|
||||||
"""
|
"""
|
||||||
|
|
@ -520,7 +529,7 @@ class delay():
|
||||||
#Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position.
|
#Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position.
|
||||||
#For testing purposes, only checks read ports.
|
#For testing purposes, only checks read ports.
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
target_period = self.find_min_period_one_port(feasible_delays_lh, feasible_delays_hl, port, lb_period, ub_period, target_period)
|
target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period)
|
||||||
#The min period of one port becomes the new lower bound. Reset the upper_bound.
|
#The min period of one port becomes the new lower bound. Reset the upper_bound.
|
||||||
lb_period = target_period
|
lb_period = target_period
|
||||||
ub_period = feasible_period
|
ub_period = feasible_period
|
||||||
|
|
@ -530,7 +539,7 @@ class delay():
|
||||||
self.targ_write_ports = []
|
self.targ_write_ports = []
|
||||||
return target_period
|
return target_period
|
||||||
|
|
||||||
def find_min_period_one_port(self, feasible_delays_lh, feasible_delays_hl, port, lb_period, ub_period, target_period):
|
def find_min_period_one_port(self, feasible_delays, port, lb_period, ub_period, target_period):
|
||||||
"""
|
"""
|
||||||
Searches for the smallest period with output delays being within 5% of
|
Searches for the smallest period with output delays being within 5% of
|
||||||
long period. For the current logic to characterize multiport, bound are required as an input.
|
long period. For the current logic to characterize multiport, bound are required as an input.
|
||||||
|
|
@ -555,24 +564,20 @@ class delay():
|
||||||
lb_period,
|
lb_period,
|
||||||
port))
|
port))
|
||||||
|
|
||||||
if self.try_period(feasible_delays_lh, feasible_delays_hl):
|
if self.try_period(feasible_delays):
|
||||||
ub_period = target_period
|
ub_period = target_period
|
||||||
else:
|
else:
|
||||||
lb_period = target_period
|
lb_period = target_period
|
||||||
|
|
||||||
if relative_compare(ub_period, lb_period, error_tolerance=0.05):
|
if relative_compare(ub_period, lb_period, error_tolerance=0.05):
|
||||||
# ub_period is always feasible. When done with a port, set the target period of the next port as the lower bound
|
# ub_period is always feasible.
|
||||||
# and reset the upperbound
|
|
||||||
return ub_period
|
return ub_period
|
||||||
#target_period = lb_period = ub_period
|
|
||||||
#ub_period = previous_period
|
|
||||||
#break
|
|
||||||
|
|
||||||
#Update target
|
#Update target
|
||||||
target_period = 0.5 * (ub_period + lb_period)
|
target_period = 0.5 * (ub_period + lb_period)
|
||||||
|
|
||||||
|
|
||||||
def try_period(self, feasible_delays_lh, feasible_delays_hl):
|
def try_period(self, feasible_delays):
|
||||||
"""
|
"""
|
||||||
This tries to simulate a period and checks if the result
|
This tries to simulate a period and checks if the result
|
||||||
works. If it does and the delay is within 5% still, it returns True.
|
works. If it does and the delay is within 5% still, it returns True.
|
||||||
|
|
@ -583,25 +588,20 @@ class delay():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
#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:
|
||||||
#Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews
|
delay_port_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names if "delay" in mname]
|
||||||
delay_measures = [results["{0}{1}".format(mname,port)] for mname in self.delay_meas_names]
|
for dname in delay_port_names:
|
||||||
|
if not relative_compare(results[dname],feasible_delays[dname],error_tolerance=0.05):
|
||||||
if not relative_compare(delay_measures[0],feasible_delays_lh[port],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(delay_measures[0],feasible_delays_lh[port]))
|
return False
|
||||||
return False
|
|
||||||
elif not relative_compare(delay_measures[1],feasible_delays_hl[port],error_tolerance=0.05):
|
|
||||||
debug.info(2,"Delay too big {0} vs {1}".format(delay_measures[1],feasible_delays_hl[port]))
|
|
||||||
return False
|
|
||||||
|
|
||||||
#key=raw_input("press return to continue")
|
#key=raw_input("press return to continue")
|
||||||
|
|
||||||
debug.info(2,"Successful period {0}, Port {5}, delay_lh={1}ns, delay_hl={2}ns, slew_lh={3}ns slew_hl={4}ns".format(self.period,
|
#Dynamic way to build string. A bit messy though.
|
||||||
delay_measures[0],
|
delay_str = ', '.join("{0}={1}ns".format(mname, results["{0}{1}".format(mname,port)]) for mname in self.delay_meas_names)
|
||||||
delay_measures[1],
|
debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
|
||||||
delay_measures[2],
|
delay_str,
|
||||||
delay_measures[3],
|
port))
|
||||||
port))
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_probe(self,probe_address, probe_data):
|
def set_probe(self,probe_address, probe_data):
|
||||||
|
|
@ -670,17 +670,14 @@ class delay():
|
||||||
# return char_data
|
# return char_data
|
||||||
|
|
||||||
# 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_lh, feasible_delays_hl) = self.find_feasible_period()
|
feasible_delays = self.find_feasible_period()
|
||||||
#Check all the delays
|
#Check all the delays
|
||||||
for k,v in feasible_delays_lh.items():
|
for k,v in feasible_delays.items():
|
||||||
debug.check(v>0,"Negative delay may not be possible")
|
debug.check(v>0,"Negative delay may not be possible: {0}={1}".format(k,v))
|
||||||
for k,v in feasible_delays_hl.items():
|
|
||||||
debug.check(v>0,"Negative delay may not be possible")
|
|
||||||
|
|
||||||
|
|
||||||
# 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))
|
||||||
min_period = self.find_min_period(feasible_delays_lh, feasible_delays_hl)
|
min_period = self.find_min_period(feasible_delays)
|
||||||
debug.check(type(min_period)==float,"Couldn't find minimum period.")
|
debug.check(type(min_period)==float,"Couldn't find minimum period.")
|
||||||
debug.info(1, "Min Period Found: {0}ns".format(min_period))
|
debug.info(1, "Min Period Found: {0}ns".format(min_period))
|
||||||
char_data["min_period"] = round_time(min_period)
|
char_data["min_period"] = round_time(min_period)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue