Die illegalen OpCodes des C64
Da sind wir also, bei den „sagenumwobenen“ illegalen OpCodes. Eigentlich ist dies kein Thema für Einsteiger, aber ich möchte in den Grundlagen einmal alle Befehle erwähnt haben. Als erstes sollte ich aber darauf hinweisen und warnen (das mache ich hier noch häufiger), dass die hier aufgeführten Befehle teilweise nicht ganz unproblematisch sind. Ihr solltet sie also mit Bedacht einsetzen.
Wir haben jetzt alle 56 Befehle des Prozessors kennengelernt, die offiziell zur Verfügung stehen. Wie wir aber wissen, besitzt der C64 einen 8-Bit-Prozessor, somit sind theoretisch 256 unterschiedliche Befehle möglich. Bei unseren 56 bisherigen kommen wir, wenn man die unterschiedlichen Adressierungsarten mit einbezieht, auf 151 verwendete Bytes. Bleiben also noch 105 mögliche Befehle übrig. Dabei handelt es sich meistens um eine Kombination aus mehreren offiziellen Befehlen (z. B. erst ein ASL und dann ein ORA). Diese mehr oder weniger sinnvollen Befehle, werden häufig als ‚illegal‘, ‚extra‘ oder ‚undocumented‘ bezeichnet. Einige Befehle haben sogar mehrere OpCodes, obwohl es sich immer um denselben Befehl handelt, dort wird also keine andere Adressierungsart verwendet.
Hardware-Exkurs: Wieso gibt es solche OpCodes überhaupt?
Ich will hier nicht wirklich in die Details gehen, es soll nur eine kurze oberflächliche Erklärung werden.
Der 6510/6502 benutzt keine MicrocodesInfoDie Befehle der CPU sind nicht fest verdrahtet, wie z. B. bei RISC-Prozessoren, sondern in einem ROM gespeichert., um die Befehle zu dekodieren, wie andere CPUs. Das „Instruction-Register“ und der Zyklus aus der „Timing Generation Logic“ werden im „Decode ROM“ zusammengefasst. Diese besteht aus 130 Zeilen zu je 21 Bits. Jede Zeile enthält nun Bit-Muster, die zur Identifikation der Befehle dienen. Dabei wird festgelegt, welche Bits im Muster 0 und welche 1 sein müssen und bei welchem Zyklus das stattfindet. Trifft ein Muster zu, so liefert die Zeile eine 1. Jeder Befehl ist hier also mit einem Bit-Muster hinterlegt, verwendet man einen illegalen OpCode, dann kann dieser auch dekodiert werden. Aber durch die ungeplanten Bit-Muster ist es nun möglich, dass mehrere Zeilen eine 1 liefern und wir so die eben erwähnte Kombination von bekannten Befehlen erhalten.
Wie kann man die Befehle nun verwenden?
Zunächst mal ist wichtig, dass das System auf dem das Programm laufen soll, diese Befehle versteht. Bei einem echten C64 ist das der Fall, auch die meisten Emulatoren können diese Befehle umsetzen, aber das muss nicht immer so sein.
Für uns als Programmierer ist es natürlich am schönsten, wenn unser Assembler diese Befehle kennt. Auch für die illegalen-Befehle gibt es Mnemonics, da diese aber nicht offiziell sind, gibt es teilweise unterschiedlichen Namen für einen Befehl. Hier muss man ggf. schauen, welche der verwendete Assembler versteht. Sollte der Assembler mit den Befehlen nichts anfangen können, dann müsst ihr wohl oder übel die gewünschten Befehle direkt als Bytes eingeben. Je nach Assembler ist es evtl. auch noch möglich sich eigene Macros für die Befehle zu bauen. Das C64 Studio versteht einen Großteil der hier erklärten Befehle, ACME einige weniger. Beim Einsatz von ACME müsst ihr als CPU-Typ außerdem 6510 angeben, sonst gibt es Fehler bei der Assemblierung. Fügt zu Beginn einfach ein !cpu 6510 in den Quellcode ein. Beim C64 Studio könnt ihr dies zur Sicherheit auch machen.
Der Turbo Assembler kennt die Befehle nicht, dort müsst ihr mit .byte arbeiten.
Die Befehle sind zum Teil echt strange, ich versuche erst gar nicht sinnvolle Beispiele anzubieten. Meiner Meinung nach sollte man diese Befehle nur im äußersten Notfall einsetzen, z. B. wenn sie dringend benötigten Platz sparen oder in einer zeitkritischen Routine einen Vorteil bringen.
Diese Liste wurde anhand der Infos auf verschiedenen Internetseiten und mit dem Buch „The Complete Commodore Inner Space Anthology“ erstellt. Ich bin trotzdem nicht ganz sicher, ob alles stimmt (z. B. habe ich bei den Taktzyklen nicht immer einen Hinweis darauf gefunden, ob und wie sich eine Überschreitung der Page-Grenze auswirkt).
Los gehts…
Genug der Vorrede, werfen wir endlich einen Blick auf die letzten Befehle des C64:
SLO bzw. ASO
slo $082d
SLO: ASL+ORA (alternatives Mnemonic: ASO)
SLO absolut ($0F, 3B, 6T, NZC)
SLO kombiniert ein ASL mit einem ORA. Dabei wird das, über die Adressierung zufindene Byte zunächst per ASL bitweise nach links verschoben und anschließend mit dem Akku ODER-Verknüpft.
Man könnte also auch schreiben:
asl $082d ora $082d
Wenn ihr jetzt mal in die Mnemonics schaut, werdet ihr feststellen, dass diese beiden Befehle zusammen 6Bytes und 10TZ benötigen. Wir können mit SLO also, 3Byte Speicher und 4TZ sparen, das ist schonmal nicht schlecht. Außerdem können wir Daten über Adressierungsarten shiften, die es beim ASL nicht gibt (z. B. absolut,Y).
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ absolut | $0f | 3 | 6 absolut,X | $1f | 3 | 7 absolut,Y | $1b | 3 | 7 Zero-Page | $07 | 2 | 5 Zero-Page,X | $17 | 2 | 6 indirekt X | $03 | 2 | 8 indirekt Y | $13 | 2 | 8
Sollte euer Assembler diesen Befehl nicht verstehen, könnt ihr ihn z. B. durch die angabe der Bytes !byte $0f, $2d, $08 (entspricht slo $082d) trotzdem verwenden.
RLA
rla $082d
RLA: ROL+AND
RLA absolut ($2F, 3B, 6T, NZC)
RLA kombiniert ein ROL mit einem AND. Dabei wird das über die Adressierung zufindene Byte zunächst per ROL bitweise nach links verschoben (von rechts wird das C-Flag eingeschoben) und anschließend mit dem Akku UND-Verknüpft.
Man könnte also auch schreiben:
rol $082d and $082d
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ absolut | $2f | 3 | 6 absolut,X | $3f | 3 | 7 absolut,Y | $3b | 3 | 7 Zero-Page | $27 | 2 | 5 Zero-Page,X | $37 | 2 | 6 indirekt X | $23 | 2 | 8 indirekt Y | $33 | 2 | 8
SRE bzw. LSE
SRE $082d
SRE: LSR+EOR (alternatives Mnemonic: LSE)
SRE absolut ($4F, 3B, 6T, NZC)
SRE kombiniert ein LSR mit einem EOR. Dabei wird das über die Adressierung zufindene Byte zunächst per LSR bitweise nach rechts verschoben und anschließend mit dem Akku exklusiv-ODER-Verknüpft.
Man könnte also auch schreiben:
lsr $082d eor $082d
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ absolut | $4f | 3 | 6 absolut,X | $5f | 3 | 7 absolut,Y | $5b | 3 | 7 Zero-Page | $47 | 2 | 5 Zero-Page,X | $57 | 2 | 6 indirekt X | $43 | 2 | 8 indirekt Y | $53 | 2 | 8
RRA
RRA $082d
RRA: ROR+ADC
RRA absolut ($6F, 3B, 6T, NZ)
RRA kombiniert ein ROR mit einem ADC. Dabei wird das über die Adressierung zufindene Byte zunächst per ROR bitweise nach rechts verschoben (das herausfallende Bit landet im C-Flag) und wird anschließend durch ADC mit dem Akku addiert (dabei wird natürlich auch das Carry-Flag vom ROR beachtet).
Man könnte also auch schreiben:
ror $082d adc $082d
Da ADC nach dem ROR ausgeführt wird, ist das C-Flag also abhängig von der Addition, wir bekommen nach dem RRA also kein Carry-Flag für das mittels ROR hinausgeschobene Bit!!
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ absolut | $6f | 3 | 6 absolut,X | $7f | 3 | 7 absolut,Y | $7b | 3 | 7 Zero-Page | $67 | 2 | 5 Zero-Page,X | $77 | 2 | 6 indirekt X | $63 | 2 | 8 indirekt Y | $73 | 2 | 8
SAX bzw. AXS
SAX $082d
SAX: Store Akku AND X-Register to memory (alternatives Mnemonic: AXS)
SAX absolut ($8F, 3B, 4T, <keine>)
SAX funktioniert so: Die Inhalte von Akku und X-Register werden UND-Verknüpft, aber OHNE eines der beiden Register zu ändern! Das Ergbnis wird dann an der angegebenen Adresse abgelegt. Die Flags im Statusregister (SR) bleiben ebenfalls unverändert!
Wollte man das mit normalen Befehlen nachbilden, dann bräuchte man eine ganze Menge davon:
php stx $082d pha and $082d sta $082d pla plp
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ absolut | $8f | 3 | 4 Zero-Page | $87 | 2 | 3 Zero-Page,Y | $97 | 2 | 4 indirekt X | $83 | 2 | 6
LAX
LAX $082D
LAX: LDA+LDX
LAX absolut ($AF, 3B, 4T, NZ)
LAX lädt das Byte, von der angegebenen Adresse, gleichzeitig in den Akku und ins X-Register.
Mit regulären Befehlen sehe das so aus:
lda $082d ldx $082d
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ absolut | $af | 3 | 4 absolut,Y | $bf | 3 | 4-5 Zero-Page | $a7 | 2 | 3 Zero-Page,Y | $b7 | 2 | 4 indirekt X | $a3 | 2 | 6 indirekt Y | $b3 | 2 | 5-6
Hier wird bei zwei Adressierungsarten ein extra Taktzyklus benötigt, falls die Page-Grenze überschritten wird.
DCP bzw. DCM
DCP $082d
DCP: DEC+CMP (alternatives Mnemonic: DCM)
DCP absolut ($CF, 3B, 4T, NZC)
DCP verringert das Byte, an der angegebenen Speicherstelle, mit DEC und vergleicht dieses dann mittels CMP mit dem Akku.
Mit regulären Befehlen sehe das so aus:
dec $082d cmp $082d
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ absolut | $cf | 3 | 6 absolut,X | $df | 3 | 7 absolut,Y | $db | 3 | 7 Zero-Page | $c7 | 2 | 5 Zero-Page,X | $d7 | 2 | 6 indirekt X | $c3 | 2 | 8 indirekt Y | $d3 | 2 | 8
ISC bzw. INS
ISC $082d
ISC: INC+SBC (alternatives Mnemonic: INS)
ISC absolut ($EF, 3B, 6T, NZC)
ISC erhöht das Byte an der angegebenen Speicherstelle, mit INC und subtrahiert es dann mit SBC vom Akku.
Mit regulären Befehlen sehe das so aus:
inc $082d sbc $082d
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ absolut | $ef | 3 | 6 absolut,X | $ff | 3 | 7 absolut,Y | $fb | 3 | 7 Zero-Page | $e7 | 2 | 5 Zero-Page,X | $f7 | 2 | 6 indirekt X | $e3 | 2 | 8 indirekt Y | $f3 | 2 | 8
ALR
ALR #$a5
ALR: AND+LSR
ALR unmittelbar ($4B, 2B, 2T, NZC)
ALR führt per AND eine UND-Verknüpfung mit dem angegebenen Wert und dem Akku durch. Abschließend wird per LSR der Akku bitweise nach rechts verschoben.
Mit regulären Befehlen sehe das so aus:
and #$a5 lsr
Hier gibt es nur die eben gezeigte Adressierungsart.
ACME kennt diesen Befehl nicht!
ARR
ARR #$a5
ARR: AND+ROR
ARR unmittelbar ($6B, 2B, 2T, NZC)
ARR führt per AND eine UND-Verknüpfung mit dem angegebenen Wert und dem Akku durch. Abschließend wird per ROR der Akku bitweise nach rechts rotiert.
Mit regulären Befehlen sehe das so aus:
and #$a5 ror
Hier gibt es ebenfalls nur die eben gezeigte Adressierungsart.
XAA
XAA #$a5
XAA: TXA+AND
XAA unmittelbar ($8B, 2B, 2T, NZ)
XAA kopiert den Inhalt des X-Register mit TAX in den Akku und führt dann eine UND-Verknüpfung mit dem angegebenen Wert und dem Akku durch.
Mit regulären Befehlen sehe das so aus:
txa and #$a5
Wieder gibt es nur die eben gezeigte Adressierungsart.
ACME kennt diesen Befehl nicht!
Nochmal LAX, aber eigentlich OAL
LAX #$a5
LAX (eigentlich OAL ORA+AND+LDX )
LAX unmittelbar ($AB, 2B, 2T, NZ)
Jetzt wird es langsam echt verrückt. 😉
Diese Version von LAX führt zuerst per ORA eine ODER-Verknüpfung mit dem Akku und dem Wert #$ee durch! Dann wird der Akku durch AND mit dem angegebenen Wert UND-Verknüpft und anschließend mittels TAX ins X-Register kopiert.
Mit regulären Befehlen sehe das so aus:
ora #$ee and #$a5 tax
Wieder gibt es nur die eben gezeigte Adressierungsart. Das C64 Studio kennt diesen Befehl, als LAX. Andere Assembler kennen OAL, was eigentlich auch besser ist, da sich das Verhalten von den anderen LAX-Befehlen unterscheidet.
ACME kennt übrigens keinen der beiden Befehle!
AXS
AXS #$a5
AXS: AND+TAX+Subtract (oder SAX)
AXS unmittelbar ($CB, 2B, 2T, NZ)
Hier wird zuerst eine UND-Verknüfung zwischen dem Akku und dem X-Register vorgenommen. Dann wird vom Ergebnis der UND-Verknüpfung der angegebenen Wert abgezogen (ohne das Carry-Flag zu beachten!) und das Ergebnis im X-Register gespeichert. Das C-Flag kann aber durch die Subtraktion wiederum gesetzt werden, das OVerflow-Flag bleibt allerdings, ebenso wie der Akku, unverändert!
Ein Nachbau ist nur mit Hilfe einer Speicheradresse möglich, nehmen wir $fb auf der Zero-Page (AXS kommt natürlich ohne $fb aus):
sta $fb txa and $fb sec sbc #$a5 tax lda $fb
Wieder gibt es nur die eben gezeigte Adressierungsart.
ACME kennt auch diesen Befehl nicht!
SKB
SKB
SKB: SKip next Byte (nächstes Byte überspringen)
SKB implizit ($80, 1B, 2-4T, <keine>)
Der Befehl SKB überspringt einfach das nächste Byte. Ein Nachbau würde nur einen Sprungbefehl (z. B. JMP) verwenden. Der Befehl kann auch noch mit weiteren OpCodes ausgelöst werden:
$82, $c2, $e2, $04, $14, $34, $44, $54, $64, $74, $d4, $f4
Eine genaue Angabe der Taktzyklen konnte ich leider nicht finden, nur das sie zwischen 2 und 4 liegen.
Weder das C64 Studio noch ACME kennen diesen Befehl!
SKW
SKW
SKW: SKip next Word (nächstes Word [zwei Byte] überspringen)
SKW implizit ($0C, 1B, 4-5T, <keine>)
Der Befehl SKW überspringt ein sog. Word (das wiederum zwei Byte entspricht). Ein Nachbau könnte wie beim SKB mit einem Sprungbefehl (z. B. JMP) erfolgen oder mit dem BIT-OpCode (wobei der das Statusregister verändert!). SKW kann auch noch mit weiteren OpCodes ausgelöst werden: $1c, $3c, $5c, $7c, $dc, $fc
Intern ist SKW eine Leseoperation, nur dass das Ergebnis nirgends gespeichert wird. Beim OpCode $0c wird eine absolute Adressierung verwendet, bei den anderen wird die absolute X-Indizierte Adressierung verwendet, dort wird dann beim Überschreiten der Page-Grenze ein weiterer Taktzyklus benötigt.
Auch diesen Befehl kennen weder ACME noch das C64 Studio.
NOP
NOP
Zum Schluß der relativ sicher verwendbaren OpCodes, bleibt noch der uns bereits bekannte NOP-Befehl. Dieser wird nicht nur beim offiziellen OpCode $ea ausgeführt, sondern auch bei ($1a, $3a, $5a, $7a, $da, $fa).
Jetzt wird es noch illegaler 😉
Die nun folgenden OpCodes sind im Buch „The Complete Commodore Inner Space Anthology“ nicht mehr beschrieben. Ich habe sie nur im Netz gefunden, allerdings ist ihr verhalten teilweise nicht vorhersagbar. Da VICE diese Befehle kennt und verarbeitet, führe ich sie der Vollständigkeit halber auf.
Die kommen Befehle werden jetzt immer verrückter und problematischer, ein sinnvoller Einsatz ist daher äußerst fragwürdig!
HLT
HLT
HLT: HaLT (Absturz verursachen)
HLT implizit ($02, 1B, ?T, <keine>)
Tja, was soll man dazu sagen?
Triff die CPU auf einen dieser OpCodes $02, $12, $22, $32, $42, $52, $62, $72, $92, $b2, $d2, $f2, dann „hängt“ sie sich auf! Nur ein Reset bzw. Neustart hilft dann weiter. Taktzyklen sind hier nicht auffindbar und wären auch vollkommen irrelevant, der Rechner steht dann eh!
Weder ACME, noch das C64 Studio kennen diesen Befehl.
TAS
TAS $082d,y
TAS: TXS+AND+STA
TAS absolut Y-indiziert ($9B, 3B, 5T, <keine>)
Zunächst werden der Akku und das X-Register per UND-Verknüpft, aber ohne das sich eines der Register ändert! Das Ergebnis wird in den Stackpointer (SP / nicht auf den Stack!!!) geschrieben. Dann wird das Ergebnis mit dem (Wert des MSB)+1 der angegebenen Adresse UND-Verknüpft und im Speicher an der angegebenen Adresse+Y-Register abgelegt. Wenn ihr das ausprobieren wollt, achtet auf den Stackpointer. Da der sehr wahrscheinlich geändert wurde (das sollte schon ein ungeheurer Zufall sein, wenn die erste UND-Verknüpfung den selben Wert wie der aktuelle SP ergibt) solltet ihr ihn mit TSX / TXS in einer Speicherstelle sichern und wiederherstellen. Die Flags bleiben dabei unverändert.
Auch das läßt sich nur unter Zuhilfenahme weiterer Speicherstellen (wir nehmen $fb & $fc auf der Zero-Page) nachbauen:
Wir gehen vom Befehl TAS $082d,y aus. stx $fb ;X in die Zero-Page, da es kein direktes AND für X und Akku gibt pha ;Akku merken php ;SR auf den Stack pla ;SR in den Akku sta $fc ;SR auf Zero-Page sichern pla ;Akku wiederherstellen pha ;und direkt wieder 'retten' and $fb ;Akku mit X (jetzt in $FB) UND-Verknüpfen sta $fb ;Ergebnis für später in $FB merken and #$09 ;UND-Verknüpung mit dem MSB ($08)+1 = $09 sta $082d,y ;Ergebnis aus dem Akku Speichern txa ;X im Akku merken ldx $fb ;Ergebnis der 1. UND-Verknüpfung nach X holen sta $fb ;Akku (gemerktes X) jetzt an $FB merken pla ;original Akku wiederholen (muss VOR dem TXS geschehen!!) txs ;X in den SP kopieren TAX ldx $fb ;auf der Zero-Page gemerktes X zurückholen sta $fb ;Akku auf dem Stack merken lda $fc ;SR in den Akku pha ;SR vom Akku auf den Stack lda $fb ;Akku wiederherstellen plp ;SR wieder auf Ausgangswert setzen
Soviel Aufwand für nichts, hat jemand einen sinnvollen Einsatz hierfür???
Weitere Adressierungsarten gibt es übrigens nicht.
SAY
SAY $082d,x
SAY: Store value AND Y-Register
SAY absolut X-indiziert ($9C, 3B, 5T, <keine>)
Es wird das Y-Register mit dem Wert des MSB+1 UND-Verknüpft und anschließend an der angegebenen Adresse gespeichert. Die Flags bleiben dabei unverändert.
Nachbauen läßt sich das ganz einfach:
php pha tya and #$09 ;MSB von SAY $082D,Y = $08 zzgl. 1 = $09 sta $082d,x pla plp
Auch hier gibt es keine anderen Adressierungsarten.
Weder ACME, noch das C64 Studio kennen diesen Befehl.
XAS
XAS $082d,y
XAS: X-Reg. AND value Stored to memory
XAS absolut Y-indiziert ($9E, 3B, 5T, <keine>)
Es wird das X-Register mit dem Wert des MSB+1 UND-Verknüpft und anschließend an der angegebenen Adresse gespeichert. Die Flags bleiben dabei unverändert.
Nachbauen läßt sich das ganz einfach:
php pha txa and #$09 ;MSB von XAS $082D,Y = $08 zzgl. 1 = $09 sta $082d,y pla plp
Auch hier gibt es keine anderen Adressierungsarten.
Weder ACME, noch das C64 Studio kennen diesen Befehl.
AXA
AXA $082d,y
AXA: Akku and X-Reg. STA
AXA absolut Y-indiziert ($9F, 3B, 5T, <keine>)
Es wird der Akku mit dem X-Register und anschließend mit dem Wert des MSB+1 UND-Verknüpft. Anschließend wird das Ergebnis an der angegebenen Adresse gespeichert. Die Flags bleiben dabei unverändert.
Zum Nachbauen benötigen wir wieder eine Speicherstelle, die der Befehl natürlich nicht verwendet, nehmen wir wieder $fb auf der Zero-Page:
php stx $fb pha and $fb and #$09 sta $082d,y pla ldx $fb plp
Übersicht der Adressierungsarten:
Adressierung | OpCode | Bytes | TZ indirekt Y | $93 | 2 | 6
Weder ACME, noch das C64 Studio kennen diesen Befehl.
ANC
ANC #$4d
ANC: Akku AND value influence Carry
ANC unmittelbar ($2B, 2B, 2T, NZC)
Der Akku wird mit dem angegebenen Wert UND-Verknüpft. Das Ergebnis steht dann auch wieder im Akku. Er sieht also zunächst wie ein normaler AND-Befehl aus, aber hier wird das N-Flag ins Carry-Flag kopiert.
Der OpCode $0b führt zum selben Befehl, wie der eben erwähnte $2b .
Ein Nachbau könnte so aussehen:
and #$4d bmi setCarry clc skb setCarry sec
LAS
LAS $082d,y
LAS: Hierzu fällt mir nur: Lade Alles mit Schrott ein 😉
LAS absolut Y-indiziert ($BB, 3B, 2T, NZ)
Der Befehl führt eine UND-Verknüpfung mit dem Byte das an der angegebenen Speicherstelle zufinden ist und dem Stackpointer (SP) durch. Das Ergebnis wird dann im Akku, X-Register und SP abgelegt.
Zum letzten Mal ein Nachbau:
tsx txa and $082d,y tax txs
Zwei letzte OpCodes, für bekannte Befehle soll es noch geben, aber auch die sind nicht abgesichert:
$89 soll ebenfalls ein NOP ausführen.
$eb soll einem einem SBC #value entsprechen.
Wer ein Wenig sucht, findet seitenweise Diskussionen über diese Befehle. Wie bereits erwähnt, gibt es teilweise ein unterschiedliches Verhalten auf verschiedenen Rechnern und teilweise bei verschiedenen Ausgangssituationen auf dem selben Computer.
Daher nochmal die Warnung mit diesen Befehlen sparsam umzugehen!
Nichts ist frustrierender als stundenlang einen Fehler zu suchen und dann festzustellen, dass der illigale OpCode sich diesmal anders verhält nur weil der Bildschirmspeicher andere Daten enthält.
So, jetzt haben wir aber wirklich alle Befehle einmal gesehen. Als nächstes gibt es noch einen ‚Abschluß‘-Beitrag und dann sind wir mit dem Assembler-Grundlagen-Tutorial durch. Danach geht es mit dem Programmieren endlich richtig los.
Meine aktive Zeit ist zwar Jahrzehnte her, aber ich meine mich dran erinnern zu können dass es auch illegale Opcodes gab für Double NOP / triple NOP.
Und zum Thema der Sinnvollen einsetzbarkeit von illegalen Opcodes, so wurden so einige davon öfter benutzt um Zyklen zu sparen. Vieles wurde für visuelle Darstellung und für Rasterinterrupts benutzt. Da kam es teilweise auf jeden Zyklus an. Hat das Timing nicht gestimmt, war die Rasterzeile nicht am Ende der Zeile.
Bin nur gerade nicht mehr sicher, ob Zyklus der richtige Name noch dafür war. Schon zu lange her.
Aber ein NOP hatte 2 und ein Double NOP 3 als Bsp.
Für mich macht der HLT Befehl dahingehend Sinn, das man damit eine Codeanipulationssicherung / Kopierschutz bauen könnte (Reines Gedankenspiel ohne jetzt eine konkrete Umsetzung im Hinterkopf zu haben)
Bei Fehlverhalten würde der Rechner mittels HLT eingefroren. Somit würde kein Warmstart oder Softwarereset helfen also der Speicher nicht reproduzierbar sein. Oder täusche ich mich ?
Klappt nicht da der Reset weiterhin möglich ist, wenn man aber die CMD80 Kennung auf eine $02 setzt dann nützt einem der Reset auch nix mehr. und man könnte so nur noch mit einem Kaltstart den C64 nutzen