Edited find_feasible period to use dynamic naming on its measured values and edited the algorithm to work with multiport.

This commit is contained in:
Hunter Nichols 2018-08-30 00:11:14 -07:00
parent 02cf51d3be
commit 78be724867
1 changed files with 64 additions and 51 deletions

View File

@ -64,11 +64,11 @@ class delay():
debug.error("Given probe_data is not an integer to specify a data bit",1)
#Adding port options here which the characterizer cannot handle. Some may be added later like ROM
if OPTS.rw_ports == 0 and OPTS.w_ports == 0 and OPTS.r_ports == 0:
debug.error("Given port options cannot be characterized.",1)
if OPTS.rw_ports == 0 and OPTS.r_ports == 0:
if len(self.targ_readwrite_ports) == 0 and len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0:
debug.error("No ports selected for characterization.",1)
if len(self.targ_readwrite_ports) == 0 and len(self.targ_read_ports) == 0:
debug.error("Characterizer does not currently support SRAMs without read ports.",1)
if OPTS.rw_ports == 0 and OPTS.w_ports == 0:
if len(self.targ_readwrite_ports) == 0 and len(self.targ_write_ports) == 0:
debug.error("Characterizer does not currently support SRAMs without write ports.",1)
def write_generic_stimulus(self):
@ -334,36 +334,55 @@ class delay():
feasible_period = float(tech.spice["feasible_period"])
#feasible_period = float(2.5)#What happens if feasible starting point is wrong?
time_out = 8
time_out = 9
while True:
debug.info(1, "Trying feasible period: {0}ns".format(feasible_period))
time_out -= 1
if (time_out <= 0):
debug.error("Timed out, could not find a feasible period.",2)
self.period = feasible_period
(success, results)=self.run_delay_simulation()
if not success:
feasible_period = 2 * feasible_period
continue
feasible_delay_lh = results["delay_lh"]
feasible_slew_lh = results["slew_lh"]
feasible_delay_hl = results["delay_hl"]
feasible_slew_hl = results["slew_hl"]
#Clear any write target ports
self.targ_write_ports = []
success = False
for port in self.readwrite_ports+self.read_ports:
debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port))
self.period = feasible_period
#Test one port at a time. Using this weird logic to avoid two for loops. Will likely change later.
if port in self.readwrite_ports:
self.targ_readwrite_ports = [port]
else:
self.targ_read_ports = [port]
(success, results)=self.run_delay_simulation()
#Clear these target ports after every simulation
self.targ_readwrite_ports = []
self.targ_read_ports = []
if not success:
feasible_period = 2 * feasible_period
break
feasible_delay_lh = results["delay_lh_{0}".format(port)]
feasible_slew_lh = results["slew_lh_{0}".format(port)]
feasible_delay_hl = results["delay_hl_{0}".format(port)]
feasible_slew_hl = results["slew_hl_{0}".format(port)]
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(feasible_delay_lh, feasible_delay_hl)
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(feasible_slew_lh, feasible_slew_hl)
debug.info(1, "Found feasible_period: {0}ns {1} {2} ".format(feasible_period,
delay_str,
slew_str))
self.period = feasible_period
return (feasible_delay_lh, feasible_delay_hl)
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(feasible_delay_lh, feasible_delay_hl)
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(feasible_slew_lh, feasible_slew_hl)
debug.info(1, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period,
delay_str,
slew_str,
port))
if success:
debug.info(1, "Found feasible_period: {0}ns".format(feasible_period))
self.period = feasible_period
return (feasible_delay_lh, feasible_delay_hl)
def parse_values(self, values_names, mult = 1.0):
"""Parses values in the timing output file. Optional multiplier."""
values = []
for vname in values_names:
value = parse_spice_list("timing", vname)
value = parse_spice_list("timing", vname.lower()) #ngspice converts all character to lower(), not tested on other sims
#Return an empty dict if any value is not a float
if type(value)!=float: #This check overrides the float check in check valid delays. I need to have a similar check here instead.
return {}
@ -384,47 +403,28 @@ class delay():
self.stim.run_sim()
#Only readwrite ports for now. Other to be added later.
for port in self.targ_readwrite_ports:
port = port.lower()
#port = port.lower()
delay_names = ["delay_hl_{0}".format(port), "delay_lh_{0}".format(port),
"slew_hl_{0}".format(port), "slew_lh_{0}".format(port)]
delays = self.parse_values(delay_names, 1e9)
delays = self.parse_values(delay_names, 1e9) # scale delays to ns
if len(delays) > 0 and not self.check_valid_delays((delays[delay_names[0]],delays[delay_names[1]],delays[delay_names[2]],delays[delay_names[3]])):
return (False,{})
result.update(delays)
power_names = ["read0_power_{0}".format(port), "write0_power_{0}".format(port),
"read1_power_{0}".format(port), "write1_power_{0}".format(port)]
powers = self.parse_values(delay_names, 1e3)
powers = self.parse_values(delay_names, 1e3) # scale power to mw
debug.check(len(powers) > 0,"Found valid delays but measured powers invalid.")
result.update(powers)
# read0_power=parse_spice_list("timing", "read0_power_{0}".format(readwrite_port))
# write0_power=parse_spice_list("timing", "write0_power_{0}".format(readwrite_port))
# read1_power=parse_spice_list("timing", "read1_power_{0}".format(readwrite_port))
# write1_power=parse_spice_list("timing", "write1_power_{0}".format(readwrite_port))
#This is to be changed later. Most of the characterization relies that these names are preserved or nothing will work.
#Therefore, changing these names would require changing names in most of delay.py functions and lib.py.
# result.update({ "delay_hl" : delay_hl*1e9,
# "delay_lh" : delay_lh*1e9,
# "slew_hl" : slew_hl*1e9,
# "slew_lh" : slew_lh*1e9,
# "read0_power" : read0_power*1e3,
# "read1_power" : read1_power*1e3,
# "write0_power" : write0_power*1e3,
# "write1_power" : write1_power*1e3})
# for read_port in self.read_ports:
# self.write_delay_measures_one_port(read_ports)
# for write_port in self.write_ports:
# self.write_delay_measures_one_port(write_ports)
# For debug, you sometimes want to inspect each simulation.
#key=raw_input("press return to continue")
# Scale results to ns and mw, respectively
# The delay is from the negative edge for our SRAM
@ -520,7 +520,8 @@ class delay():
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.
"""
#For debug purpose
self.targ_readwrite_ports = self.readwrite_ports
# Checking from not data_value to data_value
self.write_delay_stimulus()
self.stim.run_sim()
@ -838,7 +839,17 @@ class delay():
self.add_noop_all_ports("Idle cycle (if read takes >1 cycle))",
self.probe_address,data_zeros)
def get_availabe_port(self,get_read_port):
"""Returns the first accessible read or write port"""
if len(self.readwrite_ports) > 0:
return self.readwrite_ports[0]
if get_read_port and len(self.read_ports) > 0:
return self.read_ports[0]
elif not get_read_port and len(self.write_ports) > 0:
return self.write_ports[0]
return None
def create_test_cycles(self):
"""Returns a list of key time-points [ns] of the waveform (each rising edge)
of the cycles to do a timing evaluation. The last time is the end of the simulation
@ -872,11 +883,13 @@ class delay():
# self.addr_values.append([])
#Temporary logic. Loop through all target readwrite ports with characterize logic.
cur_write_port = None
for readwrite_port in self.targ_readwrite_ports:
self.gen_test_cycles_one_port(readwrite_port, readwrite_port)
cur_write_port = readwrite_port
cur_read_port = cur_write_port
#Get any available read/write port in case only a single write or read ports is being characterized.
cur_read_port = self.get_availabe_port(get_read_port=True)
cur_write_port = self.get_availabe_port(get_read_port=False)
#Characterizing the remaining target ports. Not the final design.
write_pos = 0