Added delay chain sizing for rise/fall delays. Disabled to some sizes being having very large fanouts.

This commit is contained in:
Hunter Nichols 2018-11-16 16:57:22 -08:00
parent 6e47de3f9b
commit 3716030a23
3 changed files with 76 additions and 56 deletions

View File

@ -208,7 +208,7 @@ class delay(simulation):
trig_slew_low = 0.1 * self.vdd_voltage
targ_slew_high = 0.9 * self.vdd_voltage
if 'delay' in delay_name:
trig_dir="RISE"
trig_dir="RISE" #FALL
trig_val = half_vdd
targ_val = half_vdd
trig_name = trig_clk_name
@ -429,6 +429,7 @@ class delay(simulation):
delay_names = ["{0}{1}".format(mname,port) for mname in self.delay_meas_names]
delay_names = [mname for mname in self.delay_meas_names]
delays = self.parse_values(delay_names, port, 1e9) # scale delays to ns
debug.info(2,"Delay values = {}".format(delays))
if not self.check_valid_delays(tuple(delays.values())):
return (False,{})
result[port].update(delays)
@ -646,18 +647,6 @@ class delay(simulation):
# slew=0.04
# self.try_period(target_period, feasible_delay_lh, feasible_delay_hl)
# sys.exit(1)
#For debugging, skips characterization and returns dummy values.
# char_data = self.get_empty_measure_data_dict()
# i = 1.0
# for slew in slews:
# for load in loads:
# for k,v in char_data.items():
# char_data[k].append(i)
# i+=1.0
# char_data["min_period"] = i
# char_data["leakage_power"] = i+1.0
# return char_data
# 1) Find a feasible period and it's corresponding delays using the trimmed array.
feasible_delays = self.find_feasible_period()
@ -834,34 +823,6 @@ class delay(simulation):
return (sram_data,port_data)
# delay_lh = []
# delay_hl = []
# slew_lh = []
# slew_hl = []
# for slew in slews:
# for load in loads:
# self.set_load_slew(load,slew)
# bank_delay = sram.analytical_delay(self.vdd_voltage, self.slew,self.load)
# # Convert from ps to ns
# delay_lh.append(bank_delay.delay/1e3)
# delay_hl.append(bank_delay.delay/1e3)
# slew_lh.append(bank_delay.slew/1e3)
# slew_hl.append(bank_delay.slew/1e3)
# power = self.analytical_power()
# sram_data = { "min_period": 0,
# "leakage_power": power.leakage}
# port_data = [{"delay_lh": delay_lh,
# "delay_hl": delay_hl,
# "slew_lh": slew_lh,
# "slew_hl": slew_hl,
# "read0_power": power.dynamic,
# "read1_power": power.dynamic,
# "write0_power": power.dynamic,
# "write1_power": power.dynamic,
# }]
# return (sram_data,port_data)
def analytical_power(self, slews, loads):
"""Get the dynamic and leakage power from the SRAM"""

View File

@ -103,13 +103,17 @@ class control_logic(design.design):
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
bitcell_loads = int(math.ceil(self.num_rows / 2.0))
self.replica_bitline = replica_bitline(delay_stages_heuristic, delay_fanout_heuristic, bitcell_loads, name="replica_bitline_"+self.port_type)
self.replica_bitline = replica_bitline([delay_fanout_heuristic]*delay_stages_heuristic, bitcell_loads, name="replica_bitline_"+self.port_type)
if self.sram != None and not self.is_sen_timing_okay():
#Resize the delay chain (by instantiating a new rbl) if the analytical timing failed.
#This resizes to match fall and rise delays, can make the delay chain weird sizes.
#stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic)
#self.replica_bitline = replica_bitline(stage_list, bitcell_loads, name="replica_bitline_resized_"+self.port_type)
#This resizes based on total delay.
delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic)
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads, name="replica_bitline_resized_"+self.port_type)
self.sen_delay = self.get_delay_to_sen() #get the new timing
self.replica_bitline = replica_bitline([delay_fanout]*delay_stages, bitcell_loads, name="replica_bitline_resized_"+self.port_type)
self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
self.add_mod(self.replica_bitline)
@ -124,16 +128,20 @@ class control_logic(design.design):
delay_stages = 6
else:
delay_stages = 4
return (delay_stages, delay_fanout)
def is_sen_timing_okay(self):
self.wl_delay = self.get_delay_to_wl()
self.sen_delay = self.get_delay_to_sen()
self.wl_delay_rise,self.wl_delay_fall = self.get_delays_to_wl()
self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen()
self.wl_delay = self.wl_delay_rise+self.wl_delay_fall
self.sen_delay = self.sen_delay_rise+self.sen_delay_fall
#The sen delay must always be bigger than than the wl delay. This decides how much larger the sen delay must be before
#a re-size is warranted.
if self.wl_delay*self.wl_timing_tolerance >= self.sen_delay:
if (self.wl_delay_rise*self.wl_timing_tolerance >= self.sen_delay_rise or
self.wl_delay_fall*self.wl_timing_tolerance >= self.sen_delay_fall):
return False
else:
return True
@ -155,7 +163,59 @@ class control_logic(design.design):
#Fanout can be varied as well but is a little more complicated but potentially optimal.
debug.info(1, "Setting delay chain to {} stages with {} fanout to match {} delay".format(delay_stages, delay_fanout, required_delay))
return (delay_stages, delay_fanout)
def get_dynamic_delay_fanout_list(self, previous_stages, previous_fanout):
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
previous_delay_chain_delay = (previous_fanout+1+self.parasitic_inv_delay)*previous_stages
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
fanout_rise = fanout_fall = 2 # This can be anything >=2
#The delay chain uses minimum sized inverters. There are (fanout+1)*stages inverters and each
#inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
required_delay_fall = self.wl_delay_fall*self.wl_timing_tolerance - (self.sen_delay_fall-previous_delay_chain_delay/2)
required_delay_rise = self.wl_delay_rise*self.wl_timing_tolerance - (self.sen_delay_rise-previous_delay_chain_delay/2)
debug.info(2,"Required delays from chain: fall={}, rise={}".format(required_delay_fall,required_delay_rise))
#The stages need to be equal (or at least a even number of stages with matching rise/fall delays)
while True:
stages_fall = self.calculate_stages_with_fixed_fanout(required_delay_fall,fanout_fall)
stages_rise = self.calculate_stages_with_fixed_fanout(required_delay_rise,fanout_rise)
debug.info(1,"Fall stages={}, rise stages={}".format(stages_fall,stages_rise))
if stages_fall == stages_rise:
break
elif abs(stages_fall-stages_rise) == 1:
break
#There should also be a condition to make sure the fanout does not get too large.
#Otherwise, increase the fanout of delay with the most stages, calculate new stages
elif stages_fall>stages_rise:
fanout_fall+=1
else:
fanout_rise+=1
total_stages = max(stages_fall,stages_rise)*2
debug.info(1, "New Delay chain: stages={}, fanout_rise={}, fanout_fall={}".format(total_stages, fanout_rise, fanout_fall))
#Creates interleaved fanout list of rise/fall delays. Assumes fall is the first stage.
stage_list = [fanout_fall if i%2==0 else fanout_rise for i in range(total_stages)]
return stage_list
def calculate_stages_with_fixed_fanout(self, required_delay, fanout):
from math import ceil
#Delay being negative is not an error. It implies that any amount of stages would have a negative effect on the overall delay
if required_delay<=3: #3 is the minimum delay per stage.
return 1
delay_stages = ceil(required_delay/(fanout+1+self.parasitic_inv_delay))
return delay_stages
def calculate_stage_list(self, total_stages, fanout_rise, fanout_fall):
"""Produces a list of fanouts which determine the size of the delay chain. List length is the number of stages.
Assumes the first stage is falling.
"""
stage_list = []
for i in range(total_stages):
if i%2 == 0:
stage_list.append()
def setup_signal_busses(self):
""" Setup bus names, determine the size of the busses etc """
@ -641,14 +701,14 @@ class control_logic(design.design):
width=pin.width())
def get_delay_to_wl(self):
def get_delays_to_wl(self):
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
stage_efforts = self.determine_wordline_stage_efforts()
clk_to_wl_rise,clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(stage_efforts, self.parasitic_inv_delay)
total_delay = clk_to_wl_rise + clk_to_wl_fall
debug.info(1, "Clock to wl delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_wl_rise, clk_to_wl_fall,total_delay))
return total_delay
return clk_to_wl_rise,clk_to_wl_fall
def determine_wordline_stage_efforts(self):
@ -670,7 +730,7 @@ class control_logic(design.design):
return stage_effort_list
def get_delay_to_sen(self):
def get_delays_to_sen(self):
"""Get the delay (in delay units) of the clk to a sense amp enable.
This does not incorporate the delay of the replica bitline.
"""
@ -679,7 +739,7 @@ class control_logic(design.design):
clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(stage_efforts, self.parasitic_inv_delay)
total_delay = clk_to_sen_rise + clk_to_sen_fall
debug.info(1, "Clock to s_en delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_sen_rise, clk_to_sen_fall,total_delay))
return total_delay
return clk_to_sen_rise, clk_to_sen_fall
def determine_sa_enable_stage_efforts(self):
"""Follows the clock signal to the sense amp enable signal adding each stages stage effort to a list"""

View File

@ -15,12 +15,11 @@ class replica_bitline(design.design):
line and rows is the height of the replica bit loads.
"""
def __init__(self, delay_stages, delay_fanout, bitcell_loads, name="replica_bitline"):
def __init__(self, delay_fanout_list, bitcell_loads, name="replica_bitline"):
design.design.__init__(self, name)
self.bitcell_loads = bitcell_loads
self.delay_stages = delay_stages
self.delay_fanout = delay_fanout
self.delay_fanout_list = delay_fanout_list
self.create_netlist()
if not OPTS.netlist_only:
@ -95,7 +94,7 @@ class replica_bitline(design.design):
# FIXME: The FO and depth of this should be tuned
from delay_chain import delay_chain
self.delay_chain = delay_chain([self.delay_fanout]*self.delay_stages)
self.delay_chain = delay_chain(self.delay_fanout_list)
self.add_mod(self.delay_chain)
self.inv = pinv()