diff --git a/b_asic/_preferences.py b/b_asic/_preferences.py index bc840f5c7f63a53ea7a6ba07126c809df9e86ef7..f1e9e757769e89db0f55fcae03f74348531efb01 100644 --- a/b_asic/_preferences.py +++ b/b_asic/_preferences.py @@ -3,3 +3,5 @@ EXECUTION_TIME_COLOR = (255, 100, 66, 200) SIGNAL_COLOR = (0, 0, 0) SIGNAL_LINEWIDTH = 1.0 + +OPERATION_GAP = 0.5 diff --git a/b_asic/schedule.py b/b_asic/schedule.py index 412606ba9b77e395c6bb21bf6fe2fa7ff649e7b6..f8af67ee08cf1fc02b5258280254800d86977dd7 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -20,6 +20,7 @@ from b_asic import Signal from b_asic._preferences import ( EXECUTION_TIME_COLOR, LATENCY_COLOR, + OPERATION_GAP, SIGNAL_COLOR, SIGNAL_LINEWIDTH, ) @@ -30,6 +31,7 @@ from b_asic.process import MemoryVariable, Process from b_asic.signal_flow_graph import SFG from b_asic.special_operations import Delay, Output +# Need RGB from 0 to 1 _EXECUTION_TIME_COLOR = tuple(c / 255 for c in EXECUTION_TIME_COLOR) _LATENCY_COLOR = tuple(c / 255 for c in LATENCY_COLOR) _SIGNAL_COLOR = tuple(c / 255 for c in SIGNAL_COLOR) @@ -448,14 +450,21 @@ class Schedule: ) return ret + def _get_y_position(self, op_id): + y_location = self._y_locations[op_id] + if y_location == None: + # Assign the lowest row number not yet in use + used = set( + loc for loc in self._y_locations.values() if loc is not None + ) + possible = set(range(len(self._start_times))) - used + y_location = min(possible) + self._y_locations[op_id] = y_location + return OPERATION_GAP + y_location * (1 + OPERATION_GAP) + def _plot_schedule(self, ax): line_cache = [] - y_location = 0 - for op_id, op_start_time in self._start_times.items(): - self._y_locations[op_id] = y_location - y_location += 1 - def _draw_arrow(start, end, name="", laps=0): if end[0] < start[0] or laps > 0: # Wrap around if start not in line_cache: @@ -550,12 +559,8 @@ class Schedule: yticklabels = [] ax.set_axisbelow(True) ax.grid() - ypositions = {} for op_id, op_start_time in self._start_times.items(): - y_location = self._y_locations[op_id] - if y_location is None: - raise RuntimeError(f"No y-location for operation {op_id}") - ypos = -0.5 - y_location * 1.5 + ypos = -self._get_y_position(op_id) op = self._sfg.find_by_id(op_id) # Rewrite to make better use of NumPy latency_coords, execution_time_coords = op.get_plot_coordinates() @@ -577,17 +582,17 @@ class Schedule: ) ytickpositions.append(ypos + 0.5) yticklabels.append(self._sfg.find_by_id(op_id).name) - ypositions[op_id] = ypos for op_id, op_start_time in self._start_times.items(): op = self._sfg.find_by_id(op_id) _, out_coords = op.get_io_coordinates() - source_ypos = ypositions[op_id] + source_ypos = -self._get_y_position(op_id) + for output_port in op.outputs: for output_signal in output_port.signals: dest_op = output_signal.destination.operation dest_start_time = self._start_times[dest_op.graph_id] - dest_ypos = ypositions[dest_op.graph_id] + dest_ypos = -self._get_y_position(dest_op.graph_id) ( dest_in_coords, _, @@ -605,7 +610,8 @@ class Schedule: ax.set_yticks(ytickpositions) ax.set_yticklabels(yticklabels) - yposmin = min(ypositions.values()) - 0.5 + max_pos_op_id = max(self._y_locations, key=self._y_locations.get) + yposmin = -self._get_y_position(max_pos_op_id) - OPERATION_GAP ax.axis([-1, self._schedule_time + 1, yposmin, 1]) ax.xaxis.set_major_locator(MaxNLocator(integer=True)) ax.add_line(