diff --git a/mia_uppg3.txt b/mia_uppg3.txt
index ad3b20b8744d1b1db6af89c67abb25fc969b7941..d61dbb62df11c36dc704cb7cd0ed5c2711dc54a6 100644
--- a/mia_uppg3.txt
+++ b/mia_uppg3.txt
@@ -387,22 +387,22 @@ uM:
 7f: 0000000
 
 K1:
-00: 0a
-01: 0b
-02: 0c
-03: 0f
-04: 12
-05: 15
-06: 1a
-07: 1d
-08: 1f
-09: 20
-0a: 22
-0b: 27
-0c: 00
-0d: 00
-0e: 00
-0f: 00
+00: 0a ADD
+01: 0b SUB
+02: 0c MULT
+03: 0f NOP
+04: 12 TEST
+05: 15 D
+06: 1a R 
+07: 1d T
+08: 1f TT
+09: 20 TT
+0a: 22 TTT
+0b: 27 TTTT
+0c: 00 FR
+0d: 00 FH
+0e: 00 LF
+0f: 00 FFF
 
 K2:
 00: 03
diff --git a/mia_uppg3_backup.txt b/mia_uppg3_backup.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ad3b20b8744d1b1db6af89c67abb25fc969b7941
--- /dev/null
+++ b/mia_uppg3_backup.txt
@@ -0,0 +1,411 @@
+PM:
+00: 0100
+01: 00e0
+02: 10d0
+03: 0100
+04: 0001
+05: 0cd0
+06: 0b01
+07: 9ad0
+08: a005
+09: 06d0
+0a: 1ad0
+0b: 1701
+0c: 0100
+0d: 0000
+0e: 2d00
+0f: 0001
+10: 1cd0
+11: 9d00
+12: 00ff
+13: 70f2
+14: 9100
+15: 0001
+16: 70e9
+17: 8000
+18: 0000
+19: 0000
+1a: 0000
+1b: 0000
+1c: 0000
+1d: 0000
+1e: 0000
+1f: 0000
+20: 0000
+21: 0000
+22: 0000
+23: 0000
+24: 0000
+25: 0000
+26: 0000
+27: 0000
+28: 0000
+29: 0000
+2a: 0000
+2b: 0000
+2c: 0000
+2d: 0000
+2e: 0000
+2f: 0000
+30: 0000
+31: 0000
+32: 0000
+33: 0000
+34: 0000
+35: 0000
+36: 0000
+37: 0000
+38: 0000
+39: 0000
+3a: 0000
+3b: 0000
+3c: 0000
+3d: 0000
+3e: 0000
+3f: 0000
+40: 0000
+41: 0000
+42: 0000
+43: 0000
+44: 0000
+45: 0000
+46: 0000
+47: 0000
+48: 0000
+49: 0000
+4a: 0000
+4b: 0000
+4c: 0000
+4d: 0000
+4e: 0000
+4f: 0000
+50: 0000
+51: 0000
+52: 0000
+53: 0000
+54: 0000
+55: 0000
+56: 0000
+57: 0000
+58: 0000
+59: 0000
+5a: 0000
+5b: 0000
+5c: 0000
+5d: 0000
+5e: 0000
+5f: 0000
+60: 0000
+61: 0000
+62: 0000
+63: 0000
+64: 0000
+65: 0000
+66: 0000
+67: 0000
+68: 0000
+69: 0000
+6a: 0000
+6b: 0000
+6c: 0000
+6d: 0000
+6e: 0000
+6f: 0000
+70: 0000
+71: 0000
+72: 0000
+73: 0000
+74: 0000
+75: 0000
+76: 0000
+77: 0000
+78: 0000
+79: 0000
+7a: 0000
+7b: 0000
+7c: 0000
+7d: 0000
+7e: 0000
+7f: 0000
+80: 0000
+81: 0000
+82: 0000
+83: 0000
+84: 0000
+85: 0000
+86: 0000
+87: 0000
+88: 0000
+89: 0000
+8a: 0000
+8b: 0000
+8c: 0000
+8d: 0000
+8e: 0000
+8f: 0000
+90: 0000
+91: 0000
+92: 0000
+93: 0000
+94: 0000
+95: 0000
+96: 0000
+97: 0000
+98: 0000
+99: 0000
+9a: 0000
+9b: 0000
+9c: 0000
+9d: 0000
+9e: 0000
+9f: 0000
+a0: 0000
+a1: 0000
+a2: 0000
+a3: 0000
+a4: 0000
+a5: 0000
+a6: 0000
+a7: 0000
+a8: 0000
+a9: 0000
+aa: 0000
+ab: 0000
+ac: 0000
+ad: 0000
+ae: 0000
+af: 0000
+b0: 0000
+b1: 0000
+b2: 0000
+b3: 0000
+b4: 0000
+b5: 0000
+b6: 0000
+b7: 0000
+b8: 0000
+b9: 0000
+ba: 0000
+bb: 0000
+bc: 0000
+bd: 0000
+be: 0000
+bf: 0000
+c0: 0000
+c1: 0000
+c2: 0000
+c3: 0000
+c4: 0000
+c5: 0000
+c6: 0000
+c7: 0000
+c8: 0000
+c9: 0000
+ca: 0000
+cb: 0000
+cc: 0000
+cd: 0000
+ce: 0000
+cf: 0000
+d0: 0000
+d1: 0000
+d2: 0000
+d3: 0000
+d4: 0000
+d5: 0000
+d6: 0000
+d7: 0000
+d8: 0000
+d9: 0000
+da: 0000
+db: 0000
+dc: 0000
+dd: 0000
+de: 0000
+df: 0000
+e0: 0000
+e1: 0000
+e2: 0000
+e3: 0000
+e4: 0000
+e5: 0000
+e6: 0000
+e7: 0000
+e8: 0000
+e9: 0000
+ea: 0000
+eb: 0000
+ec: 0000
+ed: 0000
+ee: 0000
+ef: 0000
+f0: 0000
+f1: 0000
+f2: 0000
+f3: 0000
+f4: 0000
+f5: 0000
+f6: 0004
+f7: cac0
+f8: bbbb
+f9: 0003
+fa: 0200
+fb: 6969
+fc: abba
+fd: ffff
+fe: 1337
+ff: 0001
+
+uM:
+00: 00f8000
+01: 008a000
+02: 0000100
+03: 0078080
+04: 00fa080
+05: 0078000
+06: 00b8080
+07: 0240000
+08: 1184000
+09: 0138080
+0a: 00b0180
+0b: 0190180
+0c: 0380000
+0d: 0880000
+0e: 0130180
+0f: 0380000
+10: 0a80000
+11: 0130180
+12: 0380000
+13: 0c80000
+14: 0130180
+15: 0041000
+16: 0380800
+17: 1a00e19
+18: 0000297
+19: 0130180
+1a: 0240000
+1b: 10c0000
+1c: 0118180
+1d: 000021a
+1e: 0000180
+1f: 0000780
+20: 0380000
+21: 0a80180
+22: 00005a5
+23: 00004a6
+24: 000029a
+25: 00004a4
+26: 0000180
+27: 000041a
+28: 0000180
+29: 0000000
+2a: 0000000
+2b: 0000000
+2c: 0000000
+2d: 0000000
+2e: 0000000
+2f: 0000000
+30: 0000000
+31: 0000000
+32: 0000000
+33: 0000000
+34: 0000000
+35: 0000000
+36: 0000000
+37: 0000000
+38: 0000000
+39: 0000000
+3a: 0000000
+3b: 0000000
+3c: 0000000
+3d: 0000000
+3e: 0000000
+3f: 0000000
+40: 0000000
+41: 0000000
+42: 0000000
+43: 0000000
+44: 0000000
+45: 0000000
+46: 0000000
+47: 0000000
+48: 0000000
+49: 0000000
+4a: 0000000
+4b: 0000000
+4c: 0000000
+4d: 0000000
+4e: 0000000
+4f: 0000000
+50: 0000000
+51: 0000000
+52: 0000000
+53: 0000000
+54: 0000000
+55: 0000000
+56: 0000000
+57: 0000000
+58: 0000000
+59: 0000000
+5a: 0000000
+5b: 0000000
+5c: 0000000
+5d: 0000000
+5e: 0000000
+5f: 0000000
+60: 0000000
+61: 0000000
+62: 0000000
+63: 0000000
+64: 0000000
+65: 0000000
+66: 0000000
+67: 0000000
+68: 0000000
+69: 0000000
+6a: 0000000
+6b: 0000000
+6c: 0000000
+6d: 0000000
+6e: 0000000
+6f: 0000000
+70: 0000000
+71: 0000000
+72: 0000000
+73: 0000000
+74: 0000000
+75: 0000000
+76: 0000000
+77: 0000000
+78: 0000000
+79: 0000000
+7a: 0000000
+7b: 0000000
+7c: 0000000
+7d: 0000000
+7e: 0000000
+7f: 0000000
+
+K1:
+00: 0a
+01: 0b
+02: 0c
+03: 0f
+04: 12
+05: 15
+06: 1a
+07: 1d
+08: 1f
+09: 20
+0a: 22
+0b: 27
+0c: 00
+0d: 00
+0e: 00
+0f: 00
+
+K2:
+00: 03
+01: 04
+02: 05
+03: 07
diff --git a/src/simudator/core/processor.py b/src/simudator/core/processor.py
index 7fbc7874819e2f12e94b0b462e604fa8d24b3001..876b62739d8b40e2257da72744252cddfea57eab 100644
--- a/src/simudator/core/processor.py
+++ b/src/simudator/core/processor.py
@@ -36,6 +36,8 @@ class Processor:
         self.max_line_len = 170
         self.line_seperator = "-"
         self.is_stopped = False
+        self.new_instruction = False
+        self.current_instructions: list[str] = []
         # TODO: keeping track of what pieces of info not to show
         # show not be done at the processor level.
         # Maybe implemenet a 'get_pretty_print_state' at module
@@ -46,12 +48,16 @@ class Processor:
                 ]
         self.lambdas: dict[str, Callable[..., bool]] = {}
 
+        # List containing all clock cycles where a new asm instruction started
+        self.assembly_cycles = [0]
+
     def do_tick(self) -> None:
         """
         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.
+        Also check for breakpoints that are reached in this cycle, and save
+        clock cycles when new assemly instructions are started.
         """
         if len(self.module_history) > self.clock - self.removed_cycles:
             # If a previous stored cycle has been loaded, discard
@@ -78,6 +84,69 @@ class Processor:
         if self.should_halt():
             self.stop()
 
+        # Set new_instruction and save clock cycle for each
+        # new assembly instruction
+        if self.is_new_instruction():
+            self.new_instruction = True
+            self.current_instruction = self.get_current_instruction()
+            self.assembly_cycles.append(self.get_clock())
+        else:
+            self.new_instruction = False
+
+    def get_current_instruction(self) -> str:
+        """
+        Return the current instruction. Useful for pipeline diagram.
+        """
+        raise NotImplemented
+
+    def run_asm_instruction(self, num_instructions = 1) -> None:
+        """
+        Runs assembler instructions on the processors 'num_instructions' times.
+
+        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 undo_asm_instruction(self, num_instructions = 1) -> None:
+        """
+        Undos 'num_instructions' numbers of assembler instructions on the CPU.
+
+        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.
+        """
+
+        current_clock_cycle = self.clock
+        index = len(self.assembly_cycles)
+        saved_cycle = self.assembly_cycles[index-1]
+
+        # Make sure we are undoing the instruction(s) we are currently on
+        while saved_cycle >= current_clock_cycle:
+            index -= 1
+            saved_cycle = self.assembly_cycles[index-1]
+
+        index -= num_instructions
+
+        # We cant undo more instructions than we have performed.
+        if index < 0:
+            raise IndexError
+
+        clockcycle = self.assembly_cycles[index]
+
+        self.load_cycle(clockcycle)
+
+        # Need +1 here since we save the start state to enable to 
+        # load the start state. This is done since we only append clock
+        # cycles to the list self.assembly_cycles when we reach a new state
+        # that has uPC set to 0, which wont happend when we load a new file.
+        self.assembly_cycles = self.assembly_cycles[:index+1]
+
+
     def run_continuously(self) -> None:
         """
         Run the processor until it halts, is stopped or reaches a breakpoint.
@@ -102,6 +171,15 @@ class Processor:
         """
         self.is_stopped = False
 
+    def is_new_instruction(self) -> bool:
+        """
+        Return true on the same clock cycle the CPU starts a new instruciton.
+
+        Should be implemented per CPU, return field new_instruction. It is up to each
+        processor to set this field to True/False correctly.
+        """
+        return self.new_instruction
+
     def stop_at_breakpoints(self) -> None:
         """
         Stop the execution if any breakpoint has been reached during this cycle.
@@ -201,9 +279,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
@@ -216,6 +294,7 @@ class Processor:
         except IndexError:
             raise IndexError
 
+
         for module_name, module_state in module_states.items():
             self.modules[module_name].set_state(module_state)
 
@@ -230,7 +309,11 @@ class Processor:
 
     def load_state_from_file(self, file_path) -> None:
         """
-        Load states for modules from a file.
+        Loads states for modules from a file.
+
+        Appends the lines from the loaded file to a long string. This string
+        is given to each module in the function 'load_from_str'. Each module
+        will thus load itself.
         """
         self.reset()
 
@@ -246,6 +329,7 @@ class Processor:
 
         module_name = None
         module_str = ""
+
         # Go through each line in the file
         lines = file.readlines()
         for line in lines:
@@ -267,7 +351,8 @@ class Processor:
                     module_str = ""
                     module_name = None
 
-        # give module anything that is left
+        # The last module will be an edge case, since we append the information
+        # after we read an empty line.
         if module_name and module_str:
             module = self.get_module(module_name)
             module.load_from_str(module_str)
@@ -275,6 +360,7 @@ class Processor:
     def save_state_to_file(self, file_path: str) -> None:
         """
         Saves the current state of the cpu to a given file.
+
         Will overwrite the given file.
         """
         file = open(file_path, "w")
@@ -462,7 +548,7 @@ class Processor:
     def get_most_fields(self, modules: dict[Module: int],
                         ignore_keys=[]) -> int:
         """
-        Returns the most number of a fields a module has. Can optionally
+        Return the most number of a fields a module has. Can optionally
         ignore keys.
         """
         fields = 0
diff --git a/src/simudator/gui/gui.py b/src/simudator/gui/gui.py
index ac2ba002cd7d41e8efa182514e5abadf082159bc..88f8a27d084ea39cd1d6e3c769693f0ef165f56f 100644
--- a/src/simudator/gui/gui.py
+++ b/src/simudator/gui/gui.py
@@ -33,6 +33,7 @@ from simudator.gui.orientation import Orientation
 from simudator.gui.port_graphics_item import PortGraphicsItem
 from simudator.gui.run_continuously_thread import RunThread
 from simudator.gui.signal_graphics_item import SignalGraphicsItem
+from simudator.gui.pipeline import PipeLine
 
 
 class View(QGraphicsView):
@@ -83,7 +84,9 @@ class View(QGraphicsView):
 
 class GUI(QMainWindow):
     """
-    This is the main class for the GUI. It handles creating the widnow for
+    Main gui class. Handles gui windows, toolbar and visualizes modules.
+
+    This is the main class for the GUI. It handles creating the window for
     the gui, aswell as the toolbar for controlling the simultaion.
     It takes a processor and visualizes its modules as boxes with the signals as lines
     between them. Graphics items for the modules and signals need to be created
@@ -128,6 +131,10 @@ class GUI(QMainWindow):
         # Using the cpu's internal status directly could case problems
         self.cpu_running = False
 
+        self.pipeline = PipeLine()
+        # Hide pipeline for now since it is not implemented yet
+        # self.pipeline.show()
+
         # Set Style, THESE ARE TEST AND DONT WORK
         app = QApplication.instance()
         app.setStyleSheet("Qwidget.QMainWindow { background-color: yellow }")
@@ -138,6 +145,9 @@ class GUI(QMainWindow):
 
     def createToolBar(self) -> None:
         """
+        Creates the toolbar containing file, layout and toolbar buttons.
+
+
         Creates the toolbar containing the file, layout and toolbar
         buttons with their respective sub buttons.
         """
@@ -246,6 +256,10 @@ class GUI(QMainWindow):
         self.stop_action.triggered.connect(self.stopToolBarButtonClick)
         toolbar.addAction(self.stop_action)
 
+        # Add Asm label 
+        self.clock_cycle_label = QLabel("Clock cycle: ", self)
+        toolbar.addWidget(self.clock_cycle_label)
+
         # Add undo button on toolbar
         backward_arrow_icon = self.style().standardIcon(QStyle.SP_MediaSeekBackward)
         self.undo_action = QAction(backward_arrow_icon, "Undo", self)
@@ -277,11 +291,47 @@ class GUI(QMainWindow):
         toolbar.addWidget(spacing)
 
         # Add clock counter
-        self.clock_label = QLabel("Clockcycle: " + str(self.cpu.get_clock()), self)
+        self.clock_label = QLabel("Clock cycles: " + str(self.cpu.get_clock()), self)
         toolbar.addWidget(self.clock_label)
 
+        # Add seperator so clock gets better spacing
+        spacing = QWidget()
+        spacing.setFixedWidth(10)
+        toolbar.addWidget(spacing)
+        toolbar.addSeparator()
+        spacing = QWidget()
+        spacing.setFixedWidth(10)
+        toolbar.addWidget(spacing)
+
+        # Add Asm label 
+        self.asm_label = QLabel("Assembler Instructions: ", self)
+        toolbar.addWidget(self.asm_label)
+
+        # Add undo asm button on toolbar
+        backward_arrow_icon = self.style().standardIcon(QStyle.SP_MediaSeekBackward)
+        self.undo_asm_action = QAction(backward_arrow_icon, "Undo Asm", self)
+        self.undo_asm_action.setStatusTip("Undo the last assembler instruction")
+        self.undo_asm_action.triggered.connect(self.undoAsmToolBarButtonClick)
+        toolbar.addAction(self.undo_asm_action)
+
+        # Add step button on toolbar
+        forward_arrow_icon = self.style().standardIcon(QStyle.SP_MediaSeekForward)
+        self.step_asm_action = QAction(forward_arrow_icon, "Step Asm", self)
+        self.step_asm_action.setStatusTip("Run one assembler instruction")
+        self.step_asm_action.triggered.connect(self.stepAsmToolBarButtonClick)
+        toolbar.addAction(self.step_asm_action)
+
+        # Add box for jump value
+        self.asm_jump_value_box = QSpinBox()
+        self.asm_jump_value_box.setMinimum(999999)
+        self.asm_jump_value_box.setMinimum(1)
+        self.asm_jump_value_box.setValue(1)
+        toolbar.addWidget(self.asm_jump_value_box)
+
     def connectModuleActions(self, action_signals: []) -> None:
         """
+        Connects modules with actions thorught ids (strings). Useful for breakpoints.
+
         This function takes a list of tuples with an
         action id (which is a predefined string) and a signal.
         It then connects the signal to a function depending on the action id.
@@ -342,6 +392,7 @@ class GUI(QMainWindow):
         if self.breakpoint_window is not None:
             self.breakpoint_window.update()
 
+
     """
     @Slot is used to explicitly mark a python method as a Qt slot
     and specify a C++ signature for it, which is used most commonly
@@ -351,8 +402,9 @@ class GUI(QMainWindow):
     @Slot(str, str, str)
     def editModuleState(self, module_name, state, value) -> None:
         """
-        Tries to change the value of module to value given by user
-        through the dialog opened by editModuleStateDialog.
+        Tries to change the value of module to value given by user.
+
+        Does this through the dialog opened by editModuleStateDialog.
         """
         try:
             parsed_value = ast.literal_eval(value)
@@ -368,8 +420,9 @@ class GUI(QMainWindow):
     @Slot(str, str, str)
     def editMemoryContent(self, module_name: str, adress: str, value: str) -> None:
         """
-        Tries to change the value at adress to value given by user
-        through the dialog opened by editModuleStateDialog.
+        Tries to change the value at adress to value given by user.
+
+        Does this through the dialog opened by editModuleStateDialog.
         """
         try:
             parsed_adress = int(adress, 16)
@@ -390,8 +443,7 @@ class GUI(QMainWindow):
     @Slot(str, str, str)
     def addStateBreakpoint(self, module_name: str, state: str, value: str) -> None:
         """
-        Tries to add a breakpoint to the module through the dialog
-        opened by stateBreakpointDialog.
+        Tries to add a breakpoint to the module through the dialog opened by stateBreakpointDialog.
         """
         try:
             parsed_value = ast.literal_eval(value)
@@ -403,8 +455,7 @@ class GUI(QMainWindow):
     @Slot(str, str)
     def addLambdaBreakpoint(self, lambda_name, kwargs_str) -> None:
         """
-        Tries to add a breakpoint to the module through the dialog
-        opened by lambdaBreakpointDialog.
+        Tries to add a breakpoint to the module through the dialog opened by lambdaBreakpointDialog.
         """
         try:
             lambda_kwargs = {}
@@ -419,8 +470,7 @@ class GUI(QMainWindow):
     @Slot(str, str, str)
     def addMemoryBreakpoint(self, module_name: str, adress: str, value: str) -> None:
         """
-        Tries to add a breakpoint to the module through the dialog
-        opened by memoryBreakpointDialog.
+        Tries to add a breakpoint to the module through the dialog opened by memoryBreakpointDialog.
         """
         try:
             parsed_adress = int(adress)
@@ -432,8 +482,7 @@ class GUI(QMainWindow):
 
     def setDisabledWhenRunning(self, is_disable):
         """
-        This function greys out buttons for actions
-        that can't be done while cpu is running.
+        Greys out buttons for actions that can't be done while cpu is running.
         """
         self.load_action.setDisabled(is_disable)
         self.save_action.setDisabled(is_disable)
@@ -444,7 +493,7 @@ class GUI(QMainWindow):
 
     def stepToolBarButtonClick(self):
         """
-        Runs the cpu a specified number of times according to the jump value box.
+        Runs the cpu a specified number of clock cycles according to the jump value box.
         """
 
         # Don't do steps if cpu is running
@@ -454,9 +503,25 @@ class GUI(QMainWindow):
         steps = self.jump_value_box.value()
         self.cpu_running = True
         self.setDisabledWhenRunning(True)
-        simulation_thread = RunThread(self.cpu, self.cpu_tick_signal, self.update_delay, False, steps)
+        simulation_thread = RunThread(self.cpu, self.cpu_tick_signal, self.update_delay, False, False, steps)
         self.threadpool.start(simulation_thread)
 
+    def stepAsmToolBarButtonClick(self):
+        """
+        Runs the cpu a specified number of asm instructions according to the jump value box.
+        """
+
+        # Don't do steps if cpu is running
+        if self.cpu_running:
+            return
+
+        steps = self.asm_jump_value_box.value()
+        self.cpu_running = True
+        self.setDisabledWhenRunning(True)
+        simultaion_thread = RunThread(self.cpu, self.cpu_tick_signal, self.update_delay, False, True, steps)
+        self.threadpool.start(simultaion_thread)
+        self.updateCpuListeners()
+
     def runToolBarButtonClick(self) -> None:
         """
         Runs the cpu until it is stopped by user input, breakpoint or similar.
@@ -509,8 +574,7 @@ class GUI(QMainWindow):
 
     def folderSaveDialog(self) -> str:
         """
-        Opens a file explorer in a new window. Returns the
-        absolute path to the selected file.
+        Opens a file explorer in a new window. Return the absolute path to the selected file.
         """
         dialog = QFileDialog()
         dialog.setFileMode(QFileDialog.AnyFile)
@@ -521,8 +585,7 @@ class GUI(QMainWindow):
 
     def folderLoadDialog(self) -> str:
         """
-        Opens a file explorer in a new window. Returns the
-        absolute path to the selected file.
+        Opens a file explorer in a new window. Return the absolute path to the selected file.
         """
         dialog = QFileDialog()
         dialog.setFileMode(QFileDialog.AnyFile)
@@ -575,6 +638,7 @@ class GUI(QMainWindow):
             self.updateCpuListeners()
 
     def undoNToolBarButtonClick(self) -> None:
+        # TODO: I dont think this is used
         """
         Undo zero to N cycles.
         """
@@ -601,9 +665,9 @@ class GUI(QMainWindow):
 
     def saveLayoutToolBarButtonClick(self) -> None:
         """
-        Saves the layout of all the modules in a (somewhat)
-        human readable format.
-        Erases the previous content of the file before saving
+        Saves the layout of all the modules in a (somewhat) human readable format.
+
+        This also erases the previous content of the file before saving
         the data.
         """
         path = self.folderSaveDialog()
@@ -644,8 +708,7 @@ class GUI(QMainWindow):
 
     def loadDefaultLayoutToolBarButtonClick(self) -> None:
         """
-        Places all the module_graphic objects in a diagonal going
-        down to the right.
+        Places all the module_graphic objects in a diagonal going down to the right.
         """
         counter = 0
         for key in self.cpu_graphics_scene.module_graphics_items:
@@ -660,6 +723,7 @@ class GUI(QMainWindow):
     def loadLayoutFromFile(self, file) -> None:
         """
         Loads a layout for the current cpu from the selected file.
+
         If at anypoint this funciton would error, the default layout
         is loaded instead.
         """
@@ -705,8 +769,7 @@ class GUI(QMainWindow):
         visibility: bool,
     ) -> None:
         """
-        Changes the graphical signal to have the positions given
-        as argument.
+        Changes the graphical signal to have the positions given as argument.
         """
         qpoints = []
         # Turn points -> QPointF
@@ -725,8 +788,7 @@ class GUI(QMainWindow):
         graphics_module_y: float,
     ) -> None:
         """
-        Changes the positions of graphical modules to the ones given
-        as argument.
+        Changes the positions of graphical modules to the ones given as argument.
         """
         graphics_module.setX(graphics_module_x)
         graphics_module.setY(graphics_module_y)
@@ -747,8 +809,8 @@ class GUI(QMainWindow):
     def saveStateMenuButtonClick(self) -> None:
         """
         Save state of cpu to file.
-        Erases the previous content of the file before saving
-        the data.
+
+        This erases the previous content of the file before saving the data.
         """
 
         # Not safe to save while running
@@ -763,7 +825,7 @@ class GUI(QMainWindow):
 
         self.cpu.save_state_to_file(path)
 
-    def openBreakpointWindow(self):
+    def openBreakpointWindow(self) -> None:
         """
         Opens window for editing breakpoints.
         """
@@ -790,7 +852,7 @@ class GUI(QMainWindow):
         """
         self.cpu_graphics_scene.setPortNamesVisibility(self.port_vis_action.isChecked())
 
-    def showSignalsMenuButtonClick(self):
+    def showSignalsMenuButtonClick(self) -> None:
         """
         Toggle shoing the signals in the graphics scene.
         """
@@ -798,7 +860,7 @@ class GUI(QMainWindow):
             self.signal_vis_action.isChecked()
         )
 
-    def toggleLayoutLockMenuButtonClick(self):
+    def toggleLayoutLockMenuButtonClick(self) -> None:
         """
         Toggles so the layout can not be edited.
         """
@@ -806,7 +868,9 @@ class GUI(QMainWindow):
 
     def loadLayoutToolBarButtonClick(self) -> None:
         """
-        Loads a given layout from a selected file. If the layout was
+        Loads a given layout from a selected file.
+
+        If the layout was
         unable to load, an error message will pop up informing the user
         and the default layout will be loaded.
         """
@@ -828,7 +892,7 @@ class GUI(QMainWindow):
         else:
             self.messageBox("File loaded successfully.")
 
-    def errorBox(self, message="Something went wrong."):
+    def errorBox(self, message="Something went wrong.") -> None:
         """
         Displays a simple box with the given error message.
         """
@@ -838,7 +902,7 @@ class GUI(QMainWindow):
         dlg.setText(message)
         dlg.exec()
 
-    def messageBox(self, message="Something happend."):
+    def messageBox(self, message="Something happend.") -> None:
         """
         Displays a simple box with the given message.
         """
@@ -848,9 +912,9 @@ class GUI(QMainWindow):
         dlg.setText(message)
         dlg.exec()
 
-    def undoToolBarButtonClick(self):
+    def undoToolBarButtonClick(self) -> None:
         """
-        Undos one processor cycle
+        Undos as many processor cycles as the number entered in the box.
         """
         try:
             steps = self.jump_value_box.value()
@@ -859,7 +923,18 @@ class GUI(QMainWindow):
         except (ValueError, IndexError):
             self.errorBox("Unable to undo the cycle.")
 
-    def addModuleGraphicsItem(self, graphics_item: ModuleGraphicsItem):
+    def undoAsmToolBarButtonClick(self) -> None:
+        """
+        Undos as many processor cycles as the number entered in the box.
+        """
+        try:
+            steps = self.asm_jump_value_box.value()
+            self.cpu.undo_asm_instruction(steps)
+            self.updateCpuListeners()
+        except (ValueError, IndexError):
+            self.errorBox("Unable to undo the cycle.")
+
+    def addModuleGraphicsItem(self, graphics_item: ModuleGraphicsItem) -> None:
         """
         Adds an item to the graphics scene.
         """
diff --git a/src/simudator/gui/module_graphics_item/memory_graphic.py b/src/simudator/gui/module_graphics_item/memory_graphic.py
index f888b0b77a26345317e5908ad7390a7a17cae1ac..208d844c22503312509224ff48892e4fe571629f 100644
--- a/src/simudator/gui/module_graphics_item/memory_graphic.py
+++ b/src/simudator/gui/module_graphics_item/memory_graphic.py
@@ -121,8 +121,7 @@ class MemoryGraphicsItem(ModuleGraphicsItem):
 
     def showMemoryContents(self) -> None:
         """
-        Create and show a MemoryWindow that displays the contents
-        of the memory module associated with this graphics item.
+        Create and show a MemoryWindow that displays the contents of the module.
         """
         self.memory_window = MemoryWindow(self.module)
         self.memory_window.show()
diff --git a/src/simudator/gui/pipeline.py b/src/simudator/gui/pipeline.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c400c06f93411d368b117796136d577687c94f0
--- /dev/null
+++ b/src/simudator/gui/pipeline.py
@@ -0,0 +1,68 @@
+from qtpy.QtWidgets import QTableWidget, QTableWidgetItem
+from typing import Any
+
+# TODO: Make the table unediatable
+class PipeLine(QTableWidget):
+    """
+    A class showing the current CPU instructions in a seperate window.
+
+    The PipeLine class displays the instruction given by the CPU. It has no
+    knowledge about the CPU itself, it only displays what is has been told to display.
+    """
+
+    def __init__(self):
+        super().__init__()
+        # Values below are temporary test values
+        """
+        self.setRowCount(5)
+        self.setColumnCount(5)
+        self.instructions = ["Add", "Sub", "Mult", "Fetch", "Nop"]
+        self.set_item(0, 0, self.instructions[0])
+        self.set_item(1, 1, self.instructions[1])
+        self.set_item(2, 2, self.instructions[2])
+        self.set_item(3, 3, self.instructions[3])
+        """
+
+
+    def set_instruction(self, instructions: list[str]) -> None:
+        """Give the pipeline the current CPU instructions."""
+        self.instructions = instructions
+
+    def set_height(self, height: int) -> None:
+        """Sets the height of the pipeline."""
+        self.setColumnCount(height)
+
+    def set_width(self, width: int) -> None:
+        """Sets the width of the pipeline."""
+        self.setRowCount(width)
+
+    def set_row_labels(self, labels: list[str]) -> None:
+        """
+        Sets the lable for each row. Does not gurantee that number of labels match rows.
+
+        Depending on the CPU architecture the labels for each row
+        can change format. In a pipelined CPU we want to assign a clock cycle
+        to each instruction. In an ARM cpu we want the current
+        CPU clock cycle for the first instruciton, and something else for the 
+        micro instrucitons.
+        """
+        raise NotImplemented
+
+    def set_col_labels(self, labels: list[str]) -> None:
+        """
+        Sets the lable for each col. Does not gurantee that number of labels match cols.
+
+        Depending on the CPU architecture the labels for each col
+        can change format. In a pipelined CPU there is no reason to differentiate
+        the different instrucitons, while in an ARM architecture there is.
+        """
+        raise NotImplemented
+
+    def set_item(self, row: int, col: int, text: str) -> None:
+        """Sets the text at position col row to the given text."""
+        item = QTableWidgetItem(text)
+
+        self.setItem(row, col, item)
+
+
+
diff --git a/src/simudator/gui/run_continuously_thread.py b/src/simudator/gui/run_continuously_thread.py
index a46a4ebd2c25c1f472caf226dc2c55af398455a0..72d0fdcbb58e3352901f21c5fca428a17200f2d4 100644
--- a/src/simudator/gui/run_continuously_thread.py
+++ b/src/simudator/gui/run_continuously_thread.py
@@ -8,35 +8,54 @@ class RunThread(QRunnable):
     a seperate thread. This allows the user to interact with the GUI while the 
     simulation is running.
 
-    After each cpu tick, this thread will emit to its given QT signal so that
+    After each CPU tick, this thread will emit to its given QT signal so that
     the GUI can update itself and possibly inform the user of when the execution 
     has halted.
     """
 
-    def __init__(self, cpu, signal, delay: float, run_continuously=True, steps=0):
+    def __init__(self, cpu, signal, delay: float, run_continuously=True, 
+                 step_asm=False, steps=0):
         super().__init__()
         self.cpu = cpu
         self.signal = signal
         self.run_continuously = run_continuously
         self.steps = steps
         self.delay = delay
+        self.step_asm = step_asm
 
     def run(self):
-        if self.run_continuously:
-            self.cpu.unstop()
-            while not self.cpu.is_stopped:
-                self.cpu.do_tick()
-                self.signal.emit(1)
-                time.sleep(self.delay)
+        if self.step_asm:
 
-        else:
-            for _ in range(self.steps):
+            while self.steps > 0:
                 self.cpu.do_tick()
+
+                # We only care about asm instructions
+                if self.cpu.is_new_instruction():
+                    self.steps -= 1
+
                 self.signal.emit(1)
                 time.sleep(self.delay)
 
                 if self.cpu.is_stopped:
                     break
 
+        else:
+            if self.run_continuously:
+                self.cpu.unstop()
+                while not self.cpu.is_stopped:
+                    self.cpu.do_tick()
+                    self.signal.emit(1)
+                    time.sleep(self.delay)
+
+            else:
+                for _ in range(self.steps):
+                    self.cpu.do_tick()
+                    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)
diff --git a/src/simudator/processor/mia/mia.py b/src/simudator/processor/mia/mia.py
index 913b2dd770255e4b10246823dead9125d5345a85..81519b1a9981a1729413ef9a477b5a1a70883965 100644
--- a/src/simudator/processor/mia/mia.py
+++ b/src/simudator/processor/mia/mia.py
@@ -280,8 +280,40 @@ class MIA_CPU(Processor):
 
         self.micro_memory = uM
 
+
         self.lambdas = {}
 
+
+    def is_new_instruction(self) -> bool:
+        return self.get_module("uPC").value == 0
+
+    def get_current_instruction(self) -> str:
+        """
+        Return a string containing the label for the current instruction.
+
+        If the label doesnt exist, the string is empty.
+        """
+        ir = self.get_module("IR")
+        op_code = ir.op
+        return self.get_module("K1").get_label(int(op_code))
+
+    def run_asm_instruction(self, num_instructions = 1) -> None:
+        """
+        Runs 'num_instructions' assembler instructions on Mia.
+
+        Default argument is one, but it is possible to specify any number of instructions.
+        """
+        while True:
+
+            if num_instructions <= 0:
+                return
+
+            if self.is_new_instruction():
+                num_instructions -= 1
+
+            self.do_tick()
+
+
     def should_halt(self) -> bool:
         micro_memory_state = self.micro_memory.get_state()
         return micro_memory_state["halt"]
diff --git a/src/simudator/processor/mia/modules/mia_memory.py b/src/simudator/processor/mia/modules/mia_memory.py
index 4721a44569fc1a0f969fe87dca81dd022ae1c8be..9aab5263db44b74c37df12640876bf42481b22f3 100644
--- a/src/simudator/processor/mia/modules/mia_memory.py
+++ b/src/simudator/processor/mia/modules/mia_memory.py
@@ -37,6 +37,9 @@ class MiaMemory(MiaBusConnector, Memory):
         )
         self.bus_control_s.add_destination(self)
 
+        # TODO: only one of these are needed
+        self.label_adress_mapping = {}
+
     def update_register(self) -> None:
         """
         Updates the value of the current adress.
@@ -78,12 +81,29 @@ class MiaMemory(MiaBusConnector, Memory):
         self.reset()
         lines = state_string.split("\n")
         for line in lines:
+
             if line:  # last line is empty from split with \n
-                line_data = line.split(": ")
-                adress = int(line_data[0], 16)
+                line_data = line.split()
                 value = int(line_data[1], 16)
+
+                # Last character of the adress is a semicolon
+                adress = int(line_data[0][:-1], 16)
+
                 self.memory[adress] = value
 
+                # There is an asm instruction label
+                if len(line_data) == 3:
+                    instr = line_data[2]
+                    self.label_adress_mapping[adress] = instr
+
+    def get_label(self, adress: int) -> str:
+        """Return the label at the given memory address if it exists, else an empty string"""
+
+        if adress in self.label_adress_mapping.keys():
+            return self.label_adress_mapping[adress]
+
+        return ""
+
     def get_input_signals(self) -> list[Signal]:
         return [
             self.bus_control_s,
diff --git a/src/simudator/processor/mia/modules/pc.py b/src/simudator/processor/mia/modules/pc.py
index 8bb3f7da68eea9f4faa02f4c0055ef5a76b94c94..4fe148bf6555c4969938fc40c73f6d2bac2e0d0a 100644
--- a/src/simudator/processor/mia/modules/pc.py
+++ b/src/simudator/processor/mia/modules/pc.py
@@ -55,10 +55,10 @@ class PC(Module, MiaBusConnector):
             self.bus_output_s.update_value(None)
 
     def update_register(self) -> None:
-        """Updates the value of the PC according to the signals sent
-        by the micro memory. If the program counter recives
-        'True' from both signals it should do nothing and wait for the
-        next cycle.
+        """Updates the value of the PC according to the signals sent by the micro memory. 
+
+        If the program counter recives 'True' from both signals it
+        should do nothing and wait for the next cycle.
         """
 
         self.increase_by_one = self.p.get_value()
@@ -78,6 +78,7 @@ class PC(Module, MiaBusConnector):
 
     def get_state(self) -> dict[str:Any]:
         """Returns a dict of the program counter state.
+
         These states are changable via set_states.
 
         Returns