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):
"""Adds the delays (delay_data objects) so the correct slew is maintained"""
delay = delays[0]
for i in range(1, len(delays)):
delay+=delays[i]
@ -1303,40 +1304,41 @@ class delay(simulation):
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]
# 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)')
max_delay = 0.0
for slew in slews:
for load in loads:
# Calculate delay based on slew and load
path_delays = self.graph.get_timing(bl_path, self.corner, slew, load)
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.error('Not finished with graph delay characterization.', 1)
# power = self.analytical_power(slews, loads)
# port_data = self.get_empty_measure_data_dict()
# relative_loads = [logical_effort.convert_farad_to_relative_c(c_farad) for c_farad in loads]
# for slew in slews:
# for load in relative_loads:
# self.set_load_slew(load,slew)
# bank_delay = self.sram.analytical_delay(self.corner, self.slew,self.load)
# for port in self.all_ports:
# for mname in self.delay_meas_names+self.power_meas_names:
# if "power" in mname:
# 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)
# Delay is only calculated on a single port and replicated for now.
for port in self.all_ports:
for mname in self.delay_meas_names+self.power_meas_names:
if "power" in mname:
port_data[port][mname].append(power.dynamic)
elif "delay" in mname and port in self.read_ports:
port_data[port][mname].append(total_delay.delay/1e3)
elif "slew" in mname and port in self.read_ports:
port_data[port][mname].append(total_delay.slew/1e3)
else:
debug.error("Measurement name not recognized: {}".format(mname),1)
# 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):
"""Get the dynamic and leakage power from the SRAM"""

View File

@ -976,40 +976,7 @@ class bank(design.design):
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
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):
"""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

View File

@ -148,17 +148,7 @@ class bitcell_array(design.design):
for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name):
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):
"""Power of Bitcell array and bitline in nW."""
from tech import drc, parameter

View File

@ -373,17 +373,7 @@ class replica_bitcell_array(design.design):
def get_rbl_br_name(self, port):
""" Return the BR for the given RBL 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):
"""Power of Bitcell array and bitline in nW."""
from tech import drc, parameter

View File

@ -144,10 +144,7 @@ class sense_amp_array(design.design):
def input_load(self):
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):
"""Get the relative capacitance of all the sense amp enable connections in the array"""
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"),
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):
"""Get the relative capacitance of the drain of the NMOS pass TX"""
from tech import parameter

View File

@ -566,31 +566,7 @@ class sram_base(design, verilog, lef):
self.sp_write_file(sp, usedMODS)
del usedMODS
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):
"""Get the all the stage efforts for each stage in the path from clk_buf to a wordline"""
stage_effort_list = []