Klassenstruktur, Relationen und Serialisierung

  • C#
  • .NET (FX) 3.0–3.5

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Klassenstruktur, Relationen und Serialisierung

    Hallo,
    für einen Hardwaresimulator, der grob und vereinfacht die Funktionsweise eines Computers zeigen soll, bin ich nun daran mein Konzept weiter auszufeilen.
    Meine Hauptkomponenten, die miteinander kommunizieren sollen wie Register und Speicher habe ich schon programmiert.
    Allerdings werden alle Komponenten von einer Wrapperklasse die ich "Simulator" nenne initialisiert und sollen von dieser auch die Register-Wert-Maxima erhalten, die der Benutzer einstellen kann.
    Da Kommunikation zwischen den einzelnen Objekten ermöglicht werden muss, habe ich mich dazu entschlossen die Simulator-Klasse als Singleton zu programmieren. So muss ich nicht jedem Register/jeder anderen Komponente die Simulator-Klasse mitgeben.
    Probleme hierbei habe ich jetzt bei dem Serialisieren und Deserialisieren. Die Einstellung der einzelnen Komponenten hängt von den Einstellungen ab, die der User im Simulator vornimmt.

    Beispiel: Benutzer legt Maximum für die Werte fest -> Alle Register, Speicher benötigen diesen Wert zur Verwaltung ihrer Werte.
    Das daraus resultierende Problem ist, dass beim Deserialisieren diese zentralen Maxima der Werte zuerst vorliegen müssen, sodass Speicher usw. deserialisiert werden kann. Denn diese Werte müssen vorhanden sein.

    Klassen (zur Verdeutlichung):
    Spoiler anzeigen

    C#-Quellcode

    1. public class Simulator {
    2. private static Simulator _instance;
    3. public static Simulator Instance {
    4. get {
    5. if (_instance == null)
    6. _instance = new Simulator();
    7. return _instance;
    8. }
    9. }
    10. private Simulator() {
    11. // Initialisieren der Komponenten
    12. Ram = new Memory(MemoryLength);
    13. }
    14. // Komponenten
    15. public Memory Ram { private set; get; }
    16. // Benutzerdefinierte Werte
    17. public int MemoryLength { get; set; } = 1000;
    18. public int MaxValue { get; set; } = 19999;
    19. }
    20. public class Memory : IEnumerable<MemoryItem> {
    21. private List<MemoryItem> _memList;
    22. private int _index = 0;
    23. public Memory(int cap) {
    24. _memList = new List<MemoryItem>(cap);
    25. for (int i = 0; i < cap; i++)
    26. Add(new MemoryItem());
    27. }
    28. public Memory() : this(Simulator.Instance.MemoryLength) {
    29. }
    30. public void Add(MemoryItem item) {
    31. if (_index >= _memList.Capacity)
    32. throw new IndexOutOfRangeException();
    33. item.Address = _index++;
    34. _memList.Add(item);
    35. }
    36. public IEnumerator<MemoryItem> GetEnumerator() => _memList.GetEnumerator();
    37. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    38. }
    39. public class MemoryItem : IMemoryItem {
    40. private int _value, _max;
    41. public MemoryItem(int max) {
    42. _max = max;
    43. }
    44. public MemoryItem() : this(Simulator.Instance.MaxValue) {
    45. }
    46. public int Address { get; set; }
    47. public int Value {
    48. get { return _value; }
    49. set {
    50. if (_value == value)
    51. return;
    52. else if (_value < 0)
    53. _value = 0;
    54. else if (_value > _max)
    55. _value = _max;
    56. else
    57. _value = value;
    58. RaisePropertiesChanged("Value", "Hi", "Lo");
    59. }
    60. }
    61. public int Hi { get { return Value / 1000; } }
    62. public int Lo { get { return Value - Hi * 1000; } }
    63. public XmlSchema GetSchema() => null;
    64. public void ReadXml(XmlReader reader) {
    65. //Deserialization
    66. }
    67. public void WriteXml(XmlWriter writer) {
    68. //Serialization
    69. }
    70. public event PropertyChangedEventHandler PropertyChanged;
    71. protected void RaisePropertiesChanged(params string[] propNames) {
    72. if (PropertyChanged != null)
    73. foreach (var name in propNames)
    74. PropertyChanged(this, new PropertyChangedEventArgs(name));
    75. }
    76. }
    77. public interface IMemoryItem : IXmlSerializable, INotifyPropertyChanged {
    78. int Address { get; set; }
    79. int Value { get; set; }
    80. int Hi { get; }
    81. int Lo { get; }
    82. }


    Wie sollte ich also vorgehen? Der Speicher wird über ein DGV dargestellt.
    imo geht das mit einer Klassenstruktur nicht gscheit abzubilden.

    Hier liegt ja eine 1:n - Relation zw. Setting und Register.
    Also ein Setting wird in vielen Registern verwendet.

    also zur Not und im Einzelfall ist das möglich, aber ziemlich gekrampft.
    Ich würd aber eh das ganze so angehen, erstmal ühaupt ein relatinales Datenmodell zu erstellen.
    Ist übersichtlicher als ein Konglomerat von selbstgebastelten Klassen, und hat auch mehr Möglichkeiten der "Beziehungs-Gestaltung"
    Ich wollte es eben zur Übung so machen. Aber es muss doch sinnvoll zu bewerkstelligen sein. Wenn zuerst die SimulatorConfiguration deserialisiert wird und dann erst die Komponenten, die auf die Settings zugreifen sollen, muss das doch so hinhauen.
    Allerdings kann ich die SimulatorConfiguration nicht an die Komponenten übergeben, da der XmlSerializer den Standard-ctor aufruft. D.h. ich müsste/könnte auf ein Singleton zurückgreifen (?) Was meinst du?

    Fortender schrieb:

    Aber es muss doch sinnvoll zu bewerkstelligen sein.
    Nein, nicht sinnvoll, jdfs. nicht mit Standard-Serialisierung.
    Serialisierung folgt jedem Verweis und versucht das verwiesene auch zu serialisieren.
    Verweisen vier Objekte auf dasselbe Setting, dann wird dieses Setting vier mal serialisiert, und's DeSerialisieren failt dann.

    Dass mehrere Objekte auf dasselbe Setting verweisen, ist nur in einem relationalen Datenmodell zu fassen.
    typDataset kann sowas fassen, und auch als xml persistieren.
    OR-Mapper können sowas auch fassen, aber nicht als xml persistieren - sondern sind immer an eine Db gebunden.
    Hi
    sofern ich das richtig geblickt habe... Was hältst du davon:
    Klasse Memory
    - Lege einen Puffer als int- oder byte-Array an. Dieser dient dir als "Memory". Zusätzlich dazu legst du ein weiteres Array an, in dem du die Register speicherst. Außerdem kannst du auch noch einen Stapel realisieren (der womöglich aber auf dem "Memory" arbeiten sollte)
    - Programme werden im "Memory" abgelegt und ähnlich Assembler gelesen/geschrieben
    - Read/Write- und Push/Pop-Operationen funktionieren wie bei einem einfachen Assembler
    - Simulator-Referenz wird nicht mitserialisiert

    Zusätzlich dazu sollte es natürlich auch GPU-Memory, usw. geben, sofern du es mit der Simulation so weit treiben willst. Auf diese variablen Inhalte würde ich entsprechend dann in der Simulator-Klasse verweisen, sodass man die in einem Rutsch wegserialisieren kann (bspw. eine Liste von "Speichereinheiten", wobei zusätzlich immer abgespeichert wird, welche Rolle die Instanz erfüllt).

    Ich würde, wenn Serialisierung, dann definitiv binäre Serialisierung wählen und die üblichen Serialisierungs-Muster verwenden.

    Viele Grüße
    ~blaze~

    ErfinderDesRades schrieb:

    jdfs. nicht mit Standard-Serialisierung

    Sagen wir im Simulator liegt: SimulatorConfiguration, Ram und weitere Komponenten vor. In allen Komponenten, welche auf die Settings zugreifen wollen, liegt dann eine Eigenschaft vor, die direkt auf Simulator.Instance.SimulatorConfiguration zugreift. Diese Eigenschaft bekommt dann das Attribut [XmlIgnore] und wir ja somit beim Serialisieren nicht berücksichtig

    ~blaze~ schrieb:

    Klasse Memory

    Eine generische Klasse Memory habe ich schon. Diese sollte eigentlich meine Zwecke erfüllen. Ich möchte jeder Speicherzelle eine Adresse zuweisen. (da vereinfacht bei 0 beginnend und incremental)
    Dazu habe ich mir ein Interface IMemoryItem geschrieben, welches IXmlSerializable und INotifyPropertyChanged implementiert und die Eigenschaft Address mit sich bringt. Meine generische Klasse setzt voraus, dass
    der Typ T dieses Interface implementiert. Mein Speicher selbst implementiert IEnumerable und dahinter arbeitet eine ganz normale generische List, mit dem Unterschied, dass jedes Item, welches hinzugefügt wird, ordentlich
    adressiert wird. Das Ganze sieht dann so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. public interface IMemoryItem : INotifyPropertyChanged, IXmlSerializable {
    2. int Address { get; set; }
    3. }
    4. public class Memory<T> : IEnumerable<T> where T : IMemoryItem, new() {
    5. private List<T> _memList;
    6. private int _index = 0, _pos = 0;
    7. public Memory(int capacity) {
    8. _memList = new List<T>(capacity);
    9. for (int i = 0; i < capacity; i++)
    10. Add(new T());
    11. }
    12. private void Add(T item) {
    13. if (_index >= _memList.Capacity)
    14. throw new IndexOutOfRangeException();
    15. item.Address = _index++;
    16. Add(item);
    17. }
    18. private void Add(object item) {
    19. _memList.Add((T)item);
    20. }
    21. //public T this[int i] => _memList[i];
    22. public int Position {
    23. get { return _pos; }
    24. set {
    25. if (value >= Capacity)
    26. throw new IndexOutOfRangeException();
    27. else
    28. _pos = value;
    29. }
    30. }
    31. public IEnumerator<T> GetEnumerator() => _memList.GetEnumerator();
    32. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    33. }



    Wenn ich jetzt einen Arbeitsspeicher simulieren will, brauche ich nur noch eine Datenklasse, welche alle nötigen Eigenschaften besitzt und die benötigte Schnittstelle implementiert, z.b. so:

    C#-Quellcode

    1. public class RamItem : IMemoryItem {
    2. public Address { get; set; }
    3. public Value { get; set; }
    4. public Opcode { get; set; }
    5. public Operand { get; set; }
    6. // Implementierung von IXmlSerializable und INotifyPropertyChanged
    7. }


    Jeder Datenwert setzt sich hier aus Opcode und Operand zusammen. Beispielsweise: 10 999 -> Opcode: 10; Operand: 999
    IXmlSerializable brauche ich nicht unbedingt, das war dazu gedacht um nur Address und Value zu speichern, da der Rest sich ja aus Value zusammensetzt, aber das selbe kann man auch mit XmlAttributen erreichen.

    Soweit mein Gedankengang

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Fortender“ ()

    Fortender schrieb:

    ErfinderDesRades schrieb:

    jdfs. nicht mit Standard-Serialisierung

    Sagen wir im Simulator liegt: SimulatorConfiguration, Ram und weitere Komponenten vor. In allen Komponenten, welche auf die Settings zugreifen wollen, liegt dann eine Eigenschaft vor, die direkt auf Simulator.Instance.SimulatorConfiguration zugreift. Diese Eigenschaft bekommt dann das Attribut [XmlIgnore] und wir ja somit beim Serialisieren nicht berücksichtig
    Wie du wolle.
    Dann erhälst du deserialisiert Komponenten, die auf keinen Simulator verweisen.
    Kann man machen, und kann man evtl. auch nachbessern, aber "Standard-Serialisierung" ist das dann nicht mehr. Zumal ich annehme, derlei Probleme tauchen noch einige mehr auf.
    Wenn Simulator ein Singleton ist, macht es doch nichts, wenn es nicht serialisiert wird oder sehe ich das falsch? Die Einstellungen müssen natürlich irgendwie gespeichert werden, aber das ist ja nicht das Problem der Klassen selbst, sondern des umgebenden Rahmens. Es reicht, wenn die Klassen selbst ihre zugrundeliegenden Daten serialisierbar machen.
    Ich persönlich hätte auch die Implementation des Memorys anders gestaltet, nämlich wie oben beschrieben. Xml-Serialisierung bläht das übertrieben groß auf. Ich halte auch die Referenz auf die Simulator-Klasse für unnötig, weiß aber auch nicht, wie du dir die Simulation vorstellst.
    Ich hätte jetzt gesagt, ein PC besteht bspw. aus Primärkomponenten
    - Prozessor(en), bzw. Prozessorkerne
    - Speicher (Drive, Memory)

    und Sekundärkomponenten (z.B. Bildschirm, Tastatur, Maus, Soundkarte, Grafikkarte, usw.)

    Diese hätte ich insofern auch so implementiert, dass es je eine Klasse für jede Komponente gibt und diese dann wieder in ihre einzelnen Unterkomponenten zerlegt werden, wie z.B. Prozessoren in Register, Ausführung, o.Ä.
    Die einzigen Komponenten, die Zustände bereithalten, sind meines Erachtens ja Speicher, Register und möglicherweise Sekundärkomponenten, sofern stack und heap im Memory realisiert werden.

    Es kommt aber halt auf die Herangehensweise an. Mit meinem Modell bist du wohl sehr nah an der Realität.

    Viele Grüße
    ~blaze~

    ~blaze~ schrieb:

    Wenn Simulator ein Singleton ist, macht es doch nichts, wenn es nicht serialisiert wird oder sehe ich das falsch?

    Ich will halt gerne alles in einer Datei speichern. Ist das für unterschiedliche Typen auch ohne weiteres mit nem BinaryFormatter machbar?

    ~blaze~ schrieb:

    Es reicht, wenn die Klassen selbst ihre zugrundeliegenden Daten serialisierbar machen

    Reicht es also die Attribute Serializable und NonSerializedzu vergeben, oder muss ich da noch mehr fummeln?

    ~blaze~ schrieb:

    Ich persönlich hätte auch die Implementation des Memorys anders gestaltet

    Eine Zelle im Arbeitsspeicher besteht aus (Adresse), Value und den sich daraus ergebenden Opcode und Operanden.

    ~blaze~ schrieb:

    Ich hätte jetzt gesagt, ein PC besteht bspw. aus Primärkomponenten

    Der Simulator soll das Zusammenspiel von meinen drei Hauptkomponenten Speicher, Steuerwerk und ALU verdeutlichen. Im Steuerwerk liegt ein Instruktionsregister, Mikrobefehlsspeicher und Programmzähler. "Kommuniziert" wird über eine Art Bussystem (Daten -und Adressbus)
    wobei ein solcher Bus zur Vereinfachung als Register dargestellt wird. Die Komponenten erhalten ihre Funktionalität durch Buttons (auch stark vereinfacht dargestellt), je einer steht für einen Mikrobefehl. Im Mikrobefehlsspeicher liegen einzelne Makros bestehend aus den Mikrobefehlen vor.
    Im Instruction Register wird Opcode von Operand getrennt, wie oben schonmal gezeigt. Ich will jetzt auch nicht mit dem kompletten Konzept langweilen. :D

    ~blaze~ schrieb:

    Ich halte auch die Referenz auf die Simulator-Klasse für unnötig

    Bei folgendem Deserialisierung-Ablauf:
    1. Config deserialisieren bzw. laden
    2. Mikrobefehlsspeicher laden
    3. Ram laden
    stellt sich mir die Frage, wie du ohne Referenz auf die Simulator-Klasse auf die Config zugreifen möchtest. In der Konfiguration stehen die Längen beider Speicher drin. Die Kapazitäten der Speicher sind fest und sollen zu Beginn vom User bestimmt werden können. Nach diesen Werten errechnet sich dann das Maximum für den Wertebereich. Meine Register/Values lassen keine Überläufe zu, sondern schneiden die Werte auf [0-Max] zurecht. Darum muss jede Komponente, die ihre Werte verwaltet auch auf die Konfiguration zugreifen können. Sinnvoller wäre dann wohl aus der Konfiguration ein Singleton zu basteln, oder nicht?

    Grüße

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Fortender“ ()

    Ja, es ist im Falle der BinaryFormatter-Klasse tatsächlich einwandfrei möglich, wenn ich mich recht erinnere.

    Fortender schrieb:

    Reicht es also die Attribute Serializable und NonSerializedzu vergeben, oder muss ich da noch mehr fummeln?

    Sollte funktionieren.

    Fortender schrieb:

    Eine Zelle im Arbeitsspeicher besteht aus (Adresse), Value und den sich daraus ergebenden Opcode und Operanden.

    Oder aber, eine Zelle besteht nur aus dem Wert. Ein Zeiger ist der Index des Array-Eintrags, der Opcode und die Operanden werden in solche Werte codiert. Somit hast du einen "Decoder", der dir die Byte-Darstellung in Opcode, usw. zurückkonstruiert. Ich kann mir schon vorstellen, wie du dir das gedacht hast, nur schätze ich, dass du durch die großen Mengen an Daten später womöglich größere Probleme haben wirst, das mit Vererbung zu lösen. In der Praxis weiß der Speicher eigentlich ja auch nicht, ob das ein Programm ist, das an der Stelle steht.
    Übrigens: Den Bus könntest du auch als eigene Klasse modellieren, wenn du möchtest.

    Fortender schrieb:

    Sinnvoller wäre dann wohl aus der Konfiguration ein Singleton zu basteln, oder nicht?

    Wie wäre es damit? Du fügst eine weitere Klasse Setup hinzu, ähnlich der Simulator-Klasse, die ein solches "Setup" aus allen Komponenten über ISerializable deserialisiert und serialisiert und unabhängig davon erzeugen kann. Die Komponenten selbst könnten dabei ebenfalls irgendwelche Helferroutinen bereitstellen, die die Daten bereitstellen oder tatsächlich selbst serialisierbar sein. Du kannst im Konstruktor theoretisch ja dann die Referenz auf die Setup-Instanz bereitstellen, sowie Speichergröße, usw.
    In meinem Modell ist die Speichergröße konstant, sobald anfänglich festgelegt. Wenn du das ändern möchtest, kannst du auch einfach eine Methode einbauen, die ermöglicht, dass die maximale Größe des Speichers sich ändert. Beachte aber, dass das ggf. zu einem out-of-memory führen kann (Abhilfe würde eine Fragmentierung der Speicherzellen, wie bspw. bei einem Array von "großen" Arrays erlauben).
    Singletons sind halt in vielen Fällen unschön, insbesondere bei Konfiguration, usw. mMn. daher versuche ich das immer, über Strukturen oder Instanzen von Klassen zu lösen. Klar, man muss das dann immer weitergeben, aber ich sehe das weniger als Nachteil, als als Vorteil aufgrund der Dynamik.

    Viele Grüße
    ~blaze~
    Ich werde mal versuchen die Serialization jetzt so wie von dir beschrieben umzusetzen.

    ~blaze~ schrieb:

    Übrigens: Den Bus könntest du auch als eigene Klasse modellieren, wenn du möchtest.

    Bisher siehts so aus: Counter sind maximal auf einen integer von 999 zu bringen. Dazu habe ich mir eine Klasse geschrieben, die wie vorhin beschrieben, dafür sorgt, dass das Maximum eingehalten wird. Ein Register kann aber Werte von 0-(z.b.)19999 annehmen. Dieser Wert wird aufgespalten in Hi-Code und Lo-Code also Opcode und Operand. Deshalb erbt meine Register-Klasse von der Counter-Klasse. In der Counter-Klasse sind schon alle nötigen Interfaces für Serialisierung und bidirektionales Databinding implementiert, sodass ich die Register-Klasse sogar für meine RamItem-Klasse verwenden kann. RamItem erbt somit von Register. So dachte ich mir das.
    In gewisser Hinsicht sind Register von der Ansicht ja nicht unbedingt verschieden von spezifischen Speicherzellen, also würde diese Ansicht schon Sinn machen. Aber ggf. wäre es wirklich besser, ein int- bzw. long-Array zu verwenden, um maximale Agilität zu ermöglichen. Du kannst dann ja bspw. ein Set aus 16 Registern verwenden, indem du eine spezifische Implementation erstellst, die bspw. so aussehen könnte

    C#-Quellcode

    1. public abstract class MemoryUnit
    2. {
    3. public long Size { get; }
    4. public abstract long GetCell(int index);
    5. public abstract void SetCell(int index, long value);
    6. }
    7. public class Registers : MemoryUnit
    8. {
    9. public long GetCell(RegisterIdentifier register);
    10. public void SetCell(RegisterIdentifier register, long value);
    11. }
    12. public enum RegisterIdentifier
    13. {
    14. RAX = 0,
    15. RBX,
    16. RBP,
    17. RSP,
    18. //... Alle Register auflisten
    19. }

    So in der Art z.B.
    In der jeweiligen Implementierung verwendest du dann einfach ein Array, den RegisterIdentifier verwendest du einfach als Index.
    Warum möchtest du eigentlich Maximum und Minimum auf Werte begrenzen, die nicht 2^n-1 sein können?

    Viele Grüße
    ~blaze~

    ~blaze~ schrieb:

    Aber ggf. wäre es wirklich besser, ein int- bzw. long-Array zu verwenden, um maximale Agilität zu ermöglichen

    Ich weiß nicht genau warum ich es nicht bei einer List<T> belassen kann, aber behaupte ich könnte auch einfach ein T[] Array verwenden und manuell einen Enumerator implementieren. Ich möchte natürlich auch nicht, dass der User riesige Maxima festlegen kann, weil es ja auch noch im DGV dargestellt werden soll und es so nur zu Rucklern kommen würde wenn ich mich nicht auch noch dadrum kümmer.

    ~blaze~ schrieb:

    Soll nur das Konzept der von-Neumann-Architektur verdeutlicht werden?

    Genau das. Deshalb auch der simple Aufbau. Den Simulator an den ich mich anlehne heißt Johnny, allerdings habe ich ihn bereits komplett nachgebaut in VB und erweitert sodass man unteranderem auf Arrays indiziert zugreifen kann. Da ich da aber ziemlichen Murks gebaut habe, möchte ich ein komplettes Redesign was das Codebehind angeht.

    ~blaze~ schrieb:

    wie es in Realität auch ist und die OP-Codes so übersetzen, dass dort die Update-Events ausgeführt werden

    Ok, könntest du mir dann nochmal schildern wie du das mit den OP-Codes bewerkstelligen würdest? Mein Opcode ist letztenendes Value / 1000 (Ganzzahldivision). Der Operand wäre dann Value - Opcode * 1000.
    Opcode ist somit nur ein Zeiger auf einen Eintrag im Mikrobefehlsspeicher.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Fortender“ ()

    Zuerst wäre ein Regelsatz recht sinnvoll, nach der du vorgehst. Z.B. soll ein Befehl (= Opcode) in den ersten 8 Bits festgelegt werden, bei Werten von 250 bis 255 (Ergo hast du 5*256+249 mögliche Opcodes), steht das 2. Byte für einen dort näher spezifizierten Befehl. Alternativ kannst du auch einfach 2 Byte große Befehle verwenden. Pro Wert wird festgelegt, wie groß der Befehl ist (daraus ergibt sich, wo der nachfolgende Befehl steht), ob es sich um einen Sprung handelt und wohin der Sprung geht, ob die Register gesichert werden sollen (das ist z.B. bei einem Methodenaufruf der Fall), usw. und im Anschluss steht dann, welche Operanden benutzt werden. Das kann bspw. in zwei 8-Bit stehen. Ich hab' mich bisher nicht dazu durchgerungen, mich näher mit der Spezifikation von x64 zu befassen, hab' also nur noch ein paar sehr verblasste Erinnerungen. Mit IL bin ich eher bewandert.
    Die Opcodes sollten möglichst effizient gemappt werden können, das geht z.B., indem man die Opcodes als Indices ansieht und entsprechend auf Einträge in einem Tabellenarray ansieht. Dort können dann bspw. Delegaten stehen, die die Aufgaben erfüllen (z.B. Add, Jump, usw.). IL-JITC und Expressions lass ich mal weg, das bläht das ganze ziemlich auf, wobei die schon echt nicht unpraktisch wären.

    Generell wäre wohl folgendes recht sinnvoll:
    - eine Liste aller Opcodes aufstellen (dazu zählen Arithmetische Operationen, Sprünge, Aufrufe, (Traps, Errors), usw. Gleitkommaoperationen)
    - die Liste zählen und eine sinnvolle Zuordnung und Unterteilung für die Opcode finden
    - diese in einem Array darstellen und die Funktionalität bspw. über Delegaten implementieren, die Zugriff auf Memory, usw. erhalten (z.B. mov [ptr], 0: setup.Memory.SetCell(ptr, 0), SetCell löst ein Ereignis aus oder markiert eine Zelle als verändert, das Update wird im zweiten Fall später ausgewertet)

    Viele Grüße
    ~blaze~