Hallo,
16 Befehle, 16-Bit Daten, 16-Bit Adressen, 16(+1) Register: Du magst die 16, oder? Für eine 16-Bit-CPU sind 64 KB physischer Adressraum definitiv zu wenig. Das tut gleich noch ein zweites Mal weh, weil sich Code, Daten und Stack diese 64 KB auch noch teilen müssen. Jeder Befehl hat 2 Byte, jede Konstante hat 2 Byte und da du keine komplexeren Befehle hast, brauchst du auch noch sehr viele davon.
Grundsätzlich: Du möchtest mindestens einen 24-Bit Adressraum und mindestens 32 (besser: 64, wegen Erweiterungen) Befehle. Alles darunter macht keinen Spaß beim Programmieren. (Ja, ich weiß, ein Z80 hat auch nur einen 16-Bit Adressraum, aber als über 35 Jahre alter 8-Bitter darf der das.)
An Logik bietest du AND, OR und XOR an: AND und OR braucht man ständig, XOR dagegen fast nie. Ersetze es lieber durch NOT (man braucht Negation und entweder Konjunktion oder Disjunktion, um alle anderen logischen Funktionen nachbilden zu können).
Deine Sprungbefehle sind etwas dürftig. Normalerweise möchte man JUMP (unbedingt), BRANCH (bedingt), CALL (mit Rücksprungmöglichkeit) haben. Dazu gehört dann natürlich auch ein RET, für Interrupts ein IRET. Wenn du PC als direkt adressierbares Register hat, kann man das aber alles relativ einfach nachbauen.
In deinem Datenblatt steht drin, dass dein JUMP entweder die auf das JUMP folgende Adresse anspringt (wenn Bedingung falsch) oder die auf JUMP folgende Adresse als Befehl ausführt (wenn Bedingung wahr). Ich glaube, das willst du nicht. Außerdem kann dein JUMP nur eine zur Compilezeit bekannte, konstante Adresse anspringen, keine zur Laufzeit errechnete. Wenn du PC als gewöhnliches Register betrachtest, dann braucht dein JUMP kein eigenständiger Befehl zu sein.
BRANCH-Befehle sind meist PC-relativ und können nicht über den gesamten Adressraum springen. Statt einer vollen 16-Bit-Adresse reichen vier Bedingungsbits und 12 Bit Sprungweite (8 KB, da jeder Befehl auf einer geraden Adresse liegen muss) eigentlich dicke aus. An Bedingungen würde ich mindestens A==B, A<B, A<=B, immer und deren Negationen anbieten ("nie" als negiertes "immer" ist dann ein NOP).
Die Befehle IN/OUT finde ich sehr hässlich gelöst. Wenn die Tabelle deine MMU-PageTable ist, dann kann man darauf nicht wirklich zugreifen. Wenn ich Page N (aus einem Taskregister) ändern möchte, dann steht N in einem Register und ist keine Konstante. Außerdem kannst du entweder IN/OUT für allgemeine Hardwarezugriffe vorsehen (damit hast du dann einen zweiten Bus, der z.B. nur im Kernelmodus zugreifbar ist) oder du lässt die Befehle ganz weg und blendest Hardware (inklusive MMU) in den Adressraum ein.
Flags sind an sich eine feine Sache, um relativ einfach Branches anzubieten. Um mit Zahlen größer als 16 Bit zu hantieren, musst du in der Lage sein, Übertrage (Carry) zu verarbeiten. Andere praktische Flags wären dann der CPU-Modus, ob die MMU aktiv ist oder nicht (nach Reset: MMU deaktiviert), ob Interrupts aktiv sind und das, was die Bedingungen ermöglicht.
LOAD und STORE finde ich etwas seltsam, weil die zusätzlich noch eine Addition/Subtraktion beinhalten. Vielleicht verstehe ich es gerade auch einfach nicht.
Deine Interruptlogik klingt kaputt (auch vom Deutsch her). Dein 64-Word-RAM ist zufällig die gleiche Tabelle, die auch die MMU enthält? Du schreibst PC an Adresse 17, liest dann die Adresse der ISR auf Adresse 18 und überschreibst danach Adresse 18 mit irgendwelchen Bits. Das heißt, während eine ISR aktiv ist, darf kein anderer Interrupt behandelt werden, da sonst eine zufällige Adresse angesprungen wird. Da du keine Befehle hast, die Interrupts abschalten können, kann das jederzeit passieren.
Dein Datenblatt enthält keine Informationen zum Alignment (ich vermute mal ein 16-Bit-Alignment für alles, d.h. du brauchst nur 15 Bit für eine Adresse). Wenigstens eine Rechtschreibprüfung hättest du ja spendieren können, so sieht das ziemlich hingeklatscht aus.
Was mir persönlich komplett fehlt, ist die Anbindung an den Rest der Welt. Eine CPU ist ja nicht nur zum Selbstzweck da, sondern soll ja auch irgendwas mit Ein- und Ausgaben tun. Ich vermute, dass du da nicht drüber nachgedacht hast und daher alles außer MMU in den Speicher gemappt werden muss. So sieht das Interrupthandlung auch aus.
Bevor du dich daran machst, deine CPU in VHDL/Verilog/xxx zu implementieren, solltest du einen Simulator in einer Programmiersprache deiner Wahl schreiben (je nachdem, was du gut kannst) und dann mal Anwendungen dafür schreiben. Dann siehst du, was verbesserungswürdig ist, fehlt oder einfach nur kaputt ist.
Vermutlich habe ich noch einige Punkte vergessen zu erwähnen. Auf SHL, SHR, SHAR und ROR bin ich nicht eingegangen, weil ich davon keine Ahnung habe. Wie negative Zahlen realisiert werden und ob die Unterstützung dafür ausreicht, weiß ich nicht (vermute aber mal ein nein, weil ein SIGN-Flag fehlt). Außerdem fehlt mir eine übersichtliche Bitdarstellung der Opcodes (kann man sich aber vermutlich aus dem Rest denken).
Ich gebe das Datenblatt hiermit an den Autor zurück.
Gruß,
Svenska