diff --git a/src/simudator/cli/cli.py b/src/simudator/cli/cli.py index 0578f640d35540598e04d9638f5caf96fca8da80..7eb5e46ddcf8349ff805b61a6b647575bdbccca0 100644 --- a/src/simudator/cli/cli.py +++ b/src/simudator/cli/cli.py @@ -73,6 +73,13 @@ class CLI: case ["rc"] | ["run_continuously"]: self.processor.run_continuously() + if self.processor.breakpoint_reached: + bp = self.processor.last_breakpoint + print(f"Reached breakpoint: {bp}") + + if self.processor.should_halt(): + print("The processor halted") + case ["r"] | ["resets"]: # self.processor.load_cycle(0) @@ -86,6 +93,13 @@ class CLI: try: for _ in range(int(user_input.split()[1])): self.processor.do_tick() + if self.processor.is_stopped: + break + if self.processor.breakpoint_reached: + bp = self.processor.last_breakpoint + print(f"Reached breakpoint: {bp}") + if self.processor.should_halt(): + print("The processor halted") except ValueError: print("Invalid value") diff --git a/src/simudator/core/processor.py b/src/simudator/core/processor.py index 0426f1430269d6577d4ef413003dfc8f793dbd34..7fbc7874819e2f12e94b0b462e604fa8d24b3001 100644 --- a/src/simudator/core/processor.py +++ b/src/simudator/core/processor.py @@ -48,8 +48,10 @@ class Processor: def do_tick(self) -> None: """ - Does one clock-cycle of the processor by running each modules - tick function, then handels the following updates. + Simulate one clock cycle of the processor. + + Run each module's tick function, then handle the following updates. + Also check for breakpoints that are reached in this cycle. """ if len(self.module_history) > self.clock - self.removed_cycles: # If a previous stored cycle has been loaded, discard @@ -58,6 +60,7 @@ class Processor: self.module_history = self.module_history[0:self.clock] self.signal_history = self.signal_history[0:self.clock] + self.unstop() self.save_cycle() self.clock += 1 @@ -71,34 +74,51 @@ class Processor: module = self.update_queue.pop(0) module.update_logic() + self.stop_at_breakpoints() + if self.should_halt(): + self.stop() - def run_continuously(self): + def run_continuously(self) -> None: """ - Runs the processor until it halts. + Run the processor until it halts, is stopped or reaches a breakpoint. """ - while not self.should_halt() and not self.is_stopped: + self.unstop() + while not self.is_stopped: self.do_tick() - # Print all reached breakpoints then exit the loop - self.breakpoint_reached = False - for _, bp in self.breakpoints.items(): - #TODO: Can make this more efficient by only checking enabled breakpoints - if bp.is_break() and bp.is_enabled: - self.breakpoint_reached = True - self.last_breakpoint = bp - - if self.breakpoint_reached: - return - def should_halt(self) -> bool: return False def stop(self) -> None: + """ + Signal to stop the execution of the processor until the processor is + instructed to run continuously or do some ticks again. + """ self.is_stopped = True def unstop(self) -> None: + """ + Reset the stop execution signal. + """ self.is_stopped = False + def stop_at_breakpoints(self) -> None: + """ + Stop the execution if any breakpoint has been reached during this cycle. + + Also record the breakpoint that was reached. + """ + self.breakpoint_reached = False + for _, bp in self.breakpoints.items(): + #TODO: Can make this more efficient by only checking enabled breakpoints + if bp.is_break() and bp.is_enabled: + self.breakpoint_reached = True + self.last_breakpoint = bp + + if self.breakpoint_reached: + self.stop() + + def reset(self): """ Resets all values in the processor and diff --git a/src/simudator/gui/gui.py b/src/simudator/gui/gui.py index 8e2348a1000667f881156678be9716ac2c8b0589..ac2ba002cd7d41e8efa182514e5abadf082159bc 100644 --- a/src/simudator/gui/gui.py +++ b/src/simudator/gui/gui.py @@ -454,7 +454,6 @@ class GUI(QMainWindow): steps = self.jump_value_box.value() self.cpu_running = True self.setDisabledWhenRunning(True) - self.cpu.unstop() simulation_thread = RunThread(self.cpu, self.cpu_tick_signal, self.update_delay, False, steps) self.threadpool.start(simulation_thread) @@ -470,7 +469,6 @@ class GUI(QMainWindow): # Create own thread for cpu simulation so gui dosent freeze self.cpu_running = True self.setDisabledWhenRunning(True) - self.cpu.unstop() simulation_thread = RunThread(self.cpu, self.cpu_tick_signal, self.update_delay) self.threadpool.start(simulation_thread) @@ -487,19 +485,6 @@ class GUI(QMainWindow): if self.update_all_values: self.updateCpuListeners() - # If a breakpoint halted the program, inform the user - # Update other visuals and set the cpu to the correct state (not running) - if self.cpu.breakpoint_reached: - self.messageBox("Reached breakpoint: " + self.cpu.last_breakpoint.__str__()) - - # When the CPU is done we want to inform the user and update visuals - if self.cpu.should_halt(): - # Only show halted message for larger steps that take time - # This is done so a user dosent have to close - # the message box after every small step - if steps > self.HALT_MESSAGE_THRESHOLD: - self.messageBox("The processor halted.") - # A signal of 0 steps signifies end of execution, i.e. the CPU has # halted or run the specified amount of ticks # => Enable the relevant parts of the GUI again @@ -508,6 +493,14 @@ class GUI(QMainWindow): self.setDisabledWhenRunning(False) self.updateCpuListeners() + # Inform user of reached break point + if self.cpu.breakpoint_reached: + self.messageBox("Reached breakpoint: " + self.cpu.last_breakpoint.__str__()) + + # Inform user of halt + if self.cpu.should_halt(): + self.messageBox("The processor halted.") + def stopToolBarButtonClick(self) -> None: """ Tells the cpu to stop. It will then stop at an appropriate in its own thread. diff --git a/src/simudator/gui/run_continuously_thread.py b/src/simudator/gui/run_continuously_thread.py index d615f61ac344002be4ddbb31e9f0062a7f403827..a46a4ebd2c25c1f472caf226dc2c55af398455a0 100644 --- a/src/simudator/gui/run_continuously_thread.py +++ b/src/simudator/gui/run_continuously_thread.py @@ -23,7 +23,8 @@ class RunThread(QRunnable): def run(self): if self.run_continuously: - while not self.cpu.should_halt() and not self.cpu.is_stopped: + self.cpu.unstop() + while not self.cpu.is_stopped: self.cpu.do_tick() self.signal.emit(1) time.sleep(self.delay) @@ -34,5 +35,8 @@ class RunThread(QRunnable): self.signal.emit(1) time.sleep(self.delay) + if self.cpu.is_stopped: + break + # Signal end of execution as having run 0 ticks self.signal.emit(0)