mirror of https://github.com/VLSIDA/OpenRAM.git
Replaced analytical characterization with graph implementation. Removed most analytical delay functions used by old chacterizer.
This commit is contained in:
parent
fc1cba099c
commit
3c44ce2df6
|
|
@ -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"""
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = []
|
||||
|
|
|
|||
Loading…
Reference in New Issue