Replaced analytical characterization with graph implementation. Removed most analytical delay functions used by old chacterizer.

This commit is contained in:
Hunter Nichols 2019-08-08 02:33:51 -07:00
parent fc1cba099c
commit 3c44ce2df6
7 changed files with 33 additions and 120 deletions

View File

@ -1277,6 +1277,7 @@ class delay(simulation):
def sum_delays(self, delays): def sum_delays(self, delays):
"""Adds the delays (delay_data objects) so the correct slew is maintained""" """Adds the delays (delay_data objects) so the correct slew is maintained"""
delay = delays[0] delay = delays[0]
for i in range(1, len(delays)): for i in range(1, len(delays)):
delay+=delays[i] delay+=delays[i]
@ -1303,39 +1304,40 @@ class delay(simulation):
bl_name,br_name = self.get_bl_name(self.graph.all_paths, port) bl_name,br_name = self.get_bl_name(self.graph.all_paths, port)
bl_path = [path for path in self.graph.all_paths if bl_name in path][0] bl_path = [path for path in self.graph.all_paths if bl_name in path][0]
# Set delay/power for slews and loads
port_data = self.get_empty_measure_data_dict()
power = self.analytical_power(slews, loads)
debug.info(1,'Slew, Load, Delay(ns), Slew(ns)') debug.info(1,'Slew, Load, Delay(ns), Slew(ns)')
max_delay = 0.0
for slew in slews: for slew in slews:
for load in loads: for load in loads:
# Calculate delay based on slew and load
path_delays = self.graph.get_timing(bl_path, self.corner, slew, load) path_delays = self.graph.get_timing(bl_path, self.corner, slew, load)
total_delay = self.sum_delays(path_delays) total_delay = self.sum_delays(path_delays)
max_delay = max(max_delay, total_delay.delay)
debug.info(1,'{}, {}, {}, {}'.format(slew,load,total_delay.delay/1e3, total_delay.slew/1e3)) debug.info(1,'{}, {}, {}, {}'.format(slew,load,total_delay.delay/1e3, total_delay.slew/1e3))
debug.error('Not finished with graph delay characterization.', 1) # Delay is only calculated on a single port and replicated for now.
# power = self.analytical_power(slews, loads) for port in self.all_ports:
# port_data = self.get_empty_measure_data_dict() for mname in self.delay_meas_names+self.power_meas_names:
# relative_loads = [logical_effort.convert_farad_to_relative_c(c_farad) for c_farad in loads] if "power" in mname:
# for slew in slews: port_data[port][mname].append(power.dynamic)
# for load in relative_loads: elif "delay" in mname and port in self.read_ports:
# self.set_load_slew(load,slew) port_data[port][mname].append(total_delay.delay/1e3)
# bank_delay = self.sram.analytical_delay(self.corner, self.slew,self.load) elif "slew" in mname and port in self.read_ports:
# for port in self.all_ports: port_data[port][mname].append(total_delay.slew/1e3)
# for mname in self.delay_meas_names+self.power_meas_names: else:
# if "power" in mname: debug.error("Measurement name not recognized: {}".format(mname),1)
# port_data[port][mname].append(power.dynamic)
# elif "delay" in mname:
# port_data[port][mname].append(bank_delay[port].delay/1e3)
# elif "slew" in mname:
# port_data[port][mname].append(bank_delay[port].slew/1e3)
# else:
# debug.error("Measurement name not recognized: {}".format(mname),1)
# period_margin = 0.1
# risefall_delay = bank_delay[self.read_ports[0]].delay/1e3
# sram_data = { "min_period":risefall_delay*2*period_margin,
# "leakage_power": power.leakage}
# debug.info(2,"SRAM Data:\n{}".format(sram_data))
# debug.info(2,"Port Data:\n{}".format(port_data))
return (sram_data,port_data)
# Estimate the period as double the delay with margin
period_margin = 0.1
sram_data = { "min_period":(max_delay/1e3)*2*period_margin,
"leakage_power": power.leakage}
debug.info(2,"SRAM Data:\n{}".format(sram_data))
debug.info(2,"Port Data:\n{}".format(port_data))
return (sram_data,port_data)
def analytical_power(self, slews, loads): def analytical_power(self, slews, loads):
"""Get the dynamic and leakage power from the SRAM""" """Get the dynamic and leakage power from the SRAM"""

View File

@ -977,39 +977,6 @@ class bank(design.design):
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos) offset=control_pos)
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,
# slew,
# self.bitcell_array.input_load())
#FIXME: Array delay is the same for every port.
word_driver_slew = 0
if self.words_per_row > 1:
bitline_ext_load = self.port_data[port].column_mux_array.get_drain_cin()
else:
bitline_ext_load = self.port_data[port].sense_amp_array.get_drain_cin()
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_slew, bitline_ext_load)
bitcell_array_slew = 0
#This also essentially creates the same delay for each port. Good structure, no substance
if self.words_per_row > 1:
sa_load = self.port_data[port].sense_amp_array.get_drain_cin()
column_mux_delay = self.port_data[port].column_mux_array.analytical_delay(corner,
bitcell_array_slew,
sa_load)
else:
column_mux_delay = []
column_mux_slew = 0
sense_amp_delay = self.port_data[port].sense_amp_array.analytical_delay(corner,
column_mux_slew,
load)
# output load of bitcell_array is set to be only small part of bl for sense amp.
return bitcell_array_delay + column_mux_delay + sense_amp_delay
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

@ -149,16 +149,6 @@ class bitcell_array(design.design):
for pin in inst.get_pins(pin_name): for pin in inst.get_pins(pin_name):
self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
def analytical_delay(self, corner, slew, load):
"""Returns relative delay of the bitline in the bitcell array"""
from tech import parameter
#The load being driven/drained is mostly the bitline but could include the sense amp or the column mux.
#The load from the bitlines is due to the drain capacitances from all the other bitlines and wire parasitics.
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
wire_unit_load = .05 * drain_load #Wires add 5% to this.
bitline_load = (drain_load+wire_unit_load)*self.row_size
return [self.cell.analytical_delay(corner, slew, load+bitline_load)]
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

@ -374,16 +374,6 @@ class replica_bitcell_array(design.design):
""" Return the BR for the given RBL port """ """ Return the BR for the given RBL port """
return self.rbl_br_names[port] return self.rbl_br_names[port]
def analytical_delay(self, corner, slew, load):
"""Returns relative delay of the bitline in the bitcell array"""
from tech import parameter
#The load being driven/drained is mostly the bitline but could include the sense amp or the column mux.
#The load from the bitlines is due to the drain capacitances from all the other bitlines and wire parasitics.
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
wire_unit_load = 0.05 * drain_load #Wires add 5% to this.
bitline_load = (drain_load+wire_unit_load)*self.row_size
return [self.cell.analytical_delay(corner, slew, load+bitline_load)]
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

@ -145,9 +145,6 @@ 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):
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"""
sense_amp_en_cin = self.amp.get_en_cin() sense_amp_en_cin = self.amp.get_en_cin()

View File

@ -210,15 +210,6 @@ class single_level_column_mux_array(design.design):
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=br_out_offset) offset=br_out_offset)
def analytical_delay(self, corner, slew, load):
from tech import parameter
"""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_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
array_load = drain_load*self.words_per_row
return [self.mux.analytical_delay(corner, slew, load+array_load)]
def get_drain_cin(self): def get_drain_cin(self):
"""Get the relative capacitance of the drain of the NMOS pass TX""" """Get the relative capacitance of the drain of the NMOS pass TX"""
from tech import parameter from tech import parameter

View File

@ -567,30 +567,6 @@ class sram_base(design, verilog, lef):
del usedMODS del usedMODS
sp.close() sp.close()
def analytical_delay(self, corner, slew,load):
""" Estimates the delay from clk -> DOUT
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:
delays[port] = self.return_delay(0,0) #Write ports do not have a lib defined delay, marked as 0
continue
clk_to_wlen_delays = control_logic.analytical_delay(corner, slew, load)
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)
total_delay = self.apply_corners_analytically(total_delay, corner)
last_slew = .1*all_delays[-1].get_absolute_delay() #slew approximated as 10% of delay
last_slew = self.apply_corners_analytically(last_slew, corner)
delays[port] = self.return_delay(delay=total_delay, slew=last_slew)
return delays
def get_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 = []