mirror of https://github.com/VLSIDA/OpenRAM.git
Added delay chain resizing based on analytical delay.
This commit is contained in:
parent
8957c556db
commit
ea1a1c7705
|
|
@ -8,6 +8,8 @@ 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"]
|
||||||
|
|
||||||
def __init__(self, size, cin, cout, parasitic):
|
def __init__(self, size, cin, cout, parasitic):
|
||||||
self.cin = cin
|
self.cin = cin
|
||||||
self.cout = cout
|
self.cout = cout
|
||||||
|
|
@ -32,4 +34,5 @@ def calculate_relative_delay(stage_effort_list, pinv=parameter["min_inv_para_del
|
||||||
total_delay = 0
|
total_delay = 0
|
||||||
for stage in stage_effort_list:
|
for stage in stage_effort_list:
|
||||||
total_delay += stage.get_stage_delay(pinv)
|
total_delay += stage.get_stage_delay(pinv)
|
||||||
return total_delay
|
return total_delay
|
||||||
|
|
||||||
|
|
@ -12,13 +12,14 @@ from dff_inv_array import dff_inv_array
|
||||||
import math
|
import math
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
import logical_effort
|
||||||
|
|
||||||
class control_logic(design.design):
|
class control_logic(design.design):
|
||||||
"""
|
"""
|
||||||
Dynamically generated Control logic for the total SRAM circuit.
|
Dynamically generated Control logic for the total SRAM circuit.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, num_rows, words_per_row, port_type="rw"):
|
def __init__(self, num_rows, words_per_row, sram=None, port_type="rw"):
|
||||||
""" Constructor """
|
""" Constructor """
|
||||||
name = "control_logic_" + port_type
|
name = "control_logic_" + port_type
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
|
|
@ -28,6 +29,11 @@ class control_logic(design.design):
|
||||||
self.words_per_row = words_per_row
|
self.words_per_row = words_per_row
|
||||||
self.port_type = port_type
|
self.port_type = port_type
|
||||||
|
|
||||||
|
#This is needed to resize the delay chain. Likely to be changed at some point.
|
||||||
|
self.sram=sram
|
||||||
|
self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model.
|
||||||
|
self.parasitic_inv_delay = 0 #Keeping 0 for now until further testing.
|
||||||
|
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
self.num_control_signals = 2
|
self.num_control_signals = 2
|
||||||
else:
|
else:
|
||||||
|
|
@ -94,13 +100,19 @@ class control_logic(design.design):
|
||||||
c = reload(__import__(OPTS.replica_bitline))
|
c = reload(__import__(OPTS.replica_bitline))
|
||||||
replica_bitline = getattr(c, OPTS.replica_bitline)
|
replica_bitline = getattr(c, OPTS.replica_bitline)
|
||||||
|
|
||||||
delay_stages, delay_fanout = self.get_delay_chain_size()
|
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
||||||
bitcell_loads = int(math.ceil(self.num_rows / 2.0))
|
bitcell_loads = int(math.ceil(self.num_rows / 2.0))
|
||||||
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads, name="replica_bitline_"+self.port_type)
|
self.replica_bitline = replica_bitline(delay_stages_heuristic, delay_fanout_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.
|
||||||
|
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.add_mod(self.replica_bitline)
|
self.add_mod(self.replica_bitline)
|
||||||
|
|
||||||
def get_delay_chain_size(self):
|
def get_heuristic_delay_chain_size(self):
|
||||||
"""Determine the size of the delay chain used for the Sense Amp Enable """
|
"""Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """
|
||||||
# FIXME: These should be tuned according to the additional size parameters
|
# FIXME: These should be tuned according to the additional size parameters
|
||||||
delay_fanout = 3 # This can be anything >=2
|
delay_fanout = 3 # This can be anything >=2
|
||||||
# Delay stages Must be non-inverting
|
# Delay stages Must be non-inverting
|
||||||
|
|
@ -112,6 +124,35 @@ class control_logic(design.design):
|
||||||
delay_stages = 4
|
delay_stages = 4
|
||||||
return (delay_stages, delay_fanout)
|
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()
|
||||||
|
|
||||||
|
#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:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
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"""
|
||||||
|
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))
|
||||||
|
|
||||||
|
delay_fanout = 3 # 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 = 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))
|
||||||
|
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.
|
||||||
|
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 setup_signal_busses(self):
|
def setup_signal_busses(self):
|
||||||
""" Setup bus names, determine the size of the busses etc """
|
""" Setup bus names, determine the size of the busses etc """
|
||||||
|
|
||||||
|
|
@ -595,26 +636,48 @@ class control_logic(design.design):
|
||||||
offset=pin.ll(),
|
offset=pin.ll(),
|
||||||
height=pin.height(),
|
height=pin.height(),
|
||||||
width=pin.width())
|
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
|
||||||
|
|
||||||
def determine_wordline_stage_efforts(self, external_cout):
|
def determine_wordline_stage_efforts(self):
|
||||||
"""Follows the clock signal to the clk_buf signal adding each stages stage effort to a list"""
|
"""Follows the clock signal to the clk_buf signal to the wordline signal for the total path efforts"""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
#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()
|
||||||
clk_buf_cap = internal_cout+external_cout
|
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(clk_buf_cap)
|
stage_effort_list += self.clkbuf.determine_clk_buf_stage_efforts(internal_cout+external_cout)
|
||||||
|
|
||||||
|
#Then ask the sram for the other path delays (from the bank)
|
||||||
|
stage_effort_list += self.sram.determine_wordline_stage_efforts()
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
||||||
def determine_sa_enable_stage_efforts(self, ext_clk_buf_cout, ext_sen_cout):
|
def get_delay_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.
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
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"""
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
#Calculate the load on clk_buf_bar
|
#Calculate the load on clk_buf_bar
|
||||||
int_clk_buf_cout = self.get_clk_buf_bar_cin()
|
int_clk_buf_cout = self.get_clk_buf_bar_cin()
|
||||||
clk_buf_bar_cout = int_clk_buf_cout+ext_clk_buf_cout
|
ext_clk_buf_cout = self.sram.get_clk_bar_cin()
|
||||||
|
|
||||||
#First stage is the clock buffer
|
#First stage is the clock buffer
|
||||||
stage1 = self.clkbuf.determine_clk_buf_bar_stage_efforts(clk_buf_bar_cout)
|
stage1 = self.clkbuf.determine_clk_buf_bar_stage_efforts(int_clk_buf_cout+ext_clk_buf_cout)
|
||||||
stage_effort_list += stage1
|
stage_effort_list += stage1
|
||||||
|
|
||||||
#nand2 stage
|
#nand2 stage
|
||||||
|
|
@ -638,7 +701,8 @@ class control_logic(design.design):
|
||||||
stage_effort_list.append(stage5)
|
stage_effort_list.append(stage5)
|
||||||
|
|
||||||
#inverter (inv8) stage, s_en output
|
#inverter (inv8) stage, s_en output
|
||||||
stage6 = self.inv8.get_effort_stage(ext_sen_cout)
|
clk_sen_cout = self.sram.get_sen_cin()
|
||||||
|
stage6 = self.inv8.get_effort_stage(clk_sen_cout)
|
||||||
stage_effort_list.append(stage6)
|
stage_effort_list.append(stage6)
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ class sram_base(design):
|
||||||
sram_config.set_local_config(self)
|
sram_config.set_local_config(self)
|
||||||
|
|
||||||
self.bank_insts = []
|
self.bank_insts = []
|
||||||
|
|
||||||
|
#For logical effort delay calculations.
|
||||||
|
self.all_mods_except_control_done = False
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Add pins for entire SRAM. """
|
""" Add pins for entire SRAM. """
|
||||||
|
|
@ -67,8 +69,6 @@ class sram_base(design):
|
||||||
# Must create the control logic before pins to get the pins
|
# Must create the control logic before pins to get the pins
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.calculate_delay_to_wl()
|
|
||||||
self.calculate_delay_to_sen()
|
|
||||||
# This is for the lib file if we don't create layout
|
# This is for the lib file if we don't create layout
|
||||||
self.width=0
|
self.width=0
|
||||||
self.height=0
|
self.height=0
|
||||||
|
|
@ -216,22 +216,6 @@ class sram_base(design):
|
||||||
c = reload(__import__(OPTS.bitcell))
|
c = reload(__import__(OPTS.bitcell))
|
||||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||||
self.bitcell = self.mod_bitcell()
|
self.bitcell = self.mod_bitcell()
|
||||||
|
|
||||||
#c = reload(__import__(OPTS.control_logic))
|
|
||||||
#self.mod_control_logic = getattr(c, OPTS.control_logic)
|
|
||||||
|
|
||||||
|
|
||||||
from control_logic import control_logic
|
|
||||||
# Create the control logic module for each port type
|
|
||||||
if OPTS.num_rw_ports>0:
|
|
||||||
self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="rw")
|
|
||||||
self.add_mod(self.control_logic_rw)
|
|
||||||
if OPTS.num_w_ports>0:
|
|
||||||
self.control_logic_w = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="w")
|
|
||||||
self.add_mod(self.control_logic_w)
|
|
||||||
if OPTS.num_r_ports>0:
|
|
||||||
self.control_logic_r = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="r")
|
|
||||||
self.add_mod(self.control_logic_r)
|
|
||||||
|
|
||||||
# Create the address and control flops (but not the clk)
|
# Create the address and control flops (but not the clk)
|
||||||
from dff_array import dff_array
|
from dff_array import dff_array
|
||||||
|
|
@ -261,7 +245,23 @@ class sram_base(design):
|
||||||
|
|
||||||
self.supply_rail_width = self.bank.supply_rail_width
|
self.supply_rail_width = self.bank.supply_rail_width
|
||||||
self.supply_rail_pitch = self.bank.supply_rail_pitch
|
self.supply_rail_pitch = self.bank.supply_rail_pitch
|
||||||
|
|
||||||
|
#The control logic can resize itself based on the other modules. Requires all other modules added before control logic.
|
||||||
|
self.all_mods_except_control_done = True
|
||||||
|
|
||||||
|
#c = reload(__import__(OPTS.control_logic))
|
||||||
|
#self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||||
|
from control_logic import control_logic
|
||||||
|
# Create the control logic module for each port type
|
||||||
|
if OPTS.num_rw_ports>0:
|
||||||
|
self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row,sram=self, port_type="rw")
|
||||||
|
self.add_mod(self.control_logic_rw)
|
||||||
|
if OPTS.num_w_ports>0:
|
||||||
|
self.control_logic_w = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row,sram=self, port_type="w")
|
||||||
|
self.add_mod(self.control_logic_w)
|
||||||
|
if OPTS.num_r_ports>0:
|
||||||
|
self.control_logic_r = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row,sram=self, port_type="r")
|
||||||
|
self.add_mod(self.control_logic_r)
|
||||||
|
|
||||||
def create_bank(self,bank_num):
|
def create_bank(self,bank_num):
|
||||||
""" Create a bank """
|
""" Create a bank """
|
||||||
|
|
@ -456,24 +456,26 @@ 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 calculate_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"""
|
||||||
stage_efforts = self.determine_wordline_stage_efforts()
|
# debug.check(self.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
||||||
clk_to_wl_delay = logical_effort.calculate_relative_delay(stage_efforts, 0)
|
# stage_efforts = self.determine_wordline_stage_efforts()
|
||||||
debug.info(1, "Clock to wordline delay is {} delay units".format(clk_to_wl_delay))
|
# clk_to_wl_delay = logical_effort.calculate_relative_delay(stage_efforts, self.pinv)
|
||||||
return clk_to_wl_delay
|
# debug.info(1, "Clock to wordline delay is {} delay units".format(clk_to_wl_delay))
|
||||||
|
# return clk_to_wl_delay
|
||||||
|
|
||||||
def determine_wordline_stage_efforts(self):
|
def determine_wordline_stage_efforts(self):
|
||||||
"""Get the all the stage efforts for each stage in the path from clk to a wordline"""
|
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
|
||||||
|
#clk
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
clk_buf_cout = self.get_clk_cin()
|
# clk_buf_cout = self.get_clk_cin()
|
||||||
#Assume rw only. There are important differences with multiport that will need to be accounted for.
|
# #Assume rw only. There are important differences with multiport that will need to be accounted for.
|
||||||
if self.control_logic_rw != None:
|
# if self.control_logic_rw != None:
|
||||||
stage_effort_list += self.control_logic_rw.determine_wordline_stage_efforts(clk_buf_cout)
|
# stage_effort_list += self.control_logic_rw.determine_wordline_stage_efforts(clk_buf_cout)
|
||||||
else:
|
# else:
|
||||||
stage_effort_list += self.control_logic_r.determine_wordline_stage_efforts(clk_buf_cout)
|
# stage_effort_list += self.control_logic_r.determine_wordline_stage_efforts(clk_buf_cout)
|
||||||
|
|
||||||
#Clk_buf then move to the bank/wordline driver. Get the delay stages there.
|
#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)
|
||||||
|
|
||||||
|
|
@ -491,27 +493,28 @@ class sram_base(design):
|
||||||
|
|
||||||
return row_addr_clk_cin + data_clk_cin + col_addr_clk_cin + bank_clk_cin
|
return row_addr_clk_cin + data_clk_cin + col_addr_clk_cin + bank_clk_cin
|
||||||
|
|
||||||
def calculate_delay_to_sen(self):
|
# def get_delay_to_sen(self):
|
||||||
"""Get the delay (in delay units) of the clk to a sense amp enable.
|
# """Get the delay (in delay units) of the clk to a sense amp enable.
|
||||||
This does not incorporate the delay of the replica bitline.
|
# This does not incorporate the delay of the replica bitline.
|
||||||
"""
|
# """
|
||||||
stage_efforts = self.determine_sa_enable_stage_efforts()
|
# debug.check(self.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
||||||
clk_to_sen_delay = logical_effort.calculate_relative_delay(stage_efforts, 0)
|
# stage_efforts = self.determine_sa_enable_stage_efforts()
|
||||||
debug.info(1, "Clock to s_en delay is {} delay units".format(clk_to_sen_delay))
|
# clk_to_sen_delay = logical_effort.calculate_relative_delay(stage_efforts, self.pinv)
|
||||||
return clk_to_sen_delay
|
# debug.info(1, "Clock to s_en delay is {} delay units".format(clk_to_sen_delay))
|
||||||
|
# return clk_to_sen_delay
|
||||||
|
|
||||||
def determine_sa_enable_stage_efforts(self):
|
# def determine_sa_enable_stage_efforts(self):
|
||||||
"""Get the all the stage efforts for each stage in the path from clk to a sense amp enable"""
|
# """Get the all the stage efforts for each stage in the path from clk to a sense amp enable"""
|
||||||
stage_effort_list = []
|
# stage_effort_list = []
|
||||||
clk_buf_bar_cout = self.get_clk_bar_cin()
|
# clk_buf_bar_cout = self.get_clk_bar_cin()
|
||||||
clk_sen_cout = self.get_sen_cin()
|
# clk_sen_cout = self.get_sen_cin()
|
||||||
#Assume rw only. There are important differences with multiport that will need to be accounted for.
|
# #Assume rw only. There are important differences with multiport that will need to be accounted for.
|
||||||
if self.control_logic_rw != None:
|
# if self.control_logic_rw != None:
|
||||||
stage_effort_list += self.control_logic_rw.determine_sa_enable_stage_efforts(clk_buf_bar_cout, clk_sen_cout)
|
# stage_effort_list += self.control_logic_rw.determine_sa_enable_stage_efforts(clk_buf_bar_cout, clk_sen_cout)
|
||||||
else:
|
# else:
|
||||||
stage_effort_list += self.control_logic_r.determine_sa_enable_stage_efforts(clk_buf_bar_cout, clk_sen_cout)
|
# stage_effort_list += self.control_logic_r.determine_sa_enable_stage_efforts(clk_buf_bar_cout, clk_sen_cout)
|
||||||
|
|
||||||
return stage_effort_list
|
# return stage_effort_list
|
||||||
|
|
||||||
def get_clk_bar_cin(self):
|
def get_clk_bar_cin(self):
|
||||||
"""Gets the capacitive load the of clock (clk_buf_bar) for the sram"""
|
"""Gets the capacitive load the of clock (clk_buf_bar) for the sram"""
|
||||||
|
|
@ -527,5 +530,5 @@ class sram_base(design):
|
||||||
bank_sen_cin = self.bank.get_sen_cin()
|
bank_sen_cin = self.bank.get_sen_cin()
|
||||||
return bank_sen_cin
|
return bank_sen_cin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue