mirror of https://github.com/VLSIDA/OpenRAM.git
Separated relative delay into rise/fall.
This commit is contained in:
parent
e9f6566e59
commit
6e47de3f9b
|
|
@ -10,12 +10,13 @@ class logical_effort():
|
|||
min_inv_cin = 1+beta
|
||||
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.cout = cout
|
||||
self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin
|
||||
self.eletrical_effort = self.cout/self.cin
|
||||
self.parasitic_scale = parasitic
|
||||
self.is_rise = out_is_rise
|
||||
|
||||
def __str__(self):
|
||||
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"]):
|
||||
"""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:
|
||||
total_delay += stage.get_stage_delay(pinv)
|
||||
return total_delay
|
||||
|
||||
if stage.is_rise:
|
||||
total_rise_delay += stage.get_stage_delay(pinv)
|
||||
else:
|
||||
total_fall_delay += stage.get_stage_delay(pinv)
|
||||
return total_rise_delay, total_fall_delay
|
||||
|
||||
|
|
@ -1225,12 +1225,12 @@ class bank(design.design):
|
|||
|
||||
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"""
|
||||
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption
|
||||
stage_effort_list = []
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,8 @@ class control_logic(design.design):
|
|||
#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)
|
||||
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)
|
||||
|
||||
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):
|
||||
"""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
|
||||
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
|
||||
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")
|
||||
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.
|
||||
delay_stages+=1
|
||||
#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(),
|
||||
width=pin.width())
|
||||
|
||||
|
||||
def get_delay_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_delay = logical_effort.calculate_relative_delay(stage_efforts, self.parasitic_inv_delay)
|
||||
debug.info(1, "Clock to wordline delay is {} delay units".format(clk_to_wl_delay))
|
||||
return clk_to_wl_delay
|
||||
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
|
||||
|
||||
|
||||
def determine_wordline_stage_efforts(self):
|
||||
"""Follows the clock signal to the clk_buf signal to the wordline signal for the total path efforts"""
|
||||
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
|
||||
internal_cout = self.ctrl_dff_array.get_clk_cin()
|
||||
external_cout = self.sram.get_clk_cin()
|
||||
#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)
|
||||
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
|
||||
|
||||
|
|
@ -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.")
|
||||
stage_efforts = self.determine_sa_enable_stage_efforts()
|
||||
clk_to_sen_delay = logical_effort.calculate_relative_delay(stage_efforts, self.parasitic_inv_delay)
|
||||
debug.info(1, "Clock to s_en delay is {} delay units".format(clk_to_sen_delay))
|
||||
return clk_to_sen_delay
|
||||
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
|
||||
|
||||
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"""
|
||||
|
|
@ -677,33 +688,41 @@ class control_logic(design.design):
|
|||
int_clk_buf_cout = self.get_clk_buf_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
|
||||
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
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#nand2 stage
|
||||
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)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#inverter stage
|
||||
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)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#Replica bitline stage
|
||||
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
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#inverter (inv2) stage
|
||||
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)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
#inverter (inv8) stage, s_en output
|
||||
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)
|
||||
return stage_effort_list
|
||||
|
||||
|
|
|
|||
|
|
@ -225,15 +225,17 @@ class delay_chain(design.design):
|
|||
dc_cin = self.inv.get_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."""
|
||||
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.
|
||||
last_stage_is_rise = inp_is_rise
|
||||
for stage_fanout in self.fanout_list:
|
||||
stage_cout = self.inv.get_cin()*(stage_fanout+1)
|
||||
if len(stage_effort_list) == len(self.fanout_list)-1: #last stage
|
||||
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)
|
||||
last_stage_is_rise = stage.is_rise
|
||||
|
||||
return stage_effort_list
|
||||
|
|
@ -615,17 +615,21 @@ class replica_bitline(design.design):
|
|||
en_cin = self.delay_chain.get_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."""
|
||||
stage_effort_list = []
|
||||
#Stage 1 is the delay chain
|
||||
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
|
||||
|
||||
#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
|
||||
#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)
|
||||
#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, last_stage_is_rise)
|
||||
stage_effort_list.append(stage2)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
|
|||
|
|
@ -240,18 +240,20 @@ class wordline_driver(design.design):
|
|||
"""Gets the capacitance of the wordline driver in absolute units (fF)"""
|
||||
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"""
|
||||
stage_effort_list = []
|
||||
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)
|
||||
last_stage_is_rise = stage1.is_rise
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
|
|||
|
|
@ -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 self.nmos_size + self.pmos_size
|
||||
|
||||
def get_effort_stage(self, cout):
|
||||
"""Returns an object representing the parameters for delay in tau units."""
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
"""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
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -187,30 +187,34 @@ class pinvbuf(design.design):
|
|||
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
|
||||
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"""
|
||||
stage_effort_list = []
|
||||
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)
|
||||
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)
|
||||
|
||||
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"""
|
||||
#After (almost) every stage, the direction of the signal inverts.
|
||||
stage_effort_list = []
|
||||
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)
|
||||
last_stage_is_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
return stage_effort_list
|
||||
|
|
@ -249,7 +249,9 @@ class pnand2(pgate.pgate):
|
|||
"""Return the relative input capacitance of a single input"""
|
||||
return self.nmos_size+self.pmos_size
|
||||
|
||||
def get_effort_stage(self, cout):
|
||||
"""Returns an object representing the parameters for delay in tau units."""
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
"""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
|
||||
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)
|
||||
|
|
@ -267,7 +267,9 @@ class pnand3(pgate.pgate):
|
|||
"""Return the relative input capacitance of a single input"""
|
||||
return self.nmos_size+self.pmos_size
|
||||
|
||||
def get_effort_stage(self, cout):
|
||||
"""Returns an object representing the parameters for delay in tau units."""
|
||||
def get_effort_stage(self, cout, inp_is_rise=True):
|
||||
"""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
|
||||
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)
|
||||
|
|
@ -488,13 +488,13 @@ class sram_base(design):
|
|||
""" LH and HL are the same in analytical model. """
|
||||
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"""
|
||||
stage_effort_list = []
|
||||
|
||||
#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.
|
||||
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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue