mirror of https://github.com/VLSIDA/OpenRAM.git
Cleaned up graph additions to characterizer.
This commit is contained in:
parent
33c17ac41c
commit
4f3340e973
|
|
@ -56,7 +56,7 @@ class timing_graph():
|
||||||
|
|
||||||
# Call the recursive helper function to print all paths
|
# Call the recursive helper function to print all paths
|
||||||
self.get_all_paths_util(src_node, dest_node, visited, path)
|
self.get_all_paths_util(src_node, dest_node, visited, path)
|
||||||
debug.info(1, "Paths found={}".format(len(self.all_paths)))
|
debug.info(2, "Paths found={}".format(len(self.all_paths)))
|
||||||
|
|
||||||
return self.all_paths
|
return self.all_paths
|
||||||
|
|
||||||
|
|
@ -69,7 +69,6 @@ class timing_graph():
|
||||||
# If current vertex is same as destination, then print
|
# If current vertex is same as destination, then print
|
||||||
# current path[]
|
# current path[]
|
||||||
if cur_node == dest_node:
|
if cur_node == dest_node:
|
||||||
debug.info(1,"{}".format(path))
|
|
||||||
self.all_paths.append(copy.deepcopy(path))
|
self.all_paths.append(copy.deepcopy(path))
|
||||||
else:
|
else:
|
||||||
# If current vertex is not destination
|
# If current vertex is not destination
|
||||||
|
|
@ -82,20 +81,6 @@ class timing_graph():
|
||||||
path.pop()
|
path.pop()
|
||||||
visited.remove(cur_node)
|
visited.remove(cur_node)
|
||||||
|
|
||||||
def get_path_preconvergence_point(self, path1, path2):
|
|
||||||
"""Assuming the inputs paths have the same starting point and end point, the
|
|
||||||
paths should split and converge at some point before/at the last stage. Finds the
|
|
||||||
point before convergence."""
|
|
||||||
debug.check(path1[0] == path2[0], "Paths must start from the same point.")
|
|
||||||
debug.check(path1[-1] == path2[-1], "Paths must end from the same point.")
|
|
||||||
#Paths must end at the same point, so the paths are traversed backwards to find
|
|
||||||
#point of convergence. There could be multiple points, only finds first.
|
|
||||||
for point1,point2 in zip(reversed(path1), reversed(path2)):
|
|
||||||
if point1 != point2:
|
|
||||||
return (point1,point2)
|
|
||||||
debug.info(1,"Pre-convergence point not found, paths are equals.")
|
|
||||||
return path1[0],path2[0]
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph)
|
return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph)
|
||||||
|
|
@ -147,7 +147,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
"""Given a list of nets, will compare the internal alias of a mod to determine
|
"""Given a list of nets, will compare the internal alias of a mod to determine
|
||||||
if the nets have a connection to this mod's net (but not inst).
|
if the nets have a connection to this mod's net (but not inst).
|
||||||
"""
|
"""
|
||||||
#path_nets = ['xsram_0.xbank0.bl0_7']
|
|
||||||
if exclusion_set == None:
|
if exclusion_set == None:
|
||||||
exclusion_set = set()
|
exclusion_set = set()
|
||||||
try:
|
try:
|
||||||
|
|
@ -155,31 +154,17 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.name_dict = {}
|
self.name_dict = {}
|
||||||
self.build_names(self.name_dict, inst_name, port_nets)
|
self.build_names(self.name_dict, inst_name, port_nets)
|
||||||
#debug.info(1,"names={}".format(list(self.name_dict)))
|
|
||||||
aliases = []
|
aliases = []
|
||||||
for net in path_nets:
|
for net in path_nets:
|
||||||
net = net.lower()
|
net = net.lower()
|
||||||
int_net = self.name_dict[net]['int_net']
|
int_net = self.name_dict[net]['int_net']
|
||||||
int_mod = self.name_dict[net]['mod']
|
int_mod = self.name_dict[net]['mod']
|
||||||
# debug.info(1,"int_net={}".format(int_net))
|
|
||||||
# debug.info(1,"int_mod={}".format(int_mod.name))
|
|
||||||
# debug.info(1,"alias_net={}".format(alias))
|
|
||||||
# debug.info(1,"alias_mod={}".format(alias_mod.name))
|
|
||||||
# debug.info(1,"mod id={}".format(id(alias_mod)))
|
|
||||||
if int_mod.is_net_alias(int_net, alias, alias_mod, exclusion_set):
|
if int_mod.is_net_alias(int_net, alias, alias_mod, exclusion_set):
|
||||||
aliases.append(net)
|
aliases.append(net)
|
||||||
# debug.info(1,"Alias found\n")
|
|
||||||
# else:
|
|
||||||
# debug.info(1,"Alias not found\n")
|
|
||||||
debug.info(1,"Aliases Found={}".format(aliases))
|
|
||||||
return aliases
|
return aliases
|
||||||
|
|
||||||
def is_net_alias(self, known_net, net_alias, mod, exclusion_set):
|
def is_net_alias(self, known_net, net_alias, mod, exclusion_set):
|
||||||
"""Checks if the alias_net in mod is the same as the input net."""
|
"""Checks if the alias_net in input mod is the same as the input net for this mod (self)."""
|
||||||
# debug.info(1,"self name={}".format(self.name))
|
|
||||||
# debug.info(1,"self mod id={}".format(id(self)))
|
|
||||||
# debug.info(1,"self pins={}".format(self.pins))
|
|
||||||
# debug.info(1,"known_net={}".format(known_net))
|
|
||||||
if self in exclusion_set:
|
if self in exclusion_set:
|
||||||
return False
|
return False
|
||||||
#Check ports of this mod
|
#Check ports of this mod
|
||||||
|
|
@ -193,8 +178,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod):
|
if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod):
|
||||||
return True
|
return True
|
||||||
elif inst_conn.lower() == known_net.lower() and subinst.mod not in mod_set:
|
elif inst_conn.lower() == known_net.lower() and subinst.mod not in mod_set:
|
||||||
# debug.info(1,"found matching conn={}".format(inst_conn))
|
|
||||||
# debug.info(1,"Setting known pin={}".format(mod_pin))
|
|
||||||
if subinst.mod.is_net_alias(mod_pin, net_alias, mod, exclusion_set):
|
if subinst.mod.is_net_alias(mod_pin, net_alias, mod, exclusion_set):
|
||||||
return True
|
return True
|
||||||
mod_set.add(subinst.mod)
|
mod_set.add(subinst.mod)
|
||||||
|
|
|
||||||
|
|
@ -216,17 +216,19 @@ class delay(simulation):
|
||||||
self.graph = graph_util.timing_graph()
|
self.graph = graph_util.timing_graph()
|
||||||
self.sram_spc_name = "X{}".format(self.sram.name)
|
self.sram_spc_name = "X{}".format(self.sram.name)
|
||||||
self.sram.build_graph(self.graph,self.sram_spc_name,self.pins)
|
self.sram.build_graph(self.graph,self.sram_spc_name,self.pins)
|
||||||
#debug.info(1,"{}".format(self.graph))
|
|
||||||
|
def set_internal_spice_names(self):
|
||||||
|
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
|
||||||
port = 0
|
port = 0
|
||||||
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), \
|
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), \
|
||||||
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
||||||
|
|
||||||
self.sen_name = self.get_sen_name(self.graph.all_paths)
|
self.sen_name = self.get_sen_name(self.graph.all_paths)
|
||||||
debug.info(1,"s_en name = {}".format(self.sen_name))
|
debug.info(2,"s_en name = {}".format(self.sen_name))
|
||||||
|
|
||||||
self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths)
|
self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths)
|
||||||
debug.info(1,"bl name={}, br name={}".format(self.bl_name,self.br_name))
|
debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
|
||||||
|
|
||||||
def get_sen_name(self, paths):
|
def get_sen_name(self, paths):
|
||||||
"""Gets the signal name associated with the sense amp enable from input paths.
|
"""Gets the signal name associated with the sense amp enable from input paths.
|
||||||
Only expects a single path to contain the sen signal name."""
|
Only expects a single path to contain the sen signal name."""
|
||||||
|
|
@ -245,13 +247,7 @@ class delay(simulation):
|
||||||
cell_mod = self.get_primary_cell_mod(cell_mods)
|
cell_mod = self.get_primary_cell_mod(cell_mods)
|
||||||
elif len(cell_mods)==0:
|
elif len(cell_mods)==0:
|
||||||
debug.error("No bitcells found. Cannot determine bitline names.", 1)
|
debug.error("No bitcells found. Cannot determine bitline names.", 1)
|
||||||
#Any sense amp instantiated should be identical, any change to that
|
|
||||||
#will require some identification to determine the mod desired.
|
|
||||||
# debug.check(self.are_mod_pins_equal(cell_mods), "Only expected one type of bitcell. Cannot perform bitline checks")
|
|
||||||
# debug.info(1,"num pbitcells={}".format(len(cell_mods)))
|
|
||||||
# debug.info(1,"cell ids={}".format([id(i) for i in cell_mods]))
|
|
||||||
|
|
||||||
#cell_mods = cell_mods[1:]
|
|
||||||
cell_bl = cell_mod.get_bl_name()
|
cell_bl = cell_mod.get_bl_name()
|
||||||
cell_br = cell_mod.get_br_name()
|
cell_br = cell_mod.get_br_name()
|
||||||
|
|
||||||
|
|
@ -705,9 +701,8 @@ class delay(simulation):
|
||||||
|
|
||||||
def check_sen_measure(self, port):
|
def check_sen_measure(self, port):
|
||||||
"""Checks that the sen occurred within a half-period"""
|
"""Checks that the sen occurred within a half-period"""
|
||||||
self.sen_meas
|
|
||||||
sen_val = self.sen_meas.retrieve_measure(port=port)
|
sen_val = self.sen_meas.retrieve_measure(port=port)
|
||||||
debug.info(1,"S_EN delay={} ns".format(sen_val))
|
debug.info(2,"S_EN delay={} ns".format(sen_val))
|
||||||
if self.sen_meas.meta_add_delay:
|
if self.sen_meas.meta_add_delay:
|
||||||
max_delay = self.period/2
|
max_delay = self.period/2
|
||||||
else:
|
else:
|
||||||
|
|
@ -729,7 +724,7 @@ class delay(simulation):
|
||||||
elif self.br_name == meas.targ_name_no_port:
|
elif self.br_name == meas.targ_name_no_port:
|
||||||
br_vals[meas.meta_str] = val
|
br_vals[meas.meta_str] = val
|
||||||
|
|
||||||
debug.info(1,"{}={}".format(meas.name,val))
|
debug.info(2,"{}={}".format(meas.name,val))
|
||||||
|
|
||||||
bl_check = False
|
bl_check = False
|
||||||
for meas in self.debug_volt_meas:
|
for meas in self.debug_volt_meas:
|
||||||
|
|
@ -762,24 +757,23 @@ class delay(simulation):
|
||||||
for polarity, meas_list in self.bit_meas.items():
|
for polarity, meas_list in self.bit_meas.items():
|
||||||
for meas in meas_list:
|
for meas in meas_list:
|
||||||
val = meas.retrieve_measure()
|
val = meas.retrieve_measure()
|
||||||
debug.info(1,"{}={}".format(meas.name, val))
|
debug.info(2,"{}={}".format(meas.name, val))
|
||||||
if type(val) != float:
|
if type(val) != float:
|
||||||
continue
|
continue
|
||||||
meas_cycle = meas.meta_str
|
meas_cycle = meas.meta_str
|
||||||
|
#Loose error conditions. Assume it's not metastable but account for noise during reads.
|
||||||
if (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.NONINVERTING) or\
|
if (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.NONINVERTING) or\
|
||||||
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.INVERTING):
|
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.INVERTING):
|
||||||
success = val < self.vdd_voltage*.1
|
success = val < self.vdd_voltage/2
|
||||||
elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\
|
elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\
|
||||||
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING):
|
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING):
|
||||||
success = val > self.vdd_voltage*.9
|
success = val > self.vdd_voltage/2
|
||||||
if not success:
|
if not success:
|
||||||
debug.info(1,("Wrong value detected on probe bit during read cycle. "
|
debug.info(1,("Wrong value detected on probe bit during read cycle. "
|
||||||
"Check writes and control logic for bugs.\n measure={}, op={}, "
|
"Check writes and control logic for bugs.\n measure={}, op={}, "
|
||||||
"bit_storage={}").format(meas.name, meas_cycle.name, polarity.name))
|
"bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name,val))
|
||||||
return success
|
return success
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
|
def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
|
||||||
"""Checks the value of the discharging bitline. Confirms s_en timing errors.
|
"""Checks the value of the discharging bitline. Confirms s_en timing errors.
|
||||||
Returns true if the bitlines are at there expected value."""
|
Returns true if the bitlines are at there expected value."""
|
||||||
|
|
@ -991,6 +985,7 @@ class delay(simulation):
|
||||||
"""Sets values which are dependent on the data address/bit being tested."""
|
"""Sets values which are dependent on the data address/bit being tested."""
|
||||||
self.set_probe(probe_address, probe_data)
|
self.set_probe(probe_address, probe_data)
|
||||||
self.create_graph()
|
self.create_graph()
|
||||||
|
self.set_internal_spice_names()
|
||||||
self.create_measurement_names()
|
self.create_measurement_names()
|
||||||
self.create_measurement_objects()
|
self.create_measurement_objects()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class pand2(pgate.pgate):
|
||||||
This is a simple buffer used for driving loads.
|
This is a simple buffer used for driving loads.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, size=1, height=None):
|
def __init__(self, name, size=1, height=None):
|
||||||
debug.info(1, "reating pnand2 {}".format(name))
|
debug.info(1, "Creating pnand2 {}".format(name))
|
||||||
self.add_comment("size: {}".format(size))
|
self.add_comment("size: {}".format(size))
|
||||||
|
|
||||||
self.size = size
|
self.size = size
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue