Der erste Schritt

Die Befehle kennenlernen

C64 Studio, AMCE & TASM

Hier dreht sich alles um den Befehlssatz des 6510. Wie bereits erwähnt, gilt dieser auch für den 6502. In Zukunft werde ich nur vom 6510 reden und einzig bei Bedarf den 6502 erwähnen. Wir werden uns Stück für Stück den Befehlssatz erarbeiten.

Da der 6510 ein 8-Bit Prozessor ist, steht ihm je Befehl ein Byte zur Verfügung. Somit kommt man auf max. 256 unterschiedliche Befehle. Aber längst nicht jedes Byte steht für einen gültigen Befehl. Viele Befehle haben außerdem unterschiedliche Adressierungsarten, die unterschiedliche Bytecodes besitzen. So gibt es z. B. allein acht verschiedene Versionen vom LDA-Befehl, je nachdem, wie die Adressierung vorgenommen wird. „Wirkliche“ Befehle gibt es nur 56 und außerdem noch einige undokumentierte.

Wir werden uns das ASM-Programm vom Basic-Vergleich noch mal anschauen.

Startet jetzt euren Editor. Nun solltet ihr auch spätestens einen Blick auf die Einrichtung eurer Entwicklungsumgebung werfen und wissen, wie man damit Programme erstellt und startet. Beim Turbo Assembler auf dem C64, solltet ihr im Auge behalten, dass sich die Syntax hin und wieder unterscheidet. Beim ersten Auftreten, erwähne ich diese Unterschiede im Tutorial, gesammelt findet ihr diese im Turbo Assembler-Beitrag.

Gebt nun das folgende Programm ein:

Turbo Assembler:Dieses Programm hatten wir ja schon bei den Grundlagen, schaut daher bei Bedarf nochmal dort nach, was alles zu beachten ist.

Nehmen wir uns dieses kleine Programm jetzt mal Zeile für Zeile vor.

Diese Angabe ist kein Befehl für den Prozessor, sondern teilt dem Assembler mit, an welcher Speicheradresse die nächsten Anweisungen stehen sollen. Dafür gebt ihr ein *= gefolgt von der Adresse (ich benutze die Hex-Schreibweise, ihr könnt aber auch Dezimalzahlen verwenden) ein.
Ab $0800 beginnt zwar das BASIC-RAM (s. „Kleine Hardwarekunde“), wie ihr aber eben gesehen habt, wollen wir die nächsten BYTEs erst ab $0801 ablegen. Dies ist die Adresse, an der die erste BASIC-Zeile erwartet wird. $0800 ist für uns tabu! Dort muss immer eine 0 stehen, sonst kommt es zu einer Fehlermeldung, wenn man RUN eingibt, um das Programm zu starten. Daher beginnen wir mit $0801.

!byte ist auch kein Befehl, es ist ein Schlüsselwort für den Assembler. Es weist den Assembler an, die folgenden Werte, direkt als Bytes im Speicher abzulegen. Hier generieren wir eine BASIC-Zeile für den Programmstart.
Wer nach Laden des Programms mal LIST eingibt, bekommt unsere Startzeile zusehen:

Schauen wir uns diesen BASIC-Start mal genauer an…

$0c, $08 : Hier haben wir die Adresse der nächsten BASIC-Zeile. Bei uns gibt es zwar keine, aber wir müssen diese Adresse trotzdem angeben. Ausrechnen können wir die Adresse, indem wir zu unserer Startadresse $0801 (s. o.) die Anzahl der von uns für die BASIC-Zeile benötigten Bytes (inkl. den beiden Bytes für diese Adresse und der ersten $00 (s. u.), aber ohne die beiden $00, $00 (s. u.) am Schluss) addieren.
Adressen werden als 16-Bit (Word) gespeichert. Dabei erwartet der 6510 zuerst das niederwertige Byte (LSB) im Speicher, dann folgt das MSB (höherwertiges Byte)helpErklärungLSB = Least Significant Byte
MSB = Most Significant Byte
Die Groß-/Kleinschreibung ist wichtig, große Buchstaben stehen für BYTE, kleine für Bit.
. Also zeigen wir hier auf die Adresse $080c = $0801 + 11 Bytes.

$e2, $07 : Das ist unsere BASIC-Zeilen-Nr. als Hex-Zahl, da diese 16-Bit groß ist, wird auch hier wieder erst das LSB, dann das MSB im Speicher abgelegt. Wer $07e2 ins Dezimalsystem umrechnet, kommt auf unsere Zeilen-Nr. 2018.

$9e : Das nächste Byte steht für den BASIC-Befehl SYS, der BASIC-Interpreter weiß dadurch, zu welcher Routine er springen muss. Dieses Byte bitte nicht mit einem Opcode verwechseln!

$20, $32, $30, $36, $32 : Diese fünf Bytes stehen einfach für den Text hinter dem SYS-Befehl. Wenn ihr eine PETSCII-Tabelle zu Rate zieht, kommt ihr auf folgende Zeichen:

$20 = Leerzeichen
$32 = 2
$30 = 0
$36 = 6
$32 = 2

$00, $00, $00 : Diese drei Bytes markieren das Ende des BASIC-Programms.
Das erste Byte steht für das Zeilenende, die nächsten beiden für das Ende des BASIC-Listings. Durch diese drei $00 erkennt der BASIC-Interpreter also das Ende des Programms und verhindert, dass es bei der Ausführung am Schluss evtl. einen Fehler gibt bzw. dass wir beim LIST Unfug angezeigt bekommen. Ohne dieses Ende würde unser Programm, das im Speicher ja direkt auf die erste BASIC-Zeile folgt, als weitere BASIC-Zeilen interpretiert werden.
Wenn man diese drei Bytes mal weg lässt, läuft unser Programm nicht mehr richtig:

Das Programm wird direkt ohne Ausgabe beendet.

Nach einem LIST sehen wir auch warum…

 

Leerzeilen dienen nur der Übersicht, diese könnt ihr je nach eurem Geschmack zur Formatierung eures Sourcecodes einsetzen.

Hier ist es endlich, unser erstes Mnemonic: LDA (die Groß- & Kleinschreibung ist beim C64 Studio und ACME übrigens egal, der Turbo Assembler zwingt euch zur Kleinschreibung).

LDA : LoaD Accumulator (lade / setze einen Wert in den Akku).
Um den Akku zu füllen, gibt es, wie eingangs erwähnt, acht unterschiedliche Möglichkeiten. Die hier verwendete nennt sich unmittelbare Adressierung, weil wir einen festen Wert #$41 (für das Pik-Symbol) direkt in den Akku schreiben. Das #$ ist hier sehr wichtig! Vergesst ihr die Raute # dann erkennt der Assembler $41 als Adresse! Ohne $ wird die Zahl als Dezimal interpretiert und ihr seht dann ein anderes Symbol auf dem BS. Bei einer unmittelbaren Adressierung benötigt LDA 2 Byte Speicher und die CPU braucht zwei Taktzyklen, um den Befehl zu verarbeiten. Die Anzahl der Taktzyklen beeinflusst die Ausführungsgeschwindigkeit eures Programms. Ihr könnt durchs Zählen der benötigten Taktzyklen berechenen, wie lange es dauert, bis ein Programm bzw. ein Teil davon abgearbetet ist. Der eindeutige OpCode für LDA mit unmittelbarer Adressierung lautet $A9. Außerdem werden das Negativ- und Zero-Flag beeinflusst.

In Zukunft gebe ich bei den Befehlen Opcode, Speicherbedarf, Taktzyklen und die betroffenen Flags in Kurzform an.

Hier lautet die Kurzform:
LDA unmittelbar ($A9, 2B, 2T, NZ)
.

Alle Details hierzu findet ihr auf der Seite Mnemonics.

LDX : LoaD X-Register (lade / setze einen Wert im X-Register / Indexregister-X)
LDX unmittelbar ($A2, 2B, 2T, NZ)
Der C64 besitzt zwei Indexregister die X– und Y-Register genannt werden. Diese Register werden häufig (so wie hier) für Schleifen verwendet, da sich deren Wert einfach verringern läßt, wie wir gleich noch sehen. Die Indexregister sind dem Akku von der Handhabung sehr ähnlich. Wir verwenden hier, wie beim LDA, die unmittelbare Adressierung um im X-Register unsere gewünschte Schleifenanzahl #$ff (255) zu hinterlegen (auch hier wieder auf #$ achten).

Wir haben jetzt also unser -Symbol im Akku und unsere Schleifenanzahl im X-Register. Als nächstes folgt der Hauptblock unseres Programms, wir geben die Zeichen mit einer Schleife auf dem Bildschirm aus.

loop ist wieder mal kein Assemblerbefehl, sondern ein Label. Diese Label werden vom Assembler verwendet, um eine bestimmte Adresse im Speicher zu finden. Ihr könnt das Label auch direkt vor den entsprechenden Befehl schreiben, ich empfinde das aber als unübersichtlich. Wir könnten Adressen auch selbst ausrechnen, das ist aber sehr arbeitsaufwändig (wenn ihr Befehle hinzufügt verschieben sich die Speicherpositionen) und fehleranfällig (wie leicht vertippt man sich und schon sucht man ewig nach einem Fehler im Programm).
Hier kennzeichnet loop den Beginn unserer Schleife. Solange die von uns gewünschte Anzahl an Durchläufen (siehe LDX) noch nicht erreicht ist, wollen wir immer wieder mit dem folgenden Befehl fortfahren.

STA: STore Accumulator (speichere den Inhalt des Akkus in…)
STA absolut X-indiziert ($9D, 3B, 5T, <keine>)
Zu Beginn unserer Schleife, wollen wir das -Zeichen auf dem BS ausgeben. Wir verwenden dafür STA, um den Inhalt des Akkus, in die angegebene Speicherstelle (hier der BS-Speicher) zu schreiben. Adressen werden (wie oben erwähnt) im Format $03ff angegeben (hier also ohne #). Da wir nicht immer auf die selbe Adresse schreiben wollen, müssen wir noch dafür sorgen, dass wir nacheinander die von uns gewünschten Speicherzellen beschreiben. Das erreichen wir durch die Angabe von ,x hinter unserer Adresse $03ff. Damit weiß der Assembler, dass er die absolute Adressierung mit Hilfe des X-Registers nehmen soll. Wenn der Befehl abgearbeitet wird, addiert die CPU auf die feste Adresse (hier $03ff) den jeweils aktuellen Inhalt des X-Registers. Da wir dieses oben mit #$ff gefüllt haben und es gleich verringern werden, geben wir die Zeichen also „rückwärts“ auf dem BS aus. Wir beginnen bei $03ff + #$ff = $04fe, dann $04fd, $04fc usw. Das X-Register ist bei uns nie kleiner als 1 (s. unten), wenn STA ausgeführt wird. Somit erklärt sich jetzt auch für alle, die in der Hardwarekunde aufgepasst haben, wieso wir die Adresse $03ff verwenden, obwohl der BS doch bei $0400 beginnt: $03FF + 1 = $0400.

DEX: DEcrement X-Register (den Inhalt vom X-Register um 1 verringern)
DEX implizit ($CA, 1B, 2T, NZ)
Nachdem wir eben einen sehr „großen“ und zeitaufwendigen Befehl hatten, folgt nun ein schön schlanker und einfacher. Der Befehl DEX zieht einfach vom Inhalt des X-Registers 1 ab. Sollte im X-Register $00 stehen, dann führt ein DEX dazu, dass es anschließend den Wert $FF hat. Dies trifft auch auf die Befehle DEY und DEC zu, die wir später noch kennenlernen. Es gibt nur diese eine Schreibweise für den DEX-Befehl, da hier keine Adressierungen möglich / nötig sind. Das Zero- und Negativ-Flag werden hier beeinflusst. Ist die Zahl nach dem DEX negativ, dann wird das N-Flag gesetzt (1), anderenfalls wird es gelöscht (0). Ist die Zahl genau 0, dann wird das Z-Flag gesetzt (1), sonst wird es gelöscht (0). Das führt uns direkt zum nächsten Befehl.

BNE: Branch on Not Equal (springe wenn nicht gleich zu…)
BNE relativ ($D0, 2B, 2-4T, <keine>)
Dieser Befehl ist wieder etwas komplexer. BNE ist mit einer IF X <> Y THEN GOTO Anweisung aus BASIC vergleichbar. Unter Assembler gibt es insgesamt acht solcher bedingten Sprünge. Damit sind Befehle gemeint, die ein Statusregister prüfen und dann entweder zu einer anderen Speicherstelle springen oder mit der nächsten Anweisung fortfahren. Ob etwas gleich oder ungleich ist, wird über das Zero-Flag geprüft (1 bedeutet gleich und 0 ungleich, zieht man z. B. zwei Zahlen von einander ab und das Ergebnis ist 0, dann sind diese Zahlen offensichtlich gleich). Dementsprechend springt BNE zur angegebenen Adresse, wenn das Zero-Flag gelöscht (Z=0), die letzte Anweisung also nicht gleich (bzw. null) ist. Da wir gelernt haben, dass eine Adresse 16-Bit lang ist, wundert ihr euch evtl. warum BNE nur 2 Byte Speicher benötigt. Das liegt daran, dass die sog. relative Adressierung verwendet wird. Der OpCode benötigt wie gewohnt ein Byte. Das zweite Byte wird für die relative Adressierung verwendet. Dabei gibt das vorzeichenbehaftete Byte an, um wieviele Bytes vor oder zurück gesprungen werden soll. Ihr könnt also max. um 127 Byte nach vorne (zu höheren Adressen) oder um -128 Byte zurück (zu niedrigeren Adressen) springen. Wer die Taktzyklen zählen möchte, der muss noch weitere Besonderheiten beachten. Wie ihr oben sehen könnt, habe ich die Ausführungszeit mit 2-4T angegeben. 2T werden benötigt, wenn der Befehl nicht springen muss und es einfach mit der nächsten Einweisung weitergeht. Muss ein Sprung ausgeführt werden, dann werden 2T+1T benötigt, erfolgt der Sprung über eine Page(Seiten)-Grenze, dann wird ein weiterer Zyklus benötigt, also 2T+1T+1T. Solltet ihr euch jetzt fragen, was springen eigentlich bedeutet, nun das ist ganz einfach. Damit ist nichts Anderes gemeint, als den Programcounter (PC / Programmzähler) auf die angegebene Zieladresse zusetzen, damit es mit dem dortigen Befehl weitergeht.

Jetzt haben wir es fast geschafft, es folgt der letzte Befehl aus unserem Programm.

RTS: ReTurn from Subroutine (springe aus der Unter(Hilfs)-Funktion zurück zum Aufrufer)
RTS implizit ($60, 1B, 6T, <keine>)
Der Befehl springt zu der aktuell auf dem Stack zu findenden Adresse (implizite Adressierung) zurück. Normalerweise wird diese Adresse vom JSR-Befehl (folgt später) auf dem Stack abgelegt. Wie ein Blick aufs Listing verrät, gibt es den in unserem Programm aber nicht!?! Bei uns steht dort eine Rücksprung-Adresse zum BASIC, die beim Programmstart auf dem Stack abgelegt wurde. Wir landen nach dem RTS also wieder mit dem blinkenden Cursor in der Eingabe des C64. Da RTS einfach die aktuelle Adresse vom Stack nimmt, ist es immens wichtig, dass wir dafür sorgen, dass der Stack die richtige Adresse enthält. Damit beschäftigen wir uns später beim JSR-Befehl.


So, das wars fürs Erste an Befehlen. Ihr solltet damit etwas experimentieren. Keine Angst, der C64 nimmt keinen Schaden, falls ihr mal Kraut und Rüben produziert. Es kommt höhstens mal vor, dass ihr Reset drücken oder den Rechner gar ausschalten müsst.

Kommentare und Variablen

Lasst uns unser Programm noch etwas verbessern. Damit wir auch in drei Jahren noch wissen, was wir uns bei bestimmten Programmstellen gedacht haben, sind Kommentare ratsam. Ein Kommentar ist nur für den Leser des Sourcecodes gedacht. Er hat keine Auswirkung auf das fertige Programm. Erstellt ihr eure Programme auf dem PC, dann könnt ihr hemmungslos Kommentare einsetzen. Auf einem echten C64 sieht das schon anders aus. Da auch beim Schreiben des Programmes im Editor, wie immer der Speicher knapp ist, müsst ihr im Hinterkopf behalten, dass auch Kommentare Platz benötigen. Einen Kommentar leitet ihr durch ein Semikolon ein. Alles was danach folgt, wird bei der Programmerstellung ignoriert.

Beim Turbo Assembler müsst ihr darauf achten, dass Kommentare nur für sich alleine in einer Zeile stehen dürfen. Beim C64 Studio und ACME können die Kommentare auch hinter Befehlen stehen.

Variablen

Durch Variablen bzw. Konstanten könnt ihr die Pfleg- und Lesbarkeit eurer Programme verbessern. Ihr könnt euch dazu einfach einen Namen ausdenken und diesem einen Wert zuweisen.

oder

Ich schreibe die Namen hier absichtlich groß, damit die im Source besser zu erkennen sind. Alles andere schreibe ich in der Regel klein. Beim Turbo Assembler müsst ihr die Namen aber in Kleinbuchstaben schreiben!

Zum Schluß noch unser überarbeitetes Programm:

Beim Turbo Assembler sieht es so aus:

Turbo Assembler – Kommentare und Variablen

Schrott!!Naja...Geht so...Ganz gut...SUPER! (31 Bewertungen | Ø 4,84 von 5 | 96,77%)

Loading...


ZurückWeiter

22 Gedanken zu „Der erste Schritt“

  1. Hallo Jörn,

    zunächst mal WOOOOOOWWW, einfach TOP was Du hier zusammengetragen hast. Ich möchte Dir herzlich danken, endlich ein Tutorial bei dem ich verstehe was genau geschieht und wie es gemacht wird…. Ich fresse mich in jeder freien Minute durch den Lesestoff durch!!!!

    Eine kleine Frage habe ich wenn Du erlaubst… Im Codebeispiel beginnt die bytezeile mit !byte $0c,$08,
    was aus meinem Verständnis 11 „Byte weiter“ ist… Im Text schreibst Du aber dann später
    Zitat: „$0b, $08 : Hier haben wir die Adresse der nächsten BASIC-Zeile.“

    Ich habe in meinem Assembler beide Werte ausprobiert, beide funktionieren… Kannst Du mir nochmal erklären, wenn es Deine Zeit zulässt, wie es richtig ist und auf was diese Adresse genau zeigen soll?
    Ich danke Dir herzlich und kann es kaum erwarten weiterzulesen….
    Gruß
    Marcus

    1. Hallo Marcus,
      der Source ist richtig, die Erklärung war es leider nicht, ich habe diese eben angepasst.

      Die erste $00 steht für das Ende der aktuellen BASIC-Zeile und muss in die Berechnung einbezogen werden. Es sind daher in der Tat 11 Bytes, die zu $0801 addiert werden müssen. Dadurch landet man dann bei $080c.
      Die letzten beiden $00 markieren das Ende des kompletten BASIC-Programmes und hier hin muss die eben errechnete Adresse zeigen.

      Gruß,
      Jörn

  2. Hallo Jörn,

    ich weiß nicht wie aktiv hier noch moderiert wird, aber ich versuche es trotzdem:

    Nachdem ich kürzlich einen C64 gewonnen habe wollte ich mich, bis das gute Stück eintrifft bereits im Voraus etwas damit vertraut machen und habe mir VICE installiert. Als Cross-Assembler habe ich sowohl ACME als auch xa installiert. Außerdem habe ich den Turbo Assembler (mittlerweile Turbo Macro Pro) als Disk-Image herumliegen, sodass ich Dinge auch direkt in VICE probieren kann.

    Es ist mir allerdings nicht gelungen, diese erste Lektion auch nur annähernd wie demonstriert abzuschließen. Ich habe den von dir geschriebene Assemblercode 1:1 kopiert, habe es sowohl mit ACME als auch mit xa assemblet und habe ihn auch wie er ist in Turbo Macro Pro in VICE eingegeben.

    Meine Resultate: Sowohl mit xa als auch mit ACME führt ein Laden des Programms mit anschließendem List nicht zur erwarteten Ausgabe

    „2018 SYS 2062“

    Stattdessen sehe ich

    „8350 2062“. Der Grund dafür hat sich durch Inspizieren des Speichers mittels PEEKs offenbart: Die Bytes $e2 und $07 sind nicht im Speicher angekommen. An Adresse $0803, wo $e2 stehen sollte, steht tatsächlich 158, also das Byte $9e, welches eigentlich an Adresse $0805 stehen sollte. Ich habe mir die von ACME und xa generierten Programme mit xxd (Hex-Dump) angeschaut, aber dort befinden sich alle Werte wie sie sein sollten (außer der Information der ersten Zeile „*=$8081“, welche komplett verloren geht). Liegt das an VICE oder was genau ist hier das Problem?

    Mit Turbo Macro Pro war das ganze noch verheerender. Nachdem ich das Programm assemblen lasse, bietet mir TMP an es mit „S“ zu starten. Tue ich das, erhalte ich in VICE ein CPU JAM bei Adresse $080A, womit ich leider auch überhaupt nichts anfangen kann, außer, dass an dieser Adresse das hereingegebene Byte $32, also die letzte „2“ in „2062“ liegt.

    Ich wäre dir überaus dankbar, wenn du mir etwas Hilfestellung geben könntest, sodass ich zumindest im Ansatz verstehe, was hier schief läuft und warum.

    Viele Grüße
    Ole

    1. Hallo Ole,
      auch wenn ich aktuell nichts neues mehr schreibe, Kommentare beantworte ich schon noch.

      Ich kenne jetzt die Syntax von xa nicht, aber ich gehe davon aus, dass du das Programm ohne Ladeadresse erstellt hast.
      Bei ACME sorgst du mit der Option „-f cbm“ dafür, dass die Ladeadresse erzeugt wird.

      Die Ladeadresse steht an den ersten beiden Bytes im fertigen Programm und legt beim C64 fest, wo das Programm bei einem LOAD“…“,8,1 im Speicher landen soll. Du lädst es offensichtlich mit LOAD“…“,8 (also OHNE ,1 – was hier auch durchaus richtig ist). Aber ohne ,1 geht der C64 von einem Basicprogramm aus, überspringt die ersten beiden Bytes und legt das Programm ab dem dritten Byte bei $0801 ab. Dort beginnt die erste Basiczeile und an $0803 / $0804 steht die Zeilennummer als LSB/MSB. Bei dir steht dort $9E / $20 was $209E bzw. dezimal 8350 ist, da wie erwähnt die Ladeadresse fehlt.

      Ich hoffe das reicht fürs erste, habe aber keine Hemmungen weitere Fragen zu stellen, falls meine kurze Erklärung doch nicht ausreicht.

      Gruß,
      Jörn

  3. Hallo Jörn,
    ich habe ein kleine Frage zum Video und dem Assembly Dump
    Im Video zeigt der Assembly Dump in Zeile 14 den Speicherwert FF 03 (Also Adresse $03FF)
    Das ist der Wert der variable „Screen“ -1, aber dazu wird doch noch der Wert des x-Registers addiert.
    Wie passt das zusammen? Hätte da nicht irgendwas zwischen 00 04 und FF 04 stehen müssen?

    LG Jens

    1. Hallo Jens,
      der Befehl lautet sta $03ff,x. Im Speicher und daher auch im Dump, wird immer $9d $ff $03 stehen. Den Inhalt des X-Registers addiert die CPU intern zur angegebenen Adresse, der Befehl ändert sich dadurch nicht.

      Ich hoffe, ich habe mich verständlich ausgedrückt.

      Gruß,
      Jörn

  4. Pingback: Linksammlung C64
  5. „[…]Der Befehl DEX zieht einfach vom Inhalt des X-Registers 1 ab.[…]
    Ist die Zahl genau 0, dann wird das Z-Flag gesetzt (1), sonst wird es gelöscht (0). “

    //Also ist X=1, dann DEX …, dann ist X=0 und Z-Flag=1 ?

    „[…]Ob etwas gleich oder ungleich ist wird über das Zero-Flag geprüft
    (0 bedeutet gleich und 1 ungleich, zieht man z. B. zwei Zahlen von einander ab und das Ergebnis ist 0, dann sind diese Zahlen offensichtlich gleich).[…]“

    //Also wenn ich X=1 und DEX mache, ist das Ergebnis 0. Weil die Zahlen sind ‚gleich‘
    //Aber das Z-Flag wird gesetzt, also Z-Flag=1. Aber dann bedeutet Z-Flag=1 ja ‚ungleich‘?!?
    //Aber die Zahlen waren doch grade noch ‚gleich‘

    „[…]Dementsprechend springt BNE zur angegebenen Adresse, wenn das Zero-Flag gesetzt[…]ist.“

    //Aber das Z-Flag wird doch nur gesetzt wenn das X nach dem DEX 0 ist?!

    Mir ist schon klar, dass der Source-Code so funktioniert wie er da steht, aber diese Erklärung verknotet mir die Gehirnwindungen.
    Übersehe ich was oder missverstehe ich was? @-@“‘

    1. Oh Mann, ich fall vom Glauben ab! Was habe ICH denn da für einen Schwachsinn geschrieben?!!

      Sorry!
      Du hast nichts übersehen, sondern bist über einen Fehler gestolpert, der so seit über drei Jahren dort stand!
      Das so etwas ausgerechnet beim ersten Beitrag passiert und solange nicht auffällt, trifft mich echt hart.

      „[…]Der Befehl DEX zieht einfach vom Inhalt des X-Registers 1 ab.[…]
      Ist die Zahl genau 0, dann wird das Z-Flag gesetzt (1), sonst wird es gelöscht (0). “
      //Also ist X=1, dann DEX …, dann ist X=0 und Z-Flag=1 ?
      Ja, soweit ist es noch richtig!

      „[…]Ob etwas gleich oder ungleich ist wird über das Zero-Flag geprüft
      (0 bedeutet gleich und 1 ungleich, zieht man z. B. zwei Zahlen von einander ab und das Ergebnis ist 0, dann sind diese Zahlen offensichtlich gleich).[…]“
      //Also wenn ich X=1 und DEX mache, ist das Ergebnis 0. Weil die Zahlen sind ‚gleich‘
      //Aber das Z-Flag wird gesetzt, also Z-Flag=1. Aber dann bedeutet Z-Flag=1 ja ‚ungleich‘?!?
      //Aber die Zahlen waren doch grade noch ‚gleich‘
      Hier stand von mir verzapfter Unfug!
      Es ist natürlich genau umgekehrt: Z=
      1 bedeutet gleich und 0 ungleich
      Das Z-Flag wird immer auf 1 gesetzt, um anzuzeigen, dass die letzte Aktion NULL war, egal ob durch DEX, INY, LDA, CMP usw.

      „[…]Dementsprechend springt BNE zur angegebenen Adresse, wenn das Zero-Flag gesetzt[…]ist.“
      //Aber das Z-Flag wird doch nur gesetzt wenn das X nach dem DEX 0 ist?!
      Nochmal Blödsinn von mir.
      BNE (Springe wenn ungleich) verzweigt natürlich, wenn Z=0 also gelöscht ist!

      Mir ist schon klar, dass der Source-Code so funktioniert wie er da steht, aber diese Erklärung verknotet mir die Gehirnwindungen.
      Übersehe ich was oder missverstehe ich was?
      Nein, du hast nichts missverstanden, ich habe dich durch meine falsche Erklärung vollkommen verwirrt.
      Ich kann mich nur nochmal entschuldigen!

      Reichen die obigen Erklärungen oder kann ich dir noch weiterhelfen?

      Gruß,
      Jörn

    1. Da liegst du falsch! Das BASIC-RAM beginnt bei $0800! Die erste BASIC Zeile beginnt zwar bei $0801, das ändert aber nichts daran, dass das BASIC RAM schon bei $0800 beginnt.

      Falls du mir nicht glaubst, hier noch weitere Quellen:

      • C64-Wiki ($0800-$9FFF 2048-40959 Page 8-159 Free BASIC program storage area (38911 bytes) )
      • Compute’s Mapping the Commodores 64 & 64C Seite 82

        2048-40959 $800-$9FFF
        BASIC Program Text
        This is the area where the actual BASIC program text is stored. The text of a BASIC program consists of linked lines of program tokens…

      PS:
      Ich fand es aber trotzdem etwas missverständlich und habe den Abschnitt um eine Erklärung ergänzt:
      Ab $0800 beginnt zwar das BASIC-RAM (s. „Kleine Hardwarekunde“), wie ihr aber eben gesehen habt, wollen wir die nächsten BYTEs erst ab $0801 ablegen. Dies ist die Adresse, an der die erste BASIC-Zeile erwartet wird. $0800 ist für uns tabu! Dort muss immer eine 0 stehen, sonst kommt es zu einer Fehlermeldung, wenn man RUN eingibt, um das Programm zu starten. Daher beginnen wir mit $0801.

      PPS:
      Danke für deine Anmerkungen. Nur durch entsprechende Rückmeldungen, kann ich die Texte weiter optimieren und Fehler, sowie Ungereimtheiten eliminieren.

      1. Hallo Jörn,

        du hast natürlich recht, ich hab selber auch nochmal im C64 für Insider nachgesehen. Lag wohl an der Macht der Gewohnheit daß ich auf $0801 kam.

  6. Hallo Jörn, tolle Seiten, ich bin begeistert. Da ich grad selber wieder auf dem C64 Trip bin arbeite ich die Seiten mal durch und habe viel Spaß dabei, tolle Arbeit. Bei den Taktzyklen des DEX Befehls habe ich gestutzt, Du hast den mit 1T angegeben. Ich meine mich zu erinnern, das es keinen Befehl mit einem Taktzyklus gab, der müsste zwei haben. Da ich kürzlich gerade mal wieder den CRE177 Beitrag von Tim Pritlove und Michael Steil gehört habe, wird das hier bestätigt (selbst NOP hat zwei 🙂 Übrigens ist der Beitrag für C64 Fans sehr zu empfehlen.
    Gruß und danke HP

    1. Igitt!
      Da hast du vollkommen Recht!!

      Da bin ich wohl mit der BYTE-Anzahl durcheinander gekommen. Ich habe das eben korrigiert. Beim DEY war es übrigens auch falsch, aber unter Mnemonics stand es für beide richtig. INX, INY und NOP sind auch korrekt.

      Danke für den Hinweis,
      Jörn

      PS: Der Text in deinem Post war irgendwie doppelt, ich habe ihn daher bereinigt. Außerdem habe ich dort noch einen Link zum CRE177-Beitrag eingefügt.

  7. Pingback: Linksammlung C64 | Stefan.Waidele.info

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Protected by WP Anti Spam