Added graph creation and functions in base class and lower level modules.

This commit is contained in:
Hunter Nichols 2019-04-24 14:23:22 -07:00
parent 4f28295e20
commit e292767166
23 changed files with 196 additions and 10 deletions

View File

@ -24,7 +24,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.name = name self.name = name
hierarchy_layout.layout.__init__(self, name) hierarchy_layout.layout.__init__(self, name)
hierarchy_spice.spice.__init__(self, name) hierarchy_spice.spice.__init__(self, name)
self.init_graph_params()
def get_layout_pins(self,inst): def get_layout_pins(self,inst):
""" Return a map of pin locations of the instance offset """ """ Return a map of pin locations of the instance offset """
@ -100,6 +100,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
os.remove(tempgds) os.remove(tempgds)
#Example graph run #Example graph run
# import graph_util
# graph = graph_util.graph() # graph = graph_util.graph()
# pins = ['A','Z','vdd','gnd'] # pins = ['A','Z','vdd','gnd']
# d.build_graph(graph,"Xpdriver",pins) # d.build_graph(graph,"Xpdriver",pins)
@ -108,6 +109,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
# debug.info(1,"{}".format(graph)) # debug.info(1,"{}".format(graph))
# graph.printAllPaths('A', 'Z') # graph.printAllPaths('A', 'Z')
def init_graph_params(self):
"""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): def build_graph(self, graph, inst_name, port_nets):
"""Recursively create graph from instances in module.""" """Recursively create graph from instances in module."""
@ -115,9 +121,10 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if len(port_nets) != len(self.pins): if len(port_nets) != len(self.pins):
debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1) debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1)
port_dict = {i:j for i,j in zip(self.pins, port_nets)} port_dict = {i:j for i,j in zip(self.pins, port_nets)}
debug.info(1, "Instance name={}".format(inst_name)) debug.info(3, "Instance name={}".format(inst_name))
for subinst, conns in zip(self.insts, self.conns): for subinst, conns in zip(self.insts, self.conns):
debug.info(1, "Sub-Instance={}".format(subinst)) if subinst in self.graph_inst_exclude:
continue
subinst_name = inst_name+'.X'+subinst.name subinst_name = inst_name+'.X'+subinst.name
subinst_ports = self.translate_nets(conns, port_dict, inst_name) subinst_ports = self.translate_nets(conns, port_dict, inst_name)
subinst.mod.build_graph(graph, subinst_name, subinst_ports) subinst.mod.build_graph(graph, subinst_name, subinst_ports)

View File

@ -74,3 +74,12 @@ class bitcell(design.design):
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #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"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 5 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl->bl, wl->br.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[2],port_nets[0])
graph.add_edge(port_nets[2],port_nets[1])

View File

@ -99,3 +99,15 @@ class bitcell_1rw_1r(design.design):
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. #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"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 8 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl0->bl0, wl0->br0, wl1->bl1, wl1->br1.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[4],port_nets[0])
graph.add_edge(port_nets[4],port_nets[1])
graph.add_edge(port_nets[5],port_nets[2])
graph.add_edge(port_nets[5],port_nets[3])

View File

@ -99,3 +99,14 @@ class bitcell_1w_1r(design.design):
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. #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"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 8 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl0->bl0, wl0->br0, wl1->bl1, wl1->br1.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[4],port_nets[0])
graph.add_edge(port_nets[4],port_nets[1])
graph.add_edge(port_nets[5],port_nets[2])
graph.add_edge(port_nets[5],port_nets[3])

View File

@ -893,3 +893,15 @@ class pbitcell(design.design):
access_tx_cin = self.readwrite_nmos.get_cin() access_tx_cin = self.readwrite_nmos.get_cin()
return 2*access_tx_cin return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Done manually to make the graph acyclic."""
#The base graph function can make this but it would contain loops and path
#searches would essentially be useless.
# Edges added wl->bl, wl->br for every port
num_wl = len(self.rw_wl_names) + len(self.w_wl_names) + len(self.r_wl_names)
wl_pos = 2*num_wl #there are this many bitlines nets before the wls in the port list
for i in range(num_wl):
bl_pos = i*2
graph.add_edge(port_nets[wl_pos+i],port_nets[bl_pos])
graph.add_edge(port_nets[wl_pos+i],port_nets[bl_pos+1])

View File

@ -29,3 +29,12 @@ class replica_bitcell(design.design):
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #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"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 5 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl->bl, wl->br.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[2],port_nets[0])
graph.add_edge(port_nets[2],port_nets[1])

View File

@ -30,3 +30,14 @@ class replica_bitcell_1rw_1r(design.design):
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. #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"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 8 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl0->bl0, wl0->br0, wl1->bl1, wl1->br1.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[4],port_nets[0])
graph.add_edge(port_nets[4],port_nets[1])
graph.add_edge(port_nets[5],port_nets[2])
graph.add_edge(port_nets[5],port_nets[3])

View File

@ -30,3 +30,14 @@ class replica_bitcell_1w_1r(design.design):
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. #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"] access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The bitcell has 8 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: wl0->bl0, wl0->br0, wl1->bl1, wl1->br1.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[4],port_nets[0])
graph.add_edge(port_nets[4],port_nets[1])
graph.add_edge(port_nets[5],port_nets[2])
graph.add_edge(port_nets[5],port_nets[3])

View File

@ -36,9 +36,11 @@ class graph():
# Create an array to store paths # Create an array to store paths
path = [] path = []
self.path_count = 0
# Call the recursive helper function to print all paths # Call the recursive helper function to print all paths
self.printAllPathsUtil(s, d,visited, path) self.printAllPathsUtil(s, d,visited, path)
debug.info(1, "Paths found={}".format(self.path_count))
def printAllPathsUtil(self, u, d, visited, path): def printAllPathsUtil(self, u, d, visited, path):
@ -50,6 +52,7 @@ class graph():
# current path[] # current path[]
if u == d: if u == d:
debug.info(1,"{}".format(path)) debug.info(1,"{}".format(path))
self.path_count+=1
else: else:
# If current vertex is not destination # If current vertex is not destination
#Recur for all the vertices adjacent to this vertex #Recur for all the vertices adjacent to this vertex

View File

@ -1279,3 +1279,9 @@ class bank(design.design):
"""Get the relative capacitance of all the sense amp enable connections in the bank""" """Get the relative capacitance of all the sense amp enable connections in the bank"""
#Current bank only uses sen as an enable for the sense amps. #Current bank only uses sen as an enable for the sense amps.
return self.sense_amp_array.get_en_cin() return self.sense_amp_array.get_en_cin()
def graph_exclude_precharge(self):
"""Precharge adds a loop between bitlines, can be excluded to reduce complexity"""
for inst in self.precharge_array_inst:
if inst != None:
self.graph_inst_exclude.add(inst)

View File

@ -193,3 +193,13 @@ class bitcell_array(design.design):
bitcell_wl_cin = self.cell.get_wl_cin() bitcell_wl_cin = self.cell.get_wl_cin()
total_cin = bitcell_wl_cin * self.column_size total_cin = bitcell_wl_cin * self.column_size
return total_cin return total_cin
def graph_exclude_bits(self, targ_row, targ_col):
"""Excludes bits in column from being added to graph except target"""
#Function is not robust with column mux configurations
for row in range(self.row_size):
if row == targ_row:
continue
self.graph_inst_exclude.add(self.cell_inst[row,targ_col])

View File

@ -50,3 +50,11 @@ class dff(design.design):
#Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. #Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width.
return parameter["dff_clk_cin"] return parameter["dff_clk_cin"]
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The cell has 5 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: clk->Q.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[2],port_nets[1])

View File

@ -621,3 +621,4 @@ class hierarchical_decoder(design.design):
else: else:
pre = self.pre3_8 pre = self.pre3_8
return pre.input_load() return pre.input_load()

View File

@ -107,3 +107,4 @@ class precharge_array(design.design):
#Assume single port #Assume single port
precharge_en_cin = self.pc_cell.get_en_cin() precharge_en_cin = self.pc_cell.get_en_cin()
return precharge_en_cin*self.columns return precharge_en_cin*self.columns

View File

@ -52,3 +52,14 @@ class sense_amp(design.design):
nmos_cin = parameter["sa_en_nmos_size"]/drc("minwidth_tx") nmos_cin = parameter["sa_en_nmos_size"]/drc("minwidth_tx")
#sen is connected to 2 pmos isolation TX and 1 nmos per sense amp. #sen is connected to 2 pmos isolation TX and 1 nmos per sense amp.
return 2*pmos_cin + nmos_cin return 2*pmos_cin + nmos_cin
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The cell has 6 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: en->dout, bl->dout
# br->dout not included to reduce complexity
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[0],port_nets[2])
graph.add_edge(port_nets[3],port_nets[2])

View File

@ -10,7 +10,7 @@ class tri_gate(design.design):
netlist should be available in the technology library. netlist should be available in the technology library.
""" """
pin_names = ["in", "en", "en_bar", "out", "gnd", "vdd"] pin_names = ["in", "out", "en", "en_bar", "gnd", "vdd"]
(width,height) = utils.get_libcell_size("tri_gate", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("tri_gate", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "tri_gate", GDS["unit"]) pin_map = utils.get_libcell_pins(pin_names, "tri_gate", GDS["unit"])
@ -42,3 +42,13 @@ class tri_gate(design.design):
def input_load(self): def input_load(self):
return 9*spice["min_tx_gate_c"] return 9*spice["min_tx_gate_c"]
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The cell has 6 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: en->out, en_bar->out, in->out.
# A liberal amount of edges were added, may be reduced later for complexity.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[0],port_nets[1])
graph.add_edge(port_nets[2],port_nets[1])
graph.add_edge(port_nets[3],port_nets[1])

View File

@ -28,3 +28,15 @@ class write_driver(design.design):
"""Get the relative capacitance of a single input""" """Get the relative capacitance of a single input"""
# This is approximated from SCMOS. It has roughly 5 3x transistor gates. # This is approximated from SCMOS. It has roughly 5 3x transistor gates.
return 5*3 return 5*3
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Handmade cells must implement this manually."""
#The cell has 6 net ports hard-coded in self.pin_names. The edges
#are based on the hard-coded name positions.
# The edges added are: din->bl, din->br, en->bl, en->br
# A liberal amount of edges were added, may be reduced later for complexity.
# Internal nodes of the handmade cell not considered, only ports. vdd/gnd ignored for graph.
graph.add_edge(port_nets[0],port_nets[1])
graph.add_edge(port_nets[0],port_nets[2])
graph.add_edge(port_nets[3],port_nets[1])
graph.add_edge(port_nets[3],port_nets[2])

View File

@ -32,6 +32,8 @@ class pnand2(pgate.pgate):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
#For characterization purposes only
self.exclude_nmos_from_graph()
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
@ -259,3 +261,10 @@ class pnand2(pgate.pgate):
""" """
parasitic_delay = 2 parasitic_delay = 2
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.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)

View File

@ -305,3 +305,19 @@ class sram_1bank(sram_base):
self.add_label(text=n, self.add_label(text=n,
layer=pin.layer, layer=pin.layer,
offset=pin.center()) offset=pin.center())
def graph_exclude_data_dff(self):
"""Removes data dff from search graph. """
#Data dffs are only for writing so are not useful for evaluating read delay.
for inst in self.data_dff_insts:
self.graph_inst_exclude.add(inst)
def graph_exclude_addr_dff(self):
"""Removes data dff from search graph. """
#Address is considered not part of the critical path, subjectively removed
for inst in self.row_addr_dff_insts:
self.graph_inst_exclude.add(inst)
if self.col_addr_dff:
for inst in self.col_addr_dff_insts:
self.graph_inst_exclude.add(inst)

View File

@ -34,6 +34,23 @@ class timing_sram_test(openram_test):
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
#Exclude things known not to be in critical path.
#Intended for characterizing read paths. Somewhat hacky implementation
s.s.bank.bitcell_array.graph_exclude_bits(15,0)
s.s.bank.graph_exclude_precharge()
s.s.graph_exclude_addr_dff()
s.s.graph_exclude_data_dff()
debug.info(1,'pins={}'.format(s.s.pins))
import graph_util
graph = graph_util.graph()
pins=['DIN0[0]', 'ADDR0[0]', 'ADDR0[1]', 'ADDR0[2]', 'ADDR0[3]', 'csb0', 'web0', 'clk0', 'DOUT0[0]', 'vdd', 'gnd']
s.s.build_graph(graph,"Xsram",pins)
graph.remove_edges('vdd')
graph.remove_edges('gnd')
debug.info(1,"{}".format(graph))
graph.printAllPaths('clk0', 'DOUT0[0]')
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)