Separated relative delay into rise/fall.

This commit is contained in:
Hunter Nichols 2018-11-14 23:34:53 -08:00
parent e9f6566e59
commit 6e47de3f9b
11 changed files with 97 additions and 51 deletions

View File

@ -10,12 +10,13 @@ class logical_effort():
min_inv_cin = 1+beta min_inv_cin = 1+beta
pinv=parameter["min_inv_para_delay"] pinv=parameter["min_inv_para_delay"]
def __init__(self, size, cin, cout, parasitic): def __init__(self, size, cin, cout, parasitic, out_is_rise=True):
self.cin = cin self.cin = cin
self.cout = cout self.cout = cout
self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin
self.eletrical_effort = self.cout/self.cin self.eletrical_effort = self.cout/self.cin
self.parasitic_scale = parasitic self.parasitic_scale = parasitic
self.is_rise = out_is_rise
def __str__(self): def __str__(self):
return "g = " + str(self.logical_effort) + ", h = " + str(self.eletrical_effort) + ", p = " + str(self.parasitic_scale)+"*pinv" return "g = " + str(self.logical_effort) + ", h = " + str(self.eletrical_effort) + ", p = " + str(self.parasitic_scale)+"*pinv"
@ -31,8 +32,16 @@ class logical_effort():
def calculate_relative_delay(stage_effort_list, pinv=parameter["min_inv_para_delay"]): def calculate_relative_delay(stage_effort_list, pinv=parameter["min_inv_para_delay"]):
"""Calculates the total delay of a given delay path made of a list of logical effort objects.""" """Calculates the total delay of a given delay path made of a list of logical effort objects."""
total_delay = 0 total_rise_delay, total_fall_delay = calculate_relative_rise_fall_delays(stage_effort_list, pinv)
return total_rise_delay + total_fall_delay
def calculate_relative_rise_fall_delays(stage_effort_list, pinv=parameter["min_inv_para_delay"]):
"""Calculates the rise/fall delays of a given delay path made of a list of logical effort objects."""
total_rise_delay, total_fall_delay = 0,0
for stage in stage_effort_list: for stage in stage_effort_list:
total_delay += stage.get_stage_delay(pinv) if stage.is_rise:
return total_delay total_rise_delay += stage.get_stage_delay(pinv)
else:
total_fall_delay += stage.get_stage_delay(pinv)
return total_rise_delay, total_fall_delay

View File

@ -1225,12 +1225,12 @@ class bank(design.design):
return results return results
def determine_wordline_stage_efforts(self, external_cout): def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
"""Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline""" """Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline"""
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption #Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption
stage_effort_list = [] stage_effort_list = []
wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout
stage_effort_list += self.wordline_driver.determine_wordline_stage_efforts(wordline_cout) stage_effort_list += self.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise)
return stage_effort_list return stage_effort_list

View File

@ -109,7 +109,8 @@ class control_logic(design.design):
#Resize the delay chain (by instantiating a new rbl) if the analytical timing failed. #Resize the delay chain (by instantiating a new rbl) if the analytical timing failed.
delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic) 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.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.add_mod(self.replica_bitline) self.add_mod(self.replica_bitline)
def get_heuristic_delay_chain_size(self): def get_heuristic_delay_chain_size(self):
@ -139,6 +140,7 @@ class control_logic(design.design):
def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout): def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout):
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays""" """Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
from math import ceil
previous_delay_chain_delay = (previous_fanout+1+self.parasitic_inv_delay)*previous_stages 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)) debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
@ -147,7 +149,7 @@ class control_logic(design.design):
#inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value #inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
required_delay = self.wl_delay*self.wl_timing_tolerance - (self.sen_delay-previous_delay_chain_delay) required_delay = self.wl_delay*self.wl_timing_tolerance - (self.sen_delay-previous_delay_chain_delay)
debug.check(required_delay > 0, "Cannot size delay chain to have negative delay") debug.check(required_delay > 0, "Cannot size delay chain to have negative delay")
delay_stages = int(required_delay/(delay_fanout+1+self.parasitic_inv_delay)) delay_stages = ceil(required_delay/(delay_fanout+1+self.parasitic_inv_delay))
if delay_stages%2 == 1: #force an even number of stages. if delay_stages%2 == 1: #force an even number of stages.
delay_stages+=1 delay_stages+=1
#Fanout can be varied as well but is a little more complicated but potentially optimal. #Fanout can be varied as well but is a little more complicated but potentially optimal.
@ -638,25 +640,33 @@ class control_logic(design.design):
height=pin.height(), height=pin.height(),
width=pin.width()) width=pin.width())
def get_delay_to_wl(self): def get_delay_to_wl(self):
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array""" """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.") 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() stage_efforts = self.determine_wordline_stage_efforts()
clk_to_wl_delay = logical_effort.calculate_relative_delay(stage_efforts, self.parasitic_inv_delay) clk_to_wl_rise,clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(stage_efforts, self.parasitic_inv_delay)
debug.info(1, "Clock to wordline delay is {} delay units".format(clk_to_wl_delay)) total_delay = clk_to_wl_rise + clk_to_wl_fall
return clk_to_wl_delay 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
def determine_wordline_stage_efforts(self): def determine_wordline_stage_efforts(self):
"""Follows the clock signal to the clk_buf signal to the wordline signal for the total path efforts""" """Follows the clock signal to the clk_buf signal to the wordline signal for the total path efforts"""
stage_effort_list = [] stage_effort_list = []
#Initial direction of clock signal for this path
is_clk_rise = False
#Calculate the load on clk_buf within the module and add it to external load #Calculate the load on clk_buf within the module and add it to external load
internal_cout = self.ctrl_dff_array.get_clk_cin() internal_cout = self.ctrl_dff_array.get_clk_cin()
external_cout = self.sram.get_clk_cin() external_cout = self.sram.get_clk_cin()
#First stage is the clock buffer #First stage is the clock buffer
stage_effort_list += self.clkbuf.determine_clk_buf_stage_efforts(internal_cout+external_cout) stage_effort_list += self.clkbuf.determine_clk_buf_stage_efforts(internal_cout+external_cout, is_clk_rise)
last_stage_is_rise = stage_effort_list[-1].is_rise
#Then ask the sram for the other path delays (from the bank) #Then ask the sram for the other path delays (from the bank)
stage_effort_list += self.sram.determine_wordline_stage_efforts() stage_effort_list += self.sram.determine_wordline_stage_efforts(last_stage_is_rise)
return stage_effort_list return stage_effort_list
@ -666,9 +676,10 @@ class control_logic(design.design):
""" """
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.") 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_sa_enable_stage_efforts() stage_efforts = self.determine_sa_enable_stage_efforts()
clk_to_sen_delay = logical_effort.calculate_relative_delay(stage_efforts, self.parasitic_inv_delay) clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(stage_efforts, self.parasitic_inv_delay)
debug.info(1, "Clock to s_en delay is {} delay units".format(clk_to_sen_delay)) total_delay = clk_to_sen_rise + clk_to_sen_fall
return clk_to_sen_delay 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
def determine_sa_enable_stage_efforts(self): 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""" """Follows the clock signal to the sense amp enable signal adding each stages stage effort to a list"""
@ -677,33 +688,41 @@ class control_logic(design.design):
int_clk_buf_cout = self.get_clk_buf_bar_cin() int_clk_buf_cout = self.get_clk_buf_bar_cin()
ext_clk_buf_cout = self.sram.get_clk_bar_cin() ext_clk_buf_cout = self.sram.get_clk_bar_cin()
#Initial direction of clock signal for this path
is_clk_rise = False
#First stage is the clock buffer #First stage is the clock buffer
stage1 = self.clkbuf.determine_clk_buf_bar_stage_efforts(int_clk_buf_cout+ext_clk_buf_cout) stage1 = self.clkbuf.determine_clk_buf_bar_stage_efforts(int_clk_buf_cout+ext_clk_buf_cout, is_clk_rise)
stage_effort_list += stage1 stage_effort_list += stage1
last_stage_rise = stage_effort_list[-1].is_rise
#nand2 stage #nand2 stage
stage2_cout = self.inv1.get_cin() stage2_cout = self.inv1.get_cin()
stage2 = self.nand2.get_effort_stage(stage2_cout) stage2 = self.nand2.get_effort_stage(stage2_cout, last_stage_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
last_stage_rise = stage_effort_list[-1].is_rise
#inverter stage #inverter stage
stage3_cout = self.replica_bitline.get_en_cin() stage3_cout = self.replica_bitline.get_en_cin()
stage3 = self.inv1.get_effort_stage(stage3_cout) stage3 = self.inv1.get_effort_stage(stage3_cout, last_stage_rise)
stage_effort_list.append(stage3) stage_effort_list.append(stage3)
last_stage_rise = stage_effort_list[-1].is_rise
#Replica bitline stage #Replica bitline stage
stage4_cout = self.inv2.get_cin() stage4_cout = self.inv2.get_cin()
stage4 = self.replica_bitline.determine_sen_stage_efforts(stage4_cout) stage4 = self.replica_bitline.determine_sen_stage_efforts(stage4_cout, last_stage_rise)
stage_effort_list += stage4 stage_effort_list += stage4
last_stage_rise = stage_effort_list[-1].is_rise
#inverter (inv2) stage #inverter (inv2) stage
stage5_cout = self.inv8.get_cin() stage5_cout = self.inv8.get_cin()
stage5 = self.inv2.get_effort_stage(stage5_cout) stage5 = self.inv2.get_effort_stage(stage5_cout, last_stage_rise)
stage_effort_list.append(stage5) stage_effort_list.append(stage5)
last_stage_rise = stage_effort_list[-1].is_rise
#inverter (inv8) stage, s_en output #inverter (inv8) stage, s_en output
clk_sen_cout = self.sram.get_sen_cin() clk_sen_cout = self.sram.get_sen_cin()
stage6 = self.inv8.get_effort_stage(clk_sen_cout) stage6 = self.inv8.get_effort_stage(clk_sen_cout, last_stage_rise)
stage_effort_list.append(stage6) stage_effort_list.append(stage6)
return stage_effort_list return stage_effort_list

View File

@ -225,15 +225,17 @@ class delay_chain(design.design):
dc_cin = self.inv.get_cin() dc_cin = self.inv.get_cin()
return dc_cin return dc_cin
def determine_delayed_en_stage_efforts(self, ext_delayed_en_cout): def determine_delayed_en_stage_efforts(self, ext_delayed_en_cout, inp_is_rise=True):
"""Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load.""" """Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load."""
stage_effort_list = [] stage_effort_list = []
#Add a stage to the list for every stage in delay chain. Stages only differ in fanout except the last which has an external cout. #Add a stage to the list for every stage in delay chain. Stages only differ in fanout except the last which has an external cout.
last_stage_is_rise = inp_is_rise
for stage_fanout in self.fanout_list: for stage_fanout in self.fanout_list:
stage_cout = self.inv.get_cin()*(stage_fanout+1) stage_cout = self.inv.get_cin()*(stage_fanout+1)
if len(stage_effort_list) == len(self.fanout_list)-1: #last stage if len(stage_effort_list) == len(self.fanout_list)-1: #last stage
stage_cout+=ext_delayed_en_cout stage_cout+=ext_delayed_en_cout
stage = self.inv.get_effort_stage(stage_cout) stage = self.inv.get_effort_stage(stage_cout, last_stage_is_rise)
stage_effort_list.append(stage) stage_effort_list.append(stage)
last_stage_is_rise = stage.is_rise
return stage_effort_list return stage_effort_list

View File

@ -615,17 +615,21 @@ class replica_bitline(design.design):
en_cin = self.delay_chain.get_cin() en_cin = self.delay_chain.get_cin()
return en_cin return en_cin
def determine_sen_stage_efforts(self, ext_cout): def determine_sen_stage_efforts(self, ext_cout, inp_is_rise=True):
"""Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load.""" """Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load."""
stage_effort_list = [] stage_effort_list = []
#Stage 1 is the delay chain #Stage 1 is the delay chain
stage1_cout = self.get_delayed_en_cin() stage1_cout = self.get_delayed_en_cin()
stage1 = self.delay_chain.determine_delayed_en_stage_efforts(stage1_cout) stage1 = self.delay_chain.determine_delayed_en_stage_efforts(stage1_cout, inp_is_rise)
stage_effort_list += stage1 stage_effort_list += stage1
#There is a disconnect between the delay chain and inverter. The rise/fall of the input to the inverter
#Will be the negation of the previous stage.
last_stage_is_rise = not stage_effort_list[-1].is_rise
#The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this #The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this
#model is intended to track every but that. Therefore, the next stage is the inverter after the rbl. #model is intended to track every but that. Therefore, the next stage is the inverter after the rbl.
stage2 = self.inv.get_effort_stage(ext_cout) stage2 = self.inv.get_effort_stage(ext_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
return stage_effort_list return stage_effort_list

View File

@ -240,18 +240,20 @@ class wordline_driver(design.design):
"""Gets the capacitance of the wordline driver in absolute units (fF)""" """Gets the capacitance of the wordline driver in absolute units (fF)"""
return self.nand2.input_load() return self.nand2.input_load()
def determine_wordline_stage_efforts(self, external_cout): def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
"""Follows the clk_buf to a wordline signal adding each stages stage effort to a list""" """Follows the clk_buf to a wordline signal adding each stages stage effort to a list"""
stage_effort_list = [] stage_effort_list = []
stage1_cout = self.nand2.get_cin() stage1_cout = self.nand2.get_cin()
stage1 = self.inv_no_output.get_effort_stage(stage1_cout) stage1 = self.inv_no_output.get_effort_stage(stage1_cout, inp_is_rise)
stage_effort_list.append(stage1) stage_effort_list.append(stage1)
last_stage_is_rise = stage1.is_rise
stage2_cout = self.inv.get_cin() stage2_cout = self.inv.get_cin()
stage2 = self.nand2.get_effort_stage(stage2_cout) stage2 = self.nand2.get_effort_stage(stage2_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
last_stage_is_rise = stage2.is_rise
stage3 = self.inv.get_effort_stage(external_cout) stage3 = self.inv.get_effort_stage(external_cout, last_stage_is_rise)
stage_effort_list.append(stage3) stage_effort_list.append(stage3)
return stage_effort_list return stage_effort_list

View File

@ -288,7 +288,9 @@ class pinv(pgate.pgate):
"""Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor""" """Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor"""
return self.nmos_size + self.pmos_size return self.nmos_size + self.pmos_size
def get_effort_stage(self, cout): def get_effort_stage(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units.""" """Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 1 parasitic_delay = 1
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay) return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)

View File

@ -187,30 +187,34 @@ class pinvbuf(design.design):
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load) inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
return inv1_delay + inv2_delay return inv1_delay + inv2_delay
def determine_clk_buf_stage_efforts(self, external_cout): def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the clk -> clk_buf path""" """Get the stage efforts of the clk -> clk_buf path"""
stage_effort_list = [] stage_effort_list = []
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
stage1 = self.inv.get_effort_stage(stage1_cout) stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise)
stage_effort_list.append(stage1) stage_effort_list.append(stage1)
last_stage_is_rise = stage1.is_rise
stage2 = self.inv2.get_effort_stage(external_cout) stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
return stage_effort_list return stage_effort_list
def determine_clk_buf_bar_stage_efforts(self, external_cout): def determine_clk_buf_bar_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the clk -> clk_buf path""" """Get the stage efforts of the clk -> clk_buf path"""
#After (almost) every stage, the direction of the signal inverts.
stage_effort_list = [] stage_effort_list = []
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
stage1 = self.inv.get_effort_stage(stage1_cout) stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise)
stage_effort_list.append(stage1) stage_effort_list.append(stage1)
last_stage_is_rise = stage_effort_list[-1].is_rise
stage2_cout = self.inv2.get_cin() stage2_cout = self.inv2.get_cin()
stage2 = self.inv1.get_effort_stage(stage2_cout) stage2 = self.inv1.get_effort_stage(stage2_cout, last_stage_is_rise)
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
last_stage_is_rise = stage_effort_list[-1].is_rise
stage3 = self.inv2.get_effort_stage(external_cout) stage3 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise)
stage_effort_list.append(stage3) stage_effort_list.append(stage3)
return stage_effort_list return stage_effort_list

View File

@ -249,7 +249,9 @@ class pnand2(pgate.pgate):
"""Return the relative input capacitance of a single input""" """Return the relative input capacitance of a single input"""
return self.nmos_size+self.pmos_size return self.nmos_size+self.pmos_size
def get_effort_stage(self, cout): def get_effort_stage(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units.""" """Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 2 parasitic_delay = 2
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay) return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)

View File

@ -267,7 +267,9 @@ class pnand3(pgate.pgate):
"""Return the relative input capacitance of a single input""" """Return the relative input capacitance of a single input"""
return self.nmos_size+self.pmos_size return self.nmos_size+self.pmos_size
def get_effort_stage(self, cout): def get_effort_stage(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units.""" """Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 3 parasitic_delay = 3
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay) return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)

View File

@ -488,13 +488,13 @@ class sram_base(design):
""" LH and HL are the same in analytical model. """ """ LH and HL are the same in analytical model. """
return self.bank.analytical_delay(vdd,slew,load) return self.bank.analytical_delay(vdd,slew,load)
def determine_wordline_stage_efforts(self): def determine_wordline_stage_efforts(self, inp_is_rise=True):
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline""" """Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
stage_effort_list = [] stage_effort_list = []
#Clk_buf originates from the control logic so only the bank is related to the wordline path #Clk_buf originates from the control logic so only the bank is related to the wordline path
external_wordline_cout = 0 #No loading on the wordline other than in the bank. external_wordline_cout = 0 #No loading on the wordline other than in the bank.
stage_effort_list += self.bank.determine_wordline_stage_efforts(external_wordline_cout) stage_effort_list += self.bank.determine_wordline_stage_efforts(external_wordline_cout, inp_is_rise)
return stage_effort_list return stage_effort_list