undocumented/illegal OpCodes im Z80

  • Es ist hier auch ganz wichtig zwischen Undokumentierten und Illegalen Befehlen zu unterscheiden. Die Undokumentierten sind absichtlich eingebaut worden, während die Illeagls nie zur Verwendung gedacht waren.


    Die Unterscheidung ist sehr sinnvoll!


    Weißt du, welche OpCodes zur einen und welche zur anderen Klasse gehören? So richtig illegale Instruktionen (mit Absturz oder NOPs als Ergebnis) kenne ich beim Z80 gar nicht (anders als beim 6502).


    Das mit dem RISC-ähnlichen Kern habe ich mir auch schon mal gedacht - nicht zuletzt angesichts der Festverdrahtung der Befehle und der nicht wenigen Ein-Byte-Opcodes. Ich suche schon seit einiger Zeit Texte zur Geschichte von RISC, die auf Inspiration der frühen 8-Bitter hinweisen. Mal schauen, ob ich da etwas finde.

  • Youngs Dokument habe ich natürlich ausführlich gelesen. Ich hab Faggin speziell zu den undokumentierten Opcodes für IX/IY in meiner letzten Mail gefragt und bin schon gespannt, was er dazu schreibt.

  • Alphabet? Naja, sieht so aus... aber im Ernst: BC ist die Abkürzung für Byte-Counter (siehe LDDR, LDIR, CPDR, INIR etc. Befehle). IX steht z.B. für IndeX Register.

    Sorry, da war ich unklar. Die Benennung der Register von A-H + L stammt ja noch aus 8080-Zeiten, und da haben z.B. DE und BC keine solche Funktionen, wie sie sie im Z80 haben (zumindest sehe ich dort keine Block-Kopier-, Block-Such- und Block-IO-Befehle; djnz fehlt da ebenfalls). Also liegt für mich die Vermutung nahe, dass sie ganz zu Beginn einfach durchs Alphabet gegangen sind, und bestimmte Buchstaben ausgelassen haben. I und J sind halt leicht einer mit dem anderen und beide mit 1 verwechselbar, speziell bei schlechten Ausdrucken; nur bei G fällt mir kein Grund ein.


    Natürlich gefällt mir Byte-Counter, Destination und Index gut, weil das ihre Funktion trefflich beschreibt. :) Ein Punkt mehr für die Truppe um Faggin, die die 8080-Mnemonics beim Z80 weg vom akademischen hin zum praktischen Einsatz geführt haben.


    MaV


    PS: Es scheint für mich ein Kniefall vor dem Z80-Team gewesen zu sein, als Intel dann dem 8086 auch Register gegeben hat, deren Bezeichnungen sich aus dem ersten Buchstaben erschließen lassen (AX - Akkumulator, BX - Basis-Register, CX - Count-Register, DX - Daten-Register).

  • Sorry, da war ich unklar. Die Benennung der Register von A-H + L stammt ja noch aus 8080-Zeiten, und da haben z.B. DE und BC keine solche Funktionen, wie sie sie im Z80 haben (zumindest sehe ich dort keine Block-Kopier-, Block-Such- und Block-IO-Befehle; djnz fehlt da ebenfalls). Also liegt für mich die Vermutung nahe, dass sie ganz zu Beginn einfach durchs Alphabet gegangen sind, und bestimmte Buchstaben ausgelassen haben. I und J sind halt leicht einer mit dem anderen und beide mit 1 verwechselbar, speziell bei schlechten Ausdrucken; nur bei G fällt mir kein Grund ein.


    Richtig, das mit B/C/D/E ist einfach druchnummeriert. Die Namen stammen dabei schon von der 8008. Blos das mit dem Auslassen stimmt nicht. In der Systematik der 8008 gab es mit M ein einziges (14 Bit) Register, das eine Speicheradresse bereitstellen konnte. Un dieses mit den 8 Bit Mitteln bearbeitbar zu machen gab es dann eben das (6-Bit) H(igh) und dsa 8 Bit L(ow) Register. Die Systematik des Assembers war da auch durchgaengig. Der speicher wurde mit M addressiert. Warum sollte man da HL schreiben? Ist doch nur unsinnige Platzverschwendung. Die 8080 fuerhrte dann ein paar Befehle ein mit denen auch BC/DE (sehr begrenzt) Addressieren konnten (LDAX/STAX), was aber immer noch nicht rechtfertigen wuerde das im Assembler zu aendern, da weiterhin nur M allgemein verwendbar war (und eine Aenderung die Sourcekompatibilitaet mit der 8008 gebrochen haette). Nichtmal mit der Z80 wurden die 3 Paare gleich verwendbar, aber da mit IX/IY es eine Reihe neuer 16 Bit Befehle gab, bei denen BC/DE zumindest als Quelle verwendbar waren, war die neue Notation sinnvoll, wenn auch nicht wirklich noetig, da man bei den 16 Bit Befehlen, wie schon bei der 8080 einfach nur das hoeherwertige Register angeben haette koennen- und IX/IY einfach nur X/Y nennen. waer auch nicht schlecht gewesen. M.E. war es eh Mist, dass LoaD anstelle von MOVe verwendet wurde ... ein Load der in den Speicher schreibt ist schon komisch. fuer mich ist das ein Store...


    (Ach ja, W/Z gab es schon bei der 8080)

    PS: Es scheint für mich ein Kniefall vor dem Z80-Team gewesen zu sein, als Intel dann dem 8086 auch Register gegeben hat, deren Bezeichnungen sich aus dem ersten Buchstaben erschließen lassen (AX - Akkumulator, BX - Basis-Register, CX - Count-Register, DX - Daten-Register).


    Noe, nicht wirklich. Es ist wiederum einfach durchnummeriert A,B,C und D jeweils mit X fuer 16 Bit, H fuer oberes Byte und L fuer unteres Byte. Und wenn man dann eines als Counter raussuchen muss, dann ist halt C naheliegend. SI, DI, BP, das sind spezielle Namen.


    Gruss H.

  • M.E. war es eh mist das LoaD anstelle von MOVe verwendet wurde ... ein Load der in den Speicher schreibt ist schon komisch. fuer mich ist das ein Store...


    SIhe's mal aus der Sicht des Speichers! :)


  • SIhe's mal aus der Sicht des Speichers! :)


    Schon klar, dann muessten aber all die transfers die vom Speicher in die CPU gehen Stores sein .... Nur als Move machts in beiden Richtungen Sinn. Davon ab, wenn ich ne CPU programmier dann seh ichs normalerweise aus CPU sicht. Aber egal, die Jungs habens so genannt, dann heists halt so.


    H.

  • Sei es nun das Alphabet oder das Akronym, nach der die Register benannt sind. Sie unterliegen danach einer Logik und sinnstiftenden Zuschreibungen (wie man aus dem Vorangegangenen ja gut heraus lesen kann). Schon deshalb ist es nicht egal, warum sie so benannt wurden, wie sie es wurden - denn auch die Ingenieure haben ja Vorstellungen umgesetzt.


    Aus der Sicht der Medienepistemologie wäre der Fall, dass "bloß das Alphabet" als Grundlage gedient hätte, sogar vielleicht noch interessanter, weil damit eine der Elektronik eigentlich fremde Tradition des Symbolischen an genau jenen Ort Einzug hielte, an dem aus Symbolen Signale werden und umgekehrt. Da muss dann sowieso ein Ordnungsprinzip gelten.

  • Also MOV ist einfach flasch, denn es ist ja kein MOVe, da die Daten nicht verschoben sondern (durch LD) ja strenggenommen nur kopiert werden. Ein MOV müsste stranggenommen das Quell-Resiter löschen.


    Aber auch nur solange man noch in der klassisch physikalischen Ansicht verharrt und glaubt, dass Dinge die man bewegt vom vorherigen Ort auch verschwinden. In der digitalen Welt gibts das ja nicht. Da wird nichts bewegt, sondern immer eine (hoffentlich singleiche) Kopie erstellt. Viele der unsinnigkeiten aktueller Rechtsinterpretationen beruhen ja auf dieser falschen interpretation - Wo eben das Laden eines Programms in den Speicher zu einem Kopiervorgang und damit einem Uhrheberrechtlich relevanten Duplikat gemacht wird (Ketzerische Frage, beim ansehen eines Bildes macht man ja auch eine Kopie, oder?).


    Ein COPY wäre von der Benennung her viel mehr logisch gewesen. Aber LD für LOAD / LADEN trifft die Sache auch ganz gut, jedenfalls ist es kein Move!


    Wenn man klassisch physikalisch denkt, dann ist auch Laden falsch. Wenn man eine Kiste auf einen Wagen laed, dann wird sie dadurch auch nicht verdoppelt/kopiert, sondern bewegt. Im Rechner wirds aber verdoppelt ...


    Das Problem mit dem LoaD in der Z80 ist, dass er in Beide Richtungen verwendet wird, Also sowohl zum Laden als auch zum Entladen. Damits von der Richtung her stimmt, muesste es Load und Store heissen: Reinladen in die CPU zur (temporaeren) Verarbeitung und rausspeichern in den Speicher zum (laengerfristigen) Speichern. Nur MOVe wie bei Intel hat mir auch nie wirklich gefallen. Es taucht zwar als abstraktion, schoen waer eigentlich alles 3 zusammen: Load/Store wenns in die Register ein und raus geht, sowie Move wenn ein Speicher/Speicher-Transfer passiert.


    Ach ja, und dann war da nicht nur die Ilusion der linearen Zeit, sondern auch die Ilusion der Existenz von Materie - alles nur leerer Raum.

  • Elektronen haben aber sowohl Masse als auch räumliche Ausdehnung - sind also Materie sogar im nicht quantenphysikalischen Sinne.

  • Sehr lustige Diskussion, auch wenn sie herzlich wenig bringt! :D
    Ob Load/LD (Z80) oder Move/MOV (x86) war mir immer relativ egal. Hauptsache man kann die selbe Befehlsschreibweise für alle Richtungen verwenden. Es werden nunmal immer Bytes und Words hin- und hergeschaufelt, ob jetzt von Speicher zum Prozessor oder andersrum, das weiß der Assembler nunmal selbst und kann es dann entsprechend übersetzen. Was ich echt blöd finde, ist, wenn zwischen Load und Store unterschieden wird oder der Befehlsname selbst schon das Register enthält, anstatt daß dieses als Parameter angehängt wird. Letzteres sorgt für eine durchgängig sauberere einheitliche Schreibweise und ein schnelleres Erlernen. Da hat Faggin im Vergleich zum 8080- und 6502-Assembler super Arbeit geleistet.
    Klar ist z.B. intern LD (DE),A ein völlig anderer Befehl als LD (HL),A, aber für den Programmierer ist es viel einfacher und sauberer, wenn er hier die jeweils gleiche Schreibweise mit üblichen verständlichen Parametern verwenden kann.


    CU,
    Prodatron

  • Sehr lustige Diskussion, auch wenn sie herzlich wenig bringt! :D


    Für mich ist das alles sehr wertvoll! Insofern will ich den Dikusssionsfluss keinesfalls abwürgen. :)

  • Da hat jeder natürlich gute Einwände und vermittelt seine Sichtweise. Nur:


    Jemand hat für den Z80 die Mnemonic LD ersonnen, und aus dem Bestand der Möglichkeiten LD zu nutzen, lässt sich eines herauslesen: Geladen wird immer in das Register/die Speicherstelle, der/die als erster Parameter angegeben wird. Das kann eine Stelle im Speicher oder ein Register des Z80 sein. Wobei ein Register auch nichts anderes als eine spezielle Speicherstelle im Prozessor ist.
    Somit ist klar, dass der LD-Befehl - so wie er für den Z80 genutzt wird - nicht aus der Sicht des Prozessors lädt und entlädt, sondern die Auswirkung des LD-Befehls aus der Sicht dieser Speicherstelle/des Registers verstanden werden muss. Oder anders formuliert: So wird der Vorgang im Prozessor mittels der LD-Mnemonic des Z80 abstrahiert.


    Ob jetzt MOVE, LOAD oder STORE besser wären, ist dann den Vorlieben der Diskutanten überlassen. Jeder einzelner Begriff davon hat ja wohl mit dem, was sich tatsächlich im Prozessor abspielt, eh nichts zu tun. Und die Wahl von LD kann man auch nicht mehr anfechten, ohne die komplette Historie des Z80 umschreiben zu müssen.
    Wir Menschen tun uns halt leichter, nicht ein völlig abstraktes Symbol dafür zu verwenden, sondern einen Begriff, der uns von irgendwoher vertraut ist. Dann "Beladen" oder "Entladen" oder "Kopieren" wir halt mal gerne. Das Prinzip ist das gleiche, wie damals als uns die Bücher, Lehrer und sonstige den Speicher als Reihen und Reihen von Kästen mit Schubladen zu erklären versuchten.

  • Ganz genau. Die Assembler-Sprache der Z80-CPU ist die erste, die ich kenne, bei der man nicht mehr auf die Art des Befehls und der Quellen/Ziele achten muß, sondern mit allgemeinen Parameter- und Befehls-Schreibweisen arbeiten kann, auch wenn am Ende ganz andere Befehle codiert werden. Das unterscheidet sie vom 6502 und 8080 und macht sie einfacher erlernbar, was ich als großen Vorteil sehe. Ein Techniker mag vielleicht anmeckern, daß es ja tatsächlich ganz verschiedene Befehle/Operationen sind, die nicht alle gleich geschrieben werden dürften (z.B. mit LD), aber schließlich soll mir ja ein Assembler die Codier-Arbeit abnehmen, anstelle, daß ich sie quasi schon im Vorfeld durch unterschiedliche Schreibweisen leisten muß. Das scheint Faggin wohl als erster richtig erkannt zu haben (oder gab's zu der Zeit schon andere?).


    CU,
    Prodatron

  • Also jetzt erinnere ich mich aber, dass es doch eine ganze Anzahl impliziter Adressierungen in Mnemonics beim Z80 gibt. Gerade bei den ganzen Einbyte-Opcodes ist doch zumindest immer der Akku enthalten. Man darf nicht den "Fehler" machen, Assembler wie eine höhere Programmiersprache zu lesen und zu lernen, sonst hat man es im Fortgang sehr schwer, wenn man an kompliziertere Programmierprojekte kommt und dann wieder maschinennah und "problemfern" denken muss. Vielleicht ist der Z80 so gesehen sogar ein Schritt weg von der "reinen Lehre" der maschinennahen Programmierung?

  • Die arithmetischen Befehle funktionieren alle nur mit dem Akku, weshalb er hier tatsächlich weggelassen werden kann. Das ist wohl, wie TFM sagte, aus 1.) Einspargründen und 2.) Kompatibilitätsgründen zum 8080 erfolgt.
    Recht hast Du bei den Bit-Shift- und Rotate-Befehlen. Hier gibt es quasi alles für alle Register, aber bei denen, die den Akku betreffen, fehlt quasi das Leerzeichen zum Parameter (blöd ausgedrückt). Da ist es allerdings auch so, daß die Befehle für die anderen Register länger und langsamer sind.

    Vielleicht ist der Z80 so gesehen sogar ein Schritt weg von der "reinen Lehre" der maschinennahen Programmierung?


    Ich würd einfach sagen, Z80-Assembler versucht die maschinencode-nahen Mnemonics ala 8080/6502 mit allgemeineren parametrisierten zu ersetzen, achtet aber noch halbwegs darauf, daß man beim Programmieren noch daran erinnert wird, daß es hier teilweise im Ergebnis Unterschiede gibt. Denn bei allen Befehlen läßt sich trotzdem noch recht gut erkennen, wieviele Bytes sie z.B. benötigen (zb: RLA und RL H, statt RL A und RL H).
    Bei den x86ern ist das viel heftiger. Da geht's tatsächlich viel stärker weg vom maschinennahen Programmieren (im Vergleich zum Z80 - es ist viel komplexer durchzublicken, was der Assembler am Ende aus dem Code macht).


    CU,
    Prodatron

  • Quote

    Also jetzt erinnere ich mich aber, dass es doch eine ganze Anzahl impliziter Adressierungen in Mnemonics beim Z80 gibt.

    Nein, genau das ist nicht der Fall. Die Mnemonics des Z80 haben (fast) keine impliziten Angaben. Es wird lediglich der Akkumulator als Parameter nicht angegeben, weil er für fast alle 8-bit Operationen als ersten Parameter implizit angenommen wird.


    ADD ist immer eine Addition, ADC immer eine Addition inkl. Carry-Bit, etc.


    EDIT:
    Die Befehle, die implizit das A-Register enthalten sind:


    DAA, RLA, RRA, RLCA, RRCA, RLD, RRD, NEG (davon sind RLA und RRA die schnelleren Varianten zu RL A und RR A)


    Des Weiteren kannst du noch diese komplexen Befehle dazurechnen:
    DJNZ, sämtliche Block-Befehle

  • Nein, genau das ist nicht der Fall.


    Und was ist mit den Block-Operationen, die sich (implizit!) immer auf das HL- und DE-Register beziehen?


    Noch ein Nachtrag zum Unterschied von "illegal" und "undocumented" Opcodes:


    In diesem Gespräch der Z80-Ingenieure geht der für die Hardware-Architektur verantwortliche Shima indirekt auf den Grund ein:


    Quote

    There were seven challenges of designing Z80. How to get higher performance than both Intel’s 8080, and also Motorola’s 6800. How to expand the number of instruction set. The next one is a most important job. How to differentiate Z80 logic from 8080 logic. Next one is usage of one-phase clock. Then chip size to be small as much as possible, and no trouble in the layout; I had a lots of trouble in layout of the 8080. The last one was how to stop the copy of layout. (...) At first in order to expand the number of instruction set with small number of transistors I introduced two prefix in the instruction. One for index register X, one for the index register Y. If the prefix instruction was added to certain instruction, including the old 8080 instruction, and the new instruction set, the prefix instruction is able to redirect the selection of each register to index register X or Y. And this was our pride for not only 16-bit index register, but also the lower or higher of index register. But we didn’t publish that one.


    Wenn die Präfixe also prinzipiell vor jeden Opcode gehängt werden können, rufen sie natürlich auch Funktionen auf, die nicht im Sinne des Erfinders sind. In Youngs Beitrag zu den "undocumented Opcodes" des Z80 ist das mit den Prefixen ja sehr ordentlich aufgelistet.

  • Und was ist mit den Block-Operationen, die sich (implizit!) immer auf das HL- und DE-Register beziehen?


    Die hab ich erwähnt:

    Quote

    Des Weiteren kannst du noch diese komplexen Befehle dazurechnen:


    DJNZ, sämtliche Block-Befehle

    Wenn du die Gesamtheit der möglichen Befehle hernimmst, ist das eine sehr geringe Zahl, und verglichen mit dem 8080er sehr transparent.



    MaV