diff --git a/mia_uppg3.txt b/mia_uppg3.txt
index d61dbb62df11c36dc704cb7cd0ed5c2711dc54a6..b752d1a8049af126da4c59eb188d6765e8bb78ee 100644
--- a/mia_uppg3.txt
+++ b/mia_uppg3.txt
@@ -387,22 +387,22 @@ uM:
 7f: 0000000
 
 K1:
-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
+00: 0a LOAD
+01: 0b STORE
+02: 0c ADD
+03: 0f SUB
+04: 12 AND
+05: 15 LSR
+06: 1a BRA
+07: 1d BNE
+08: 1f HALT
+09: 20 CMP
+0a: 22 BGE
+0b: 27 BEQ
+0c: 00
+0d: 00 
+0e: 00
+0f: 00
 
 K2:
 00: 03
diff --git a/src/simudator/cli/cli.py b/src/simudator/cli/cli.py
index a375743567c885d6d9f284ab2d6413db0828b4b2..8cece34ab1733200d85c52e342092bc5f697c8fc 100644
--- a/src/simudator/cli/cli.py
+++ b/src/simudator/cli/cli.py
@@ -6,16 +6,16 @@ from os.path import exists, isdir
 from simudator.core.processor import Processor
 
 HELP_TEXT = """Here is a list of possible commands:
-CLI control: 
+CLI control:
    - h, help : Shows this message.
 
    - q, quit : Closes the program. Nothing will be saved.
 
-Simulation control: 
+Simulation control:
    - n [x], next [x]: Simulates x ticks.
      If no x is given, simulates one tick.
 
-   - rc, run_continuously: 
+   - rc, run_continuously:
      Continuously simulate ticks until a HALT is signalled
      or a breakpoint is reached.
 
@@ -30,72 +30,78 @@ State information:
    - p, print: Prints all states of all modules.
 
    - pl, printlist [add/remove] [module name] ...:
-     Add or remove the given modules to a list of modules to print. If no 
+     Add or remove the given modules to a list of modules to print. If no
      arguments are given, i.e. "pl" or "printlist" on their own, all the modules 
      in the list will be printed.
 
-   - pp, pretty print: Prints relevant processor state information in a 
+   - pp, pretty print: Prints relevant processor state information in a
      readable and compact format.
 
-   - ppv, pretty print verbose: Prints all processor state information in a 
+   - ppv, pretty print verbose: Prints all processor state information in a
      readable and compact format.
 
-Breakpoints: 
+Breakpoints:
    - p br, print breaks: Prints all breakpoints.
 
-   - p br lam, print break lambdas: 
-     Prints all available lambdas of this processor to use for lambda 
-     breakpoints. 
+   - p br lam, print break lambdas:
+     Prints all available lambdas of this processor to use for lambda
+     breakpoints.
 
    - br state, break state [module name] [state name] [value]:
-     Add a breakpoint for the module with the given name. The breakpoint brakes 
+     Add a breakpoint for the module with the given name. The breakpoint brakes
      when the specified state of the module has the specified value.
 
-   - br mem, break memory [module name] [adress] [value]:
-     Add a breakpoint for a memory module with the given name. The breakpoint 
-     breaks when the specified adress of the memory has the specified value.
+   - br mem, break memory [module name] [address] [value]:
+     Add a breakpoint for a memory module with the given name. The breakpoint
+     breaks when the specified address of the memory has the specified value.
 
    - br lam, break lambda [lambda_name] [keyword argument] ...:
-     Add a breakpoint that uses the referenced lambda to evaluate when to 
-     break. Any module names in the keyword arguments will be substituted with 
+     Add a breakpoint that uses the referenced lambda to evaluate when to
+     break. Any module names in the keyword arguments will be substituted with
      the actual module. Strings must be enclosed with quotation marks.
 
    - rm br [id], remove break [id]:
      Remove the breakpoint with the given ID.
 
-File I/O: 
+File I/O:
    - l, load [path]:
      Loads a processors state from a given file path.
 
    - sf, save to file [path]:
-     Saves the processor state to the specified file. 
+     Saves the processor state to the specified file.
 """
 
 
 class CLI:
     """
     Terminal based program for controlling a processor.
+
     Mostly used for testing and debugging.
+
+    Parameters
+    ----------
+    processor : Processor
     """
 
     def __init__(self, processor: Processor):
-        self.running = True
-        self.processor = processor
-        self.print_list = []
+        self._running = True
+        self._processor = processor
+        self._print_list = []
 
     def run(self) -> None:
-        """
-        Runs the CLI.
-        Will put the user in an input loop where they can send commands to the program
+        """Run the CLI.
+
+        Put the user in an input loop where they can send commands to the
+        program.
         """
 
         print("Welcome to simuDAtor!")
 
-        while self.running:
+        while self._running:
             # Get user commands here
             user_input = input("> ")
 
-            # Note: Keep the order of the cases consistent with the help text 
+            # Note: Keep the order of the cases consistent with the help text
             # for convenience
             match user_input.split():
                 # CLI control -------------------------------------------------
@@ -106,7 +112,7 @@ class CLI:
                 case ["q"] | ["quit"]:
                     # Ends the loop
                     print("Goodbye")
-                    self.running = False
+                    self._running = False
 
                 # Simulation control ------------------------------------------
                 case ["n"] | ["next"]:
@@ -114,7 +120,7 @@ class CLI:
                     # this could take time for larger simulations,
                     # could be good to add loading icon and stop user input
 
-                    self.processor.do_tick()
+                    self._processor.do_tick()
 
                 case ["n", _] | ["next", _]:
                     # runs a given number of ticks
@@ -123,32 +129,32 @@ class CLI:
 
                     try:
                         for _ in range(int(user_input.split()[1])):
-                            self.processor.do_tick()
-                            if self.processor.is_stopped:
+                            self._processor.do_tick()
+                            if self._processor.is_stopped:
                                 break
-                        if self.processor.breakpoint_reached:
-                            bp = self.processor.last_breakpoint
+                        if self._processor.breakpoint_reached:
+                            bp = self._processor.last_breakpoint
                             print(f"Reached breakpoint: {bp}")
-                        if self.processor.should_halt():
+                        if self._processor.should_halt():
                             print("The processor halted")
                     except ValueError:
                         print("Invalid value")
 
                 case ["rc"] | ["run_continuously"]:
-                    self.processor.run_continuously()
-                    if self.processor.breakpoint_reached:
-                        bp = self.processor.last_breakpoint
+                    self._processor.run_continuously()
+                    if self._processor.breakpoint_reached:
+                        bp = self._processor.last_breakpoint
                         print(f"Reached breakpoint: {bp}")
 
-                    if self.processor.should_halt():
+                    if self._processor.should_halt():
                         print("The processor halted")
 
                 case ["u"] | ["undo"]:
                     # undo one clock cycles
 
-                    current_cycle = self.processor.get_clock()
+                    current_cycle = self._processor.get_clock()
                     try:
-                        self.processor.load_cycle(max(current_cycle - 1, 0))
+                        self._processor.load_cycle(max(current_cycle - 1, 0))
                     except IndexError:
                         print("Index out of range")
 
@@ -162,46 +168,46 @@ class CLI:
                         print("Invalid value")
                         continue
 
-                    current_cycle = self.processor.get_clock()
+                    current_cycle = self._processor.get_clock()
                     try:
-                        self.processor.load_cycle(max(current_cycle - number, 0))
+                        self._processor.load_cycle(max(current_cycle - number, 0))
                     except IndexError:
                         print("Index out of range")
 
                 case ["r"] | ["resets"]:
                     # self.processor.load_cycle(0)
-                    self.processor.reset()
+                    self._processor.reset()
 
                 # State information -------------------------------------------
                 case ["c"] | ["clock"]:
                     # shows current clockcycle
-                    print("Clock is at: ", str(self.processor.get_clock()))
+                    print("Clock is at: ", str(self._processor.get_clock()))
 
                 case ["p"] | ["print"]:
                     print("\n")
                     # prints all module states, is most prbably hard to read
-                    for module in self.processor.get_modules():
+                    for module in self._processor.get_modules():
                         module.print_module()
                         print("\n")
 
                 case ["pl", *_] | ["printlist", *_]:
-                    self.print_list_command(user_input.split())
+                    self._print_list_command(user_input.split())
 
                 case ["pp"] | ["pretty print"]:
                     # pretty print the modules of the processor
-                    self.processor.pretty_print()
+                    self._processor.pretty_print()
 
                 case ["ppv"] | ["pretty print verbose"]:
                     # pretty print the modules of the processor
                     # with all available information
-                    self.processor.pretty_print_verbose()
+                    self._processor.pretty_print_verbose()
 
                 # Breakpoints -------------------------------------------------
                 case ["p", "br"] | ["print", "breaks"]:
-                    self.processor.print_breakpoints()
+                    self._processor.print_breakpoints()
 
                 case ["p", "br", "lam"] | ["print", "break", "lambdas"]:
-                    lambdas = self.processor.get_breakpoint_lambdas()
+                    lambdas = self._processor.get_breakpoint_lambdas()
                     if not lambdas:
                         print("There are no lambdas for this processor.")
                     else:
@@ -212,7 +218,7 @@ class CLI:
                     state_name = user_input.split()[3]
                     val = ast.literal_eval(user_input.split()[4])
                     try:
-                        self.processor.add_state_breakpoint(
+                        self._processor.add_state_breakpoint(
                             module_name, state_name, val
                         )
                     except ValueError as e:
@@ -221,9 +227,11 @@ class CLI:
                 case ["br", "mem", _, _, _] | ["break", "memory", _, _, _]:
                     module_name = user_input.split()[2]
                     try:
-                        adress = ast.literal_eval(user_input.split()[3])
+                        address = ast.literal_eval(user_input.split()[3])
                         value = ast.literal_eval(user_input.split()[4])
-                        self.processor.add_memory_breakpoint(module_name, adress, value)
+                        self._processor.add_memory_breakpoint(
+                            module_name, address, value
+                        )
                     except ValueError as e:
                         print(e)
 
@@ -235,14 +243,14 @@ class CLI:
                         key, value = kwarg.split('=')
                         kwargs[key] = ast.literal_eval(value)
                     try:
-                        self.processor.add_lambda_breakpoint(lambda_name, **kwargs)
+                        self._processor.add_lambda_breakpoint(lambda_name, **kwargs)
                     except ValueError as e:
                         print(e)
 
                 case ["rm", "br", _] | ["remove", "break", _]:
                     try:
                         bp_id = int(user_input.split()[2])
-                        if not self.processor.remove_breakpoint(bp_id):
+                        if not self._processor.remove_breakpoint(bp_id):
                             print(f"No breakpoint with ID {bp_id}")
                     except ValueError:
                         print("Breakpoint ID must be an integer")
@@ -251,36 +259,38 @@ class CLI:
                 case ["l", _] | ["load", _]:
                     # load processor state from file
                     try:
-                        self.processor.reset()
-                        self.processor.load_state_from_file(user_input.split()[1])
+                        self._processor.reset()
+                        self._processor.load_state_from_file(user_input.split()[1])
                     except FileNotFoundError:
                         print("No file called ", user_input.split()[1], " was found")
 
                 case ["sf"] | ["save to file"]:
                     file_path = "cpu_save_file"
-                    self.processor.save_state_to_file(file_path)
+                    self._processor.save_state_to_file(file_path)
 
                 case ["sf", _] | ["save to file", _]:
                     file_path = user_input.split()[1]
-                    self.check_file_path(file_path)
+                    self._save_to_file(file_path)
 
                 # -------------------------------------------------------------
                 case _:
                     # message for unknown command
                     print("Unknown command. Write \"help\" for assistance.")
 
-    def check_file_path(self, file_path) -> None:
-        """
-        Checks the file path user gave as input. If it is a directory
-        this funciton will simply return and not write anything. If it
-        is a file that already exists it will demand a 'yes' or 'no' from
-        user to decide if it should write over the existing file.
-        If the given file does not exist it will simply create the file.
+    def _save_to_file(self, file_path: str) -> None:
+        """Save the processor state to the given file path.
+
+        No save is made if the file path is a directory. If the file already
+        exists, the user is given the choice to overwrite the file.
+
+        Parameters
+        ----------
+        file_path : str
         """
 
         # Given file does not exist, save_state_to_file will create it
         if not exists(file_path):
-            self.processor.save_state_to_file(file_path)
+            self._processor.save_state_to_file(file_path)
 
         else:
             # We dont touch directories
@@ -299,17 +309,27 @@ class CLI:
                     print("Please give an input of 'yes' or 'no'!")
 
             if overwrite == "yes":
-                self.processor.save_state_to_file(file_path)
-                return
-            else:
-                return
-
-    def print_list_command(self, user_input):
+                self._processor.save_state_to_file(file_path)
+
+    def _print_list_command(self, user_input: list[str]) -> None:
+        """Add/remove modules to internal list or print all modules in the
+        internal list.
+
+        Parameters
+        ----------
+        user_input : list[str]
+            A print list command split by spaces. Should be on the format
+            ``["printlist", "add", MODULE_NAME, ...]`` or
+            ``["printlist", "remove", MODULE_NAME, ...]`` to add or remove
+            modules, where MODULE_NAME is the name of a module as a string,
+            or ``["printlist"]`` to print all added modules.
+            (``"printlist"`` can be substituted with ``"pl"``)
+        """
         # no additional commands so only print
         if len(user_input) == 1:
             print("\n")
-            for name in self.print_list:
-                self.processor.get_module(name).print_module()
+            for name in self._print_list:
+                self._processor.get_module(name).print_module()
                 print("\n")
             return
 
@@ -319,17 +339,19 @@ class CLI:
             for name in names:
                 # check if name exists
                 try:
-                    self.processor.get_module(name)
-                    if name not in self.print_list:
-                        self.print_list.append(name)
+                    self._processor.get_module(name)
+                    if name not in self._print_list:
+                        self._print_list.append(name)
                 except KeyError:
-                    print("No module named", name,)
-
+                    print(
+                        "No module named",
+                        name,
+                    )
 
         elif user_input[1] == "remove":
             for name in names:
-                if name in self.print_list:
-                    self.print_list.remove(name)
+                if name in self._print_list:
+                    self._print_list.remove(name)
                 else:
                     print(name, "not in print list")
         else:
diff --git a/src/simudator/core/breakpoint.py b/src/simudator/core/breakpoint.py
index 85855446cfe5b97cbf7d14b0b27843f1ca75aa59..115d3b460829840050d19ceead5c55dc2b8fd3bc 100644
--- a/src/simudator/core/breakpoint.py
+++ b/src/simudator/core/breakpoint.py
@@ -1,9 +1,34 @@
 class Breakpoint:
+
+    __slots__ = "is_enabled"
+    """
+    Base class for beakpoints, intended to be subclassed.
+
+    Attributes
+    ----------
+    is_enabled : bool
+        Used to check and toggle if a breakpoint is on or off.
+    """
+
     def __init__(self):
         self.is_enabled = True
 
     def is_break(self) -> bool:
+        """Check if the breakpoint has been reached.
+
+        Returns
+        -------
+        bool
+            ``True`` if the breakpoint has been reached, ``False`` otherwise.
+        """
         return False
 
     def set_enabled(self, is_enabled: bool) -> None:
+        """Toggle the breakpoint on or off.
+
+        Parameters
+        ----------
+        is_enabled : bool
+            ``True`` to toggle on, ``False`` to toggle off.
+        """
         self.is_enabled = is_enabled
diff --git a/src/simudator/core/breakpoint_lambda.py b/src/simudator/core/breakpoint_lambda.py
index 64a3e9f581a1d8dc4385e4ee806a23c24217534b..52bff4bb3f88d631197bbc45cfd08f45f977c093 100644
--- a/src/simudator/core/breakpoint_lambda.py
+++ b/src/simudator/core/breakpoint_lambda.py
@@ -4,14 +4,32 @@ from simudator.core.breakpoint import Breakpoint
 
 
 class LambdaBreakpoint(Breakpoint):
+
+    __slots__ = ("_lambda_func", "_kwargs")
+    """
+    A breakpoint that uses a given function to decide whether the breakpoint
+    has been reached or not.
+
+    Parameters
+    ----------
+    lambda_func : Callable
+        The function used to decide if the breakpoint has been reached.
+
+        ``lambda_func(**kwargs) -> bool``
+        Should return ``True`` if the breakpoint has been reached, ``False``
+        otherwise.
+    **kwargs
+        Arguments to pass to `lambda_func`.
+    """
+
     def __init__(self, lambda_func: Callable[..., bool], **kwargs) -> None:
         super().__init__()
-        self.lambda_func = lambda_func
-        self.kwargs = kwargs
+        self._lambda_func = lambda_func
+        self._kwargs = kwargs
 
     def is_break(self):
-        return self.lambda_func(**self.kwargs)
+        return self._lambda_func(**self._kwargs)
 
     def __str__(self) -> str:
-        s = f"Lambda {self.lambda_func.__name__} with kwargs {self.kwargs}"
+        s = f"Lambda {self._lambda_func.__name__} with kwargs {self._kwargs}"
         return s
diff --git a/src/simudator/core/breakpoint_memory.py b/src/simudator/core/breakpoint_memory.py
index c62e65ce67d7e84feb29939b28eb902d0f768f41..8dbd66348eea3a2da753a1c1402bde9f638301e9 100644
--- a/src/simudator/core/breakpoint_memory.py
+++ b/src/simudator/core/breakpoint_memory.py
@@ -5,15 +5,32 @@ from simudator.core.modules import Memory
 
 
 class MemoryBreakpoint(Breakpoint):
-    def __init__(self, memory: Memory, adress: int, value: Any) -> None:
+
+    __slots__ = ("_memory", "_address", "_value")
+
+    """
+    A breakpoint class for memory modules to break when a certain address
+    of the memory has a certain value.
+
+    Parameters
+    ----------
+    memory : Memory
+        Memory module to check the contents of.
+    address : int
+        Address of the memory module to break at.
+    value : Any
+        Value of the address that triggers the breakpoint.
+    """
+
+    def __init__(self, memory: Memory, address: int, value: Any) -> None:
         super().__init__()
-        self.memory = memory
-        self.adress = adress
-        self.value = value
+        self._memory = memory
+        self._address = address
+        self._value = value
 
     def is_break(self):
-        memory_content = self.memory.get_state()["memory"]
-        return memory_content[self.adress] == self.value
+        memory_content = self._memory.get_state()["memory"]
+        return memory_content[self._address] == self._value
 
     def __str__(self) -> str:
-        return f"{self.memory.name} {self.adress}: {self.value}"
+        return f"{self._memory.name} {self._address}: {self._value}"
diff --git a/src/simudator/core/breakpoint_state.py b/src/simudator/core/breakpoint_state.py
index c7fce9723223a80814e6f40508a0c636b2ae5f9c..58b042cbabf727bfb5ec1f523617592c0035595c 100644
--- a/src/simudator/core/breakpoint_state.py
+++ b/src/simudator/core/breakpoint_state.py
@@ -5,14 +5,30 @@ from simudator.core.module import Module
 
 
 class StateBreakpoint(Breakpoint):
+
+    __slots__ = ("_module", "_state", "_value")
+    """
+    A breakpoint class to break when the state variable for a module reaches
+    a specified value.
+
+    Parameters
+    ----------
+    module : Module
+        Module to check the state of.
+    state : str
+        Name of the state variable of the module to check the value of.
+    value : Any
+        Value of the state variable to break at.
+    """
+
     def __init__(self, module: Module, state: str, value: Any) -> None:
         super().__init__()
-        self.module = module
-        self.state = state
-        self.value = value
+        self._module = module
+        self._state = state
+        self._value = value
 
     def is_break(self):
-        return self.module.get_state()[self.state] == self.value
+        return self._module.get_state()[self._state] == self._value
 
     def __str__(self) -> str:
-        return self.module.name + " " + self.state + " == " + str(self.value)
+        return self._module.name + " " + self._state + " == " + str(self._value)
diff --git a/src/simudator/core/module.py b/src/simudator/core/module.py
index 107abfbb0d96e264c5de745c13f8c5f934bcfff4..12f28830dabea48cad56db6a2610c5f33e0e076f 100644
--- a/src/simudator/core/module.py
+++ b/src/simudator/core/module.py
@@ -6,10 +6,30 @@ from simudator.core.signal import Signal
 class Module:
     """
     This class specifies the basic functionality of all module types.
-    The modules are processor componenets in the processor,
+    The modules are processor components in the processor,
     such as ALU, busses, registers and more.
+
+    Parameters
+    ----------
+    signals : dict[str, Signal]
+        Dictionary containing all signals connected to the module. Input
+        signals should have keys beginning with 'in\_' and output signals keys
+        beginning with 'out\_'.
+    name : str
+        Name of the module.
+
+    Attributes
+    ----------
+    name : str
+        Name of the module.
+    signals : dict[str, Signal]
+        The signals connected to this module. The key for a signal can be
+        regarded as the name of a signal 'port' of the module. The keys should
+        be prefixed with 'in\_' for input signals and 'out\_' for output signals.
     """
 
+    __slots__ = ("name", "signals")
+
     def __init__(self, signals: dict[str, Signal], name: str = "") -> None:
         self.name = name
         self.signals = signals
@@ -19,29 +39,38 @@ class Module:
                 signal.add_destination(self)
 
     def update_register(self) -> None:
+        """Simulate module behaviour for saving input into the internal state
+        during a clock tick.
+
+        This method should be used for any module that has any 'internal'
+        registers. Exact behaviour is specified in each module subclass.
         """
-        Simulates module behaviour for saving input into the internal state
-        during a clock tick. Exact behaviour is specifid in each module type.
-        """
-        raise NotImplemented
+        raise NotImplementedError
 
     def output_register(self) -> None:
+        """Simulate module behaviour for outputting data from internal
+        registers, if any, to output signals during a clock tick.
+
+        Exact behaviour is specified in each module subclass.
         """
-        Simulates module behaviour for giving data to output signals
-        during a clock tick. Exact behaviour is specifid in each module type.
-        """
-        raise NotImplemented
+        raise NotImplementedError
 
     def update_logic(self) -> None:
         """
-        Simulates behaviour for sending output using the internal state
-        during a clock tick. Exact behaviour is specifid in each module type.
+        Simulate behaviour for sending output using the internal state
+        during a clock tick. Exact behaviour is specified in each module type.
         """
-        raise NotImplemented
+        raise NotImplementedError
 
     def get_state(self) -> dict:
         """
-        Returns a dict of the module states.
+        Return the state of the module.
+
+        Returns
+        -------
+        dict[str, Any]
+            State of the module represented as a dictionary with one key for
+            each state variable.
         """
         state_dict = dict()
         state_dict["name"] = self.name
@@ -49,7 +78,12 @@ class Module:
 
     def get_gui_state(self) -> dict:
         """
-        Returns a dict of the module states that should be displayed in a GUI.
+        Return the state of the module as should be displayed in a GUI.
+
+        See Also
+        --------
+        get_state :
+            Similar method that includes state variables not related to the GUI.
         """
         state_dict = dict()
         state_dict["name"] = self.name
@@ -57,43 +91,56 @@ class Module:
 
     def set_state(self, state: dict) -> None:
         """
-        Sets the modules state to one given in dict. Dict format will be
-        diffrent for each type of module so use get_state to get correct format.
+        Set the state of the module.
+
+        Parameters
+        ----------
+        state : dict[str, Any]
+            Module state represented as a dictionary.
         """
         self.name = state["name"]
 
     def get_output_signals(self) -> list[Signal]:
-        """
-        Returns the modules output signals. Assumes all output signals are
-        stored with a key beginning in 'out' in the signals dictionary.
+        """Return the output signals of the module.
+
+        Assumes all output signals are stored with a key beginning in 'out\_' in
+        the signals dictionary.
+
+        Returns
+        -------
+        list[Signal]
+            List of all output signals of this module.
         """
         return [signal for key, signal in self.signals.items() if key[0:3] == "out"]
 
     def get_input_signals(self) -> list[Signal]:
-        """
-        Returns the modules input signals. Assumes all input signals are stored
-        with a key beginning in 'in' in the signals dictionary.
+        """Return the input signals of the module.
+
+        Assumes all input signals are stored with a key beginning in 'in\_' in
+        the signals dictionary.
+
+        Returns
+        -------
+        list[Signal]
+            List of all input signals of this module.
         """
         return [signal for key, signal in self.signals.items() if key[0:2] == "in"]
 
     def reset(self) -> None:
-        """
-        Resets the module to its default state.
-        """
-        raise NotImplemented
+        """Reset the module to its default state."""
+        raise NotImplementedError
 
-    def load_from_str(self, state_string):
-        """
-        Sets the modules state according to a string.
+    def load_from_str(self, state_string) -> None:
+        """Set the module state according to a string.
 
-        Each module class will parse and set its own state.
+        Each module subclass decides the format of the string.
         """
-        raise NotImplemented
+        raise NotImplementedError
 
     def get_longest_line_len(self, ignore_keys=None) -> int:
-        """
-        Helper function for pretty_print that returns the length of
-        the longest line to print for a module.
+        """Return the length of the longest line when printing the module.
+
+        Helper function for pretty_print.
         """
 
         if ignore_keys == None:
@@ -111,9 +158,7 @@ class Module:
         return longest_line_len
 
     def print_module(self) -> None:
-        """
-        Prints the module directly to terminal
-        """
+        """Print the module."""
         print(self.name)
 
     def _helper_save_state_to_file(self, file_path: str, content: str) -> bool:
@@ -138,12 +183,19 @@ class Module:
         return True
 
     def save_state_to_file(self, file_path: str) -> bool:
-        """
-        Tries to save the module state to a given file.
+        """Save the modules state to file.
 
-        Returns true on success and false otherwise.
+        Parameters
+        ----------
+        file_path : str
+            Path to the file to save to.
+
+        Returns
+        -------
+        bool
+            True if saving succeeded, False otherwise.
         """
-        raise NotImplemented
+        raise NotImplementedError
 
     def __str__(self) -> str:
         return self.name
diff --git a/src/simudator/core/modules/demux.py b/src/simudator/core/modules/demux.py
index fa77b582b8a4925d8c359cbef61ec3a9d7a5f614..2aeb731c2e414cd161b71ec38ea2743d0be6ffbf 100644
--- a/src/simudator/core/modules/demux.py
+++ b/src/simudator/core/modules/demux.py
@@ -6,11 +6,32 @@ from simudator.core.signal import Signal
 
 class Demux(Module):
     """
-    A general demux that allows an arbitrary amount of outputs to map
-    to a single input. The output side is controlled by the control
-    signal 'from_demux_s'.
+    A general demultiplexer that allows an arbitrary amount of outputs to map
+    to a single input.
+
+    Assumes the value sent from input to outputs is an integer.
+
+    Parameters
+    ----------
+    control : Signal
+        Control signal of which the value is used to index which
+        output signal to output to.
+    bit_length : int
+        Maximum number of bits for the value outputted by the demux. All extra
+        bits of the input value are discarded.
+    input : Signal
+        Input signal of which the value is forwarded to the currently
+        selected output signal.
+    outputs : list[Signal]
+        List of output signals to demultiplex the input signal value to.
+    name : str
+        Name of the demultiplexer module.
+    value : Any
+        Initial value to output to the currently selected output signal.
     """
 
+    __slots__ = ("_bit_length", "_value")
+
     def __init__(
         self,
         control: Signal,
@@ -31,57 +52,51 @@ class Demux(Module):
 
         super().__init__(signals, name)
 
-        # mask and bit_length
-        self.bit_length = bit_length
-        self.mask = 2**self.bit_length - 1
+        self._bit_length = bit_length
 
         # Value to be read/written
-        self.value = value
+        self._value = value
 
     def update_register(self) -> None:
         """
-        Read the input value and update the value of the demux.
+        Read the input signal value and update the value of the demux.
         """
+
         input_value = self.signals["in_input"].get_value()
-        self.value = input_value & self.mask
+        mask = 2**self._bit_length - 1
+        self._value = input_value & mask
 
-    def output_register(self):
-        """
-        Read which signal to write to from the control signal
-        'from_demux_s' and forward the input to that output signal.
+    def output_register(self) -> None:
+        """Read which signal to write to from the control signal and forward
+        the input to that output signal.
         """
         output_index = self.signals["in_control"].get_value()
         output_signal_key = f"out_output_{output_index}"
-        self.signals[output_signal_key].update_value(self.value)
+        self.signals[output_signal_key].update_value(self._value)
 
-    def update_logic(self):
-        """
-        Do nothing.
+    def update_logic(self) -> None:
+        """Do nothing.
 
-        The demux has no logic
+        The demux has no logic.
         """
         pass
 
     def get_state(self) -> dict[str, Any]:
-        """
-        Returns a dict of the demux state.
-        """
         state = super().get_state()
-        state["value"] = self.value
-        state["bit_length"] = self.bit_length
-        state["mask"] = self.mask
+        state["value"] = self._value
+        state["bit_length"] = self._bit_length
 
         return state
 
-    def save_state_to_file(self, file_path: str) -> bool:
-        content = self.name + ":\nvalue: " + str(self.value) + "\n\n"
-        return super()._helper_save_state_to_file(file_path, content)
+    def set_state(self, state: dict[str, Any]) -> None:
+        """Set the name and value of the demux.
 
-    def set_state(self, state: dict) -> None:
-        """
-        Sets the name and value of the demux.
+        Parameters
+        ----------
+        state : dict[str, Any]
+            The state of the demux to load. Should contain the keys "value" and
+            "bit_length", both with values of type ``int``.
         """
         super().set_state(state)
-        self.value = state["value"]
-        self.bit_length = state["bit_length"]
-        self.mask = state["mask"]
+        self._value = state["value"]
+        self._bit_length = state["bit_length"]
diff --git a/src/simudator/core/modules/memory.py b/src/simudator/core/modules/memory.py
index d7fc4dce7a659003abfbaf34cfedce21c87357d1..4aa611c4aca4ac542b6a67c3cba48b4fd1e551d5 100644
--- a/src/simudator/core/modules/memory.py
+++ b/src/simudator/core/modules/memory.py
@@ -1,5 +1,7 @@
 from __future__ import annotations
 
+from typing import Any
+
 from simudator.core.module import Module
 from simudator.core.signal import Signal
 
@@ -7,43 +9,66 @@ from simudator.core.signal import Signal
 class Memory(Module):
     """
     A general size memory module.
+
+    Parameters
+    ----------
+    input : Signal
+        Signal of which the value may be written to the current address.
+    output : Signal
+        Signal to which the content of the current address is written.
+    control : Signal
+        Signal used to enable or disable write to the current address. Assumed
+        to output ``bool``.
+    address : Signal
+        Signal used to address the memory. Assumed to output ``int``.
+    size : int
+        Size of the address space of the memory.
+    name : str
+        Name of the module.
+    """
+
+    __slots__ = (
+        "_memory",
+        "_current_address",
+        "_is_write",
+    )
+    """
+    Constants used to textually pad the values of the memory when saving to
+    file.
     """
+    MEMORY_VALUE_PADDING = 2
+    MEMORY_ADDRESS_PADDING = 2
 
     def __init__(
         self,
-        input_signal: Signal,
-        output_signal: Signal,
-        control_signal: Signal,
-        address_signal: Signal,
+        input: Signal,
+        output: Signal,
+        control: Signal,
+        address: Signal,
         size: int,
-        value_padding: int = 2,
-        address_padding: int = 2,
         name="Memory",
     ) -> None:
 
         # signals
         signals = {
-            "in_input": input_signal,
-            "in_control": control_signal,
-            "in_address": address_signal,
-            "out_content": output_signal,
+            "in_input": input,
+            "in_control": control,
+            "in_address": address,
+            "out_content": output,
         }
 
         # Init super class
         super().__init__(signals, name)
 
         # Internal state
-        self.memory = [0 for _ in range(size)]
-        self.current_address = 0
-        self.is_write = False
-
-        # Values used to format the strings when saving state to file
-        self.address_padding = address_padding
-        self.value_padding = value_padding
+        self._memory = [0 for _ in range(size)]
+        self._current_address = 0
+        self._is_write = False
 
     def update_register(self):
-        if self.is_write:
-            self.memory[self.current_address] = self.signals["in_input"].get_value()
+        if self._is_write:
+            value = self.signals["in_input"].get_value()
+            self._memory[self._current_address] = value
 
     def output_register(self) -> None:
         pass
@@ -55,44 +80,44 @@ class Memory(Module):
         ctrl_sig = self.signals["in_control"]
         out_sig = self.signals["out_content"]
         if adr_sig.get_value() is not None and ctrl_sig.get_value() is not None:
-            self.is_write = ctrl_sig.get_value()
-            self.current_address = adr_sig.get_value()
-            out_sig.update_value(self.memory[self.current_address])
+            self._is_write = ctrl_sig.get_value()
+            self._current_address = adr_sig.get_value()
+            out_sig.update_value(self._memory[self._current_address])
 
     def print_module(self) -> None:
         print("", self.name, "\n -----")
-        for address, value in enumerate(self.memory):
+        for address, value in enumerate(self._memory):
             if value:
                 print("", str(hex(address)), "", str(hex(value)), "\n")
 
-    def get_state(self) -> dict:
+    def get_state(self) -> dict[str, Any]:
         state = super().get_state()
-        state["is_write"] = self.is_write
-        state["current_address"] = self.current_address
-        state["memory"] = self.memory[:]
+        state["is_write"] = self._is_write
+        state["current_address"] = self._current_address
+        state["memory"] = self._memory[:]
         return state
 
-    def get_gui_state(self) -> dict:
+    def get_gui_state(self) -> dict[str, Any]:
         state = super().get_gui_state()
-        state["current_address"] = self.current_address
-        state["memory"] = self.memory[:]
+        state["current_address"] = self._current_address
+        state["memory"] = self._memory[:]
         return state
 
-    def set_state(self, state: dict) -> None:
+    def set_state(self, state: dict[str, Any]) -> None:
         super().set_state(state)
         if "is_write" in state:
-            self.is_write = state["is_write"]
+            self._is_write = state["is_write"]
         if "current_address" in state:
-            self.current_address = state["current_address"]
+            self._current_address = state["current_address"]
         if "memory" in state:
-            self.memory = state["memory"]
+            self._memory = state["memory"]
 
     def reset(self) -> None:
         """
         Reset the memory to 0 for each address.
         """
-        for i in range(len(self.memory)):
-            self.memory[i] = 0
+        for i in range(len(self._memory)):
+            self._memory[i] = 0
 
     def get_longest_line_len(self, ignore_keys=None) -> int:
         """
@@ -105,7 +130,7 @@ class Memory(Module):
 
         longest_memory_line = 0
 
-        for value in self.memory:
+        for value in self._memory:
             value_len = len(str(value))
             if value_len > longest_memory_line:
                 longest_memory_line = value_len
@@ -117,14 +142,16 @@ class Memory(Module):
         Helper function for pretty_print that returns the length of
         the largest address in the memory to print for a module.
         """
-        return len(str(len(self.memory)))
+        return len(str(len(self._memory)))
 
     def save_state_to_file(self, file_path: str) -> bool:
         content = ""
         content = self.name + ":\n"
-        for index, value in enumerate(self.memory):
-            content += str(hex(index)[2:].rjust(self.address_padding, "0")) + ": "
-            content += str(hex(value)[2:].rjust(self.value_padding, "0"))
+        for index, value in enumerate(self._memory):
+            content += (
+                str(hex(index)[2:].rjust(self.MEMORY_ADDRESS_PADDING, "0")) + ": "
+            )
+            content += str(hex(value)[2:].rjust(self.MEMORY_VALUE_PADDING, "0"))
             content += "\n"
         content += "\n"
         return super()._helper_save_state_to_file(file_path, content)
diff --git a/src/simudator/core/modules/mux.py b/src/simudator/core/modules/mux.py
index 70a9ff77b4d71488851957ef66fe0dff0f88e594..cf8e06a9f48366c4dc8a269661dd0825a18e5d5d 100644
--- a/src/simudator/core/modules/mux.py
+++ b/src/simudator/core/modules/mux.py
@@ -6,14 +6,33 @@ from simudator.core.signal import Signal
 
 class Mux(Module):
     """
-    A general mux that allows an arbitrary amount of input to map
-    to a single output. The input side is controlled by the control
-    signal 'to_mux_s'.
+    A general mux that allows an arbitrary amount of input to map to a single
+    output.
+
+    Parameters
+    ----------
+    control : Signal
+        Control signal of which the value is used to index which
+        input signal to read from.
+    bit_length : int
+        Maximum number of bits for the value outputted by the mux. All extra
+        bits of the input value are discarded.
+    inputs : list[Signal]
+        List of input signals to select from to output onto the output signal.
+    output : Signal
+        Signal onto which the value of the currently selected input is
+        outputted.
+    name : str
+        Name of the multiplexer module.
+    value : Any
+        Initial value to output to the output signal.
     """
 
+    __slots__ = ("_bit_length", "_value")
+
     def __init__(
         self,
-        to_mux: Signal,
+        control: Signal,
         bit_length: int,
         output: Signal,
         inputs: list[Signal] = [],
@@ -23,7 +42,7 @@ class Mux(Module):
 
         # Signals
         signals = {
-            "in_control": to_mux,
+            "in_control": control,
             "out": output,
         }
         for i, s in enumerate(inputs):
@@ -33,68 +52,65 @@ class Mux(Module):
         super().__init__(signals, name)
 
         # mask and bit_length
-        self.bit_length = bit_length
-        self.mask = 2**self.bit_length - 1
+        self._bit_length = bit_length
 
         # Value to be read/written
-        self.value = value
+        self._value = value
 
     def update_register(self) -> None:
-        """
-        Read which signal to read from the control signal
-        'to_mux_s' and forward that signal to the output.
+        """Read which signal to read from the control signal and forward that
+        signal to the output.
         """
         input_index = self.signals["in_control"].get_value()
         input_signal_key = f"in_input_{input_index}"
         input_value = self.signals[input_signal_key].get_value()
-        self.value = input_value & self.mask
+        mask = 2**self._bit_length - 1
+        self._value = input_value & mask
 
     def output_register(self):
+        """Output the value of the currently selected input signal to the
+        output signal.
         """
-        Output the value of the mux to its output.
-        """
-        self.signals["out"].update_value(self.value)
+        self.signals["out"].update_value(self._value)
 
     def update_logic(self):
-        """
-        Do nothing.
+        """Do nothing.
 
         The mux has no logic.
         """
         pass
 
     def get_state(self) -> dict[str, Any]:
-        """
-        Returns a dict of the mux state.
-        """
         state = super().get_state()
-        state["value"] = self.value
-        state["bit_length"] = self.bit_length
-        state["mask"] = self.mask
+        state["value"] = self._value
+        state["bit_length"] = self._bit_length
 
         return state
 
     def save_state_to_file(self, file_path: str) -> bool:
-        content = self.name + ":\nvalue: " + str(self.value) + "\n\n"
+        content = self.name + ":\nvalue: " + str(self._value) + "\n\n"
         return super()._helper_save_state_to_file(file_path, content)
 
-    def set_state(self, state: dict) -> None:
-        """
-        Sets the name and value of the mux.
+    def set_state(self, state: dict[str, Any]) -> None:
+        """Set the name, value and bit length of the demux.
+
+        Parameters
+        ----------
+        state : dict[str, Any]
+            The state of the demux to load. Should contain the keys "name",
+            "value" and "bit_length" with values of type ``str``, ``int`` and
+            ``int`` respectively.
         """
         super().set_state(state)
-        self.value = state["value"]
-        self.bit_length = state["bit_length"]
-        self.mask = state["mask"]
+        self._value = state["value"]
+        self._bit_length = state["bit_length"]
 
     def print_module(self) -> None:
         print(
             self.name,
             "\n-----",
             "\nvalue: ",
-            self.value,
+            self._value,
             "\nbit length: ",
-            self.bit_length,
-            "\nmask: ",
-            self.mask,
+            self._bit_length,
         )
diff --git a/src/simudator/core/modules/register.py b/src/simudator/core/modules/register.py
index d729b948a18d1a56b7576837f80e8c3e7cd6d562..723638511324f405f79ab56e456635ed597a2e00 100644
--- a/src/simudator/core/modules/register.py
+++ b/src/simudator/core/modules/register.py
@@ -8,9 +8,22 @@ from simudator.core.signal import Signal
 
 class Register(Module):
     """
-    A simple module that can store a value.
+    A simple module that can store and output a value.
+
+    Parameters
+    ----------
+    input : Signal
+        Signal from which the value is stored in the register.
+    output : Signal
+        Signal onto which the value of the register is outputted.
+    value : Any
+        Initial value of the register.
+    name : str
+        Name of the register.
     """
 
+    __slots__ = "_value"
+
     def __init__(
         self,
         input_signal: Signal,
@@ -27,39 +40,33 @@ class Register(Module):
 
         # init the instance
         super().__init__(signals, name)
-        self.value = value
+        self._value = value
 
     def update_register(self) -> None:
-        """
-        Propagate the input signal to the registers internal state.
-        Throw away bits larger than the length of the register.
+        """Update the internal value of the register with the input signal.
+
+        Any extra bits that do not fit the bit length of the register are
+        thrown away.
         """
         input_value = self.signals["in_content"].get_value()
         if input_value is None:
             return
-        self.value = input_value
+        self._value = input_value
 
     def output_register(self) -> None:
-        """
-        Propagate the value of the register to the output signal.
-        It is the response of the destination to know when it should
-        read the output.
-        """
-        self.signals["out_content"].update_value(self.value)
+        """Output the value of the register onto the output signal."""
+        self.signals["out_content"].update_value(self._value)
 
     def update_logic(self):
-        """
+        """Do nothing.
+
         The register has no logic.
         """
         pass
 
     def get_state(self) -> dict[str, Any]:
-        """
-        Returns a dict of the register state.
-        These states are changable via set_states.
-        """
         state = super().get_state()
-        state["value"] = self.value
+        state["value"] = self._value
         return state
 
     def get_gui_state(self) -> dict:
@@ -68,19 +75,25 @@ class Register(Module):
 
     def set_state(self, state: dict[str, Any]) -> None:
         """
-        Sets the register state to one given in dict.
+        Set the state of the register.
+
+        Parameters
+        ----------
+        state : dict[str, Any]
+            The state of the register to load. Should contain the keys "name"
+            and "value" with values of type ``str`` and ``int`` respectively.
         """
         self.name = state["name"]
-        self.value = state["value"]
+        self._value = state["value"]
 
     def reset(self) -> None:
         """
-        Resets the register to 0.
+        Reset the register to 0.
         """
-        self.value = 0
+        self._value = 0
 
     def save_state_to_file(self, file_path: str) -> bool:
-        content = self.name + ":\nvalue:: " + str(self.value) + "\n\n"
+        content = self.name + ":\nvalue:: " + str(self._value) + "\n\n"
         return super()._helper_save_state_to_file(file_path, content)
 
     def print_module(self) -> None:
@@ -89,71 +102,72 @@ class Register(Module):
             self.name,
             "\n -----",
             "\n value: ",
-            self.value,
+            self._value,
         )
 
 
 class IntegerRegister(Register):
     """
-    A simple module that can store an integer value with a given bit-length.
+    A register intended to store integers only.
+
+    Parameters
+    ----------
+    input : Signal
+        Signal from which the value is stored in the register.
+    output : Signal
+        Signal onto which the value of the register is outputted.
+    bit_length : int
+        Maximum number of bits of the input to store in the register. All extra
+        bits of the input value are discarded.
+    value : Any
+        Initial value of the register.
+    name : str
+        Name of the register.
     """
 
+    __slots__ = "_bit_length"
+
     def __init__(
         self,
-        input_signal: Signal,
-        output_signal: Signal,
+        input: Signal,
+        output: Signal,
         bit_length: int,
         value: int = 0,
         name: str | None = None,
     ) -> None:
 
-        # set the registers name
+        # set the name
         if name is None:
             name = f"{bit_length}-bit register"
 
-        super().__init__(input_signal, output_signal, value=value, name=name)
+        super().__init__(input, output, value=value, name=name)
 
         # set the bit length of the register
-        self.bit_length = bit_length
-
-        # set the registers mask. An 8 bit register should
-        # have the mask 1111 1111, aka one '1' for every bit
-        self.mask = 2**bit_length - 1
+        self._bit_length = bit_length
 
     def update_register(self) -> None:
-        """
-        Propagate the input signal to the registers internal state.
-        Throw away bits larger than the length of the register.
-        """
         super().update_register()
-        self.value = self.value & self.mask
+        mask = 2**self._bit_length - 1
+        self._value = self._value & mask
 
     def get_state(self) -> dict[str, Any]:
-        """
-        Returns a dict of the register state.
-        These states are changable via set_states.
-        """
         state = super().get_state()
-        state["bit_length"] = self.bit_length
+        state["bit_length"] = self._bit_length
         return state
 
     def set_state(self, state: dict[str, Any]) -> None:
-        """
-        Sets the register state to one given in dict.
-        """
         super().set_state(state)
         if "bit_length" in state:
-            self.bit_length = state["bit_length"]
-            self.mask = 2**self.bit_length - 1
+            self._bit_length = state["bit_length"]
 
     def save_state_to_file(self, file_path: str) -> bool:
-        content = self.name + ":\nvalue: " + hex(self.value)[2:] + "\n\n"
+        content = self.name + ":\nvalue: " + hex(self._value)[2:] + "\n\n"
         return super()._helper_save_state_to_file(file_path, content)
 
-    def load_from_str(self, state_string):
+    def load_from_str(self, state_string) -> None:
         string_pair = state_string.split(": ")
         # TODO: Maybe check if it starts with value: ?
-        self.value = int(string_pair[1], 16)
+        self._value = int(string_pair[1], 16)
 
 
 class Flag(IntegerRegister):
@@ -173,8 +187,8 @@ class Flag(IntegerRegister):
 
         # set the flags name
         super().__init__(
-            input_signal=input_signal,
-            output_signal=output_signal,
+            input=input_signal,
+            output=output_signal,
             bit_length=bit_length,
             value=value,
             name=name,
@@ -188,15 +202,16 @@ class Flag(IntegerRegister):
         to activate (ex: loop counter reaches zero -> set L flag to 1)
         """
         input_value = self.signals["in_content"].get_value()
-        self.value = input_value & self.mask
+        mask = 2**self._bit_length - 1
+        self._value = input_value & mask
 
     def get_gui_state(self) -> dict:
         state = super().get_gui_state()
-        state["value"] = self.value
+        state["value"] = self._value
         return state
 
     def save_state_to_file(self, file_path: str) -> bool:
-        content = self.name + ":\nvalue: " + str(self.value) + "\n\n"
+        content = self.name + ":\nvalue: " + str(self._value) + "\n\n"
         return super()._helper_save_state_to_file(file_path, content)
 
     def print_module(self) -> None:
@@ -205,9 +220,7 @@ class Flag(IntegerRegister):
             self.name,
             "\n -----",
             "\n value: ",
-            self.value,
+            self._value,
             "\n bit length: ",
-            self.bit_length,
-            "\n mask: ",
-            self.mask,
+            self._bit_length,
         )
diff --git a/src/simudator/core/processor.py b/src/simudator/core/processor.py
index f7ee51b677119a49a3cbb5706531eca24d153904..409879cac7324eb0c649bfb4dcf78d25639ea781 100644
--- a/src/simudator/core/processor.py
+++ b/src/simudator/core/processor.py
@@ -17,30 +17,72 @@ from .signal import Signal
 class Processor:
     """
     Main class for controlling the processor.
+
     Uses modules and signals to simulate processor components behaviour.
     """
 
-    def __init__(self):
+    __slots__ = (
+        "modules",
+        "signals",
+        "clock",
+        "update_queue",
+        "module_history",
+        "signal_history",
+        "breakpoint_id_counter",
+        "breakpoints",
+        "breakpoint_reached",
+        "last_breakpoint",
+        "cycles_to_save",
+        "removed_cycles",
+        "max_line_len",
+        "line_separator",
+        "is_stopped",
+        "new_instruction",
+        "current_instructions",
+        "ignore_keys",
+        "lambdas",
+        "assembly_cycles",
+        "line_separator",
+    )
+
+    LINE_SEPARATOR = "-"
+    MAX_LINE_LEN = 170
+    CYCLES_TO_SAVE = 10000
+
+    def __init__(self) -> None:
+        # For simulation
         self.modules: dict[str, Module] = dict()
         self.signals = []
         self.clock = 0
         self.update_queue = []
-        self.module_history: list[dict[str, dict[str, Any]]] = []
-        self.signal_history: list[list] = []  # TODO: Is this needed?
+        self.is_stopped = False
+
+        # Breakpoint handling
         self.breakpoint_id_counter = 1
         self.breakpoints: dict[int, Breakpoint] = {}
         self.breakpoint_reached = False
         self.last_breakpoint = None
-        self.cycles_to_save = 10000
+        self.lambdas: dict[str, Callable[..., bool]] = {}
+
+        # Saving processor state for saving/loading to file and undoing ticks
         self.removed_cycles = 0
-        self.max_line_len = 170
-        self.line_seperator = "-"
-        self.is_stopped = False
+        self.assembly_cycles = [0]  # Map asm instruction to clock cycle
+        self.module_history: list[dict[str, dict[str, Any]]] = []
+        self.signal_history: list[list] = []  # TODO: Is this needed?
+
+        # For showing which instructions are being done and signalling
+        # the start of a new one
         self.new_instruction = False
-        self.current_instructions: list[str] = []
+
+        # It is the responsibility of the CPU to tell the gui:s pipeline
+        # diagram what information to be displayed and how to display it.
+        # Thus each CPU keeps track of its current instructions together with
+        # each instructions position in the pipeline diagram.
+        self.current_instructions: list[tuple[str, int, int]] = []
+
         # 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
+        # Maybe implement a 'get_pretty_print_state' at module
         # level?
         self.ignore_keys = [
             "bit_length",
@@ -51,18 +93,13 @@ class Processor:
             "decrement_by_one",
             "bus_id",
         ]
-        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.
+        """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, and save
-        clock cycles when new assemly instructions are started.
+        clock cycles when new assembly instructions are started.
         """
         if len(self.module_history) > self.clock - self.removed_cycles:
             # If a previous stored cycle has been loaded, discard
@@ -93,37 +130,80 @@ class Processor:
         # new assembly instruction
         if self.is_new_instruction():
             self.new_instruction = True
-            self.current_instruction = self.get_current_instruction()
+            self.current_instructions = self.get_current_instructions()
             self.assembly_cycles.append(self.get_clock())
         else:
             self.new_instruction = False
 
-    def get_current_instruction(self) -> str:
+    def get_current_instructions(self) -> list[tuple[str, int, int]]:
+        """Return a list of the current instructions with their positions.
+
+        Each entry in the list is a tuple of a instruction with its column and
+        row position for the pipeline diagram.
+
+        Returns
+        -------
+        list[tuple[str, int, int]]
+            A list of instructions represented as tuples. Each tuple contains
+            the instruction and its position in the pipeline.
         """
-        Return the current instruction. Useful for pipeline diagram.
+        raise NotImplementedError
+
+    def get_pipeline_dimensions(self) -> tuple[int, int]:
+        """Return the dimensions of the pipeline of the processor.
+
+        Returns
+        -------
+        width : int
+            The width of the pipeline (number of cycles to display at a time).
+        depth : int
+           Depth of the pipeline.
         """
-        raise NotImplemented
+        raise NotImplementedError
 
-    def run_asm_instruction(self, num_instructions=1) -> None:
+    def get_asm_instruction(self) -> str:
+        """Return a string containing the 'code' for the current assembly
+        instruction.
+
+        What 'code' refers to is up to each processor to define. It could be a
+        memory address, an instruction label or something else.
+
+        Returns
+        -------
+        str
+            The current assembly instruction.
         """
-        Runs assembler instructions on the processors 'num_instructions' times.
+        raise NotImplementedError
+
+    def run_asm_instruction(self, num_instructions=1) -> None:
+        """Run a number of assembly instructions.
+
+        Defaults to running 1 instruction unless some other number is provided.
+
+        Parameters
+        ----------
+        num_instructions : int
+            Number of assembly instructions to perform.
 
-        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.
+        Notes
+        -----
+        This should be implemented per processor and thus we
+        raise NotImplementedError.
         """
 
-        raise NotImplemented
+        raise NotImplementedError
 
     def undo_asm_instruction(self, num_instructions=1) -> None:
         """
-        Undos 'num_instructions' numbers of assembler instructions on the CPU.
+        Undo a number of assembly 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'.
+        Default argument is one, but it is possible to specify any number of
+        instructions.
 
-        Undos asm instructions by finding the corresponding clock cycle before
-        said number of asm intructions started and loading that clock cycle.
+        Parameters
+        ----------
+        num_instructions : int
+            Number of assembly instructions to undo.
         """
 
         current_clock_cycle = self.clock
@@ -148,7 +228,7 @@ class Processor:
         # 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.
+        # that has uPC set to 0, which wont happen when we load a new file.
         self.assembly_cycles = self.assembly_cycles[: index + 1]
 
     def run_continuously(self) -> None:
@@ -161,48 +241,51 @@ class Processor:
 
     def should_halt(self) -> bool:
         """
-        Return True when the processor should halt, otherwise False.
+        Return whether the processor should halt this clock cycle or not.
 
-        Note
+        Returns
+        -------
+        bool
+            ``True`` if the processor should halt, ``False`` otherwise.
+
+        Notes
         ----
         Each processor should implement the condition for True in its subclass.
-        If we intead raise NotImplemented as we do in all other cases when the
-        functionality should be implemented in the subclass we lose the ability
-        to test modules on the base processor class.
+        If we instead raise NotImplementedError as we do in all other cases
+        when the functionality should be implemented in the subclass we lose
+        the ability to test modules on the base processor class.
         """
         return False
 
     def stop(self) -> None:
-        """
-        Signal to stop the execution of the processor until the processor is
+        """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.
-        """
+        """Reset the stop execution signal."""
         self.is_stopped = False
 
     def is_new_instruction(self) -> bool:
         """
-        Return true on the same clock cycle the CPU starts a new instruciton.
+        Return true on the same clock cycle the CPU starts a new instruction.
 
-        Should be implemented per CPU, return field new_instruction. It is up to each
-        processor to set this field to True/False correctly.
+        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.
+        """Stop the execution if any breakpoint has been reached during this
+        clock 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
+            # 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
@@ -211,8 +294,7 @@ class Processor:
             self.stop()
 
     def reset(self):
-        """
-        Reset the processor to its start state.
+        """Reset the processor to its start state.
 
         This resets all modules and removes any saved states for undoing clock
         cycles. A round of value propagation is done to reset signals too.
@@ -232,45 +314,83 @@ class Processor:
             module.update_logic()
 
     def add_modules_to_update(self, module: Module) -> None:
-        """
-        Queues module to be updated at the end of clock cycle.
+        """Queue a module to be updated at the end of clock cycle.
+
+        Parameters
+        ----------
+        module : Module
+            Module to queue for update.
+
+        See Also
+        --------
+        Module.update_logic :
+            Method for updating a module.
         """
         if module not in self.update_queue:
             self.update_queue.append(module)
 
     def add_module(self, module: Module) -> None:
-        """
-        Add module into the processor.
+        """Add module to be simulated by the processor.
+
+        Parameters
+        ----------
+        module : Module
+            Module to add.
         """
         self.modules[module.name] = module
 
     def get_module(self, name: str) -> Module:
-        """
-        Get module with specific name.
+        """Get module with specific name.
+
+        Parameters
+        ----------
+        name : str
+            Name of the module to get.
+
+        Returns
+        -------
+        Module
+            The module with the specified name.
         """
         return self.modules[name]
 
     def get_modules(self) -> list[Module]:
-        """
-        Get list of all modules.
+        """Get list of all modules.
+
+        Returns
+        -------
+        list[Module]
+            List of all modules in the processor.
         """
         return list(self.modules.values())
 
     def add_signals(self, signals: list[Signal]) -> None:
-        """
-        Add signals into the processor.
+        """Add signals to the processor.
+
+        Parameters
+        ----------
+        list[Signal]
+            List of signals to add for simulation.
         """
         self.signals += signals
 
     def get_clock(self) -> int:
-        """
-        Get current clockcycle.
+        """Get the current clockcycle number.
+
+        Returns
+        -------
+        int
+            Current clock cycle number of the processor.
         """
         return self.clock
 
     def set_clock(self, value: int) -> None:
-        """
-        Set current clockcycle.
+        """Set current clockcycle number.
+
+        Parameters
+        ----------
+        value : int
+            Cycle number to set the clock to.
         """
         self.clock = value
 
@@ -283,7 +403,7 @@ class Processor:
 
         # Only save a specified number of cycles,
         # saving every cycle can easily eat all ram
-        if len(self.module_history) > self.cycles_to_save:
+        if len(self.module_history) > Processor.CYCLES_TO_SAVE:
             self.module_history.pop(0)
             self.removed_cycles += 1
 
@@ -292,10 +412,15 @@ class Processor:
         self.module_history.append(module_states)
 
     def load_cycle(self, cycle: int) -> None:
-        """
-        Load the state of all modules as they were at the specified clock cycle.
+        """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.
+
+        Parameters
+        ----------
+        cycle : int
+            Number of the cycle to load.
         """
 
         cycle_index = cycle - self.removed_cycles
@@ -320,13 +445,13 @@ class Processor:
             module = self.update_queue.pop(0)
             module.update_logic()
 
-    def load_state_from_file(self, file_path) -> None:
-        """
-        Loads states for modules from a file.
+    def load_state_from_file(self, file_path: str) -> None:
+        """Load 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.
+        Parameters
+        ----------
+        file_path : str
+            Path to the file containing the processor state to load.
         """
         self.reset()
 
@@ -339,6 +464,9 @@ class Processor:
         else:
             raise ValueError  # Else raise error
 
+        # 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.
         module_name = None
         module_str = ""
 
@@ -370,10 +498,14 @@ class Processor:
             module.load_from_str(module_str)
 
     def save_state_to_file(self, file_path: str) -> None:
-        """
-        Saves the current state of the cpu to a given file.
+        """Save the current state of the cpu to file.
 
         Will overwrite the given file.
+
+        Parameters
+        ----------
+        file_path : str
+            Path to the file to write to.
         """
         file = open(file_path, "w")
         file.write("")
@@ -383,19 +515,27 @@ class Processor:
             module.save_state_to_file(file_path)
 
     def pretty_print(self) -> None:
+        """Print the processor state in a readable and compact format."""
         self.pretty_print_verbose(self.ignore_keys)
 
     def pretty_print_verbose(self, ignore_keys=None) -> None:
         """
-        Prints the most relevant information about each module
-        compact and pretty. Fields of modules can be ignored with the
-        optional argument 'ignore_keys'.
+        Print the most relevant information about each module in a compact and
+        readable format.
+
+        State variables of modules can be ignored with the optional argument.
+
+        Parameters
+        ----------
+        ignore_keys : list[str]
+            List of names of state variables of modules to exclude when
+            printing module states.
         """
         # TODO: ignore keys per module and not for all modules
         memory_modules = []
         other_modules = []
 
-        if ignore_keys == None:
+        if ignore_keys is None:
             ignore_keys = []
 
         # TODO: remove isinstance(module, micro_memory)
@@ -419,16 +559,17 @@ class Processor:
         module_to_line_length = {}
         # get the longest line length for all other_modules
         for module in other_modules:
-            line_len = module.get_longest_line_len(ignore_keys) + 3  # +3 for padding
+            # +3 for padding
+            line_len = module.get_longest_line_len(ignore_keys) + 3
 
             # TODO: what to do if two or more modules has the same name
             module_to_line_length[module] = line_len
 
         groups = self.group_pp_modules(module_to_line_length)
 
-        print(self.line_seperator * self.max_line_len)
+        print(Processor.LINE_SEPARATOR * Processor.MAX_LINE_LEN)
 
-        # print each group seperate
+        # print each group separate
         for group in groups:
             self.pretty_print_names(group)
 
@@ -457,40 +598,46 @@ class Processor:
                             real_keys[row] + ": " + str(module_state[real_keys[row]])
                         )
 
-                    # padd the string so each string has the same
-                    # length
+                    # pad the string so each string has the same length
                     total_padding += module_to_line_length[module]
                     string = string.ljust(total_padding)
                     # replace last to chars with a separator and padding
                     string = string[0:-2] + "| "
 
                 print(string)
-            print(self.line_seperator * self.max_line_len)
+            print(Processor.LINE_SEPARATOR * Processor.MAX_LINE_LEN)
 
         for memory_module in memory_modules:
             self.pretty_print_memory(memory_module)
 
-    def pretty_print_memory(self, module: Module) -> None:
+    def pretty_print_memory(self, module: Memory) -> None:
+        """Print a memory module in a compact and readable format.
+
+        Parameters
+        ----------
+        module : Memory
+            Memory module to print the state of.
+        """
         print(module.name)
-        print(self.line_seperator * self.max_line_len)
+        print(Processor.LINE_SEPARATOR * Processor.MAX_LINE_LEN)
 
         longest_line_len = module.get_longest_line_len()
         # longest_line_len = self.get_longest_memory_value(module.memory)
         string = ""
         last_mem_len = module.get_largest_mem_adr()
 
-        for i, value in enumerate(module.memory):
+        for i, value in enumerate(module.get_state()["memory"]):
 
-            # create a new string containg the adress and the value
-            # of the memory adress formattet to fit with the largest
-            # adress and largest memory value
+            # create a new string containing the address and the value
+            # of the memory address formatted to fit with the largest
+            # address and largest memory value
             new_row = (str(i).ljust(last_mem_len) + ": " + str(value)).ljust(
                 longest_line_len + last_mem_len + 3
             ) + "|"
 
             # only add the string if there is space for it, else
             # print the string and start a new
-            if len(string + new_row) + 1 > self.max_line_len:
+            if len(string + new_row) + 1 > Processor.MAX_LINE_LEN:
                 print(string)
                 string = new_row
             else:
@@ -501,16 +648,21 @@ class Processor:
                 else:
                     string = new_row
         print(string)
-        print(self.line_seperator * self.max_line_len)
+        print(Processor.LINE_SEPARATOR * Processor.MAX_LINE_LEN)
         print()
 
     def pretty_print_names(self, module_to_line_length: dict[Module, int]) -> None:
         """
-        Prints the name of the modules in one row, but pretty.
+        Print the name of the modules in one row with formatting.
 
+        Adds spacing between the names so that the longest state variable of
+        each module has space to be printed below the name.
 
-        Adds spacing between the names so that the modules
-        longest field will have space to be printed below.
+        Parameters
+        ----------
+        module_to_line_length : dict[Module, int]
+            Mapping from module to length of the longest state variable of
+            the module.
         """
         name_string = ""
         total_len = 0
@@ -525,9 +677,20 @@ class Processor:
     def group_pp_modules(
         self, module_to_line_length: dict[Module, int]
     ) -> list[dict[Module, int]]:
-        """
-        Groups the modules to be pretty printed into groups with a
-        total line length lower than 'self.max_line_len'.
+        """Group the modules to be pretty printed into groups with a
+        total line length lower than 'Processor.MAX_LINE_LEN'.
+
+        Parameters
+        ----------
+        module_to_line_length : dict[Module, int]
+            Mapping from module to length of the longest state variable of
+            the module (takes as the line length).
+
+        Returns
+        -------
+        list[dict[Module, int]]
+            List of mappings from module to line length, each mapping
+            representing a group of modules for printing.
         """
 
         groups = [{}]
@@ -536,7 +699,7 @@ class Processor:
         for module in module_to_line_length:
 
             # Make sure the line is not to long
-            if line_len + module_to_line_length[module] < self.max_line_len:
+            if line_len + module_to_line_length[module] < Processor.MAX_LINE_LEN:
                 line_len += module_to_line_length[module]
                 groups[group_index][module] = module_to_line_length[module]
 
@@ -550,8 +713,21 @@ class Processor:
 
     def fields_to_list(self, module: Module, ignore_keys=[]) -> list[str]:
         """
-        Return a list containing all the keys for a module except the name.
-        Optinal argument to ignore specific keys.
+        Return a list containing all state variable names, excluding module
+        name, for a module.
+        Optional argument to ignore specific state variables.
+
+        Parameters
+        ----------
+        module : Module
+            Module to get state variable names from.
+        ignore_keys : list[str]
+            List of state variable names to exclude.
+
+        Returns
+        -------
+        list[str]
+            List of state variable names, excluding module name, of a module.
         """
         return [
             key
@@ -559,12 +735,29 @@ class Processor:
             if key != "name" and key not in ignore_keys
         ]
 
-    def get_most_fields(self, modules: dict[Module:int], ignore_keys=[]) -> int:
-        """
-        Return the most number of a fields a module has.
+    def get_most_fields(self, modules: dict[Module, int], ignore_keys=None) -> int:
+        """Get the maximum number of state variables among all modules.
 
         Can optionally ignore keys.
+
+        Parameters
+        ----------
+        modules : dict[Module, int]
+            Mapping from module to length of the longest state variable of
+            the module. Used as a list of modules to take the maximum over.
+        ignore_keys : list[str]
+            State variables to exclude.
+
+        Returns
+        -------
+        int
+            The maximum of the number of module state variables among all
+            modules of the processor.
         """
+
+        if ignore_keys is None:
+            ignore_keys = []
+
         fields = 0
         for module in modules:
             module_fields = len(self.fields_to_list(module, ignore_keys))
@@ -576,6 +769,24 @@ class Processor:
     def add_state_breakpoint(
         self, module_name: str, state_name: str, value: Any
     ) -> None:
+        """Add a module state breakpoint to the processor.
+
+        Parameters
+        ----------
+            module_name : str
+                Name of the module for which a breakpoint will be added.
+            state_name : str
+                Name of the state variable of the module to put a breakpoint
+                on.
+            value : Any
+                Value of the state variable that triggers the breakpoint.
+
+        Raises
+        ------
+        ValueError
+            If the module does not exist or if the state variable does not
+            exist in the module.
+        """
 
         if module_name not in self.modules:
             raise ValueError(f"No module named {module_name}")
@@ -590,19 +801,43 @@ class Processor:
         self.breakpoint_id_counter += 1
 
     def remove_breakpoint(self, id: int) -> bool:
+        """Remove a specific breakpoint.
+
+        Parameters
+        ----------
+        id : int
+            ID of the breakpoint to be removed.
+        """
         if id in self.breakpoints:
             del self.breakpoints[id]
             return True
         return False
 
     def print_breakpoints(self) -> None:
+        """Print all breakpoints of the processor."""
         if not self.breakpoints:
             print("There are no breakpoints.")
         else:
             for bp_id, bp in self.breakpoints.items():
                 print(f"BP {bp_id}: {bp}")
 
-    def add_memory_breakpoint(self, module_name: str, adress: int, value: Any) -> None:
+    def add_memory_breakpoint(self, module_name: str, address: int, value: Any) -> None:
+        """Add a breakpoint for a memory module.
+
+        Parameters
+        ----------
+        module_name : str
+            Name of the memory module for which a breakpoint will be added.
+        address : int
+            Address of the memory module to break at.
+        value : Any
+            Value of the address that triggers the breakpoint.
+
+        Raises
+        ------
+        ValueError
+            If the module does not exist or is not a memory.
+        """
 
         if module_name not in self.modules:
             raise ValueError(f"No module named {module_name}")
@@ -611,14 +846,42 @@ class Processor:
         if "memory" not in module.get_state():
             raise ValueError(f"Module {module_name} is not a memory.")
 
-        bp = MemoryBreakpoint(module, adress, value)
+        bp = MemoryBreakpoint(module, address, value)
         self.breakpoints[self.breakpoint_id_counter] = bp
         self.breakpoint_id_counter += 1
 
     def get_breakpoint_lambdas(self) -> list[str]:
+        """Get all functions available for lambda breakpoints.
+
+        Returns
+        -------
+        list[str]
+            List of names of all functions of the processor that are available
+            for adding lambda breakpoints.
+        """
+
         return list(self.lambdas.keys())
 
     def add_lambda_breakpoint(self, lambda_name: str, **kwargs) -> None:
+        """Add a lambda breakpoint to the processor.
+
+        Module names used in the keyword arguments are substituted by the
+        actual modules before being passed on to the lambda breakpoint
+        function.
+
+        Parameters
+        ----------
+        lambda_name : str
+            Name of the lambda breakpoint function to be used by the
+            breakpoint.
+        **kwargs
+            Arguments to pass to the breakpoint function.
+
+        Raises
+        ------
+        ValueError
+            If the  lambda breakpoint function does not exist.
+        """
         # Substitute any module names for the module instances
         # This is to be able to externally create general lambda breakpoints
         # that can take any values as arguments while also having a way to take
@@ -637,4 +900,13 @@ class Processor:
         self.breakpoint_id_counter += 1
 
     def set_enabled_breakpoint(self, bp_id: int, is_enabled: bool) -> None:
+        """Toggle a breakpoint to enabled or disabled.
+
+        Parameters
+        ----------
+        bp_id : int
+            ID of the breakpoint to toggle.
+        is_enabled : bool
+            ``True`` to enable, ``False`` to disable the breakpoint.
+        """
         self.breakpoints[bp_id].set_enabled(is_enabled)
diff --git a/src/simudator/core/signal.py b/src/simudator/core/signal.py
index cfd6de19272193b4bd11aca329a0ad72ecb903f6..8db1d14133278add895bc9b776f778addb5116df 100644
--- a/src/simudator/core/signal.py
+++ b/src/simudator/core/signal.py
@@ -5,54 +5,79 @@ from typing import Any
 
 class Signal:
     """
-    Handles datatransportation between modules in the processor.
-    Each signal has one source module and can have multiple
-    destination modules.
+    Signal class to send data between modules in a processor.
+
+    Parameters
+    ----------
+    processor : Processor
+        Processor that the signal belongs to. Needed to queue processor modules
+        for update.
+    name : str
+        Name of the signal.
+    value : Any
+        Initial value of the signal.
     """
-    def __init__(self, processor: Processor, name: str = "Signal", value = None):
-        self.processor = processor
-        self.name = name
-        self.source = None
-        self.destinations = set()
-        self.value = value
+
+    __slots__ = ("_processor", "_name", "_source", "_destinations", "_value")
+
+    def __init__(self, processor: Processor, name: str = "Signal", value=None):
+        self._processor = processor
+        self._name = name
+        self._source = None
+        self._destinations = set()
+        self._value = value
 
     def add_destination(self, module: Module) -> None:
-        """
-        Add a destination module that the signal will send new
+        """Add a module as a destination that the signal will send new
         values to.
         """
-        self.destinations.add(module)
-
-    def set_source(self, module: Module) -> None:
-        """
-        Set source module that will send values through the signal.
-        """
-        self.source = module
+        self._destinations.add(module)
 
     def update_value(self, value) -> None:
         """
-        Sets value in signal and queues destination moduels for update.
+        Set the value of the signal and queue destination modules for update.
+
+        Parameters
+        ----------
+        value : Any
+            Value to set the signal to.
         """
-        if value != self.value:
-            self.value = value
+        if value != self._value:
+            self._value = value
             # Inform the processor on what modules have been given
             # signal so they can update
-            for destination in self.destinations:
-                self.processor.add_modules_to_update(destination)
+            for destination in self._destinations:
+                self._processor.add_modules_to_update(destination)
 
     def get_value(self) -> Any:
-        """
-        Get the signals current value.
-        """
-        return self.value
+        """Get the current value of the signal.
 
-    def set_value(self, value) -> None:
+        Returns
+        -------
+        Any
+            Value of the signal.
         """
-        Set the value of the signal without queuing the destination
-        modules of the signal for update. This method should not
-        be called by a module.
+        return self._value
+
+    def set_value(self, value: Any) -> None:
+        """Set the value of the signal without queuing the destination
+        modules of the signal for update.
+
+        This method should not be called by a module.
+
+        Parameters
+        ----------
+        value : any
+            Value to set the signal to.
         """
-        self.value = value
+        self._value = value
 
     def get_name(self) -> str:
-        return self.name
+        """Return the name of the signal.
+
+        Returns
+        -------
+        str
+            Name of the signal.
+        """
+        return self._name
diff --git a/src/simudator/gui/dialogs/lambda_breakpoint_dialog.py b/src/simudator/gui/dialogs/lambda_breakpoint_dialog.py
index 824131527bb809a225dc46337a9d0f4b96c2f0e6..9343ff10232952031b2d7e8aa40891d2b9996db4 100644
--- a/src/simudator/gui/dialogs/lambda_breakpoint_dialog.py
+++ b/src/simudator/gui/dialogs/lambda_breakpoint_dialog.py
@@ -13,6 +13,7 @@ from qtpy.QtWidgets import (
 
 
 class LambdaBreakpointDialog(QDialog):
+
     accepted = pyqtSignal(str, str, name="accepted")
 
     def __init__(
diff --git a/src/simudator/gui/gui.py b/src/simudator/gui/gui.py
index 825164f619a955d230c9b401701ba3ab7891ebc8..94e61e82608032f45b76d977261749b13b65120c 100644
--- a/src/simudator/gui/gui.py
+++ b/src/simudator/gui/gui.py
@@ -132,8 +132,7 @@ class GUI(QMainWindow):
         self.cpu_running = False
 
         self.pipeline = PipeLine()
-        # Hide pipeline for now since it is not implemented yet
-        # self.pipeline.show()
+        self.init_pipeline()
 
         # Set Style, THESE ARE TEST AND DONT WORK
         app = QApplication.instance()
@@ -363,14 +362,31 @@ class GUI(QMainWindow):
                 case "CLOCKUPDATE":
                     signal.connect(self.updateCpuClockCycle)
 
+    def init_pipeline(self) -> None:
+        """Initialize the pipeline diagram. 
+
+        Sets its height, width and instructions.
+        """
+        size = self.cpu.get_pipeline_dimensions()
+
+        self.pipeline.set_height(size[0])
+        self.pipeline.set_width(size[1])
+        self.update_pipeline()
+
+        self.pipeline.show()
+
     def updateCpuListeners(self) -> None:
         """
-        Updates the graphics items in the scene and the clock.
+        Updates the graphics items in the scene, the clock, and the pipeline diagram.
 
         Used after the cpu has run or when the user has edited somehting.
         """
         self.cpu_graphics_scene.updateGraphicsItems()
         self.updateCpuClockCycle()
+        self.update_pipeline()
+
+    def update_pipeline(self) -> None:
+        self.pipeline.set_instructions(self.cpu.get_current_instructions())
 
     def updateCpuClockCycle(self) -> None:
         """
diff --git a/src/simudator/gui/pipeline.py b/src/simudator/gui/pipeline.py
index 9023ef17475fa40212b42481e56e0235b0a12bf7..fc9d78012115a011bfc6574414ba6c8a478b6a67 100644
--- a/src/simudator/gui/pipeline.py
+++ b/src/simudator/gui/pipeline.py
@@ -3,7 +3,6 @@ from typing import Any
 from qtpy.QtWidgets import QTableWidget, QTableWidgetItem
 
 
-# TODO: Make the table unediatable
 class PipeLine(QTableWidget):
     """
     A class showing the current CPU instructions in a seperate window.
@@ -14,27 +13,40 @@ class PipeLine(QTableWidget):
 
     def __init__(self):
         super().__init__()
-        # Values below are temporary test values
+
+    def set_instructions(self, instructions: list[tuple[str, int, int]]) -> None:
         """
-        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])
+        Give the pipeline the current CPU instructions.
+
+        Parameters
+        ----------
+        instructions: A list of tuples of a string and two ints.
+                      The string containing the current instruction where the two ints
+                      represents the instructions col and row position.
+
+        See Also
+        --------
+        simudator.core.processor.get_current_instructions :
+            Instructions are set from get_current_instructions() in the Processor class.
         """
 
-    def set_instruction(self, instructions: list[str]) -> None:
-        """Give the pipeline the current CPU instructions."""
         self.instructions = instructions
+        for i in range(len(self.instructions)):
+            instruction = self.instructions[i][0]
+            col = self.instructions[i][1]
+            row = self.instructions[i][2]
+            self.set_item(row, col, instruction)
 
     def set_height(self, height: int) -> None:
-        """Sets the height of the pipeline."""
+        """
+        Sets the height of the pipeline.
+        """
         self.setColumnCount(height)
 
     def set_width(self, width: int) -> None:
-        """Sets the width of the pipeline."""
+        """
+        Sets the width of the pipeline.
+        """
         self.setRowCount(width)
 
     def set_row_labels(self, labels: list[str]) -> None:
@@ -60,7 +72,9 @@ class PipeLine(QTableWidget):
         raise NotImplemented
 
     def set_item(self, row: int, col: int, text: str) -> None:
-        """Sets the text at position col row to the given text."""
+        """
+        Sets the text at position col row to the given text.
+        """
         item = QTableWidgetItem(text)
 
         self.setItem(row, col, item)
diff --git a/src/simudator/processor/mia/gui/mia_grx_graphic.py b/src/simudator/processor/mia/gui/mia_grx_graphic.py
index 5474f915cc91a374f4fcccebadba008389e3a073..d7d94295ee0adc6f33fc7dc5f1c60d5beaa9bfc5 100644
--- a/src/simudator/processor/mia/gui/mia_grx_graphic.py
+++ b/src/simudator/processor/mia/gui/mia_grx_graphic.py
@@ -28,6 +28,7 @@ class GrxGraphicsItem(ModuleGraphicsItem):
     REGISTER_MARGIN = 10
     LINE_LENGTH = 30
     MUX_WIDTH = 80
+    REGISTER_LENGTH = 4
 
     def __init__(self, module: GRX):
         self.register_text_labels = []
@@ -43,7 +44,9 @@ class GrxGraphicsItem(ModuleGraphicsItem):
         for index, register_value in enumerate(self.module.registers):
             # Make text to display for register
             name = "Gr" + str(index)
-            hex_length = math.ceil(self.state["bit_length"] / 4)
+
+            # Mia uses 4 hex numbers to represent the registers
+            hex_length = self.REGISTER_LENGTH
             value_text = f"0x{register_value:0{hex_length}x}"
             full_text = name + ": " + value_text[2:]
 
@@ -145,7 +148,9 @@ class GrxGraphicsItem(ModuleGraphicsItem):
         for index, register_value in enumerate(self.module.registers):
             text = self.register_text_labels[index]
             name = "Gr" + str(index)
-            hex_length = math.ceil(self.state["bit_length"] / 4)
+
+            # Mia uses 4 hex numbers for each register
+            hex_length = self.REGISTER_LENGTH
 
             value_text = f"0x{register_value:0{hex_length}x}"
             full_text = name + ": " + value_text[2:]
diff --git a/src/simudator/processor/mia/gui/mia_memory_graphic.py b/src/simudator/processor/mia/gui/mia_memory_graphic.py
index 303ddb8d9cccd9b2e53139c4b9de9fe0fdb26766..ec29b7717ebc86efe8b0762dc07f3abef6ca34a1 100644
--- a/src/simudator/processor/mia/gui/mia_memory_graphic.py
+++ b/src/simudator/processor/mia/gui/mia_memory_graphic.py
@@ -2,6 +2,7 @@ import ast
 
 from qtpy.QtCore import Slot
 from qtpy.QtWidgets import (
+    QErrorMessage,
     QGraphicsRectItem,
     QGraphicsSimpleTextItem,
     QTextEdit,
@@ -28,6 +29,7 @@ class MiaMemoryGraphicsItem(MemoryGraphicsItem):
     def __init__(self, memory_module: Memory, **kwargs):
         super().__init__(memory_module, **kwargs)
         self.memory_window = None
+        self._errorMessageWidget = QErrorMessage()
 
     def draw_graphics_item(self) -> None:
         # Same as normal memory but no control signal
@@ -94,9 +96,9 @@ class MiaMemoryGraphicsItem(MemoryGraphicsItem):
                 module_name, str(parsed_address), str(parsed_value)
             )
         except SyntaxError as e:
-            self.errorMessageWidget.showMessage(str(e))
+            self._errorMessageWidget.showMessage(str(e))
         except ValueError:
-            self.errorMessageWidget.showMessage(
+            self._errorMessageWidget.showMessage(
                 "You must enter a hexadecimal" "number preceeded by '0x' (e.g." "0xc3)."
             )
 
@@ -106,16 +108,27 @@ class MiaMemoryGraphicsItem(MemoryGraphicsItem):
         Same as prent function but also prases data so it is hexadecimal.
         """
         try:
-            parsed_address = int(address, 16)
+            parsed_adress = int(address, 16)
             parsed_value = ast.literal_eval(value)
         except SyntaxError as e:
-            self.errorMessageWidget.showMessage(str(e))
+            self._errorMessageWidget.showMessage(str(e))
         except ValueError:
-            self.errorMessageWidget.showMessage(
+            self._errorMessageWidget.showMessage(
                 "You must enter a hexadecimal" "number preceeded by '0x' (e.g." "0xc3)."
             )
         else:
             module_state = self.module.get_state()
-            module_state['memory'][parsed_address] = parsed_value
+            try:
+                if parsed_adress < 0:
+                    raise IndexError
+                module_state['memory'][parsed_adress] = parsed_value
+            except IndexError:
+                self._errorMessageWidget.showMessage(
+                    "Address entered was outside the memory space. Adress must be between 0 and 0xff."
+                )
+            else:
+                self.module.set_state(module_state)
+                self.update_graphics_signal.emit()
+            module_state['memory'][parsed_adress] = parsed_value
             self.module.set_state(module_state)
             self.update_graphics_signal.emit()
diff --git a/src/simudator/processor/mia/mia.py b/src/simudator/processor/mia/mia.py
index 724ad94bedb46e5ab898ce607003f193b5a94f93..1b6d95d866d8a1a63dff4809f2a4eb62a32faf21 100644
--- a/src/simudator/processor/mia/mia.py
+++ b/src/simudator/processor/mia/mia.py
@@ -1,4 +1,5 @@
 import sys
+from typing import Any
 
 from simudator.cli.cli import CLI
 from simudator.core.modules import Flag
@@ -31,7 +32,6 @@ from simudator.processor.mia.modules.mia_grx import GRX
 from simudator.processor.mia.modules.mia_memory import MiaMemory
 from simudator.processor.mia.modules.micro_memory import MicroMemory
 from simudator.processor.mia.modules.micro_pc import MicroPC
-
 from simudator.processor.mia.modules.pc import PC
 
 
@@ -138,8 +138,6 @@ class MIA_CPU(Processor):
         # PM specific
         pm_size = 256
         pm_bus_id = 0b010
-        pm_address_padding = 2
-        pm_value_padding = 4
         pm = MiaMemory(
             pm_bus,
             bus_pm,
@@ -147,8 +145,6 @@ class MIA_CPU(Processor):
             bus_control,
             pm_size,
             pm_bus_id,
-            value_padding=pm_value_padding,
-            address_padding=pm_address_padding,
             name="PM",
         )
 
@@ -160,8 +156,6 @@ class MIA_CPU(Processor):
 
         # K1 specific
         k1_size = 16
-        k1_address_padding = 2
-        k1_value_padding = 2
         k1 = MiaMemory(
             always_write_signal,
             uPC_k1,
@@ -170,14 +164,10 @@ class MIA_CPU(Processor):
             k1_size,
             always_write_id,
             name="K1",
-            address_padding=k1_address_padding,
-            value_padding=k1_value_padding,
         )
 
         # K2 specific
         k2_size = 4
-        k2_address_padding = 2
-        k2_value_padding = 2
         k2 = MiaMemory(
             always_write_signal,
             uPC_k2,
@@ -186,8 +176,6 @@ class MIA_CPU(Processor):
             k2_size,
             always_write_id,
             name="K2",
-            address_padding=k2_address_padding,
-            value_padding=k2_value_padding,
         )
 
         # IR specific
@@ -281,9 +269,28 @@ class MIA_CPU(Processor):
     def is_new_instruction(self) -> bool:
         return self.get_module("uPC").value == 0
 
-    def get_current_instruction(self) -> str:
+    def get_current_instructions(self) -> list[tuple[str, int, int]]:
+        asm_instr = self.get_asm_instruction()
+        micro_instr = self.get_micro_instruction()
+        asm = (asm_instr, 1, 0)
+        micro = (micro_instr, 1, 1)
+        asm_title = ("Assembler", 0, 0)
+        micro_title = ("Micro", 0, 1)
+        return [asm, micro, asm_title, micro_title]
+
+    def get_micro_instruction(self) -> str:
+        """
+        Return a string containing the address for the current micro instruction in hex, e.g. 0a4b.
+        """
+        uM = self.get_module("uM").get_state()
+        curr_instr = uM["curr_instr"]
+        memory = uM["memory"]
+
+        return '0x' + format(memory[curr_instr], '07x')
+
+    def get_asm_instruction(self) -> str:
         """
-        Return a string containing the label for the current instruction.
+        Return a string containing the label for the current assembly instruction.
 
         If the label doesnt exist, the string is empty.
         """
@@ -291,6 +298,14 @@ class MIA_CPU(Processor):
         op_code = ir.op
         return self.get_module("K1").get_label(int(op_code))
 
+    def get_pipeline_dimensions(self) -> tuple[int, int]:
+        """
+        Mia should show the current assembly instruction and the current micro instruction.
+
+        One Extra column to specify what the values represent.
+        """
+        return (2, 2)
+
     def run_asm_instruction(self, num_instructions=1) -> None:
         """
         Runs 'num_instructions' assembler instructions on Mia.
diff --git a/src/simudator/processor/mia/modules/alu.py b/src/simudator/processor/mia/modules/alu.py
index 3f9cbdb3484545f7ff5febc2849020b61f3406f8..482da580be76ab06e8f941cbf00ef8febd577e5c 100644
--- a/src/simudator/processor/mia/modules/alu.py
+++ b/src/simudator/processor/mia/modules/alu.py
@@ -14,6 +14,8 @@ class ALU(Module):
     Will do all calulations as two's complement binary numbers.
     """
 
+    __slots__ = ("z_value", "n_value", "o_value", "c_value", "hr_value")
+
     WORD_LENGTH = 16
 
     def __init__(
@@ -562,7 +564,11 @@ class ALU(Module):
     # ----- Internal operations -----
 
     def update_flags(
-        self, binary_a: [int], binary_b: [int], binary_result: [int], carry: int
+        self,
+        binary_a: list[int],
+        binary_b: list[int],
+        binary_result: list[int],
+        carry: int,
     ) -> None:
         """
         Will update the flags depending on inputed values and the result.
@@ -603,7 +609,7 @@ class ALU(Module):
         """
 
         # Make empty binary number for result
-        new_binary_number = [0 for i in range(self.WORD_LENGTH)]
+        new_binary_number = [0 for _ in range(self.WORD_LENGTH)]
 
         # Change each bits value
         for bit_index in range(self.WORD_LENGTH):
@@ -614,14 +620,16 @@ class ALU(Module):
 
         return new_binary_number
 
-    def add_binary_numbers(self, binary_a: [int], binary_b: [int]) -> ([int], int):
+    def add_binary_numbers(
+        self, binary_a: list[int], binary_b: list[int]
+    ) -> tuple[list[int], int]:
         """
         Returns a tuple with the sum of two binary numbers
         and the carry bit from the calculations
         """
 
         # Make new binary number to store results
-        binary_sum = [0 for i in range(self.WORD_LENGTH)]
+        binary_sum = [0 for _ in range(self.WORD_LENGTH)]
 
         # Need carry for calculation
         carry = 0
@@ -645,22 +653,22 @@ class ALU(Module):
 
         return (binary_sum, carry)
 
-    def binary_and(self, binary_a: int, binary_b: int) -> int:
+    def binary_and(self, binary_a: list[int], binary_b: list[int]) -> list[int]:
         """
         Calculate and between binary two numbers
         """
-        binary_and = [0 for i in range(self.WORD_LENGTH)]
+        binary_and = [0 for _ in range(self.WORD_LENGTH)]
 
         for binary_index in range(self.WORD_LENGTH):
             binary_and[binary_index] = binary_a[binary_index] & binary_b[binary_index]
 
         return binary_and
 
-    def binary_or(self, binary_a: [int], binary_b: [int]) -> [int]:
+    def binary_or(self, binary_a: list[int], binary_b: list[int]) -> list[int]:
         """
         Calculate or between two binary numbers
         """
-        binary_or = [0 for i in range(self.WORD_LENGTH)]
+        binary_or = [0 for _ in range(self.WORD_LENGTH)]
 
         for binary_index in range(self.WORD_LENGTH):
             binary_or[binary_index] = binary_a[binary_index] | binary_b[binary_index]
diff --git a/src/simudator/processor/mia/modules/ar.py b/src/simudator/processor/mia/modules/ar.py
index f0613cf7c0e121ff156e62cdac3f559861677471..5ca55569f7678c4a57cc67b5adb8a4f8090a0129 100644
--- a/src/simudator/processor/mia/modules/ar.py
+++ b/src/simudator/processor/mia/modules/ar.py
@@ -8,6 +8,11 @@ class AR(IntegerRegister, MiaBusConnector):
     Register for saving AlU calculations in MIA.
     """
 
+    # Python does not allow multiple inherintence if more than one of the
+    # parent classes uses __slots__. Thus we also includes the __slots__
+    # from MiaBusConnector.
+    __slots__ = ("bus_id", "bus_control_s")
+
     def __init__(
         self,
         alu_input_signal: Signal,
@@ -28,7 +33,7 @@ class AR(IntegerRegister, MiaBusConnector):
 
     def output_register(self) -> None:
         # always update alu
-        self.signals["out_alu"].update_value(self.value)
+        self.signals["out_alu"].update_value(self._value)
 
         # only update bus when asked too
         if self.write_to_bus():
@@ -48,7 +53,7 @@ class AR(IntegerRegister, MiaBusConnector):
             self.name,
             "\n -----",
             "\n value: ",
-            hex(self.value),
+            hex(self._value),
             "\n bit length: ",
-            self.bit_length,
+            self._bit_length,
         )
diff --git a/src/simudator/processor/mia/modules/asr.py b/src/simudator/processor/mia/modules/asr.py
index dbf5e8a9a16bbb6b16d802a0b6deea40c48eaa87..52db394554dbaf045e44ca106ad3df0a7af6b361 100644
--- a/src/simudator/processor/mia/modules/asr.py
+++ b/src/simudator/processor/mia/modules/asr.py
@@ -8,6 +8,11 @@ class ASR(IntegerRegister, MiaBusConnector):
     Register for controlling the memory andress in MIA.
     """
 
+    # Python does not allow multiple inherintence if more than one of the
+    # parent classes uses __slots__. Thus we also includes the __slots__
+    # from MiaBusConnector.
+    __slots__ = ("bus_id", "bus_control_s")
+
     def __init__(
         self,
         bus_input_signal: Signal,
@@ -36,7 +41,7 @@ class ASR(IntegerRegister, MiaBusConnector):
             self.name,
             "\n -----",
             "\n value: ",
-            hex(self.value),
+            hex(self._value),
             "\n bit length: ",
-            self.bit_length,
+            self._bit_length,
         )
diff --git a/src/simudator/processor/mia/modules/bus.py b/src/simudator/processor/mia/modules/bus.py
index 9e1112abbce45e8b85fbe3b488289df213b9ad1d..62f56271db27a2d4971f99152dff25e19f38fe52 100644
--- a/src/simudator/processor/mia/modules/bus.py
+++ b/src/simudator/processor/mia/modules/bus.py
@@ -10,6 +10,8 @@ class Bus(Module):
     input signal can send a value to the bus at a time.
     """
 
+    __slots__ = ()
+
     def __init__(
         self, inputs: list[Signal] = [], outputs: list[Signal] = [], name: str = "Bus"
     ) -> None:
diff --git a/src/simudator/processor/mia/modules/hr.py b/src/simudator/processor/mia/modules/hr.py
index 7acc3ad5e2b5eb331099dc5f03eb8816380a3e06..bd74491b83632dcbe52679eaba363326fece177c 100644
--- a/src/simudator/processor/mia/modules/hr.py
+++ b/src/simudator/processor/mia/modules/hr.py
@@ -8,6 +8,11 @@ class HR(IntegerRegister, MiaBusConnector):
     Register for saving large AlU calculations in MIA.
     """
 
+    # Python does not allow multiple inherintence if more than one of the 
+    # parent classes uses __slots__. Thus we also includes the __slots__
+    # from MiaBusConnector.
+    __slots__ = ("bus_id", "bus_control_s")
+
     def __init__(
         self,
         alu_input_signal: Signal,
@@ -16,11 +21,11 @@ class HR(IntegerRegister, MiaBusConnector):
         bus_output_signal: Signal,
         bus_control_signal: Signal,
         bus_id: int,
-        bit_lenght: int,
+        bit_length: int,
         name="HR",
     ) -> None:
         IntegerRegister.__init__(
-            self, bus_input_signal, bus_output_signal, bit_lenght, name=name
+            self, bus_input_signal, bus_output_signal, bit_length, name=name
         )
         MiaBusConnector.__init__(self, bus_control_signal, bus_id)
 
@@ -40,7 +45,8 @@ class HR(IntegerRegister, MiaBusConnector):
 
         elif self.signals["in_alu"].get_value() is not None:
             input_value = self.signals["in_alu"].get_value()
-            self.value = input_value & self.mask
+            mask = 2**self._bit_length - 1
+            self._value = input_value & mask
 
     def output_register(self) -> None:
         """
@@ -49,7 +55,7 @@ class HR(IntegerRegister, MiaBusConnector):
         output the alu signal.
         """
 
-        self.signals["out_alu"].update_value(self.value)
+        self.signals["out_alu"].update_value(self._value)
 
         if self.write_to_bus():
             IntegerRegister.output_register(self)
@@ -66,7 +72,7 @@ class HR(IntegerRegister, MiaBusConnector):
             self.name,
             "\n -----",
             "\n value: ",
-            hex(self.value),
+            hex(self._value),
             "\n bit length: ",
-            self.bit_length,
+            self._bit_length,
         )
diff --git a/src/simudator/processor/mia/modules/ir.py b/src/simudator/processor/mia/modules/ir.py
index 776df1eec8d75f25e35373b9c6293ea139922b87..00ee7de233523a7795616879f8c8ff968071e181 100644
--- a/src/simudator/processor/mia/modules/ir.py
+++ b/src/simudator/processor/mia/modules/ir.py
@@ -12,6 +12,11 @@ class IR(Module, MiaBusConnector):
     several fields.
     """
 
+    # Python does not allow multiple inherintence if more than one of the
+    # parent classes uses __slots__. Thus we also includes the __slots__
+    # from MiaBusConnector.
+    __slots__ = ("op", "grx", "m", "a", "bus_id", "instruction", "bus_control_s")
+
     def __init__(
         self,
         to_bus: Signal,
@@ -24,7 +29,6 @@ class IR(Module, MiaBusConnector):
         bus_id=0,
         name: str = "IR",
     ) -> None:
-        MiaBusConnector.__init__(self, bus_control, bus_id)
 
         signals = {
             "in_input": from_bus,
@@ -34,6 +38,7 @@ class IR(Module, MiaBusConnector):
             "out_m": m_s,
         }
         Module.__init__(self, signals, name)
+        MiaBusConnector.__init__(self, bus_control, bus_id)
 
         # Internal values
         self.op = 0
diff --git a/src/simudator/processor/mia/modules/lc.py b/src/simudator/processor/mia/modules/lc.py
index 3202506e6e64e1b2486929df94d51b7b8a2f59b7..357e46be5fed5ee27e523a6e2a426f49411a00bc 100644
--- a/src/simudator/processor/mia/modules/lc.py
+++ b/src/simudator/processor/mia/modules/lc.py
@@ -12,6 +12,15 @@ class LC(Module):
     increase by one or read from mM_uADR.
     """
 
+    __slots__ = (
+        "value",
+        "read_from_bus",
+        "read_from_uADR",
+        "decrement_by_one",
+        "bit_length",
+        "mask",
+    )
+
     def __init__(
         self,
         mM_control: Signal,
diff --git a/src/simudator/processor/mia/modules/mia_bus_connect.py b/src/simudator/processor/mia/modules/mia_bus_connect.py
index caf7fe303c30b5b8c9ed5a71b5281882d4303036..e5607b1f82509d93fba475bce0ebcc7b68bd3729 100644
--- a/src/simudator/processor/mia/modules/mia_bus_connect.py
+++ b/src/simudator/processor/mia/modules/mia_bus_connect.py
@@ -9,6 +9,11 @@ class MiaBusConnector:
     Has logic for controlling when to read and write to bus.
     """
 
+    # Python does not allow multiple inherintence if more than one of the 
+    # parent classes uses __slots__. Since the modules that inherit from MiaBusConnector
+    # also inherits from other classes we leave this class __slots__ empty.
+    __slots__ = ()
+
     def __init__(self, bus_control: Signal, bus_id: int = 0) -> None:
         # init the name
         self.bus_id = bus_id
diff --git a/src/simudator/processor/mia/modules/mia_grx.py b/src/simudator/processor/mia/modules/mia_grx.py
index c139d2cd887929e5b046670916efa90da72e2a91..27d40fbe8a6a6ef760e2bebb458d3cdd8e38197e 100644
--- a/src/simudator/processor/mia/modules/mia_grx.py
+++ b/src/simudator/processor/mia/modules/mia_grx.py
@@ -14,6 +14,18 @@ class GRX(Module, MiaBusConnector):
     registers should be indexed by the GRx bits or the M bits.
     """
 
+    # Python does not allow multiple inherintence if more than one of the 
+    # parent classes uses __slots__. Thus we also includes the __slots__
+    # from MiaBusConnector.
+    __slots__ = (
+        "grx_control",
+        "m_control",
+        "s_control",
+        "bus_id",
+        "registers",
+        "bus_control_s",
+    )
+
     def __init__(
         self,
         to_bus: Signal,
@@ -25,7 +37,6 @@ class GRX(Module, MiaBusConnector):
         bus_id: int,
         name="GRx",
         registers=[0 for _ in range(4)],
-        bit_length=16,
     ) -> None:
         # Set connection to/from bus and bus_id
         MiaBusConnector.__init__(self, bus_control, bus_id)
@@ -44,9 +55,6 @@ class GRX(Module, MiaBusConnector):
         # set the registers
         self.registers = registers
 
-        # set the bit_length
-        self.bit_length = bit_length
-
     def update_register(self):
         """
         If the module should read from the bus, update the correct
@@ -97,7 +105,6 @@ class GRX(Module, MiaBusConnector):
         """
         state = {
             "name": self.name,
-            "bit_length": self.bit_length,
             "registers": self.registers[:],
         }
         return state
@@ -114,8 +121,6 @@ class GRX(Module, MiaBusConnector):
         Sets the grx state to one given in dict.
         """
         self.name = state["name"]
-        if "bit_length" in state:
-            self.bit_length = state["bit_length"]
         self.registers = state["registers"]
 
     def reset(self) -> None:
@@ -156,8 +161,6 @@ class GRX(Module, MiaBusConnector):
             "\n -----",
             "\n bus_id: ",
             self.bus_id,
-            "\n bit_length: ",
-            self.bit_length,
             "\n GR0: ",
             hex(self.registers[0]),
             "\n GR1: ",
diff --git a/src/simudator/processor/mia/modules/mia_memory.py b/src/simudator/processor/mia/modules/mia_memory.py
index cc66d8b853a2c176b5c2cc4bc9d13dc2c54cabc2..4b2ca42c137f718c4260e5ab9064f2a5a8b2d573 100644
--- a/src/simudator/processor/mia/modules/mia_memory.py
+++ b/src/simudator/processor/mia/modules/mia_memory.py
@@ -11,6 +11,11 @@ class MiaMemory(MiaBusConnector, Memory):
     to/from the mia bus.
     """
 
+    # Python does not allow multiple inherintence if more than one of the
+    # parent classes uses __slots__. Thus we also includes the __slots__
+    # from MiaBusConnector.
+    __slots__ = ("label_adress_mapping", "bus_id", "bus_control_s")
+
     def __init__(
         self,
         input_signal: Signal,
@@ -19,8 +24,6 @@ class MiaMemory(MiaBusConnector, Memory):
         bus_control_s: Signal,
         size: int = 1,
         bus_id: int = 0,
-        value_padding: int = 2,
-        address_padding: int = 2,
         name: str = "PM",
     ) -> None:
         MiaBusConnector.__init__(self, bus_control_s, bus_id)
@@ -32,12 +35,9 @@ class MiaMemory(MiaBusConnector, Memory):
             address_signal,
             size,
             name=name,
-            value_padding=value_padding,
-            address_padding=address_padding,
         )
         self.bus_control_s.add_destination(self)
 
-        # TODO: only one of these are needed
         self.label_adress_mapping = {}
 
     def update_register(self) -> None:
@@ -45,14 +45,16 @@ class MiaMemory(MiaBusConnector, Memory):
         Updates the value of the current address.
         """
         if self.read_from_bus():
-            self.memory[self.current_address] = self.signals["in_input"].get_value()
+            self._memory[self._current_address] = self.signals["in_input"].get_value()
 
     def output_register(self) -> None:
         """
         Outputs the value of the current address.
         """
         if self.write_to_bus():
-            self.signals["out_content"].update_value(self.memory[self.current_address])
+            self.signals["out_content"].update_value(
+                self._memory[self._current_address]
+            )
         else:
             self.signals["out_content"].update_value(None)
 
@@ -63,15 +65,17 @@ class MiaMemory(MiaBusConnector, Memory):
         """
         address_value = self.signals["in_address"].get_value()
         if address_value is not None:
-            self.current_address = address_value
+            self._current_address = address_value
             if self.write_to_bus():
-                self.signals["out_content"].update_value(self.memory[self.current_address])
+                self.signals["out_content"].update_value(
+                    self._memory[self._current_address]
+                )
             else:
                 self.signals["out_content"].update_value(None)
 
     def reset(self) -> None:
-        size = len(self.memory)
-        self.memory = [0 for i in range(size)]
+        size = len(self._memory)
+        self._memory = [0 for _ in range(size)]
 
     def load_from_str(self, state_string) -> None:
         """
@@ -89,7 +93,7 @@ class MiaMemory(MiaBusConnector, Memory):
                 # Last character of the adress is a semicolon
                 adress = int(line_data[0][:-1], 16)
 
-                self.memory[adress] = value
+                self._memory[adress] = value
 
                 # There is an asm instruction label
                 if len(line_data) == 3:
diff --git a/src/simudator/processor/mia/modules/micro_memory.py b/src/simudator/processor/mia/modules/micro_memory.py
index d5cb88d9b6b1db4edb0d4eb33431c9abb5a6d5dc..5995909ed6befcdbe0f8e821d4b519216bee40e8 100644
--- a/src/simudator/processor/mia/modules/micro_memory.py
+++ b/src/simudator/processor/mia/modules/micro_memory.py
@@ -17,6 +17,22 @@ class MicroMemory(Module):
     cycle.
     """
 
+    __slots__ = (
+        "curr_instr",
+        "z_flag_val",
+        "n_flag_val",
+        "c_flag_val",
+        "o_flag_val",
+        "l_flag_val",
+        "memory",
+        "halt",
+        "adress_padding",
+        "value_padding",
+    )
+
+    MEMORY_ADDRESS_PADDING = 2
+    MEMORY_VALUE_PADDING = 7
+
     def __init__(
         self,
         alu: Signal,
@@ -35,7 +51,7 @@ class MicroMemory(Module):
         o_flag: Signal,
         l_flag: Signal,
         name: str = "uM",
-        address_padding: int = 2,
+        adress_padding: int = 2,
         value_padding: int = 7,
     ) -> None:
         """
@@ -108,11 +124,11 @@ class MicroMemory(Module):
         self.c_flag_val = 0
         self.o_flag_val = 0
         self.l_flag_val = 0
-        self.memory = [0 for i in range(128)]
+        self.memory = [0 for _ in range(128)]
         self.halt = False  # Used for signalling a HALT
 
         # paddings to ensure saving to file has the correct format
-        self.address_padding = address_padding
+        self.adress_padding = adress_padding
         self.value_padding = value_padding
 
     def update_logic(self) -> None:
@@ -167,7 +183,7 @@ class MicroMemory(Module):
         if (0b0001 <= alu_field <= 0b0010) or (0b0100 <= alu_field <= 0b1000):
             # Special case for writing to the ALU from the bus, in which case
             # the FB field of the instruction is ignored (overwritten, even)
-            # (The ALU does not have an actual bus address in the MIA processor)
+            # (The ALU does not have an actual bus adress in the MIA processor)
             fb_field = 0b1000
 
         # Handle LC according to the LC field
@@ -265,14 +281,15 @@ class MicroMemory(Module):
         value 0 are not printed.
         """
         print("", self.name, "\n -----\n")
-        for address in range(len(self.memory)):
-            if self.memory[address] != 0:
-                print("", str(address), "", str(self.memory[address]), "\n")
+        for adress in range(len(self.memory)):
+            if self.memory[adress] != 0:
+                print("", str(adress), "", str(self.memory[adress]), "\n")
 
     def get_state(self) -> dict:
         state = super().get_state()
         state["memory"] = self.memory[:]
         state["halt"] = self.halt
+        state["curr_instr"] = self.curr_instr
         return state
 
     def get_gui_state(self) -> dict[str, Any]:
@@ -304,12 +321,12 @@ class MicroMemory(Module):
 
     def load_from_str(self, state_string) -> None:
         """Load the contents of the micro memory from a string consisting of a
-        row for every address. Each row should be formatted as 'ADR: VALUE'.
-        Both the address and the value should be written in hex notation.
+        row for every adress. Each row should be formatted as 'ADR: VALUE'.
+        Both the adress and the value should be written in hex notation.
         Adresses which are not specified in the string will receive the value
         0.
 
-        Example string where all addresses except for 0x00, 0x01 and 0xb0
+        Example string where all adresses except for 0x00, 0x01 and 0xb0
         receive the value 0 by default::
 
             '
@@ -325,15 +342,17 @@ class MicroMemory(Module):
         for line in lines:
             if line:  # last line is empty from split with \n
                 line_data = line.split(": ")
-                address = int(line_data[0], 16)
+                adress = int(line_data[0], 16)
                 value = int(line_data[1], 16)
-                self.memory[address] = value
+                self.memory[adress] = value
 
     def save_state_to_file(self, file_path: str) -> bool:
         content = self.name + ":\n"
         for index, value in enumerate(self.memory):
-            content += str(hex(index)[2:].rjust(self.address_padding, "0")) + ": "
-            content += str(hex(value)[2:].rjust(self.value_padding, "0"))
+            content += (
+                str(hex(index)[2:].rjust(self.MEMORY_ADDRESS_PADDING, "0")) + ": "
+            )
+            content += str(hex(value)[2:].rjust(self.MEMORY_VALUE_PADDING, "0"))
             content += "\n"
 
         content += "\n"
@@ -341,7 +360,7 @@ class MicroMemory(Module):
 
     def get_largest_mem_adr(self) -> int:
         """Helper function for pretty_print that returns the length of
-        the largest address in the memory to print for a module.
+        the largest adress in the memory to print for a module.
         """
         return len(str(len(self.memory)))
 
diff --git a/src/simudator/processor/mia/modules/micro_pc.py b/src/simudator/processor/mia/modules/micro_pc.py
index 38d884c8f746beb40bc0be29b0c934b2916968a7..efaaeb27dc330f321d87efc52e5c299380f3d1d2 100644
--- a/src/simudator/processor/mia/modules/micro_pc.py
+++ b/src/simudator/processor/mia/modules/micro_pc.py
@@ -11,6 +11,8 @@ class MicroPC(Module):
     to read from or write to.
     """
 
+    __slots__ = ("value", "bit_length")
+
     def __init__(
         self,
         control_signal: Signal,
@@ -20,12 +22,10 @@ class MicroPC(Module):
         from_supc: Signal,
         to_um: Signal,
         from_um: Signal,
-        bit_length: int = 8,
         name: str = "uPC",
     ) -> None:
 
         self.value = 0
-        self.bit_length = bit_length
 
         # Signals
         signals = {
@@ -69,7 +69,6 @@ class MicroPC(Module):
     def get_state(self) -> dict:
         state = super().get_state()
         state["value"] = self.value
-        state["bit_length"] = self.bit_length
         return state
 
     def get_gui_state(self) -> dict:
@@ -82,8 +81,6 @@ class MicroPC(Module):
     def set_state(self, state: dict) -> None:
         super().set_state(state)
         self.value = state["value"]
-        if "bit_length" in state:
-            self.bit_length = state["bit_length"]
 
     def reset(self) -> None:
         """
diff --git a/src/simudator/processor/mia/modules/pc.py b/src/simudator/processor/mia/modules/pc.py
index c7ee4df7e7daae2eba2b7bc791903455cac817fc..c80424982e48899236a49592e303cabdcbfcba29 100644
--- a/src/simudator/processor/mia/modules/pc.py
+++ b/src/simudator/processor/mia/modules/pc.py
@@ -17,6 +17,11 @@ class PC(Module, MiaBusConnector):
     value on the bus. If both are true it does nothing.
     """
 
+    # Python does not allow multiple inherintence if more than one of the 
+    # parent classes uses __slots__. Thus we also includes the __slots__
+    # from MiaBusConnector.
+    __slots__ = ("bus_id", "bus_control_s", "value", "increase_by_one")
+
     def __init__(
         self,
         p: Signal,
diff --git a/src/simudator/processor/simple/simple.py b/src/simudator/processor/simple/simple.py
index 7b66364741fab4904a2eb9d0cf6c41ba42c76587..2d01160fd065a187a574c6873ab474e67db04fd6 100644
--- a/src/simudator/processor/simple/simple.py
+++ b/src/simudator/processor/simple/simple.py
@@ -15,6 +15,8 @@ class SIMPLE_CPU(Processor):
     This cpu is made to test core modules and module graphics items for these modules.
     """
 
+    __slots__ = ()
+
     def __init__(self) -> None:
         super().__init__()
         # Creating all signals
diff --git a/test/test_core/test_demux.py b/test/test_core/test_demux.py
index acf92510f17faaf59c475e6426384214ac68eec8..e4c59c3d04f7dc5f73d11c131cfabf87b5301120 100644
--- a/test/test_core/test_demux.py
+++ b/test/test_core/test_demux.py
@@ -38,7 +38,6 @@ def test_get_state():
     assert state["name"] == "Demux"
     assert state["value"] == 7
     assert state["bit_length"] == 5
-    assert state["mask"] == 31
 
 
 def test_set_state():
@@ -46,7 +45,6 @@ def test_set_state():
     state["name"] = "Demux"
     state["value"] = 6
     state["bit_length"] = 2
-    state["mask"] = 3
 
     cpu = Processor()
     from_demux = Signal(cpu)
@@ -57,10 +55,10 @@ def test_set_state():
 
     demux.set_state(state)
 
-    assert demux.name == "Demux"
-    assert demux.value == 6
-    assert demux.bit_length == 2
-    assert demux.mask == 3
+    state = demux.get_state()
+    assert state["name"] == "Demux"
+    assert state["value"] == 6
+    assert state["bit_length"] == 2
 
 
 def test_writing_to_output():
diff --git a/test/test_core/test_mux.py b/test/test_core/test_mux.py
index 7dab6d3630af58eef3411ca0f7763b6fb839bf09..fed767a99b0ebbcd6460ec126adbde0b224e6fa3 100644
--- a/test/test_core/test_mux.py
+++ b/test/test_core/test_mux.py
@@ -38,7 +38,6 @@ def test_get_state():
     assert state["name"] == "Mux"
     assert state["value"] == 7
     assert state["bit_length"] == 5
-    assert state["mask"] == 31
 
 
 def test_set_state():
@@ -58,9 +57,8 @@ def test_set_state():
     mux.set_state(state)
 
     assert mux.name == "Mux"
-    assert mux.value == 6
-    assert mux.bit_length == 2
-    assert mux.mask == 3
+    assert mux._value == 6
+    assert mux._bit_length == 2
 
 
 def test_writing_to_output():
diff --git a/test/test_core/test_register.py b/test/test_core/test_register.py
index ae6f51127da4fb86673387e86e9abb1b2b83d000..1d1d85589a2a2851b7e9cf9710282b2c4eca8180 100644
--- a/test/test_core/test_register.py
+++ b/test/test_core/test_register.py
@@ -26,7 +26,7 @@ def test_set_state():
     register.set_state(state)
 
     assert register.name == "Reg"
-    assert register.value == 14
+    assert register._value == 14
 
 
 def test_get_state():
@@ -51,4 +51,4 @@ def test_signal_propagation():
     input_s.update_value(10)
     cpu.do_tick()
 
-    assert register.value == 10
+    assert register._value == 10
diff --git a/test/test_mia/test_lc.py b/test/test_mia/test_lc.py
index aaa591c611a661a94302578b79dd0c2ba4400d0d..407979aead137cf1d3d965f5377442dbc7f822c6 100644
--- a/test/test_mia/test_lc.py
+++ b/test/test_mia/test_lc.py
@@ -84,7 +84,7 @@ def test_write_to_l_flag():
     # The loop counter will now change its value from 1 to 0 which
     # should set the L flag to 1 in the same cycle
     cpu.do_tick()
-    assert l_flag.value == 1
+    assert l_flag._value == 1
 
 
 def test_reset_l_flag():
@@ -110,7 +110,7 @@ def test_reset_l_flag():
     mM_uADR_s.update_value(10)
 
     cpu.do_tick()
-    assert l_flag.value == 0
+    assert l_flag._value == 0
 
 
 def test_lc_do_nothing():
diff --git a/test/test_mia/test_step.py b/test/test_mia/test_step.py
index 028945db7c22021a701b68765ee734d70608f9e0..e83de422418ab74ad1b6adce9b5bdba52f6e0423 100644
--- a/test/test_mia/test_step.py
+++ b/test/test_mia/test_step.py
@@ -1,3 +1,4 @@
+from simudator.core.processor import Processor
 from simudator.processor.mia.mia import MIA_CPU
 
 
@@ -16,7 +17,7 @@ def test_increment_10():
 def test_max_undo():
     cpu = MIA_CPU()
     cpu.load_state_from_file("mia_uppg3.txt")
-    max_undo = cpu.cycles_to_save
+    max_undo = Processor.CYCLES_TO_SAVE
 
     for _ in range(2 * max_undo):
         cpu.do_tick()