From b9089b611c39e64c0537c4893e845cbc37fa4a84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20H=C3=B6gstedt?= <marin.hogstedt@hotmail.com>
Date: Tue, 11 Jun 2024 09:52:59 +0200
Subject: [PATCH] can now step backwards in asm instr. The first backstep
 sometimes signals it cant be loaded when it can. The last back step (aka when
 going from clock cycle 5 to 0) never works

---
 src/simudator/core/processor.py    | 19 ++++++++++++++++---
 src/simudator/gui/gui.py           |  3 ++-
 src/simudator/processor/mia/mia.py | 28 ++++++++++++++++++++++++++--
 3 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/src/simudator/core/processor.py b/src/simudator/core/processor.py
index c1983ca..543e578 100644
--- a/src/simudator/core/processor.py
+++ b/src/simudator/core/processor.py
@@ -48,6 +48,9 @@ class Processor:
                 ]
         self.lambdas: dict[str, Callable[..., bool]] = {}
 
+        # List containing all clock cycles where a new asm instruction started
+        self.assembly_cycles = []
+
     def do_tick(self) -> None:
         """
         Simulate one clock cycle of the processor.
@@ -96,6 +99,16 @@ class Processor:
 
         raise NotImplemented
 
+    def undo_asm_instruction(self, num_instructions = 1) -> None:
+        """
+        Undos 'num_instructions' numbers of assembler instructions on the processors.
+
+        Default argument is one, but it is possible to specify any number of instructions.
+        This should be implemented per processor and thus we raise NotImplemented.
+        """
+
+        raise NotImplemented
+
     def run_continuously(self) -> None:
         """
         Run the processor until it halts, is stopped or reaches a breakpoint.
@@ -228,9 +241,9 @@ class Processor:
 
     def load_cycle(self, cycle: int) -> None:
         """
-        Load the state of all modules as they were at the specified
-        clock cycle. This does not erase the history of states for the
-        later cycles.
+        Load the state of all modules as they were at the specified clock cycle.
+
+        This does not erase the history of states for the later cycles.
         """
 
         cycle_index = cycle - self.removed_cycles
diff --git a/src/simudator/gui/gui.py b/src/simudator/gui/gui.py
index 9910e33..ebab5d4 100644
--- a/src/simudator/gui/gui.py
+++ b/src/simudator/gui/gui.py
@@ -928,9 +928,10 @@ class GUI(QMainWindow):
         """
         Undos as many processor cycles as the number entered in the box.
         """
+        print(self.cpu.assembly_cycles)
         try:
             steps = self.asm_jump_value_box.value()
-            self.cpu.load_cycle(max(self.cpu.get_clock() - steps, 0))
+            self.cpu.undo_asm_instruction(steps)
             self.updateCpuListeners()
         except (ValueError, IndexError):
             self.errorBox("Unable to undo the cycle.")
diff --git a/src/simudator/processor/mia/mia.py b/src/simudator/processor/mia/mia.py
index b5c1003..632248c 100644
--- a/src/simudator/processor/mia/mia.py
+++ b/src/simudator/processor/mia/mia.py
@@ -280,8 +280,6 @@ class MIA_CPU(Processor):
 
         self.micro_memory = uM
 
-        # List containing all clock cycles where a new asm instruction started
-        self.assembly_cycles = []
 
         self.lambdas = {}
 
@@ -296,6 +294,7 @@ class MIA_CPU(Processor):
             self.new_instruction = True
             self.current_instruction = self.get_current_instrution()
             self.assembly_cycles.append(self.get_clock())
+            self.finished_assembly_instructions += 1
         else:
             self.new_instruction = False
 
@@ -323,6 +322,31 @@ class MIA_CPU(Processor):
 
             self.do_tick()
 
+    def undo_asm_instruction(self, num_instructions = 1) -> None:
+        """
+        Undos 'num_instructions' numbers of assembler instructions on Mia.
+
+        Default argument is one, but it is possible to specify any number of instructions.
+        Undo assembler instrucion assumes the CPU is always at the end of the list
+        'self.assembly_cycles'.
+
+        Undos asm instructions by finding the corresponding clock cycle before 
+        said number of asm intructions started and loading that clock cycle.
+        """
+
+        index = len(self.assembly_cycles)
+        index -= num_instructions
+
+        # We cant undo more instructions than we have performed.
+        if index < 0:
+            raise IndexError
+
+        clockcycle = self.assembly_cycles[index]
+        self.assembly_cycles = self.assembly_cycles[:index]
+
+        self.load_cycle(clockcycle)
+
+
     def should_halt(self) -> bool:
         micro_memory_state = self.micro_memory.get_state()
         return micro_memory_state["halt"]
-- 
GitLab