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
hierarchy_layout.layout.__init__(self, name)
hierarchy_spice.spice.__init__(self, name)
self.init_graph_params()
def get_layout_pins(self,inst):
""" 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)
#Example graph run
# import graph_util
# graph = graph_util.graph()
# pins = ['A','Z','vdd','gnd']
# d.build_graph(graph,"Xpdriver",pins)
@ -108,6 +109,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
# debug.info(1,"{}".format(graph))
# 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):
"""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):
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)}
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):
debug.info(1, "Sub-Instance={}".format(subinst))
if subinst in self.graph_inst_exclude:
continue
subinst_name = inst_name+'.X'+subinst.name
subinst_ports = self.translate_nets(conns, port_dict, inst_name)
subinst.mod.build_graph(graph, subinst_name, subinst_ports)

View File

@ -24,7 +24,7 @@ class bitcell(design.design):
self.width = bitcell.width
self.height = bitcell.height
self.pin_map = bitcell.pin_map
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1
size = 0.5 #This accounts for bitline being drained thought the access TX and internal node
@ -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.
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 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.
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 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.
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 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()
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.
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 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.
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 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.
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 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
path = []
self.path_count = 0
# 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):
@ -50,6 +52,7 @@ class graph():
# current path[]
if u == d:
debug.info(1,"{}".format(path))
self.path_count+=1
else:
# If current vertex is not destination
#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"""
#Current bank only uses sen as an enable for the sense amps.
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()
total_cin = bitcell_wl_cin * self.column_size
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.
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:
pre = self.pre3_8
return pre.input_load()

View File

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

View File

@ -51,4 +51,15 @@ class sense_amp(design.design):
pmos_cin = parameter["sa_en_pmos_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.
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.
"""
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"])
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):
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"""
# This is approximated from SCMOS. It has roughly 5 3x transistor gates.
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:
self.create_layout()
#For characterization purposes only
self.exclude_nmos_from_graph()
def create_netlist(self):
self.add_pins()
@ -259,3 +261,10 @@ class pnand2(pgate.pgate):
"""
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)

View File

@ -305,3 +305,19 @@ class sram_1bank(sram_base):
self.add_label(text=n,
layer=pin.layer,
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

@ -26,7 +26,7 @@ class bitcell_1rw_1r_array_test(openram_test):
OPTS.num_w_ports = 0
a = factory.create(module_type="bitcell_array", cols=4, rows=4)
self.local_check(a)
globals.end_openram()
# run the test from the command line

View File

@ -22,7 +22,7 @@ class array_test(openram_test):
debug.info(2, "Testing 4x4 array for 6t_cell")
a = factory.create(module_type="bitcell_array", cols=4, rows=4)
self.local_check(a)
globals.end_openram()
# run the test from the command line

View File

@ -20,7 +20,7 @@ class tri_gate_array_test(openram_test):
debug.info(1, "Testing tri_gate_array for columns=8, word_size=8")
a = factory.create(module_type="tri_gate_array", columns=8, word_size=8)
self.local_check(a)
debug.info(1, "Testing tri_gate_array for columns=16, word_size=8")
a = factory.create(module_type="tri_gate_array", columns=16, word_size=8)
self.local_check(a)

View File

@ -33,6 +33,23 @@ class timing_sram_test(openram_test):
c.recompute_sizes()
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
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"
s.sp_write(tempspice)