mirror of https://github.com/VLSIDA/OpenRAM.git
Added graph creation and functions in base class and lower level modules.
This commit is contained in:
parent
4f28295e20
commit
e292767166
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
@ -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])
|
||||
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
@ -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])
|
||||
|
|
@ -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])
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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])
|
||||
|
||||
|
||||
|
|
@ -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])
|
||||
|
||||
|
|
@ -621,3 +621,4 @@ class hierarchical_decoder(design.design):
|
|||
else:
|
||||
pre = self.pre3_8
|
||||
return pre.input_load()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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])
|
||||
|
||||
|
|
@ -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])
|
||||
|
|
@ -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])
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue