From a500d7ee3dffcf53efba6eaec7637cc82880492b Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Tue, 9 Apr 2019 02:49:52 -0700 Subject: [PATCH] Adjusted bitcell analytical delays for multiport cells. --- compiler/bitcells/bitcell_1rw_1r.py | 17 ++++++----------- compiler/bitcells/bitcell_1w_1r.py | 17 ++++++----------- compiler/bitcells/pbitcell.py | 17 +++++++++++------ compiler/modules/bank.py | 3 +-- compiler/sram_base.py | 2 +- 5 files changed, 25 insertions(+), 31 deletions(-) diff --git a/compiler/bitcells/bitcell_1rw_1r.py b/compiler/bitcells/bitcell_1rw_1r.py index a96dcff0..e597167f 100644 --- a/compiler/bitcells/bitcell_1rw_1r.py +++ b/compiler/bitcells/bitcell_1rw_1r.py @@ -2,6 +2,7 @@ import design import debug import utils from tech import GDS,layer,parameter,drc +import logical_effort class bitcell_1rw_1r(design.design): """ @@ -25,18 +26,12 @@ class bitcell_1rw_1r(design.design): self.pin_map = bitcell_1rw_1r.pin_map def analytical_delay(self, corner, slew, load=0, swing = 0.5): - # delay of bit cell is not like a driver(from WL) - # so the slew used should be 0 - # it should not be slew dependent? - # because the value is there - # the delay is only over half transsmission gate - from tech import spice - r = spice["min_tx_r"]*3 - c_para = spice["min_tx_drain_c"] - result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing) - return result + 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. + read_port_load = 0.5 #min size NMOS gate load + return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False) - 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 """ bitcell_pins = ["bl0_{0}".format(col), diff --git a/compiler/bitcells/bitcell_1w_1r.py b/compiler/bitcells/bitcell_1w_1r.py index e2cc662b..cf487fba 100644 --- a/compiler/bitcells/bitcell_1w_1r.py +++ b/compiler/bitcells/bitcell_1w_1r.py @@ -2,6 +2,7 @@ import design import debug import utils from tech import GDS,layer,parameter,drc +import logical_effort class bitcell_1w_1r(design.design): """ @@ -25,18 +26,12 @@ class bitcell_1w_1r(design.design): self.pin_map = bitcell_1w_1r.pin_map def analytical_delay(self, corner, slew, load=0, swing = 0.5): - # delay of bit cell is not like a driver(from WL) - # so the slew used should be 0 - # it should not be slew dependent? - # because the value is there - # the delay is only over half transsmission gate - from tech import spice - r = spice["min_tx_r"]*3 - c_para = spice["min_tx_drain_c"] - result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing) - return result + 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. + read_port_load = 0.5 #min size NMOS gate load + return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False) - 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 """ bitcell_pins = ["bl0_{0}".format(col), diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index 55712e44..94c294db 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -5,6 +5,7 @@ from tech import drc, parameter, spice from vector import vector from ptx import ptx from globals import OPTS +import logical_effort class pbitcell(design.design): """ @@ -867,12 +868,16 @@ class pbitcell(design.design): self.add_path("metal1", [Q_bar_pos, vdd_pos]) def analytical_delay(self, corner, slew, load=0, swing = 0.5): - #FIXME: Delay copied exactly over from bitcell - from tech import spice - r = spice["min_tx_r"]*3 - c_para = spice["min_tx_drain_c"] - result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing) - return result + 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. + + #Internal loads due to port configs are halved. This is to account for the size already being halved + #for stacked TXs, but internal loads do not see this size estimation. + write_port_load = self.num_w_ports*logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])/2 + read_port_load = self.num_r_ports/2 #min size NMOS gate load + total_load = load+read_port_load+write_port_load + return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False) def analytical_power(self, corner, load): """Bitcell power in nW. Only characterizes leakage.""" diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 5df8ee87..5b556660 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -1215,7 +1215,7 @@ class bank(design.design): offset=control_pos, rotate=90) - def analytical_delay(self, corner, slew, load): + def analytical_delay(self, corner, slew, load, port): """ 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, @@ -1224,7 +1224,6 @@ class bank(design.design): #FIXME: Array delay is the same for every port. word_driver_slew = 0 - port = 0 if self.words_per_row > 1: bitline_ext_load = self.column_mux_array[port].get_drain_cin() else: diff --git a/compiler/sram_base.py b/compiler/sram_base.py index a7f0e965..6d859358 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -517,7 +517,7 @@ class sram_base(design, verilog, lef): 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... + wlen_to_dout_delays = self.bank.analytical_delay(corner,slew,load,port) #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