Added updated analytical characterization with combined models

This commit is contained in:
Hunter Nichols 2019-04-02 01:09:31 -07:00
parent 97777475b4
commit f6eefc1728
14 changed files with 240 additions and 93 deletions

View File

@ -2,6 +2,7 @@ import design
import debug import debug
import utils import utils
from tech import GDS,layer,parameter,drc from tech import GDS,layer,parameter,drc
import logical_effort
class bitcell(design.design): class bitcell(design.design):
""" """
@ -24,18 +25,23 @@ class bitcell(design.design):
self.height = bitcell.height self.height = bitcell.height
self.pin_map = bitcell.pin_map self.pin_map = bitcell.pin_map
def analytical_delay(self, corner, slew, load=0, swing = 0.5): # def analytical_delay(self, corner, slew, load=0, swing = 0.5):
# delay of bit cell is not like a driver(from WL) # # delay of bit cell is not like a driver(from WL)
# so the slew used should be 0 # # so the slew used should be 0
# it should not be slew dependent? # # it should not be slew dependent?
# because the value is there # # because the value is there
# the delay is only over half transsmission gate # # the delay is only over half transsmission gate
from tech import spice # from tech import spice
r = spice["min_tx_r"]*3 # r = spice["min_tx_r"]*3
c_para = spice["min_tx_drain_c"] # c_para = spice["min_tx_drain_c"]
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing) # result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
return result # return result
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1
size = 0.5 #This accounts for bitline being drained thought the access TX and internal node
cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
return logical_effort.logical_effort('bitline', size, cin, load, parasitic_delay, False)
def list_bitcell_pins(self, col, row): def list_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """

View File

@ -9,6 +9,7 @@ class logical_effort():
beta = parameter["beta"] beta = parameter["beta"]
min_inv_cin = 1+beta min_inv_cin = 1+beta
pinv=parameter["min_inv_para_delay"] pinv=parameter["min_inv_para_delay"]
tau = parameter['le_tau']
def __init__(self, name, size, cin, cout, parasitic, out_is_rise=True): def __init__(self, name, size, cin, cout, parasitic, out_is_rise=True):
self.name = name self.name = name
@ -30,30 +31,40 @@ class logical_effort():
def get_stage_effort(self): def get_stage_effort(self):
return self.logical_effort*self.eletrical_effort return self.logical_effort*self.eletrical_effort
def get_parasitic_delay(self, pinv): def get_parasitic_delay(self):
return pinv * self.parasitic_scale return logical_effort.pinv * self.parasitic_scale
def get_stage_delay(self, pinv): def get_stage_delay(self):
return self.get_stage_effort()+self.get_parasitic_delay(pinv) return self.get_stage_effort()+self.get_parasitic_delay()
def calculate_delays(stage_effort_list, pinv): def get_absolute_delay(self):
return logical_effort.tau*self.get_stage_delay()
def calculate_delays(stage_effort_list):
"""Convert stage effort objects to list of delay values""" """Convert stage effort objects to list of delay values"""
return [stage.get_stage_delay(pinv) for stage in stage_effort_list] return [stage.get_stage_delay() for stage in stage_effort_list]
def calculate_relative_delay(stage_effort_list, pinv=parameter["min_inv_para_delay"]): def calculate_relative_delay(stage_effort_list):
"""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_rise_delay, total_fall_delay = calculate_relative_rise_fall_delays(stage_effort_list, pinv) total_rise_delay, total_fall_delay = calculate_relative_rise_fall_delays(stage_effort_list)
return total_rise_delay + total_fall_delay return total_rise_delay + total_fall_delay
def calculate_absolute_delay(stage_effort_list):
"""Calculates the total delay of a given delay path made of a list of logical effort objects."""
total_delay = 0
for stage in stage_effort_list:
total_delay+=stage.get_absolute_delay()
return total_delay
def calculate_relative_rise_fall_delays(stage_effort_list, pinv=parameter["min_inv_para_delay"]): def calculate_relative_rise_fall_delays(stage_effort_list):
"""Calculates the rise/fall delays of a given delay path made of a list of logical effort objects.""" """Calculates the rise/fall delays of a given delay path made of a list of logical effort objects."""
debug.info(2, "Calculating rise/fall relative delays") debug.info(2, "Calculating rise/fall relative delays")
total_rise_delay, total_fall_delay = 0,0 total_rise_delay, total_fall_delay = 0,0
for stage in stage_effort_list: for stage in stage_effort_list:
debug.info(2, stage) debug.info(2, stage)
if stage.is_rise: if stage.is_rise:
total_rise_delay += stage.get_stage_delay(pinv) total_rise_delay += stage.get_stage_delay()
else: else:
total_fall_delay += stage.get_stage_delay(pinv) total_fall_delay += stage.get_stage_delay()
return total_rise_delay, total_fall_delay return total_rise_delay, total_fall_delay

View File

@ -1216,36 +1216,62 @@ class bank(design.design):
rotate=90) rotate=90)
def analytical_delay(self, corner, slew, load): # def analytical_delay(self, corner, slew, load):
""" return analytical delay of the bank""" # """ return analytical delay of the bank"""
results = [] # results = []
decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load()) # decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load())
word_driver_delay = self.wordline_driver.analytical_delay(corner, # word_driver_delay = self.wordline_driver.analytical_delay(corner,
decoder_delay.slew, # decoder_delay.slew,
self.bitcell_array.input_load()) # self.bitcell_array.input_load())
# #FIXME: Array delay is the same for every port.
# bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew)
# #This also essentially creates the same delay for each port. Good structure, no substance
# for port in self.all_ports:
# if self.words_per_row > 1:
# column_mux_delay = self.column_mux_array[port].analytical_delay(corner,
# bitcell_array_delay.slew,
# self.sense_amp_array.input_load())
# else:
# column_mux_delay = self.return_delay(delay = 0.0, slew=word_driver_delay.slew)
# bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner,
# column_mux_delay.slew,
# self.bitcell_array.output_load())
# # output load of bitcell_array is set to be only small part of bl for sense amp.
# results.append(decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay)
# return results
def analytical_delay(self, corner, slew, load):
""" return analytical delay of the bank. This will track the clock to output path"""
#FIXME: This delay is determined in the control logic. Should be moved here.
# word_driver_delay = self.wordline_driver.analytical_delay(corner,
# slew,
# self.bitcell_array.input_load())
#FIXME: Array delay is the same for every port. #FIXME: Array delay is the same for every port.
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew) word_driver_slew = 0
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_slew)
#This also essentially creates the same delay for each port. Good structure, no substance #This also essentially creates the same delay for each port. Good structure, no substance
for port in self.all_ports: if self.words_per_row > 1:
if self.words_per_row > 1: column_mux_delay = self.column_mux_array[port].analytical_delay(corner,
column_mux_delay = self.column_mux_array[port].analytical_delay(corner, bitcell_array_delay.slew,
bitcell_array_delay.slew, self.sense_amp_array.input_load())
self.sense_amp_array.input_load()) else:
else: column_mux_delay = []
column_mux_delay = self.return_delay(delay = 0.0, slew=word_driver_delay.slew)
column_mux_slew = 0
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner, sense_amp_delay = self.sense_amp_array.analytical_delay(corner,
column_mux_delay.slew, column_mux_slew,
self.bitcell_array.output_load()) self.bitcell_array.output_load())
# output load of bitcell_array is set to be only small part of bl for sense amp. # output load of bitcell_array is set to be only small part of bl for sense amp.
results.append(decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay) return bitcell_array_delay + column_mux_delay + sense_amp_delay
return results
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True): 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

View File

@ -4,6 +4,7 @@ from tech import drc, spice
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
import logical_effort
class bitcell_array(design.design): class bitcell_array(design.design):
""" """
@ -130,23 +131,32 @@ class bitcell_array(design.design):
self.add_power_pin(pin_name, pin.center(), 0, pin.layer) self.add_power_pin(pin_name, pin.center(), 0, pin.layer)
# def analytical_delay(self, corner, slew, load=0):
# from tech import drc
# wl_wire = self.gen_wl_wire()
# wl_wire.return_delay_over_wire(slew)
# wl_to_cell_delay = wl_wire.return_delay_over_wire(slew)
# # hypothetical delay from cell to bl end without sense amp
# bl_wire = self.gen_bl_wire()
# cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
# # hence just use the whole c
# bl_swing = 0.1
# cell_delay = self.cell.analytical_delay(corner, wl_to_cell_delay.slew, cell_load, swing = bl_swing)
# #we do not consider the delay over the wire for now
# return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
# wl_to_cell_delay.slew)
def analytical_delay(self, corner, slew, load=0): def analytical_delay(self, corner, slew, load=0):
from tech import drc """Returns relative delay of the bitline in the bitcell array"""
wl_wire = self.gen_wl_wire() #The load being driven/drained is mostly the bitline but could include the sense amp or the column mux.
wl_wire.return_delay_over_wire(slew) #The load from the bitlines is due to the drain capacitances from all the other bitlines and wire parasitics.
drain_parasitics = .5 #each bitcell adds half a parasitic to the delay
wl_to_cell_delay = wl_wire.return_delay_over_wire(slew) wire_parasitics = .05 * drain_parasitics #Wires add 5% to this.
# hypothetical delay from cell to bl end without sense amp bitline_load = (drain_parasitics+wire_parasitics)*self.row_size * logical_effort.logical_effort.pinv
bl_wire = self.gen_bl_wire() return [self.cell.analytical_delay(corner, slew, load+bitline_load)]
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
# hence just use the whole c
bl_swing = 0.1
cell_delay = self.cell.analytical_delay(corner, wl_to_cell_delay.slew, cell_load, swing = bl_swing)
#we do not consider the delay over the wire for now
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
wl_to_cell_delay.slew)
def analytical_power(self, corner, load): def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW.""" """Power of Bitcell array and bitline in nW."""
from tech import drc, parameter from tech import drc, parameter

View File

@ -33,10 +33,10 @@ class control_logic(design.design):
self.num_words = num_rows*words_per_row self.num_words = num_rows*words_per_row
self.enable_delay_chain_resizing = True self.enable_delay_chain_resizing = True
self.inv_parasitic_delay = logical_effort.logical_effort.pinv
#Determines how much larger the sen delay should be. Accounts for possible error in model. #Determines how much larger the sen delay should be. Accounts for possible error in model.
self.wl_timing_tolerance = 1 self.wl_timing_tolerance = 1
self.parasitic_inv_delay = parameter["min_inv_para_delay"]
self.wl_stage_efforts = None self.wl_stage_efforts = None
self.sen_stage_efforts = None self.sen_stage_efforts = None
@ -219,7 +219,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 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.inv_parasitic_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))
delay_fanout = 3 # This can be anything >=2 delay_fanout = 3 # This can be anything >=2
@ -227,7 +227,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 = ceil(required_delay/(delay_fanout+1+self.parasitic_inv_delay)) delay_stages = ceil(required_delay/(delay_fanout+1+self.inv_parasitic_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.
@ -237,7 +237,7 @@ class control_logic(design.design):
def get_dynamic_delay_fanout_list(self, previous_stages, previous_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""" """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 previous_delay_chain_delay = (previous_fanout+1+self.inv_parasitic_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))
fanout_rise = fanout_fall = 2 # This can be anything >=2 fanout_rise = fanout_fall = 2 # This can be anything >=2
@ -284,9 +284,9 @@ class control_logic(design.design):
def calculate_stages_with_fixed_fanout(self, required_delay, fanout): def calculate_stages_with_fixed_fanout(self, required_delay, fanout):
from math import ceil 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 #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+self.parasitic_inv_delay: #3 is the minimum delay per stage (with pinv=0). if required_delay <= 3+self.inv_parasitic_delay: #3 is the minimum delay per stage (with pinv=0).
return 1 return 1
delay_stages = ceil(required_delay/(fanout+1+self.parasitic_inv_delay)) delay_stages = ceil(required_delay/(fanout+1+self.inv_parasitic_delay))
return delay_stages return delay_stages
def calculate_stage_list(self, total_stages, fanout_rise, fanout_fall): def calculate_stage_list(self, total_stages, fanout_rise, fanout_fall):
@ -850,14 +850,14 @@ class control_logic(design.design):
def get_delays_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""" """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.")
self.wl_stage_efforts = self.determine_wordline_stage_efforts() self.wl_stage_efforts = self.get_wordline_stage_efforts()
clk_to_wl_rise,clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(self.wl_stage_efforts, self.parasitic_inv_delay) clk_to_wl_rise,clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(self.wl_stage_efforts)
total_delay = clk_to_wl_rise + clk_to_wl_fall 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)) 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 clk_to_wl_rise,clk_to_wl_fall return clk_to_wl_rise,clk_to_wl_fall
def determine_wordline_stage_efforts(self): def get_wordline_stage_efforts(self):
"""Follows the gated_clk_bar -> wl_en -> wordline signal for the total path efforts""" """Follows the gated_clk_bar -> wl_en -> wordline signal for the total path efforts"""
stage_effort_list = [] stage_effort_list = []
@ -871,7 +871,7 @@ class control_logic(design.design):
last_stage_is_rise = stage_effort_list[-1].is_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(last_stage_is_rise) stage_effort_list += self.sram.get_wordline_stage_efforts(last_stage_is_rise)
return stage_effort_list return stage_effort_list
@ -880,17 +880,15 @@ class control_logic(design.design):
This does not incorporate the delay of the replica bitline. This does not incorporate the delay of the replica bitline.
""" """
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.")
self.sen_stage_efforts = self.determine_sa_enable_stage_efforts() self.sen_stage_efforts = self.get_sa_enable_stage_efforts()
clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(self.sen_stage_efforts, self.parasitic_inv_delay) clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(self.sen_stage_efforts)
total_delay = clk_to_sen_rise + clk_to_sen_fall 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)) 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 clk_to_sen_rise, clk_to_sen_fall return clk_to_sen_rise, clk_to_sen_fall
def determine_sa_enable_stage_efforts(self): def get_sa_enable_stage_efforts(self):
"""Follows the gated_clk_bar signal to the sense amp enable signal adding each stages stage effort to a list""" """Follows the gated_clk_bar signal to the sense amp enable signal adding each stages stage effort to a list"""
stage_effort_list = [] stage_effort_list = []
#Calculate the load on clk_buf_bar
ext_clk_buf_cout = self.sram.get_clk_bar_cin()
#Initial direction of clock signal for this path #Initial direction of clock signal for this path
last_stage_rise = True last_stage_rise = True
@ -917,7 +915,54 @@ class control_logic(design.design):
"""Gets a list of the stages and delays in order of their path.""" """Gets a list of the stages and delays in order of their path."""
if self.sen_stage_efforts == None or self.wl_stage_efforts == None: if self.sen_stage_efforts == None or self.wl_stage_efforts == None:
debug.error("Model delays not calculated for SRAM.", 1) debug.error("Model delays not calculated for SRAM.", 1)
wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts, self.parasitic_inv_delay) wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts)
sen_delays = logical_effort.calculate_delays(self.sen_stage_efforts, self.parasitic_inv_delay) sen_delays = logical_effort.calculate_delays(self.sen_stage_efforts)
return wl_delays, sen_delays return wl_delays, sen_delays
def analytical_delay(self, corner, slew, load):
"""Gets the analytical delay from clk input to wl_en output"""
stage_effort_list = []
#Calculate the load on clk_buf_bar
ext_clk_buf_cout = self.sram.get_clk_bar_cin()
#Operations logic starts on negative edge
last_stage_rise = False
#First stage(s), clk -(pdriver)-> clk_buf.
clk_buf_cout = self.replica_bitline.get_en_cin()
stage_effort_list += self.clk_buf_driver.get_stage_efforts(clk_buf_cout, last_stage_rise)
last_stage_rise = stage_effort_list[-1].is_rise
#Second stage, clk_buf -(inv)-> clk_bar
clk_bar_cout = self.and2.get_cin()
stage_effort_list += self.and2.get_stage_efforts(clk_bar_cout, last_stage_rise)
last_stage_rise = stage_effort_list[-1].is_rise
#Third stage clk_bar -(and)-> gated_clk_bar
gated_clk_bar_cin = self.get_gated_clk_bar_cin()
stage_effort_list.append(self.inv.get_stage_effort(gated_clk_bar_cin, last_stage_rise))
last_stage_rise = stage_effort_list[-1].is_rise
#Stages from gated_clk_bar -------> wordline
stage_effort_list += self.get_wordline_stage_efforts()
return stage_effort_list
def get_clk_buf_cin(self):
"""Get the loads that are connected to the buffered clock.
Includes all the DFFs and some logic."""
#Control logic internal load
int_clk_buf_cap = self.inv.get_cin() + self.ctrl_dff_array.get_clk_cin() + self.and2.get_cin()
#Control logic external load (in the other parts of the SRAM)
ext_clk_buf_cap = self.sram.get_clk_bar_cin()
return int_clk_buf_cap + ext_clk_buf_cap
def get_gated_clk_bar_cin(self):
"""Get intermediates net gated_clk_bar's capacitance"""
total_cin = 0
total_cin += self.wl_en_driver.get_cin()
if self.port_type == 'rw':
total_cin +=self.and2.get_cin()
return total_cin

View File

@ -2,6 +2,7 @@ import design
import debug import debug
import utils import utils
from tech import GDS,layer, parameter,drc from tech import GDS,layer, parameter,drc
import logical_effort
class sense_amp(design.design): class sense_amp(design.design):
""" """
@ -31,12 +32,13 @@ class sense_amp(design.design):
bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file. bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file.
return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff
def analytical_delay(self, corner, slew, load=0.0): def analytical_delay(self, corner, slew, load):
from tech import spice #Delay of the sense amp will depend on the size of the amp and the output load.
r = spice["min_tx_r"]/(10) parasitic_delay = 1
c_para = spice["min_tx_drain_c"] cin = (parameter["sa_inv_pmos_size"] + parameter["sa_inv_nmos_size"])/drc("minwidth_tx")
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew) sa_size = parameter["sa_inv_nmos_size"]/drc("minwidth_tx")
return self.return_delay(result.delay, result.slew) cc_inv_cin = cin
return logical_effort.logical_effort('column_mux', sa_size, cin, load+cc_inv_cin, parasitic_delay, False)
def analytical_power(self, corner, load): def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW""" """Returns dynamic and leakage power. Results in nW"""

View File

@ -136,8 +136,8 @@ class sense_amp_array(design.design):
def input_load(self): def input_load(self):
return self.amp.input_load() return self.amp.input_load()
def analytical_delay(self, corner, slew, load=0.0): def analytical_delay(self, corner, slew, load):
return self.amp.analytical_delay(corner, slew=slew, load=load) return [self.amp.analytical_delay(corner, slew=slew, load=load)]
def get_en_cin(self): def get_en_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the array""" """Get the relative capacitance of all the sense amp enable connections in the array"""

View File

@ -227,3 +227,10 @@ class single_level_column_mux_array(design.design):
result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = volt_swing) result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = volt_swing)
return self.return_delay(result.delay, result.slew) return self.return_delay(result.delay, result.slew)
def analytical_delay(self, corner, slew, load):
"""Returns relative delay that the column mux adds"""
#Single level column mux will add parasitic loads from other mux pass transistors and the sense amp.
drain_parasitics = .5 #Assumed parasitics from unused TXs
array_load = drain_parasitics*self.words_per_row*logical_effort.pinv
return [self.mux.analytical_delay(corner, slew, load+array_load)]

View File

@ -125,3 +125,8 @@ class pand2(pgate.pgate):
stage_effort_list.append(stage2) stage_effort_list.append(stage2)
return stage_effort_list return stage_effort_list
def get_cin(self):
"""Return the relative input capacitance of a single input"""
return self.nand.get_cin()

View File

@ -180,5 +180,9 @@ class single_level_column_mux(design.design):
width=self.bitcell.width, width=self.bitcell.width,
height=self.height) height=self.height)
def analytical_delay(self, corner, slew, load):
"""Returns relative delay that the column mux. Difficult to convert to LE model."""
parasitic_delay = 1
cin = 2*self.tx_size #This is not CMOS, so using this may be incorrect.
return logical_effort.logical_effort('column_mux', self.tx_size, cin, load, parasitic_delay, False)

View File

@ -11,6 +11,7 @@ from design import design
from verilog import verilog from verilog import verilog
from lef import lef from lef import lef
from sram_factory import factory from sram_factory import factory
import logical_effort
class sram_base(design, verilog, lef): class sram_base(design, verilog, lef):
""" """
@ -500,10 +501,26 @@ class sram_base(design, verilog, lef):
def analytical_delay(self, corner, slew,load): def analytical_delay(self, corner, slew,load):
""" LH and HL are the same in analytical model. """ """ Estimates the delay from clk -> DOUT
return self.bank.analytical_delay(corner,slew,load) LH and HL are the same in analytical model. """
delays = {}
for port in self.all_ports:
if port in self.readonly_ports:
control_logic = self.control_logic_r
elif port in self.readwrite_ports:
control_logic = self.control_logic_rw
else:
continue
clk_to_wlen_delays = control_logic.analytical_delay(corner, slew, load)
wlen_to_dout_delays = self.bank.analytical_delay(corner,slew,load) #port should probably be specified...
all_delays = clk_to_wlen_delays+wlen_to_dout_delays
total_delay = logical_effort.calculate_absolute_delay(all_delays)
last_slew = .1*all_delays[-1].get_absolute_delay() #slew approximated as 10% of delay
delays[port] = self.return_delay(delay=total_delay, slew=last_slew)
return delays
def determine_wordline_stage_efforts(self, inp_is_rise=True): def get_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 = []
@ -541,4 +558,12 @@ class sram_base(design, verilog, lef):
return self.bank.get_sen_cin() return self.bank.get_sen_cin()
def get_dff_clk_buf_cin(self):
"""Get the relative capacitance of the clk_buf signal.
Does not get the control logic loading but everything else"""
total_cin = 0
total_cin += self.row_addr_dff.get_clk_cin()
total_cin += self.data_dff.get_clk_cin()
if self.col_addr_size > 0:
total_cin += self.col_addr_dff.get_clk_cin()
return total_cin

View File

@ -15,7 +15,7 @@ class lib_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
OPTS.netlist_only = True
from characterizer import lib from characterizer import lib
from sram import sram from sram import sram
from sram_config import sram_config from sram_config import sram_config

View File

@ -336,6 +336,7 @@ spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input na
spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor. spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor.
#Parameters related to sense amp enable timing and delay chain/RBL sizing #Parameters related to sense amp enable timing and delay chain/RBL sizing
parameter['le_tau'] = 8 #In pico-seconds. FIXME:This is an assumed value, not measured.
parameter["static_delay_stages"] = 4 parameter["static_delay_stages"] = 4
parameter["static_fanout_per_stage"] = 3 parameter["static_fanout_per_stage"] = 3
parameter["static_fanout_list"] = parameter["static_delay_stages"]*[parameter["static_fanout_per_stage"]] parameter["static_fanout_list"] = parameter["static_delay_stages"]*[parameter["static_fanout_per_stage"]]
@ -344,6 +345,8 @@ parameter["6tcell_wl_cin"] = 3 #relative capacitance
parameter["min_inv_para_delay"] = 2.4 #Tau delay units parameter["min_inv_para_delay"] = 2.4 #Tau delay units
parameter["sa_en_pmos_size"] = .72 #micro-meters parameter["sa_en_pmos_size"] = .72 #micro-meters
parameter["sa_en_nmos_size"] = .27 #micro-meters parameter["sa_en_nmos_size"] = .27 #micro-meters
parameter["sa_inv_pmos_size"] = .54 #micro-meters
parameter["sa_inv_nmos_size"] = .27 #micro-meters
parameter["rbl_height_percentage"] = .5 #Height of RBL compared to bitcell array parameter["rbl_height_percentage"] = .5 #Height of RBL compared to bitcell array
################################################### ###################################################

View File

@ -302,6 +302,7 @@ spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input na
spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor. spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor.
#Logical Effort relative values for the Handmade cells #Logical Effort relative values for the Handmade cells
parameter['le_tau'] = 40 #In pico-seconds. FIXME:This is an assumed value, not measured.
parameter["static_delay_stages"] = 4 parameter["static_delay_stages"] = 4
parameter["static_fanout_per_stage"] = 3 parameter["static_fanout_per_stage"] = 3
parameter["static_fanout_list"] = parameter["static_delay_stages"]*[parameter["static_fanout_per_stage"]] parameter["static_fanout_list"] = parameter["static_delay_stages"]*[parameter["static_fanout_per_stage"]]
@ -310,6 +311,8 @@ parameter["6tcell_wl_cin"] = 2
parameter["min_inv_para_delay"] = .5 parameter["min_inv_para_delay"] = .5
parameter["sa_en_pmos_size"] = 24*_lambda_ parameter["sa_en_pmos_size"] = 24*_lambda_
parameter["sa_en_nmos_size"] = 9*_lambda_ parameter["sa_en_nmos_size"] = 9*_lambda_
parameter["sa_inv_pmos_size"] = 18*_lambda_
parameter["sa_inv_nmos_size"] = 9*_lambda_
parameter["rbl_height_percentage"] = .5 #Height of RBL compared to bitcell array parameter["rbl_height_percentage"] = .5 #Height of RBL compared to bitcell array
################################################### ###################################################