Added sense amp enable delay calculation.

This commit is contained in:
Hunter Nichols 2018-11-08 20:47:34 -08:00
parent b8061d3a4e
commit 8957c556db
21 changed files with 276 additions and 26 deletions

View File

@ -1,7 +1,7 @@
import design
import debug
import utils
from tech import GDS,layer, parameter
from tech import GDS,layer,parameter,drc
class bitcell(design.design):
"""
@ -94,7 +94,8 @@ class bitcell(design.design):
return total_power
def get_wl_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
"""Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width.
return parameter["6tcell_wl_cin"]
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin

View File

@ -1,7 +1,7 @@
import design
import debug
import utils
from tech import GDS,layer
from tech import GDS,layer,parameter,drc
class bitcell_1rw_1r(design.design):
"""
@ -96,3 +96,10 @@ class bitcell_1rw_1r(design.design):
total_power = self.return_power(dynamic, leakage)
return total_power
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin

View File

@ -905,4 +905,10 @@ class pbitcell(design.design):
leakage = spice["bitcell_leakage"]
dynamic = 0 #temporary
total_power = self.return_power(dynamic, leakage)
return total_power
return total_power
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#pbitcell uses the different sizing for the port access tx's. Not accounted for in this model.
access_tx_cin = self.readwrite_nmos.get_cin()
return 2*access_tx_cin

View File

@ -1,7 +1,7 @@
import design
import debug
import utils
from tech import GDS,layer
from tech import GDS,layer,drc,parameter
class replica_bitcell(design.design):
"""
@ -21,3 +21,10 @@ class replica_bitcell(design.design):
self.width = replica_bitcell.width
self.height = replica_bitcell.height
self.pin_map = replica_bitcell.pin_map
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin

View File

@ -1,7 +1,7 @@
import design
import debug
import utils
from tech import GDS,layer
from tech import GDS,layer,drc,parameter
class replica_bitcell_1rw_1r(design.design):
"""
@ -21,3 +21,11 @@ class replica_bitcell_1rw_1r(design.design):
self.width = replica_bitcell_1rw_1r.width
self.height = replica_bitcell_1rw_1r.height
self.pin_map = replica_bitcell_1rw_1r.pin_map
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin

View File

@ -1,6 +1,6 @@
import debug
import design
from tech import drc, spice
from tech import drc, spice,parameter
from vector import vector
from globals import OPTS
from pbitcell import pbitcell
@ -79,4 +79,8 @@ class replica_pbitcell(design.design):
self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
self.copy_layout_pin(self.prbc_inst, "vdd")
self.copy_layout_pin(self.prbc_inst, "gnd")
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This module is made using a pbitcell. Get the cin from that module
return self.prbc.get_wl_cin()

View File

@ -13,4 +13,23 @@ class logical_effort():
self.cout = cout
self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin
self.eletrical_effort = self.cout/self.cin
self.parasitic = parasitic
self.parasitic_scale = parasitic
def __str__(self):
return "g = " + str(self.logical_effort) + ", h = " + str(self.eletrical_effort) + ", p = " + str(self.parasitic_scale)+"*pinv"
def get_stage_effort(self):
return self.logical_effort*self.eletrical_effort
def get_parasitic_delay(self, pinv):
return pinv * self.parasitic_scale
def get_stage_delay(self, pinv):
return self.get_stage_effort()+self.get_parasitic_delay(pinv)
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
for stage in stage_effort_list:
total_delay += stage.get_stage_delay(pinv)
return total_delay

View File

@ -964,4 +964,19 @@ class bank(design.design):
"""Get the relative capacitance of all the clk connections in the bank"""
#Current bank only uses clock (clk_buf) as an enable for the wordline driver.
total_clk_cin = self.wordline_driver.get_clk_cin()
return total_clk_cin
return total_clk_cin
def get_clk_bar_cin(self):
"""Get the relative capacitance of all the clk_bar connections in the bank"""
#Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array.
#Assume single port
port = 0
total_clk_bar_cin = self.precharge_array[port].get_en_cin()
return total_clk_bar_cin
def get_sen_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the bank"""
#Current bank only uses sen as an enable for the sense amps.
total_sen_cin = self.sense_amp_array.get_en_cin()
return total_sen_cin

View File

@ -603,7 +603,51 @@ class control_logic(design.design):
internal_cout = self.ctrl_dff_array.get_clk_cin()
clk_buf_cap = internal_cout+external_cout
#First stage is the clock buffer
stage_effort_list += self.clkbuf.determine_wordline_stage_efforts(clk_buf_cap)
stage_effort_list += self.clkbuf.determine_clk_buf_stage_efforts(clk_buf_cap)
return stage_effort_list
def determine_sa_enable_stage_efforts(self, ext_clk_buf_cout, ext_sen_cout):
"""Follows the clock signal to the sense amp enable signal adding each stages stage effort to a list"""
stage_effort_list = []
#Calculate the load on clk_buf_bar
int_clk_buf_cout = self.get_clk_buf_bar_cin()
clk_buf_bar_cout = int_clk_buf_cout+ext_clk_buf_cout
#First stage is the clock buffer
stage1 = self.clkbuf.determine_clk_buf_bar_stage_efforts(clk_buf_bar_cout)
stage_effort_list += stage1
#nand2 stage
stage2_cout = self.inv1.get_cin()
stage2 = self.nand2.get_effort_stage(stage2_cout)
stage_effort_list.append(stage2)
#inverter stage
stage3_cout = self.replica_bitline.get_en_cin()
stage3 = self.inv1.get_effort_stage(stage3_cout)
stage_effort_list.append(stage3)
#Replica bitline stage
stage4_cout = self.inv2.get_cin()
stage4 = self.replica_bitline.determine_sen_stage_efforts(stage4_cout)
stage_effort_list += stage4
#inverter (inv2) stage
stage5_cout = self.inv8.get_cin()
stage5 = self.inv2.get_effort_stage(stage5_cout)
stage_effort_list.append(stage5)
#inverter (inv8) stage, s_en output
stage6 = self.inv8.get_effort_stage(ext_sen_cout)
stage_effort_list.append(stage6)
return stage_effort_list
def get_clk_buf_bar_cin(self):
"""Get the relative capacitance off the clk_buf_bar signal internal to the control logic"""
we_nand_cin = self.nand2.get_cin()
if self.port_type == "rw":
nand_mod = self.nand3
else:
nand_mod = self.nand2
sen_nand_cin = nand_mod.get_cin()
return we_nand_cin + sen_nand_cin

View File

@ -219,4 +219,21 @@ class delay_chain(design.design):
start=mid_point,
end=mid_point.scale(1,0))
def get_cin(self):
"""Get the enable input ralative capacitance"""
#Only 1 input to the delay chain which is connected to an inverter.
dc_cin = self.inv.get_cin()
return dc_cin
def determine_delayed_en_stage_efforts(self, ext_delayed_en_cout):
"""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.
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_effort_list.append(stage)
return stage_effort_list

View File

@ -102,3 +102,9 @@ class precharge_array(design.design):
for i in range(self.columns):
offset = vector(self.pc_cell.width * i, 0)
self.local_insts[i].place(offset)
def get_en_cin(self):
"""Get the relative capacitance of all the clk connections in the precharge array"""
#Assume single port
precharge_en_cin = self.pc_cell.get_en_cin()
return precharge_en_cin*self.columns

View File

@ -608,4 +608,29 @@ class replica_bitline(design.design):
offset=pin.ll(),
height=pin.height(),
width=pin.width())
def get_en_cin(self):
"""Get the enable input relative capacitance"""
#The enable is only connected to the delay, get the cin from that module
en_cin = self.delay_chain.get_cin()
return en_cin
def determine_sen_stage_efforts(self, ext_cout):
"""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)
stage_effort_list += stage1
#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)
stage_effort_list.append(stage2)
return stage_effort_list
def get_delayed_en_cin(self):
access_tx_cin = self.access_tx.get_cin()
rbc_cin = self.replica_bitcell.get_wl_cin()
return access_tx_cin + rbc_cin

View File

@ -1,7 +1,7 @@
import design
import debug
import utils
from tech import GDS,layer
from tech import GDS,layer, parameter,drc
class sense_amp(design.design):
"""
@ -41,3 +41,9 @@ class sense_amp(design.design):
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
total_power = self.return_power()
return total_power
def get_en_cin(self):
"""Get the relative capacitance of sense amp enable gate cin"""
pmos_cin = parameter["sa_en_pmos_size"]/drc("minwidth_tx")
nmos_cin = parameter["sa_en_nmos_size"]/drc("minwidth_tx")
return 2*pmos_cin + nmos_cin

View File

@ -140,3 +140,7 @@ class sense_amp_array(design.design):
def analytical_delay(self, slew, load=0.0):
return self.amp.analytical_delay(slew=slew, load=load)
def get_en_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the array"""
sense_amp_en_cin = self.amp.get_en_cin()
return sense_amp_en_cin * self.words_per_row

View File

@ -187,7 +187,7 @@ class pinvbuf(design.design):
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
return inv1_delay + inv2_delay
def determine_wordline_stage_efforts(self, external_cout):
def determine_clk_buf_stage_efforts(self, external_cout):
"""Get the stage efforts of the clk -> clk_buf path"""
stage_effort_list = []
stage1_cout = self.inv1.get_cin() + self.inv2.get_cin()
@ -197,4 +197,20 @@ class pinvbuf(design.design):
stage2 = self.inv2.get_effort_stage(external_cout)
stage_effort_list.append(stage2)
return stage_effort_list
def determine_clk_buf_bar_stage_efforts(self, external_cout):
"""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)
stage_effort_list.append(stage1)
stage2_cout = self.inv2.get_cin()
stage2 = self.inv1.get_effort_stage(stage2_cout)
stage_effort_list.append(stage2)
stage3 = self.inv2.get_effort_stage(external_cout)
stage_effort_list.append(stage3)
return stage_effort_list

View File

@ -23,6 +23,7 @@ class pnand3(pgate.pgate):
# We have trouble pitch matching a 3x sizes to the bitcell...
# If we relax this, we could size this better.
self.size = size
self.nmos_size = 2*size
self.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc("minwidth_tx")
@ -261,3 +262,12 @@ class pnand3(pgate.pgate):
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transition_prob = spice["nand3_transition_prob"]
return transition_prob*(c_load + c_para)
def get_cin(self):
"""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."""
parasitic_delay = 3
return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay)

View File

@ -234,3 +234,9 @@ class precharge(pgate.pgate):
width=width,
height=height)
def get_en_cin(self):
"""Get the relative capacitance of the enable in the precharge cell"""
#The enable connect to three pmos gates. They all use the same size pmos.
pmos_cin = self.pmos.get_cin()
return 3*pmos_cin

View File

@ -353,4 +353,6 @@ class ptx(design.design):
if self.connect_active:
self.connect_fingered_active(drain_positions, source_positions)
def get_cin(self):
"""Returns the relative gate cin of the tx"""
return self.tx_width/drc("minwidth_tx")

View File

@ -5,7 +5,7 @@ import debug
from importlib import reload
from vector import vector
from globals import OPTS, print_time
import logical_effort
from design import design
class sram_base(design):
@ -67,7 +67,8 @@ class sram_base(design):
# Must create the control logic before pins to get the pins
self.add_modules()
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
self.width=0
self.height=0
@ -455,9 +456,12 @@ class sram_base(design):
""" LH and HL are the same in analytical model. """
return self.bank.analytical_delay(vdd,slew,load)
def calculate_delay_to_wl(self):
def calculate_delay_to_wl(self):
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
stage_efforts = self.determine_wordline_stage_efforts()
return 0
clk_to_wl_delay = logical_effort.calculate_relative_delay(stage_efforts, 0)
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):
"""Get the all the stage efforts for each stage in the path from clk to a wordline"""
@ -483,8 +487,45 @@ class sram_base(design):
col_addr_clk_cin = 0
if self.col_addr_size > 0:
col_addr_clk_cin = self.col_addr_dff.get_clk_cin()
#Bank cin...
bank_clk_cin = self.bank.get_clk_cin()
return row_addr_clk_cin + data_clk_cin + col_addr_clk_cin + bank_clk_cin
def calculate_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.
"""
stage_efforts = self.determine_sa_enable_stage_efforts()
clk_to_sen_delay = logical_effort.calculate_relative_delay(stage_efforts, 0)
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):
"""Get the all the stage efforts for each stage in the path from clk to a sense amp enable"""
stage_effort_list = []
clk_buf_bar_cout = self.get_clk_bar_cin()
clk_sen_cout = self.get_sen_cin()
#Assume rw only. There are important differences with multiport that will need to be accounted for.
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)
else:
stage_effort_list += self.control_logic_r.determine_sa_enable_stage_efforts(clk_buf_bar_cout, clk_sen_cout)
return stage_effort_list
def get_clk_bar_cin(self):
"""Gets the capacitive load the of clock (clk_buf_bar) for the sram"""
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
#Only the precharge cells use this signal (other than the control logic)
bank_clk_cin = self.bank.get_clk_bar_cin()
return bank_clk_cin
def get_sen_cin(self):
"""Gets the capacitive load the of sense amp enable for the sram"""
#As clk_buf_bar is an output of the control logic. The cap for that module is not determined here.
#Only the sense_amps use this signal (other than the control logic)
bank_sen_cin = self.bank.get_sen_cin()
return bank_sen_cin

View File

@ -329,8 +329,11 @@ spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input na
spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor.
#Logical Effort relative values for the Handmade cells
spice["dff_clk_cin"] = 30.6
parameter["6tcell_wl_cin"] = 3
parameter["dff_clk_cin"] = 30.6 #relative capacitance
parameter["6tcell_wl_cin"] = 3 #relative capacitance
parameter["min_inv_para_delay"] = .5 #Tau delay units
parameter["sa_en_pmos_size"] = .72 #micro-meters
parameter["sa_en_nmos_size"] = .27 #micro-meters
###################################################
##END Spice Simulation Parameters

View File

@ -297,6 +297,9 @@ spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input no
#Logical Effort relative values for the Handmade cells
parameter["dff_clk_cin"] = 27.5
parameter["6tcell_wl_cin"] = 2
parameter["min_inv_para_delay"] = .5
parameter["sa_en_pmos_size"] = 24*_lambda_
parameter["sa_en_nmos_size"] = 9*_lambda_
###################################################
##END Spice Simulation Parameters