diff --git a/b_asic/gui_utils/icons.py b/b_asic/gui_utils/icons.py index 85fa6c818eafe920ef5e771d37a38f3086d96dc2..4bd348a886bb12d8a81716f208d4d9382db3af13 100644 --- a/b_asic/gui_utils/icons.py +++ b/b_asic/gui_utils/icons.py @@ -33,6 +33,9 @@ ICONS = { 'full-screen-exit': 'mdi6.fullscreen-exit', 'warning': 'fa5s.exclamation-triangle', 'port-numbers': 'fa5s.hashtag', + 'swap': 'fa5s.arrows-alt-v', + 'asap': 'fa5s.fast-backward', + 'alap': 'fa5s.fast-forward', } diff --git a/b_asic/schedule.py b/b_asic/schedule.py index db668d10c300123e86666ed0f04181207afe4b12..a4655e076b73193af06817cb75cdb3116bc520b5 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -644,6 +644,56 @@ class Schedule: self._start_times[graph_id] = new_start return self + def move_operation_alap(self, graph_id: GraphID) -> "Schedule": + """ + Move an operation as late as possible in the schedule. + + This is basically the same as:: + + schedule.move_operation(graph_id, schedule.forward_slack(graph_id)) + + but Outputs will only move to the end of the schedule. + + Parameters + ---------- + graph_id : GraphID + The graph id of the operation to move. + """ + op = self._sfg.find_by_id(graph_id) + if op is None: + raise ValueError(f"No operation with graph_id {graph_id!r} in schedule") + if isinstance(op, Output): + self.move_operation( + graph_id, self.schedule_time - self._start_times[graph_id] + ) + else: + self.move_operation(graph_id, self.forward_slack(graph_id)) + return self + + def move_operation_asap(self, graph_id: GraphID) -> "Schedule": + """ + Move an operation as soon as possible in the schedule. + + This is basically the same as:: + + schedule.move_operation(graph_id, -schedule.backward_slack(graph_id)) + + but Inputs will only move to the start of the schedule. + + Parameters + ---------- + graph_id : GraphID + The graph id of the operation to move. + """ + op = self._sfg.find_by_id(graph_id) + if op is None: + raise ValueError(f"No operation with graph_id {graph_id!r} in schedule") + if isinstance(op, Input): + self.move_operation(graph_id, -self._start_times[graph_id]) + else: + self.move_operation(graph_id, -self.backward_slack(graph_id)) + return self + def _remove_delays_no_laps(self) -> None: """Remove delay elements without updating laps. Used when loading schedule.""" delay_list = self._sfg.find_by_type_name(Delay.type_name()) diff --git a/b_asic/scheduler_gui/operation_item.py b/b_asic/scheduler_gui/operation_item.py index c84529fafe27b5b7569e6ca60c4a68faa6579e01..e6d823e03397b57adcfb79a94a2814460606f97c 100644 --- a/b_asic/scheduler_gui/operation_item.py +++ b/b_asic/scheduler_gui/operation_item.py @@ -21,8 +21,10 @@ from qtpy.QtWidgets import ( QMenu, ) -# B-ASIC from b_asic.graph_component import GraphID + +# B-ASIC +from b_asic.gui_utils.icons import get_icon from b_asic.operation import Operation from b_asic.scheduler_gui._preferences import ( OPERATION_EXECUTION_TIME_INACTIVE, @@ -305,10 +307,20 @@ class OperationItem(QGraphicsItemGroup): def _open_context_menu(self): menu = QMenu() - swap = QAction("Swap") + swap = QAction(get_icon('swap'), "Swap") menu.addAction(swap) swap.setEnabled(self._operation.is_swappable) swap.triggered.connect(self._swap_io) + slacks = self._parent._schedule.slacks(self._operation.graph_id) + asap = QAction(get_icon('asap'), "Move as soon as possible") + asap.triggered.connect(self._move_asap) + asap.setEnabled(slacks[0] > 0) + menu.addAction(asap) + alap = QAction(get_icon('alap'), "Move as late as possible") + alap.triggered.connect(self._move_alap) + alap.setEnabled(slacks[1] > 0) + menu.addAction(alap) + menu.addSeparator() execution_time_plot = QAction( f"Show execution times for {self._operation.type_name()}" ) @@ -321,3 +333,9 @@ class OperationItem(QGraphicsItemGroup): def _execution_time_plot(self, event=None) -> None: self._parent._execution_time_plot(self._operation.type_name()) + + def _move_asap(self, event=None): + self._parent._schedule.move_operation_asap(self._operation.graph_id) + + def _move_alap(self, event=None): + self._parent._schedule.move_operation_alap(self._operation.graph_id)