From 2786b9be215757e7e92225f688ccef1dafbfdc51 Mon Sep 17 00:00:00 2001 From: Samuel Fagerlund <samfa392@student.liu.se> Date: Mon, 17 Jun 2024 13:58:03 +0200 Subject: [PATCH] Implement Tmin --- b_asic/signal_flow_graph.py | 90 ++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py index fb784913..a4d11674 100644 --- a/b_asic/signal_flow_graph.py +++ b/b_asic/signal_flow_graph.py @@ -1688,13 +1688,101 @@ class SFG(AbstractOperation): return Schedule(self, algorithm="ASAP").schedule_time + def dfs(self, graph, start, end): + """ + Find loop(s) in graph + + Parameters + ---------- + graph : dictionary + The dictionary that are to be searched for loops. + start : key in dictionary graph + The "node" in the dictionary that are set as the start point. + end : key in dictionary graph + The "node" in the dictionary that are set as the end point. + """ + fringe = [(start, [])] + while fringe: + state, path = fringe.pop() + if path and state == end: + yield path + continue + for next_state in graph[state]: + if next_state in path: + continue + fringe.append((next_state, path + [next_state])) + def iteration_period_bound(self) -> int: """ Return the iteration period bound of the SFG. If -1, the SFG does not have any loops and therefore no iteration period bound. + + Returns + ------- + The iteration period bound. """ - raise NotImplementedError() + inputs_used = [] + for used_input in self._used_ids: + if 'in' in str(used_input): + used_input = used_input.replace("in", "") + inputs_used.append(int(used_input)) + if inputs_used == []: + raise ValueError("No inputs to sfg") + for input in inputs_used: + input_op = self._input_operations[input] + queue: Deque[Operation] = deque([input_op]) + visited: Set[Operation] = {input_op} + dict_of_sfg = {} + while queue: + op = queue.popleft() + for output_port in op.outputs: + if not (isinstance(op, Input) or isinstance(op, Output)): + dict_of_sfg[op.graph_id] = [] + for signal in output_port.signals: + if signal.destination is not None: + new_op = signal.destination.operation + if not (isinstance(op, Input) or isinstance(op, Output)): + if not isinstance(new_op, Output): + dict_of_sfg[op.graph_id] += [new_op.graph_id] + if new_op not in visited: + queue.append(new_op) + visited.add(new_op) + else: + raise ValueError("Destination does not exist") + if dict_of_sfg == {}: + raise ValueError( + "the SFG does not have any loops and therefore no iteration period bound." + ) + cycles = [ + [node] + path + for node in dict_of_sfg + for path in self.dfs(dict_of_sfg, node, node) + ] + if cycles == []: + return -1 + op_and_latency = {} + for op in self.operations: + for lista in cycles: + for element in lista: + if op.type_name() not in op_and_latency: + op_and_latency[op.type_name()] = op.latency + t_l_values = [] + for loop in cycles: + loop.pop() + time_of_loop = 0 + number_of_t_in_loop = 0 + for element in loop: + if ''.join([i for i in element if not i.isdigit()]) == 't': + number_of_t_in_loop += 1 + for key, item in op_and_latency.items(): + if key in element: + time_of_loop += item + if number_of_t_in_loop == 0 or number_of_t_in_loop == 1: + t_l_values.append(time_of_loop) + else: + t_l_values.append(time_of_loop / number_of_t_in_loop) + return max(t_l_values) def edit(self) -> Dict[str, "SFG"]: """Edit SFG in GUI.""" -- GitLab