Merge branch 'dev' into control_fix

This commit is contained in:
Matt Guthaus 2019-08-10 13:07:30 -07:00
commit 8d6a4c74e7
48 changed files with 241 additions and 475 deletions

View File

@ -18,13 +18,16 @@ class timing_graph():
def __init__(self):
self.graph = defaultdict(set)
self.all_paths = []
self.edge_mods = {}
def add_edge(self, src_node, dest_node):
"""Adds edge to graph. Nodes added as well if they do not exist."""
def add_edge(self, src_node, dest_node, edge_mod):
"""Adds edge to graph. Nodes added as well if they do not exist.
Module which defines the edge must be provided for timing information."""
src_node = src_node.lower()
dest_node = dest_node.lower()
self.graph[src_node].add(dest_node)
self.edge_mods[(src_node, dest_node)] = edge_mod
def add_node(self, node):
"""Add node to graph with no edges"""
@ -34,8 +37,8 @@ class timing_graph():
self.graph[node] = set()
def remove_edges(self, node):
"""Helper function to remove edges, useful for removing vdd/gnd"""
node = node.lower()
self.graph[node] = set()
@ -93,7 +96,33 @@ class timing_graph():
# Remove current vertex from path[] and mark it as unvisited
path.pop()
visited.remove(cur_node)
visited.remove(cur_node)
def get_timing(self, path, corner, slew, load):
"""Returns the analytical delays in the input path"""
if len(path) == 0:
return []
delays = []
cur_slew = slew
for i in range(len(path)-1):
path_edge_mod = self.edge_mods[(path[i], path[i+1])]
# On the output of the current stage, get COUT from all other mods connected
cout = 0
for node in self.graph[path[i+1]]:
output_edge_mod = self.edge_mods[(path[i+1], node)]
cout+=output_edge_mod.get_cin()
# If at the last output, include the final output load
if i == len(path)-2:
cout+=load
delays.append(path_edge_mod.analytical_delay(corner, slew, cout))
cur_slew = delays[-1].slew
return delays
def __str__(self):
""" override print function output """

View File

@ -110,7 +110,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
"""Initializes parameters relevant to the graph creation"""
#Only initializes a set for checking instances which should not be added
self.graph_inst_exclude = set()
def build_graph(self, graph, inst_name, port_nets):
"""Recursively create graph from instances in module."""
@ -219,7 +219,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
for inp in input_pins+inout_pins:
for out in output_pins+inout_pins:
if inp != out: #do not add self loops
graph.add_edge(pin_dict[inp], pin_dict[out])
graph.add_edge(pin_dict[inp], pin_dict[out], self)
def __str__(self):
""" override print function output """

View File

@ -13,7 +13,7 @@ import tech
from delay_data import *
from wire_spice_model import *
from power_data import *
import logical_effort
class spice():
"""
@ -304,14 +304,48 @@ class spice():
def analytical_delay(self, corner, slew, load=0.0):
"""Inform users undefined delay module while building new modules"""
debug.warning("Design Class {0} delay function needs to be defined"
# FIXME: Slew is not used in the model right now. Can be added heuristically as linear factor
relative_cap = logical_effort.convert_farad_to_relative_c(load)
stage_effort = self.get_stage_effort(relative_cap)
# If it fails, then keep running with a valid object.
if stage_effort == None:
return delay_data(0.0, 0.0)
abs_delay = stage_effort.get_absolute_delay()
corner_delay = self.apply_corners_analytically(abs_delay, corner)
SLEW_APPROXIMATION = 0.1
corner_slew = SLEW_APPROXIMATION*corner_delay
return delay_data(corner_delay, corner_slew)
def get_stage_effort(self, corner, slew, load=0.0):
"""Inform users undefined delay module while building new modules"""
debug.warning("Design Class {0} logical effort function needs to be defined"
.format(self.__class__.__name__))
debug.warning("Class {0} name {1}"
.format(self.__class__.__name__,
self.name))
# return 0 to keep code running while building
return delay_data(0.0, 0.0)
return None
def get_cin(self):
"""Returns input load in Femto-Farads. All values generated using
relative capacitance function then converted based on tech file parameter."""
# Override this function within a module if a more accurate input capacitance is needed.
# Input/outputs with differing capacitances is not implemented.
relative_cap = self.input_load()
return logical_effort.convert_relative_c_to_farad(relative_cap)
def input_load(self):
"""Inform users undefined relative capacitance functions used for analytical delays."""
debug.warning("Design Class {0} input capacitance function needs to be defined"
.format(self.__class__.__name__))
debug.warning("Class {0} name {1}"
.format(self.__class__.__name__,
self.name))
return 0
def cal_delay_with_rc(self, corner, r, c ,slew, swing = 0.5):
"""
Calculate the delay of a mosfet by

View File

@ -36,7 +36,7 @@ class bitcell(design.design):
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
def get_stage_effort(self, load):
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.
@ -94,10 +94,10 @@ class bitcell(design.design):
debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets))
return None
def get_wl_cin(self):
def input_load(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: This applies to bitline capacitances as well.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin

View File

@ -36,7 +36,7 @@ class bitcell_1rw_1r(design.design):
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
def get_stage_effort(self, load):
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.
@ -118,11 +118,11 @@ class bitcell_1rw_1r(design.design):
total_power = self.return_power(dynamic, leakage)
return total_power
def get_wl_cin(self):
def input_load(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.
# FIXME: This applies to bitline capacitances as well.
# 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
@ -141,8 +141,8 @@ class bitcell_1rw_1r(design.design):
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"])
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self)
graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self)
# Port 1 edges
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl1"], pin_dict["br1"])
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)

View File

@ -36,7 +36,7 @@ class bitcell_1w_1r(design.design):
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
def get_stage_effort(self, load):
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.
@ -116,11 +116,11 @@ class bitcell_1w_1r(design.design):
total_power = self.return_power(dynamic, leakage)
return total_power
def get_wl_cin(self):
def input_load(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.
# FIXME: This applies to bitline capacitances as well.
# 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
@ -139,6 +139,6 @@ class bitcell_1w_1r(design.design):
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl1"], pin_dict["br1"])
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)
# Port 1 is a write port, so its timing is not considered here.

View File

@ -934,7 +934,7 @@ class pbitcell(design.design):
return "wl{}".format(port)
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
def get_stage_effort(self, load):
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.
@ -954,9 +954,11 @@ class pbitcell(design.design):
total_power = self.return_power(dynamic, leakage)
return total_power
def get_wl_cin(self):
def input_load(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.
# FIXME: This applies to bitline capacitances as well.
# 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
@ -973,6 +975,6 @@ class pbitcell(design.design):
for pin_zip in [rw_pin_names, r_pin_names]:
for wl,bl,br in pin_zip:
graph.add_edge(pin_dict[wl],pin_dict[bl])
graph.add_edge(pin_dict[wl],pin_dict[br])
graph.add_edge(pin_dict[wl],pin_dict[bl], self)
graph.add_edge(pin_dict[wl],pin_dict[br], self)

View File

@ -31,6 +31,20 @@ class replica_bitcell(design.design):
self.height = replica_bitcell.height
self.pin_map = replica_bitcell.pin_map
self.add_pin_types(self.type_list)
def get_stage_effort(self, load):
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 input_load(self):
"""Return the relative capacitance of the access transistor gates"""
# FIXME: This applies to bitline capacitances as well.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage."""
@ -40,13 +54,6 @@ class replica_bitcell(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.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -32,11 +32,18 @@ class replica_bitcell_1rw_1r(design.design):
self.pin_map = replica_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
def get_stage_effort(self, load):
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 input_load(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.
# FIXME: This applies to bitline capacitances as well.
# 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
@ -46,8 +53,8 @@ class replica_bitcell_1rw_1r(design.design):
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"])
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self)
graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self)
# Port 1 edges
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl1"], pin_dict["br1"])
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)

View File

@ -32,11 +32,18 @@ class replica_bitcell_1w_1r(design.design):
self.pin_map = replica_bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
def get_stage_effort(self, load):
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 input_load(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.
# FIXME: This applies to bitline capacitances as well.
# 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
@ -47,6 +54,6 @@ class replica_bitcell_1w_1r(design.design):
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for the read port.
# Port 1 edges
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl1"], pin_dict["br1"])
graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)
# Port 0 is a write port, so its timing is not considered here.

View File

@ -84,8 +84,4 @@ 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

@ -247,7 +247,7 @@ class delay(simulation):
def create_graph(self):
"""Creates timing graph to generate the timing paths for the SRAM output."""
self.sram.bank.bitcell_array.init_graph_params() # Removes previous bit exclusions
self.sram.bank.bitcell_array.bitcell_array.init_graph_params() # Removes previous bit exclusions
self.sram.bank.bitcell_array.graph_exclude_bits(self.wordline_row, self.bitline_column)
# Generate new graph every analysis as edges might change depending on test bit
@ -1275,39 +1275,71 @@ class delay(simulation):
# Add test cycle of read/write port pair. One port could have been used already, but the other has not.
self.gen_test_cycles_one_port(cur_read_port, cur_write_port)
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]
return delay
def analytical_delay(self, slews, loads):
"""
Return the analytical model results for the SRAM.
"""
if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0:
debug.warning("Analytical characterization results are not supported for multiport.")
# Probe set to 0th bit, does not matter for analytical delay.
self.set_probe('0', 0)
self.create_graph()
self.set_internal_spice_names()
self.create_measurement_names()
power = self.analytical_power(slews, loads)
port = self.read_ports[0]
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port),
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
# Select the path with the bitline (bl)
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()
relative_loads = [logical_effort.convert_farad_to_relative_c(c_farad) for c_farad in loads]
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 relative_loads:
self.set_load_slew(load,slew)
bank_delay = self.sram.analytical_delay(self.corner, self.slew,self.load)
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))
# 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:
port_data[port][mname].append(bank_delay[port].delay/1e3)
elif "slew" in mname:
port_data[port][mname].append(bank_delay[port].slew/1e3)
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
risefall_delay = bank_delay[self.read_ports[0]].delay/1e3
sram_data = { "min_period":risefall_delay*2*period_margin,
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)
return (sram_data,port_data)
def analytical_power(self, slews, loads):
"""Get the dynamic and leakage power from the SRAM"""

View File

@ -23,23 +23,23 @@ class logical_effort():
self.cin = cin
self.cout = cout
self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin
self.eletrical_effort = self.cout/self.cin
self.electrical_effort = self.cout/self.cin
self.parasitic_scale = parasitic
self.is_rise = out_is_rise
def __str__(self):
return "Name={}, g={}, h={}, p={}*pinv, rise_delay={}".format(self.name,
self.logical_effort,
self.eletrical_effort,
self.electrical_effort,
self.parasitic_scale,
self.is_rise
)
def get_stage_effort(self):
return self.logical_effort*self.eletrical_effort
return self.logical_effort*self.electrical_effort
def get_parasitic_delay(self):
return logical_effort.pinv * self.parasitic_scale
return logical_effort.pinv*self.parasitic_scale
def get_stage_delay(self):
return self.get_stage_effort()+self.get_parasitic_delay()
@ -78,4 +78,7 @@ def calculate_relative_rise_fall_delays(stage_effort_list):
def convert_farad_to_relative_c(c_farad):
"""Converts capacitance in Femto-Farads to relative capacitance."""
return c_farad*parameter['cap_relative_per_ff']
def convert_relative_c_to_farad(c_relative):
"""Converts capacitance in logical effort relative units to Femto-Farads."""
return c_relative/parameter['cap_relative_per_ff']

View File

@ -945,40 +945,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
@ -197,15 +187,6 @@ class bitcell_array(design.design):
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire
def output_load(self, bl_pos=0):
bl_wire = self.gen_bl_wire()
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
# set as one segment for now
def input_load(self):
wl_wire = self.gen_wl_wire()
return wl_wire.return_input_cap()
def get_wordline_cin(self):
"""Get the relative input capacitance from the wordline connections in all the bitcell"""
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns

View File

@ -924,7 +924,8 @@ class control_logic(design.design):
last_stage_rise = False
#First stage(s), clk -(pdriver)-> clk_buf.
clk_buf_cout = self.replica_bitline.get_en_cin()
#clk_buf_cout = self.replica_bitline.get_en_cin()
clk_buf_cout = 0
stage_effort_list += self.clk_buf_driver.get_stage_efforts(clk_buf_cout, last_stage_rise)
last_stage_rise = stage_effort_list[-1].is_rise

View File

@ -48,11 +48,6 @@ class dff(design.design):
transition_prob = spice["flop_transition_prob"]
return transition_prob*(c_load + c_para)
def analytical_delay(self, corner, slew, load = 0.0):
# dont know how to calculate this now, use constant in tech file
result = self.return_delay(spice["dff_delay"], spice["dff_slew"])
return result
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.

View File

@ -160,11 +160,6 @@ class dff_array(design.design):
self.add_via_center(layers=("metal2","via2","metal3"),
offset=vector(clk_pin.cx(),clk_ypos))
def analytical_delay(self, corner, slew, load=0.0):
return self.dff.analytical_delay(corner, slew=slew, load=load)
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin()

View File

@ -177,16 +177,7 @@ class dff_buf(design.design):
self.add_path("metal1", [self.mid_qb_pos, qb_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=qb_pos)
def analytical_delay(self, corner, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load())
inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=self.inv2.input_load())
inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
return dff_delay + inv1_delay + inv2_delay
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.

View File

@ -193,11 +193,6 @@ class dff_buf_array(design.design):
self.add_via_center(layers=("metal2","via2","metal3"),
offset=vector(clk_pin.cx(),clk_ypos))
def analytical_delay(self, corner, slew, load=0.0):
return self.dff.analytical_delay(slew=slew, load=load)
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin()

View File

@ -150,15 +150,7 @@ class dff_inv(design.design):
offset=dout_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=dout_pin.center())
def analytical_delay(self, corner, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load())
inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=load)
return dff_delay + inv1_delay
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
return self.dff.get_clk_cin()

View File

@ -190,12 +190,6 @@ class dff_inv_array(design.design):
self.add_via_center(layers=("metal2","via2","metal3"),
offset=vector(clk_pin.cx(),clk_ypos))
def analytical_delay(self, corner, slew, load=0.0):
return self.dff.analytical_delay(corner, slew=slew, load=load)
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin()

View File

@ -596,28 +596,6 @@ class hierarchical_decoder(design.design):
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=rail_pos)
def analytical_delay(self, corner, slew, load = 0.0):
# A -> out
if self.determine_predecodes(self.num_inputs)[1]==0:
pre = self.pre2_4
nand = self.nand2
else:
pre = self.pre3_8
nand = self.nand3
a_t_out_delay = pre.analytical_delay(corner, slew=slew,load = nand.input_load())
# out -> z
out_t_z_delay = nand.analytical_delay(corner, slew= a_t_out_delay.slew,
load = self.inv.input_load())
result = a_t_out_delay + out_t_z_delay
# Z -> decode_out
z_t_decodeout_delay = self.inv.analytical_delay(corner, slew = out_t_z_delay.slew , load = load)
result = result + z_t_decodeout_delay
return result
def input_load(self):
if self.determine_predecodes(self.num_inputs)[1]==0:
pre = self.pre2_4

View File

@ -56,21 +56,4 @@ class hierarchical_predecode2x4(hierarchical_predecode):
["A_0", "Abar_1"],
["Abar_0", "A_1"],
["A_0", "A_1"]]
return combination
def analytical_delay(self, corner, slew, load = 0.0 ):
# in -> inbar
a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load())
# inbar -> z
b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load())
# Z -> out
a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load)
return a_t_b_delay + b_t_z_delay + a_t_out_delay
def input_load(self):
return self.nand.input_load()
return combination

View File

@ -65,21 +65,4 @@ class hierarchical_predecode3x8(hierarchical_predecode):
["A_0", "Abar_1", "A_2"],
["Abar_0", "A_1", "A_2"],
["A_0", "A_1", "A_2"]]
return combination
def analytical_delay(self, corner, slew, load = 0.0 ):
# A -> Abar
a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load())
# Abar -> z
b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load())
# Z -> out
a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load)
return a_t_b_delay + b_t_z_delay + a_t_out_delay
def input_load(self):
return self.nand.input_load()
return combination

View File

@ -827,22 +827,4 @@ class multibank(design.design):
rotate=90)
self.add_via(layers=("metal2","via2","metal3"),
offset=in_pin + self.m2m3_via_offset,
rotate=90)
def analytical_delay(self, corner, slew, load):
""" return analytical delay of the bank"""
decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load())
word_driver_delay = self.wordline_driver.analytical_delay(corner, decoder_delay.slew, self.bitcell_array.input_load())
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew)
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner, bitcell_array_delay.slew,
self.bitcell_array.output_load())
# output load of bitcell_array is set to be only small part of bl for sense amp.
data_t_DATA_delay = self.tri_gate_array.analytical_delay(corner, bl_t_data_out_delay.slew, load)
result = decoder_delay + word_driver_delay + bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay
return result
rotate=90)

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
@ -403,15 +393,6 @@ class replica_bitcell_array(design.design):
cell_power.leakage * self.column_size * self.row_size)
return total_power
def gen_wl_wire(self):
if OPTS.netlist_only:
width = 0
else:
width = self.width
wl_wire = self.generate_rc_net(int(self.column_size), width, drc("minwidth_metal1"))
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
return wl_wire
def gen_bl_wire(self):
if OPTS.netlist_only:
height = 0
@ -422,15 +403,6 @@ class replica_bitcell_array(design.design):
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire
def output_load(self, bl_pos=0):
bl_wire = self.gen_bl_wire()
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
# set as one segment for now
def input_load(self):
wl_wire = self.gen_wl_wire()
return wl_wire.return_input_cap()
def get_wordline_cin(self):
"""Get the relative input capacitance from the wordline connections in all the bitcell"""
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns

View File

@ -33,15 +33,18 @@ class sense_amp(design.design):
self.pin_map = sense_amp.pin_map
self.add_pin_types(self.type_list)
def input_load(self):
def get_cin(self):
# FIXME: This input load will be applied to both the s_en timing and bitline timing.
#Input load for the bitlines which are connected to the source/drain of a TX. Not the selects.
from tech import spice, parameter
# Default is 8x. Per Samira and Hodges-Jackson book:
# "Column-mux transistors driven by the decoder must be sized for optimal speed"
bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file.
return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff
return spice["min_tx_drain_c"]*(bitline_pmos_size)#ff
def analytical_delay(self, corner, slew, load):
def get_stage_effort(self, load):
#Delay of the sense amp will depend on the size of the amp and the output load.
parasitic_delay = 1
cin = (parameter["sa_inv_pmos_size"] + parameter["sa_inv_nmos_size"])/drc("minwidth_tx")

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

@ -12,7 +12,7 @@ from tech import GDS,layer
class tri_gate(design.design):
"""
This module implements the tri gate cell used in the design for
This module implements the tri gate cell used in the design forS
bit-line isolation. It is a hand-made cell, so the layout and
netlist should be available in the technology library.
"""
@ -36,19 +36,13 @@ class tri_gate(design.design):
self.pin_map = tri_gate.pin_map
self.add_pin_types(self.type_list)
def analytical_delay(self, corner, slew, load=0.0):
from tech import spice
r = spice["min_tx_r"]
c_para = spice["min_tx_drain_c"]
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
total_power = self.return_power()
return total_power
def input_load(self):
def get_cin(self):
return 9*spice["min_tx_gate_c"]
def build_graph(self, graph, inst_name, port_nets):

View File

@ -120,10 +120,4 @@ class tri_gate_array(design.design):
layer="metal1",
offset=enbar_pin.ll().scale(0, 1),
width=width,
height=drc("minwidth_metal1"))
def analytical_delay(self, corner, slew, load=0.0):
return self.tri.analytical_delay(corner, slew = slew, load = load)
height=drc("minwidth_metal1"))

View File

@ -210,21 +210,6 @@ class wordline_driver(design.design):
start=wl_offset,
end=wl_offset-vector(self.m1_width,0))
def analytical_delay(self, corner, slew, load=0):
# decode -> net
decode_t_net = self.nand2.analytical_delay(corner, slew, self.inv.input_load())
# net -> wl
net_t_wl = self.inv.analytical_delay(corner, decode_t_net.slew, load)
return decode_t_net + net_t_wl
def input_load(self):
"""Gets the capacitance of the wordline driver in absolute units (fF)"""
return self.nand2.input_load()
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
"""Follows the clk_buf to a wordline signal adding each stages stage effort to a list"""
stage_effort_list = []

View File

@ -110,14 +110,6 @@ class pand2(pgate.pgate):
width=pin.width(),
height=pin.height())
def analytical_delay(self, corner, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
nand_delay = self.nand.analytical_delay(corner, slew=slew, load=self.inv.input_load())
inv_delay = self.inv.analytical_delay(corner, slew=nand_delay.slew, load=load)
return nand_delay + inv_delay
def get_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the A or B -> Z path"""
stage_effort_list = []

View File

@ -113,14 +113,6 @@ class pbuf(pgate.pgate):
width=a_pin.width(),
height=a_pin.height())
def analytical_delay(self, corner, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
inv1_delay = self.inv1.analytical_delay(corner, slew=slew, load=self.inv2.input_load())
inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
return inv1_delay + inv2_delay
def get_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the A -> Z path"""
stage_effort_list = []

View File

@ -173,30 +173,6 @@ class pdriver(pgate.pgate):
offset=a_pin.center(),
width = a_pin.width(),
height = a_pin.height())
def input_load(self):
return self.inv_list[0].input_load()
def analytical_delay(self, corner, slew, load=0.0):
""" Calculate the analytical delay of INV1 -> ... -> INVn """
cout_list = []
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
cout_list.append(inv.input_load())
cout_list.append(load)
input_slew = slew
delays = []
for inv,cout in zip(self.inv_list,cout_list):
delays.append(inv.analytical_delay(corner, slew=input_slew, load=cout))
input_slew = delays[-1].slew
delay = delays[0]
for i in range(len(delays)-1):
delay += delays[i]
return delay
def get_sizes(self):
""" Return the relative sizes of the buffers """

View File

@ -255,15 +255,6 @@ class pinv(pgate.pgate):
self.connect_pin_to_rail(self.pmos_inst,"S","vdd")
def input_load(self):
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def analytical_delay(self, corner, slew, load=0.0):
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
@ -281,11 +272,11 @@ class pinv(pgate.pgate):
transition_prob = spice["inv_transition_prob"]
return transition_prob*(c_load + c_para)
def get_cin(self):
def input_load(self):
"""Return the capacitance of the gate connection in generic capacitive
units relative to the minimum width of a transistor"""
return self.nmos_size + self.pmos_size
def get_stage_effort(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
@ -293,7 +284,7 @@ class pinv(pgate.pgate):
parasitic_delay = 1
return logical_effort.logical_effort(self.name,
self.size,
self.get_cin(),
self.input_load(),
cout,
parasitic_delay,
not inp_is_rise)

View File

@ -178,15 +178,7 @@ class pinvbuf(pgate.pgate):
offset=a_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
def analytical_delay(self, corner, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
inv1_delay = self.inv1.analytical_delay(corner, slew=slew, load=self.inv2.input_load())
inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
return inv1_delay + inv2_delay
def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the clk -> clk_buf path"""
stage_effort_list = []

View File

@ -37,10 +37,7 @@ class pnand2(pgate.pgate):
# Creates the netlist and layout
pgate.pgate.__init__(self, name, height)
#For characterization purposes only
#self.exclude_nmos_from_graph()
def create_netlist(self):
self.add_pins()
self.add_ptx()
@ -233,17 +230,6 @@ class pnand2(pgate.pgate):
width=contact.m1m2.first_layer_height,
height=contact.m1m2.first_layer_width)
def input_load(self):
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def analytical_delay(self, corner, slew, load=0.0):
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
@ -261,23 +247,16 @@ class pnand2(pgate.pgate):
transition_prob = spice["nand2_transition_prob"]
return transition_prob*(c_load + c_para)
def get_cin(self):
def input_load(self):
"""Return the relative input capacitance of a single input"""
return self.nmos_size+self.pmos_size
def get_stage_effort(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 2
return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
def exclude_nmos_from_graph(self):
"""Exclude the nmos TXs from the graph to reduce complexity"""
#The pull-down network has an internal net which causes 2 different in->out paths
#Removing them simplifies generic path searching.
self.graph_inst_exclude.add(self.nmos1_inst)
self.graph_inst_exclude.add(self.nmos2_inst)
return logical_effort.logical_effort(self.name, self.size, self.input_load(), cout, parasitic_delay, not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""

View File

@ -243,16 +243,6 @@ class pnand3(pgate.pgate):
width=contact.m1m2.first_layer_width,
height=contact.m1m2.first_layer_height)
def input_load(self):
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def analytical_delay(self, corner, slew, load=0.0):
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
@ -270,7 +260,7 @@ class pnand3(pgate.pgate):
transition_prob = spice["nand3_transition_prob"]
return transition_prob*(c_load + c_para)
def get_cin(self):
def input_load(self):
"""Return the relative input capacitance of a single input"""
return self.nmos_size+self.pmos_size
@ -279,7 +269,7 @@ class pnand3(pgate.pgate):
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 3
return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
return logical_effort.logical_effort(self.name, self.size, self.input_load(), cout, parasitic_delay, not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""

View File

@ -227,16 +227,6 @@ class pnor2(pgate.pgate):
width=contact.m1m2.first_layer_height,
height=contact.m1m2.first_layer_width)
def input_load(self):
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def analytical_delay(self, corner, slew, load=0.0):
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)

View File

@ -210,18 +210,11 @@ class ptristate_inv(pgate.pgate):
self.connect_pin_to_rail(self.nmos1_inst,"S","gnd")
self.connect_pin_to_rail(self.pmos1_inst,"S","vdd")
def analytical_delay(self, corner, slew, load=0.0):
from tech import spice
r = spice["min_tx_r"]
c_para = spice["min_tx_drain_c"]
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
total_power = self.return_power()
return total_power
def input_load(self):
def get_cin(self):
return 9*spice["min_tx_gate_c"]

View File

@ -189,7 +189,7 @@ class single_level_column_mux(pgate.pgate):
width=self.bitcell.width,
height=self.height)
def analytical_delay(self, corner, slew, load):
def get_stage_effort(self, corner, slew, load):
"""Returns relative delay that the column mux. Difficult to convert to LE model."""
parasitic_delay = 1
cin = 2*self.tx_size #This is not CMOS, so using this may be incorrect.

View File

@ -562,31 +562,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 = []

View File

@ -15,7 +15,7 @@ from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 21_model_delay_test")
# @unittest.skip("SKIPPING 21_model_delay_test")
class model_delay_test(openram_test):
""" Compare the accuracy of the analytical model with a spice simulation. """
@ -51,23 +51,28 @@ class model_delay_test(openram_test):
import tech
loads = [tech.spice["msflop_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
# Run a spice characterization
spice_data, port_data = d.analyze(probe_address, probe_data, slews, loads)
spice_data.update(port_data[0])
# Run analytical characterization
model_data, port_data = d.analytical_delay(slews, loads)
model_data.update(port_data[0])
#Only compare the delays
# Only compare the delays
spice_delays = {key:value for key, value in spice_data.items() if 'delay' in key}
model_delays = {key:value for key, value in model_data.items() if 'delay' in key}
debug.info(1,"Spice Delays={}".format(spice_delays))
debug.info(1,"Model Delays={}".format(model_delays))
if OPTS.tech_name == "freepdk45":
error_tolerance = 0.25
elif OPTS.tech_name == "scn4m_subm":
error_tolerance = 0.25
else:
self.assertTrue(False) # other techs fail
# Check if no too many or too few results
self.assertTrue(len(spice_delays.keys())==len(model_delays.keys()))

View File

@ -14,7 +14,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 23_lib_sram_model_corners_test")
#@unittest.skip("SKIPPING 23_lib_sram_model_corners_test")
class lib_model_corners_lib_test(openram_test):
def runTest(self):

View File

@ -14,7 +14,7 @@ import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 23_lib_sram_model_test")
#@unittest.skip("SKIPPING 23_lib_sram_model_test")
class lib_sram_model_test(openram_test):
def runTest(self):

View File

@ -16,7 +16,7 @@ from sram_factory import factory
import debug
import getpass
@unittest.skip("SKIPPING 30_openram_front_end_test")
#@unittest.skip("SKIPPING 30_openram_front_end_test")
class openram_front_end_test(openram_test):
def runTest(self):