Kapitel 4: Das Tutorial zur Assemblersprache des 6502-Mikroprozessors

Kapitel 4 Das Tutorial Zur Assemblersprache Des 6502 Mikroprozessors



Kapitel 4: Das Tutorial zur Assemblersprache des 6502-Mikroprozessors

4.1 Einführung

Der Mikroprozessor 6502 wurde 1975 auf den Markt gebracht. Er wurde damals als Mikroprozessor für einige Personalcomputer wie Apple II, Commodore 64 und BBC Micro verwendet.







Der Mikroprozessor 6502 wird auch heute noch in großen Stückzahlen produziert. Es handelt sich nicht mehr um eine zentrale Recheneinheit, die heute in Personalcomputern (Laptops) zum Einsatz kommt, sie wird aber immer noch in großen Stückzahlen produziert und auch heute noch in elektronischen und elektrischen Geräten eingesetzt. Um die moderneren Computerarchitekturen zu verstehen, ist es sehr hilfreich, einen älteren, aber recht erfolgreichen Mikroprozessor wie den 6502 zu untersuchen.



Da er einfach zu verstehen und zu programmieren ist, ist er einer der besten (wenn nicht sogar der beste) Mikroprozessor für den Assemblerunterricht. Assemblersprache ist eine Low-Level-Sprache, die zum Programmieren eines Computers verwendet werden kann. Beachten Sie, dass sich die Assemblersprache für einen Mikroprozessor von der Assemblersprache eines anderen Mikroprozessors unterscheidet. In diesem Kapitel wird die Assemblersprache des 6502-Mikroprozessors gelehrt. Genauer gesagt handelt es sich um den 65C02, der eingelernt, aber einfach als 6502 bezeichnet wird.



Ein früher berühmter Computer hieß Commodore_64. Der 6502 ist ein Mikroprozessor der 6500-Familie. Der Commodore_64-Computer verwendet den 6510-Mikroprozessor. Der Mikroprozessor 6510 hat 6500 µP. Der Befehlssatz des 6502 µP umfasst fast alle Befehle des 6510 µP. Das Wissen dieses und des nächsten Kapitels basiert auf dem Computer commodore_64. Dieses Wissen dient als Grundlage für die Erläuterung moderner Computerarchitekturen und moderner Betriebssysteme in diesem Teil des Online-Karrierekurses.





Computerarchitektur bezieht sich auf die Komponenten der Hauptplatine des Computers und auf eine Erklärung, wie die Daten innerhalb jeder Komponente, insbesondere im Mikroprozessor, fließen, wie die Daten zwischen den Komponenten fließen und auch wie die Daten interagieren. Der Singular für Daten ist Datum. Eine effektive Möglichkeit, die Computerarchitektur eines Computers zu studieren, besteht darin, die Assemblersprache des Motherboards zu studieren.

Der Commodore_64-Computer soll ein 8-Bit-Computerwort-Computer sein. Das bedeutet, dass die Informationen in Form von Acht-Bit-Binärcodes gespeichert, übertragen und manipuliert werden.



Blockdiagramm des Commodore 64-Motherboards
Das Blockdiagramm des Commodore 64-Motherboards ist:


Abb. 4.1 Blockdiagramm der Commodore_64-Systemeinheit

Stellen Sie sich den Mikroprozessor 6510 als Mikroprozessor 6502 vor. Der Gesamtspeicher besteht aus einer Reihe von Bytes (8 Bit pro Byte). Es gibt den Direktzugriffsspeicher (Lese-/Schreibspeicher), in den die Bytes geschrieben oder gelöscht werden können. Wenn der Computer ausgeschaltet wird, werden alle Informationen im Arbeitsspeicher (RAM) gelöscht. Es gibt auch den Nur-Lese-Speicher (ROM). Wenn der Computer ausgeschaltet wird, bleiben die Informationen im ROM erhalten (werden nicht gelöscht).

Es gibt den Eingangs-/Ausgangsanschluss (Schaltkreis), der im Diagramm als Eingangs-/Ausgangsgeräte bezeichnet wird. Dieser Anschluss sollte nicht mit den Anschlüssen verwechselt werden, die an den vertikalen Flächen links und rechts oder vorne und hinten der Computersystemeinheit sichtbar sind. Das sind zwei verschiedene Dinge. Die Verbindungen von diesem inneren Port zu den Peripheriegeräten wie Festplatte (oder Diskette), Tastatur und Monitor sind im Diagramm nicht dargestellt.

Im Diagramm sind drei Busse (Gruppen elektrischer, sehr kleiner Drahtleiter) zu sehen. Jede Leitung kann ein Bit 1 oder ein Bit 0 übertragen. Der Datenbus für die Übertragung von Acht-Bit-Bytes auf einmal (ein Taktimpuls) zum RAM und zum Eingabe-/Ausgabe-Port (Eingabe-/Ausgabegeräte) ist bidirektional. Der Datenbus ist acht Bit breit.

Alle Komponenten sind an den Adressbus angeschlossen. Der Adressbus ist vom Mikroprozessor aus unidirektional. Für den Adressbus gibt es sechzehn Leiter, von denen jeder ein Bit (1 oder 0) trägt. Sechzehn Bits werden in einem Taktimpuls gesendet.

Da ist der Steuerbus. Einige der Leiter des Steuerbusses würden jeweils ein Bit vom Mikroprozessor an die anderen Komponenten übertragen. Einige Steuerleitungen übertragen die Bits vom Ein-/Ausgabe-Port (IO) zum Mikroprozessor.

Computerspeicher
RAM und ROM werden als eine Speicherbaugruppe betrachtet. Diese Baugruppe wird schematisch wie folgt dargestellt, wobei Hexadezimalzahlen das Präfix „$“ haben:


Abb. 4.11 Speicherlayout für den Commodore 64-Computer

Der RAM ist von 0000 16 zu DFFF 16 was als von $0000 bis $DFFF geschrieben wird. Bei der Assemblersprache 6502 µP wird einer Hexadezimalzahl „$“ vorangestellt und nicht 16 oder H oder Hex als Suffix (tiefgestellt). Alle Informationen im RAM gehen verloren, wenn der Computer ausgeschaltet wird. Der ROM beginnt bei $E000 bis $FFFF. Es verfügt über Unterprogramme, die beim Ausschalten des Computers nicht ausgeführt werden. Diese Unterprogramme sind die am häufigsten verwendeten Routinen, die bei der Programmierung helfen. Das Anwenderprogramm ruft sie auf (siehe nächstes Kapitel).

Der Speicherplatz (Bytes) von $0200 bis $D000 ist für die Benutzerprogramme vorgesehen. Der Platz von $D000 bis $DFFF ist für Informationen vorgesehen, die sich direkt auf die Peripheriegeräte (Eingabe-/Ausgabegeräte) beziehen. Dies ist Teil des Betriebssystems. Das Betriebssystem des Commodore-64-Computers besteht also aus zwei Hauptteilen: dem Teil im ROM, der nie ausgeht, und dem Teil von $D000 bis $DFFF, der ausgeht, wenn der Strom ausgeschaltet wird. Diese IO-Daten (Eingabe/Ausgabe) müssen bei jedem Einschalten des Computers von einer Festplatte geladen werden. Heute werden solche Daten als Peripherietreiber bezeichnet. Die Peripheriegeräte beginnen beim Eingabe-/Ausgabegeräteanschluss über die Anschlüsse auf der Hauptplatine bis zu den erkennbaren Anschlüssen an den vertikalen Flächen des Computers, an die der Monitor, die Tastatur usw. angeschlossen sind, und an die Peripheriegeräte selbst (Monitor, Tastatur usw.). .).

Der Speicher besteht aus 2 16 = 65.536 Byte-Speicherorte. In hexadezimaler Form sind dies 10000 16 = 10000 H = 10000 verhexen = 10.000 $ Standorte. Beim Rechnen beginnt das Zählen zur Basis zwei, zur Basis zehn, zur Basis sechzehn usw. bei 0 und nicht bei 1. Der erste Ort ist also eigentlich die Ortsnummer 0000000000000000 2 = 0 10 = 0000 16 = 0000 $. In der Assemblersprache 6502 µP wird der Identifizierung eines Adressorts ein $ vorangestellt und es gibt kein Suffix oder Index. Der letzte Standort ist die Standortnummer 1111111111111111 2 = 65.535 10 = FFFF 16 = $FFFF und nicht 10000000000000000 2 oder 65.536 10 oder 10000 16 oder 10.000 $. Die 10000000000000000 2 , 65.536 10 , 10000 16 , oder $10000 gibt die Gesamtzahl der Byte-Speicherorte an.

Hier, 2 16 = 65.536 = 64 x 1024 = 64 x 2 10 = 64 Kbyte (Kilobyte). Das Suffix 64 im Namen Commodore-64 bedeutet 64 KB Gesamtspeicher (RAM und ROM). Ein Byte besteht aus 8 Bits, und die 8 Bits werden an einem Byte-Speicherort im Speicher abgelegt.

Der 64 KByte große Speicher ist in Seiten unterteilt. Jede Seite hat 0100 16 = 256 10 Byte-Speicherorte. Der erste 256 10 = erste 0100 16 Standorte ist Seite 0. Die zweite ist Seite 1, die dritte ist Seite 2 und so weiter.

Um die 65.536 Orte anzusprechen, sind für jeden Ort (Adresse) 16 Bit notwendig. Der Adressbus vom Mikroprozessor zum Speicher besteht also aus 16 Leitungen; eine Zeile für ein Bit. Ein Bit ist entweder 1 oder 0.

Die 6502 µP-Register
Ein Register ist wie die Bytezellen für einen Bytespeicherort. Der 6502 µP verfügt über sechs Register: fünf 8-Bit-Register und ein 16-Bit-Register. Das 16-Bit-Register wird Programmzähler genannt und mit PC abgekürzt. Es enthält die Speicheradresse für den nächsten Befehl. Ein Assemblerprogramm besteht aus Anweisungen, die im Speicher abgelegt werden. Sechzehn (16) verschiedene Bits werden benötigt, um eine bestimmte Bytestelle im Speicher zu adressieren. Bei einem bestimmten Taktimpuls werden diese Bits zum Lesen eines Befehls an die 16-Bit-Adressleitungen des Adressbusses gesendet. Alle Register für den 6502 µP sind wie folgt dargestellt:


Abb. 4.12 6502 µP-Register

Der Programmzähler oder PC ist im Diagramm als 16-Bit-Register zu sehen. Die niederwertigen acht Bits werden als PCL für Program Counter Low bezeichnet. Die höherwertigen acht Bits werden als PCH für Program Counter High bezeichnet. Eine Anweisung im Speicher des Commodore-64 kann aus einem, zwei oder drei Bytes bestehen. Die 16 Bits im PC verweisen auf den nächsten auszuführenden Befehl im Speicher. Unter den Schaltkreisen im Mikroprozessor werden zwei als Arithmetic Logic Unit und Instruction Decoder bezeichnet. Wenn der aktuelle Befehl, der im µP (Mikroprozessor) verarbeitet wird, ein Byte lang ist, erhöhen diese beiden Schaltkreise den PC für den nächsten Befehl um 1 Einheit. Wenn der aktuelle Befehl, der im µP verarbeitet wird, zwei Bytes lang ist, also zwei aufeinanderfolgende Bytes im Speicher belegt, erhöhen diese beiden Schaltkreise den PC für den nächsten Befehl um 2 Einheiten. Wenn der aktuelle Befehl, der im µP verarbeitet wird, drei Bytes lang ist, also drei aufeinanderfolgende Bytes im Speicher belegt, erhöhen diese beiden Schaltkreise den PC für den nächsten Befehl um 3 Einheiten.

Der Akkumulator „A“ ist ein 8-Bit-Allzweckregister, das das Ergebnis der meisten arithmetischen und logischen Operationen speichert.

Die Register „X“ und „Y“ dienen jeweils der Zählung der Programmschritte. Die Zählung in der Programmierung beginnt bei 0. Daher werden sie als Indexregister bezeichnet. Sie haben noch ein paar andere Zwecke.

Obwohl das Stapelzeigerregister „S“ 9 Bits hat, wird es als Acht-Bit-Register betrachtet. Sein Inhalt verweist auf eine Byte-Position auf Seite 1 des Random Access Memory (RAM). Seite 1 beginnt ab Byte $0100 (256 10 ) in Byte $01FF (511 10 ). Wenn ein Programm ausgeführt wird, bewegt es sich von einer Anweisung zur nächsten aufeinanderfolgenden Anweisung im Speicher. Dies ist jedoch nicht immer der Fall. Es gibt Zeiten, in denen es von einem Speicherbereich zu einem anderen springt, um die Anweisungen dort nacheinander weiter auszuführen. Als Stack wird Seite 1 im RAM verwendet. Der Stack ist ein großer RAM-Speicherbereich, der die nächsten Adressen für die Fortsetzung des Codes enthält, von wo aus ein Sprung erfolgt. Die Codes mit Sprunganweisungen befinden sich nicht im Stapel. sie sind woanders in der Erinnerung. Nachdem die Sprungbefehle jedoch ausgeführt wurden, befinden sich die Fortsetzungsadressen (keine Codesegmente) im Stapel. Sie wurden aufgrund der Sprung- oder Verzweigungsanweisungen dorthin verschoben.

Das 8-Bit-Prozessorstatusregister von P ist eine besondere Art von Register. Die einzelnen Bits stehen in keinem Zusammenhang oder sind miteinander verbunden. Jedes Bit dort wird als Flag bezeichnet und unabhängig von den anderen geschätzt. Die Bedeutung der Flags wird im Folgenden je nach Bedarf angegeben.

Der erste und letzte Bitindex für jedes Register sind im vorherigen Diagramm über jedem Register angegeben. Die Zählung des Bitindex (der Position) in einem Register beginnt rechts bei 0.

Speicherseiten im Binär-, Hexadezimal- und Dezimalformat
Die folgende Tabelle zeigt den Anfang der Speicherseiten im Binär-, Hexadezimal- und Dezimalformat:

Jede Seite hat 1.0000.0000 2 Anzahl der Bytes, die 100 entspricht H Anzahl der Bytes, die 256 entspricht 10 Anzahl der Bytes. Im vorherigen Speicherdiagramm werden die Seiten von Seite 0 an nach oben und nicht nach unten angezeigt, wie in der Tabelle angegeben.

Die Binär-, Hexadezimal- und Dezimalspalten dieser Tabelle geben die Speicherbyte-Positionsadressen in ihren verschiedenen Basen an. Beachten Sie, dass für die Seite Null nur die Bits für das untere Byte beim Codieren eingegeben werden müssen. Die Bits für das höhere Byte können weggelassen werden, da sie immer Nullen sind (für Seite Null). Für die restlichen Seiten sollten die Bits für das höhere Byte verwendet werden.

Der Rest dieses Kapitels erklärt die 6502 µP-Assemblersprache unter Verwendung aller vorherigen Informationen. Um die Sprache schnell zu verstehen, muss der Leser zur Basis sechzehn statt zur Basis zehn addieren und subtrahieren. Eigentlich soll es Basis zwei sein, aber die Berechnung in Basis zwei ist umständlich. Denken Sie daran, dass beim Addieren zweier Zahlen zur Basis zwei ein Übertrag immer noch 1 ist, wie zur Basis zehn. Aber wenn man zwei Zahlen zur Basis zwei subtrahiert, ergibt sich eine Entlehnung von zwei und nicht von zehn wie zur Basis zehn. Wenn man zwei Zahlen zur Basis sechzehn addiert, ist ein Übertrag immer noch 1 wie zur Basis zehn. Aber wenn man zwei Zahlen zur Basis sechzehn subtrahiert, ergibt eine Entlehnung sechzehn und nicht zehn wie zur Basis zehn.

4.2 Anweisungen zur Datenübertragung

Betrachten Sie die folgende Tabelle mit Anweisungen zur Datenübertragung in Assemblersprache für den 6502 µP:

Wenn ein Byte (8 Bits) von einem Speicherbyte-Speicherort in das Akkumulatorregister, X-Register oder Y-Register kopiert wird, wird das geladen. Wenn ein Byte von einem dieser Register an einen Speicherbyte-Speicherort kopiert wird, handelt es sich um eine Übertragung. Wenn ein Byte von einem Register in ein anderes kopiert wird, wird es immer noch übertragen. In der zweiten Spalte der Tabelle zeigt der Pfeil die Kopierrichtung für ein Byte an. Die restlichen vier Spalten zeigen verschiedene Adressierungsmodi.

Ein Eintrag in der Spalte „Adressierungsmodus“ ist der tatsächliche Bytecode für den entsprechenden mnemonischen Teil der Anweisung im Hexadezimalformat. AE ist beispielsweise der eigentliche Bytecode für LDX, der im absoluten Adressierungsmodus wie AE ein Byte aus dem Speicher in das X-Register lädt 16 = 10101110 2 . Die Bits für LDX an einem Speicherbyte-Speicherort sind also 10101110.

Beachten Sie, dass es für den mnemonischen LDX-Teil des Befehls drei mögliche Bytes gibt, nämlich A2, AE und A6, und jedes für einen bestimmten Adressierungsmodus. Wenn das Byte, das in das X-Register geladen wird, nicht von einem Speicherbyte-Speicherort kopiert werden soll, muss der Wert mit (direkt nach) der LDX-Mnemonik in der Anweisung hexadezimal oder dezimal eingegeben werden. In diesem Kapitel werden solche Werte hexadezimal eingegeben. Da es sich um eine unmittelbare Adressierung handelt, ist das tatsächliche Byte im Speicher zur Darstellung von LDX A2 16 = 10100010 2 und nicht AE 16 was gleich 10101110 ist 2 .

In der Tabelle werden alle Bytes unter den Überschriften „Adressierungsmodus“ als Operationscodes bezeichnet, was als Opcodes abgekürzt wird. Abhängig vom Adressierungsmodus kann es mehr als einen Opcode für eine Mnemonik geben.

Notiz: Das Wort „Laden“ in der Computersystemeinheit kann zwei Bedeutungen haben: Es kann sich auf das Laden einer Datei von einer Festplatte in den Speicher des Computers beziehen oder es kann sich auf die Übertragung eines Bytes von einem Speicherbyte-Speicherort in ein Mikroprozessorregister beziehen .

Es gibt mehr Adressierungsmodi als die vier in der Tabelle für den 6502 µP.

Sofern nicht anders angegeben, beginnt der gesamte Benutzerprogrammcode in diesem Kapitel bei Adresse 0200 16 Dies ist der Anfang des Benutzerbereichs im Speicher.

Speicher M und Akku A

Speicher zu Akku

Sofortige Adressierung
Die folgende Anweisung speichert die Nummer FF 16 = 255 10 in den Akku:

LDA #$FF

Das „$“ wird nicht nur zur Identifizierung einer Speicheradresse verwendet. Im Allgemeinen wird es verwendet, um anzuzeigen, dass die nächste Zahl, die folgt, hexadezimal ist. In diesem Fall ist $FF nicht die Adresse eines Speicherbyte-Speicherorts. Es ist die Nummer 255 10 im Hexadezimalformat. Die Basis 16 oder einer ihrer anderen äquivalenten Indizes darf nicht in der Assembler-Anweisung geschrieben werden. Das „#“ gibt an, dass es sich bei dem, was als nächstes folgt, um den Wert handelt, der in das Akkumulatorregister geschrieben werden soll. Der Wert kann auch zur Basis zehn geschrieben werden, was in diesem Kapitel jedoch nicht erfolgt. Das „#“ bedeutet sofortige Adressierung.

Eine Mnemonik hat eine gewisse Ähnlichkeit mit der entsprechenden englischen Phrase. „LDA #$FF“ bedeutet, dass die Nummer 255 geladen wird 10 in den Akkumulator A. Da es sich um eine unmittelbare Adressierung aus der vorherigen Tabelle handelt, ist LDA A9 und nicht AD oder A5. A9 ist im Binärformat 101010001. Wenn sich A9 für LDA also in der Adresse $0200 im Speicher befindet, befindet sich $FF in der Adresse $0301 = 0300 + 1. Das #$FF ist genau der Operand für die LDA-Mnemonik.

Absolute Adressierung
Wenn sich der Wert von $FF an der Stelle $0333 im Speicher befindet, lautet die vorherige Anweisung:

LDA 0333 $

Beachten Sie das Fehlen von #. In diesem Fall bedeutet das Fehlen von #, dass das, was folgt, eine Speicheradresse ist und nicht der interessierende Wert (nicht der Wert, der in den Akkumulator geschrieben werden soll). Der Opcode für LDA ist dieses Mal also AD und nicht A9 oder A5. Der Operand für LDA ist hier die Adresse $0333 und nicht der Wert $FF. $FF befindet sich an einem Ort von 0333 $, der ziemlich weit entfernt ist. Die Anweisung „LDA $0333“ belegt drei aufeinanderfolgende Speicherplätze im Speicher und nicht zwei, wie in der vorherigen Abbildung der Fall war. „AD“ für LDA steht an der Stelle „0200 $“. Das untere Byte von 0333, also 33, befindet sich an der Stelle $0301. Das höhere Byte von $0333, also 03, befindet sich an der Stelle $0302. Dies ist Little Endianness, das von der 6502-Assemblersprache verwendet wird. Die Assemblersprachen verschiedener Mikroprozessoren sind unterschiedlich.

Dies ist ein Beispiel für absolute Adressierung. $0333 ist die Adresse des Standorts, der $FF hat. Der Befehl besteht aus drei aufeinanderfolgenden Bytes und enthält weder $FF noch seinen tatsächlichen Byte-Speicherort.

Zero-Page-Adressierung

Gehen Sie davon aus, dass sich der $FF-Wert im Speicherort $0050 auf Seite Null befindet. Die Byte-Speicherorte für die Nullseite beginnen bei $0000 und enden bei $00FF. Das sind 256 10 Standorte insgesamt. Jede Seite des Commodore-64-Speichers ist 256 10 lang. Beachten Sie, dass das höhere Byte für alle möglichen Speicherorte im Nullseitenbereich im Speicher Null ist. Der Zero-Page-Adressierungsmodus ist derselbe wie der absolute Adressierungsmodus, das höhere Byte von 00 wird jedoch nicht in den Befehl eingegeben. Um also $FF von der Position $0050 in den Akkumulator zu laden, lautet die Anweisung für den Zero-Page-Adressierungsmodus:

LDA 50 $

Dabei ist LDA A5 und nicht A9 oder AD, A5 16 = 10100101 2 . Denken Sie daran, dass jedes Byte im Speicher aus 8 Zellen besteht und jede Zelle ein Bit enthält. Die Anweisung besteht hier aus zwei aufeinanderfolgenden Bytes. A5 für LDA befindet sich im Speicherort $0200 und die $50-Adresse ohne das höhere Byte 00 befindet sich im Speicherort $0301. Das Fehlen von 00, das ein Byte im gesamten 64-KB-Speicher verbraucht hätte, spart Speicherplatz.

Akku zum Speicher

Absolute Adressierung
Die folgende Anweisung kopiert einen Bytewert, egal um welchen Wert es sich handelt, aus dem Akkumulator in den Speicherort $1444:

SIE SIND 1444 $

Dabei soll es sich um eine Übertragung vom Akku auf den Speicher handeln. Es wird nicht geladen. Das Laden ist das Gegenteil. Das Opcode-Byte für STA ist 8D 16 = 10001101 2 . Diese Anweisung besteht aus drei aufeinanderfolgenden Bytes im Speicher. Die 8D 16 befindet sich am Standort $0200. Die 44 16 der Adresse $1444 befindet sich am Standort $0201. Und 14 16 befindet sich im Bereich $0202 – Little Endianness. Das tatsächlich kopierte Byte ist nicht Teil der Anweisung. Für STA wird hier 8D und nicht 85 für Zero-Page-Adressierung (in der Tabelle) verwendet.

Keine Seitenadressierung
Die folgende Anweisung kopiert einen Bytewert, egal um welchen Wert es sich handelt, aus dem Akkumulator in den Speicherort $0050 auf Seite Null:

STA $0050

Das Opcode-Byte für STA ist hier 85 16 = 10000101 2 . Diese Anweisung besteht aus zwei aufeinanderfolgenden Bytes im Speicher. Die 85 16 befindet sich am Standort $0200. Die 50 16 der Adresse $0050 befindet sich am Standort $0201. Das Problem der Endianness stellt sich hier nicht, da die Adresse nur ein Byte hat, nämlich das untere Byte. Das tatsächlich kopierte Byte ist nicht Teil der Anweisung. Für STA wird hier 85 und nicht 8D für Zero-Page-Adressierung verwendet.

Es macht keinen Sinn, die unmittelbare Adressierung zu verwenden, um ein Byte vom Akku an eine Stelle im Speicher zu übertragen. Dies liegt daran, dass bei der unmittelbaren Adressierung der tatsächliche Wert wie $FF in der Anweisung angegeben werden muss. Für die Übertragung eines Bytewerts von einem Register im µP an einen beliebigen Speicherort ist daher keine unmittelbare Adressierung möglich.

LDX-, STX-, LDY- und STY-Mnemoniken
LDX und STX ähneln LDA bzw. STA. Hier wird jedoch das X-Register verwendet und nicht das A-Register (Akkumulator). LDY und STY ähneln LDA bzw. STA. Aber hier wird das Y-Register verwendet und nicht das A-Register. In Tabelle 4.21 finden Sie jeden Opcode im Hexadezimalformat, der einer bestimmten Mnemonik und einem bestimmten Adressierungsmodus entspricht.

Übertragungen von Register zu Register
Die beiden vorherigen Befehlssätze in Tabelle 4.21 befassen sich mit dem Kopieren (Übertragung) von Speicher-/Mikroprozessorregistern und dem Kopieren (Übertragung) von Registern/Registern. Die Befehle TAX, TXA, TAY, TYA, TSX und TXS führen das Kopieren (Übertragen) vom Register im Mikroprozessor in ein anderes Register desselben Mikroprozessors durch.

Um das Byte von A nach X zu kopieren, lautet die Anweisung:

STEUER

Um das Byte von X nach A zu kopieren, lautet die Anweisung:

TX

Um das Byte von A nach Y zu kopieren, lautet die Anweisung:

HAND

Um das Byte von Y nach A zu kopieren, lautet die Anweisung:

TYA

Beim Commodore 64-Computer befindet sich der Stapel auf Seite 1 direkt nach Seite 0 im Speicher. Wie jede andere Seite besteht sie aus 25610 10 Byte-Positionen, von $0100 bis $01FF. Normalerweise wird ein Programm von einer Anweisung zur nächsten aufeinanderfolgenden Anweisung im Speicher ausgeführt. Von Zeit zu Zeit erfolgt ein Sprung zu einem anderen Speichercodesegment (Anweisungssatz). Der Stapelbereich im Speicher (RAM) enthält die nächsten Befehlsadressen, an denen die Sprünge (oder Verzweigungen) zur Programmfortsetzung aufgehört haben.

Der Stapelzeiger „S“ ist ein 9-Bit-Register im 6502 µP. Das erste Bit (ganz links) ist immer 1. Alle Byte-Positionsadressen auf Seite eins beginnen mit 1, gefolgt von 8 verschiedenen Bits für die 256 10 Standorte. Der Stapelzeiger hat die Adresse der Stelle auf Seite 1, die die Adresse des nächsten Befehls enthält, den das Programm zurückgeben und mit dem es fortfahren muss, nachdem es das aktuelle Codesegment (zu dem gesprungen wurde) ausgeführt hat. Da das erste Bit aller Adressen des Stapels (Seite eins) mit 1 beginnt, muss das Stapelzeigerregister nur die restlichen acht Bits enthalten. Schließlich ist sein erstes Bit, das ganz links (das neunte Bit von rechts) ist, immer 1.

Um das Byte von S nach X zu kopieren, lautet die Anweisung:

TSX

Um das Byte von X nach S zu kopieren, lautet die Anweisung:

TXT

Die Register-zu-Register-Anweisungen benötigen keinen Operanden. Sie bestehen nur aus der Eselsbrücke. Jede Mnemonik hat ihren Opcode im Hexadezimalformat. Dies erfolgt im impliziten Adressierungsmodus, da kein Operand vorhanden ist (keine Speicheradresse, kein Wert).

Notiz: Es gibt keine X-zu-Y- oder Y-zu-X-Übertragung (Kopieren).

4.3 Arithmetische Operationen

Die Schaltung, die Arithmetic Logic Unit im 6502 µP, kann jeweils nur zwei Acht-Bit-Zahlen addieren. Es subtrahiert nicht, es multipliziert nicht und es dividiert nicht. Die folgende Tabelle zeigt die Opcodes und Adressierungsmodi für arithmetische Operationen:

Notiz: Alle Mnemoniken für arithmetische Operationen und andere Arten von Operationen (d. h. alle 6502-Mnemoniken) benötigen ein Byte Operationscode (Op). Wenn es mehr als einen Adressierungsmodus für die Mnemonik gibt, gibt es unterschiedliche Opcodes für dieselbe Mnemonik: einen pro Adressierungsmodus. C, D und V in der Tabelle sind die Flags des Statusregisters. Ihre Bedeutung wird später bei Bedarf erläutert.

Addition vorzeichenloser Zahlen
Beim 6502 µP sind die vorzeichenbehafteten Zahlen Zweierkomplementzahlen. Die vorzeichenlosen Zahlen sind gewöhnliche positive Zahlen, die bei Null beginnen. Für ein Byte mit acht Bits ist die kleinste vorzeichenlose Zahl also 00000000 2 = 0 10 = 00 16 und die größte vorzeichenlose Zahl ist 11111111 2 = 255 10 = FF 16 . Für zwei vorzeichenlose Zahlen lautet die Addition:

A+M+C→A

Das bedeutet, dass der 8-Bit-Inhalt des Akkumulators vom Rechenwerk zu einem Byte (8-Bit) aus dem Speicher addiert wird. Nach der Addition von A und M geht der Übertrag zum neunten Bit an die Übertragsflagzelle im Statusregister. Jedes vorherige Übertragsbit aus einer vorherigen Addition, das sich noch in der Übertragsflag-Zelle im Statusregister befindet, wird ebenfalls zur Summe von A und M addiert, sodass A+M+C→A entsteht. Das Ergebnis wird in den Akku zurückgelegt.

Wenn der Zinszusatz lautet:

A + M

Und es besteht keine Notwendigkeit, einen vorherigen Übertrag hinzuzufügen. Das Übertragsflag muss gelöscht werden, was auf 0 gesetzt wird, sodass die Addition wie folgt lautet:

A+M+0→A dasselbe wie A+M→A

Notiz: Wenn M zu A addiert wird und ein Übertrag von 1 auftritt, weil das Ergebnis größer als 255 ist 10 = 11111111 2 = FF 16 , das ist ein neuer Carry. Dieser neue Übertrag von 1 wird automatisch an die Übertrags-Flag-Zelle gesendet, falls er für das nächste zu summierende Acht-Bit-Paar (ein weiteres A + M) benötigt wird.

Code zum Hinzufügen von zwei vorzeichenlosen Acht-Bits
00111111 2 +00010101 2 ist das gleiche wie 3F 16 + 15 16 Das ist dasselbe wie 63 10 +21 10 . Das Ergebnis ist 010101002 2 Das ist dasselbe wie 54 16 und 84 10 . Das Ergebnis liegt nicht über der maximalen Zahl für acht Bits, die 255 beträgt 10 = 11111111 2 = FF 16 . Es gibt also keinen resultierenden Übertrag von 1. Anders ausgedrückt: Der resultierende Übertrag ist 0. Vor der Addition gibt es keinen vorherigen Übertrag von 1. Mit anderen Worten, der vorherige Übertrag ist 0. Der Code für diese Addition kann sein:

CLC
LDA #$3F
ADC #$15

Notiz: Beim Eingeben der Assemblersprache wird am Ende jeder Anweisung die „Enter“-Taste der Tastatur gedrückt. Dieser Code enthält drei Anweisungen. Der erste Befehl (CLC) löscht das Übertragsflag, falls eine vorherige Addition 1 hat. CLC kann nur im impliziten Adressierungsmodus durchgeführt werden. Die Mnemonik für den impliziten Adressierungsmodus benötigt keinen Operanden. Dadurch wird die Übertragszelle des Statusregisters von P gelöscht. Das Löschen bedeutet, dass der Übertragsflag-Zelle das Bit 0 gegeben wird. Die nächsten beiden Anweisungen im Code verwenden den Direktadressierungsmodus. Bei der unmittelbaren Adressierung gibt es nur einen Operanden für die Mnemonik, der eine Zahl ist (und weder eine Speicher- noch eine Registeradresse). Daher muss der Nummer ein „#“ vorangestellt werden. Das „$“ bedeutet, dass die folgende Zahl hexadezimal ist.

Die zweite Anweisung lädt die Nummer 3F 16 in den Akku. Für den dritten Befehl nimmt die Arithmetik-Logik-Einheitsschaltung des µP den vorherigen (gelöschten) Übertrag von 0 (auf 0 gezwungen) der Übertrags-Flag-Zelle des Statusregisters und addiert ihn zu 15 16 sowie auf den Wert, der bereits im 3F steht 16 Akkumulator und legt das komplette Ergebnis wieder in den Akkumulator zurück. In diesem Fall ergibt sich ein Übertrag von 0. Die ALU (Arithmetic Logic Unit) sendet (gibt) 0 in die Übertragsflagzelle des Statusregisters. Das Prozessorstatusregister und das Statusregister bedeuten dasselbe. Wenn sich ein Übertrag von 1 ergab, sendet die ALU 1 an das Übertragsflag des Statusregisters.

Die drei Zeilen des vorherigen Codes müssen im Speicher sein, bevor sie ausgeführt werden. Der Opcode 1816 für CLC (implizite Adressierung) befindet sich an der Byte-Position $0200. Der Opcode A9 16 für LDA (sofortige Adressierung) befindet sich an der Byte-Position $0201. Die Nummer 3F 10 befindet sich im Byte-Speicherort $0202. Der Opcode 69 16 für LDA (sofortige Adressierung) befindet sich an der Byte-Position $0203. Die Zahl 15 10 befindet sich im Byte-Speicherort $0204.

Notiz: LDA ist ein Übertragungsbefehl (Ladebefehl) und kein arithmetischer Befehl (Mnemonik).

Code zum Hinzufügen von zwei vorzeichenlosen Sechzehn-Bits
Alle Register im 6502 µP sind im Wesentlichen 8-Bit-Register, mit Ausnahme des PC (Programmzähler), der 16 Bit hat. Sogar das Statusregister ist 8 Bit breit, obwohl seine acht Bits nicht zusammenwirken. In diesem Abschnitt wird die Addition von zwei 16 vorzeichenlosen Bits mit einem Übertrag vom ersten Paar aus acht Bits zum zweiten Paar aus acht Bits betrachtet. Der hier interessierende Übertrag ist der Übertrag von der achten Bitposition zur neunten Bitposition.

Die Zahlen seien 0010101010111111 2 = 2ABF16 16 = 10.943 10 und 0010101010010101 2 = 2A95 16 = 10.901 10 . Die Summe ist 0101010101010100 2 = 5554 16 = 21.844 10 .

Die Addition dieser beiden vorzeichenlosen Zahlen zur Basis zwei erfolgt wie folgt:

Die folgende Tabelle zeigt die gleiche Addition mit dem Übertrag von 1 von der achten Bit- zur neunten Bit-Position, beginnend von rechts:

Bei der Codierung werden zuerst die beiden unteren Bytes hinzugefügt. Anschließend sendet die ALU (Arithmetic Logic Unit) den Übertrag von 1 von der achten Bitposition zur neunten Bitposition an die Carry-Flag-Zelle im Statusregister. Das Ergebnis von 0 1 0 1 0 1 0 0 ohne Übertrag geht in den Akkumulator. Dann wird das zweite Bytepaar mit dem Übertrag hinzugefügt. Die ADC-Mnemonik bedeutet, dass automatisch mit dem vorherigen Übertrag addiert wird. In diesem Fall darf der vorherige Übertrag, der 1 ist, vor der zweiten Addition nicht geändert werden. Da bei der ersten Addition ein etwaiger vorheriger Übertrag nicht Teil dieser vollständigen Addition ist, muss er gelöscht (auf 0 gesetzt) ​​werden.

Für die vollständige Addition der beiden Bytepaare lautet die erste Addition:

A + M + 0 -> A

Der zweite Zusatz ist:

A + M + 1 -> A

Daher muss das Carry-Flag kurz vor der ersten Addition gelöscht werden (angegebener Wert 0). Das folgende Programm, dessen Erklärung der Leser lesen muss, verwendet für diese Summierung den absoluten Adressierungsmodus:

CLC
LDA 0213 $
ADC 0215 $
; Kein Löschen, da der Carry-Flag-Wert benötigt wird
STA $0217
LDA 0214 $
ADC 0216 $
STA $0218

Beachten Sie, dass bei der Assemblersprache 6502 ein Semikolon einen Kommentar beginnt. Dies bedeutet, dass bei der Ausführung des Programms das Semikolon und alles, was sich rechts davon befindet, ignoriert wird. Das zuvor geschriebene Programm wird in einer Textdatei mit dem vom Programmierer gewählten Namen und der Erweiterung „.asm“ gespeichert. Das vorherige Programm ist nicht genau das Programm, das zur Ausführung in den Speicher verschoben wird. Das entsprechende Programm im Speicher wird als übersetztes Programm bezeichnet, wobei die Mnemoniken durch die Opcodes (Bytes) ersetzt werden. Jeder Kommentar verbleibt in der Assembler-Textdatei und wird entfernt, bevor das übersetzte Programm den Speicher erreicht. Tatsächlich gibt es heute zwei Dateien, die auf der Festplatte gespeichert sind: die „.asm“-Datei und die „.exe“-Datei. Die „.asm“-Datei ist die in der vorherigen Abbildung. Die „.exe“-Datei ist die „.asm“-Datei, in der alle Kommentare entfernt und alle Mnemoniken durch ihre Opcodes ersetzt wurden. Beim Öffnen in einem Texteditor ist die Datei „.exe“ nicht erkennbar. Sofern nicht anders angegeben, wird für die Zwecke dieses Kapitels die Datei „.exe“ beginnend mit dem Speicherort $0200 in den Speicher kopiert. Dies ist die andere Bedeutung von Laden.

Die beiden zu addierenden 16-Bit-Zahlen belegen für die absolute Adressierung vier Bytes im Speicher: zwei Bytes pro Zahl (Speicher ist eine Folge von Bytes). Bei der absoluten Adressierung befindet sich der Operand des Opcodes im Speicher. Das Summierungsergebnis ist zwei Bytes breit und muss ebenfalls im Speicher abgelegt werden. Das ergibt insgesamt 6 10 = 6 16 Bytes für Ein- und Ausgänge. Die Eingaben erfolgen nicht über die Tastatur und die Ausgabe erfolgt nicht über den Monitor oder Drucker. Die Eingaben liegen im Speicher (RAM) und die Ausgabe (Summierungsergebnis) geht in diesem Fall zurück in den Speicher (RAM).

Bevor ein Programm ausgeführt wird, muss sich zunächst die übersetzte Version im Speicher befinden. Betrachtet man den vorherigen Programmcode, erkennt man, dass die Anweisungen ohne Kommentar 19 ausmachen 10 = 13 16 Bytes. Das Programm nimmt also von $0200 Byte-Speicherplätzen im Speicher bis zu $0200 + $13 – $1 = $0212 Byte-Speicherplätzen (beginnend bei $0200 und nicht bei $0201, was – $1 impliziert). Durch Addition der 6 Bytes für die Eingabe- und Ausgabezahlen endet das gesamte Programm bei $0212 + $6 = $0218. Die Gesamtlänge des Programms beträgt 19 16 = 25 10 .

Das untere Byte des Augends sollte sich in der Adresse $0213 befinden, und das höhere Byte desselben Augends sollte sich in der Adresse $0214 befinden – Little Endianness. Ebenso sollte sich das untere Byte des Addends in der Adresse $0215 befinden und das höhere Byte desselben Addends in der Adresse $0216 – Little Endianness. Das untere Byte des Ergebnisses (Summe) sollte sich in der Adresse $0217 befinden, und das höhere Byte desselben Ergebnisses sollte sich in der Adresse $0218 befinden – Little Endianness.

Der Opcode 18 16 für CLC (implizite Adressierung) befindet sich an der Byte-Position von $0200. Der Opcode für „LDA $0213“, also AD 16 für LDA (absolute Adressierung) befindet sich an der Byte-Position von $0201. Das untere Byte des Augenends, das 10111111 ist, befindet sich im Speicherbyte-Speicherort von $0213. Denken Sie daran, dass jeder Opcode ein Byte belegt. Die „$0213“-Adresse von „LDA $0213“ befindet sich in den Byte-Speicherorten von $0202 und $0203. Der Befehl „LDA $0213“ lädt das untere Byte des Augends in den Akkumulator.

Der Opcode für „ADC $0215“, also 6D 16 für ADC (absolute Adressierung) befindet sich an der Byte-Position von $0204. Das untere Byte des Addends, das 10010101 ist, befindet sich an der Byte-Position $0215. Die „$0215“-Adresse von „ADC $0215“ befindet sich in den Byte-Speicherorten von $0205 und $0206. Der Befehl „ADC $0215“ fügt das untere Byte des Addends zum unteren Byte des bereits im Akkumulator befindlichen Augends hinzu. Das Ergebnis wird zurück in den Akkumulator gelegt. Jeder Übertrag nach dem achten Bit wird an das Übertragsflag des Statusregisters gesendet. Die Carry-Flag-Zelle darf nicht gelöscht werden, bevor die höheren Bytes zum zweiten Mal hinzugefügt werden. Dieser Übertrag wird automatisch zur Summe der höheren Bytes addiert. Tatsächlich wird aufgrund von CLC zu Beginn automatisch ein Übertrag von 0 zur Summe der unteren Bytes hinzugefügt (was bedeutet, dass kein Übertrag hinzugefügt wird).

Der Kommentar dauert die nächsten 48 10 = 30 16 Bytes. Dies bleibt jedoch nur in der Textdatei „.asm“ bestehen. Es gelangt nicht in die Erinnerung. Es wird durch die Übersetzung entfernt, die vom Assembler (einem Programm) durchgeführt wird.

Für die nächste Anweisung, die „STA $0217“ lautet, lautet der Opcode von STA 8D 16 (absolute Adressierung) befindet sich an der Byte-Position von $0207. Die „$0217“-Adresse von „STA $0217“ befindet sich in den Speicherplätzen von $0208 und $0209. Der Befehl „STA $0217“ kopiert den 8-Bit-Inhalt des Akkumulators in den Speicherort $0217.

Das höhere Byte des Augends, das 00101010 ist, befindet sich an der Speicherstelle von $0214, und das höhere Byte des Addends, das 00101010 ist, befindet sich an der Bytestelle von $02 16 . Der Opcode für „LDA $0214“, also AD16 für LDA (absolute Adressierung), befindet sich an der Byte-Position von $020A. Die „$0214“-Adresse von „LDA $0214“ befindet sich an den Orten $020B und $020C. Der Befehl „LDA $0214“ lädt das höhere Byte des Augends in den Akkumulator und löscht alles, was sich im Akkumulator befindet.

Der Opcode für „ADC $0216“, also 6D 16 für ADC (absolute Adressierung) befindet sich an der Byte-Position von $020D. Die „$0216“-Adresse von „ADC 0216“ befindet sich in den Byte-Speicherorten $020E und $020F. Der Befehl „ADC $0216“ fügt das höhere Byte des Summanden zum höheren Byte des Augenden hinzu, der sich bereits im Akkumulator befindet. Das Ergebnis wird zurück in den Akkumulator gelegt. Liegt ein Übertrag von 1 vor, wird dieser bei dieser zweiten Addition automatisch in die Übertragszelle des Statusregisters eingefügt. Obwohl der Übertrag über das sechzehnte Bit (links) hinaus für dieses Problem nicht erforderlich ist, ist es hilfreich zu überprüfen, ob ein Übertrag von 1 aufgetreten ist, indem überprüft wird, ob das Übertragsflag auf 1 gesetzt wurde.

Für den nächsten und letzten Befehl, der „STA $0218“ ist, befindet sich der Opcode von STA, der 8D16 (absolute Adressierung) ist, an der Byte-Position von $0210. Die „$0218“-Adresse von „STA $0218“ befindet sich in den Speicherplätzen von $0211 und $0212. Der Befehl „STA $0218“ kopiert den 8-Bit-Inhalt des Akkumulators in den Speicherort $0218. Das Ergebnis der Addition der beiden 16-Bit-Zahlen ist 0101010101010100, wobei sich das untere Byte von 01010100 im Speicherort $0217 und das höhere Byte 01010101 im Speicherort $0218 befindet – Little Endianness.

Subtraktion
Beim 6502 µP sind die vorzeichenbehafteten Zahlen Zweierkomplementzahlen. Eine Zweierkomplementzahl kann aus acht Bits, sechzehn Bits oder einem beliebigen Vielfachen von acht Bits bestehen. Beim Zweierkomplement ist das erste Bit von links das Vorzeichenbit. Bei einer positiven Zahl ist dieses erste Bit 0, um das Vorzeichen anzuzeigen. Die restlichen Bits bilden auf normale Weise die Zahl. Um das Zweierkomplement einer negativen Zahl zu erhalten, invertieren Sie alle Bits für die entsprechende positive Zahl und addieren Sie dann vom rechten Ende her 1 zum Ergebnis.

Um eine positive Zahl von einer anderen positiven Zahl zu subtrahieren, wird der Subtrahend in eine negative Zweierkomplementzahl umgewandelt. Dann werden der Minuend und die neue negative Zahl wie gewohnt addiert. Die 8-Bit-Subtraktion ergibt also:

Dabei wird der Übertrag als 1 angenommen. Das Ergebnis im Akkumulator ist die Differenz im Zweierkomplement. Um also zwei Zahlen zu subtrahieren, muss das Übertragsflag gesetzt (auf 1 gesetzt) ​​werden.

Beim Subtrahieren zweier 16-Bit-Zahlen erfolgt die Subtraktion zweimal wie bei der Addition zweier 16-Bit-Zahlen. Da die Subtraktion beim 6502 µP eine Form der Addition ist, wird beim Subtrahieren zweier 16-Bit-Zahlen das Übertragsflag nur einmal für die erste Subtraktion gesetzt. Bei der zweiten Subtraktion erfolgt die Einstellung des Übertragsflags automatisch.

Die Programmierung der Subtraktion für 8-Bit-Zahlen oder 16-Bit-Zahlen erfolgt ähnlich wie die Programmierung der Addition. Das Carry-Flag muss jedoch ganz am Anfang gesetzt werden. Die Mnemonik hierfür lautet:

Subtraktion mit positiven Sechzehn-Bit-Zahlen
Betrachten Sie die Subtraktion mit den folgenden Zahlen:

Bei dieser Subtraktion handelt es sich nicht um ein Zweierkomplement. Da die Subtraktion bei 6502 µP im Zweierkomplement erfolgt, erfolgt die Subtraktion zur Basis zwei wie folgt:

Das Ergebnis des Zweierkomplements ist dasselbe wie das Ergebnis, das man aus der gewöhnlichen Subtraktion erhält. Beachten Sie jedoch, dass die 1, die von rechts zur siebzehnten Bitposition geht, ignoriert wird. Der Minuend und der Subtrahend werden in jeweils zwei Achterbits aufgeteilt. Das Zweierkomplement 10010110 des unteren Bytes des Subtrahends wird unabhängig von seinem höheren Byte und einem etwaigen Übertrag bestimmt. Das Zweierkomplement von 11101011 des höheren Bytes des Subtrahends wird unabhängig von seinem unteren Byte und einem etwaigen Übertrag bestimmt.

Die 16 Bits des Minuends liegen bereits im Zweierkomplement vor, beginnend mit 0 von links. Es ist also keine Anpassung in Bits erforderlich. Beim 6502 µP wird das untere Byte des Minuenden unverändert zum unteren Byte des Zweierkomplements des Subtrahenden addiert. Das untere Byte des Minuenden wird nicht im Zweierkomplement umgewandelt, da die sechzehn Bits des gesamten Minuenden bereits im Zweierkomplement stehen müssen (mit einer 0 als erstes Bit links). Bei dieser ersten Addition wird aufgrund der 1=0 SEC-Anweisung ein obligatorischer Übertrag von 1 hinzugefügt.

Bei der aktuellen effektiven Subtraktion gibt es einen Übertrag von 1 (der Addition) vom achten Bit zum neunten Bit (von rechts). Da es sich dabei praktisch um eine Subtraktion handelt, wird jedes Bit, das sich im Übertragsflag im Statusregister befinden soll, ergänzt (invertiert). Der Übertrag von 1 wird also im C-Flag zu 0. In der zweiten Operation wird das höhere Byte des Minuenden zum höheren Zweierkomplement-Byte des Subtrahenden addiert. Das automatisch ergänzte Carry-Flag-Bit des Statusregisters (in diesem Fall 0) wird ebenfalls hinzugefügt (zu den höheren Bytes). Jede 1, die über das sechzehnte Bit von rechts hinausgeht, wird ignoriert.

Der nächste Schritt besteht darin, das gesamte Schema wie folgt zu codieren:

SEK
LDA 0213 $
SBC 0215 $
; Kein Löschen, da der invertierte Carry-Flag-Wert benötigt wird
STA $0217
LDA 0214 $
SBC 0216 $
STA $0218

Denken Sie daran, dass bei der Assemblersprache 6502 ein Semikolon einen Kommentar beginnt, der nicht in die übersetzte Programmversion im Speicher aufgenommen wird. Die beiden 16-Bit-Zahlen zur Subtraktion belegen bei absoluter Adressierung vier Bytes Speicher; zwei pro Zahl (Speicher ist eine Reihe von Bytes). Diese Eingaben erfolgen nicht über die Tastatur. Das Summierungsergebnis beträgt zwei Bytes und muss ebenfalls an einer anderen Stelle im Speicher abgelegt werden. Diese Ausgabe erfolgt nicht auf dem Monitor oder Drucker; es geht in die Erinnerung. Das ergibt insgesamt 6 10 = 6 16 Bytes für Ein- und Ausgänge, die im Speicher (RAM) abgelegt werden sollen.

Bevor ein Programm ausgeführt wird, muss es sich zunächst im Speicher befinden. Betrachtet man den Programmcode, erkennt man, dass die Anweisungen ohne Kommentar 19 ausmachen 10 = 13 16 Bytes. Da alle Programme in diesem Kapitel an der Speicherstelle von $0200 beginnen, wechselt das Programm von der Bytestelle von $0200 im Speicher zur Bytestelle von $0200 + $13 – $1 = $0212 (beginnend bei $0200 und nicht bei $0201). Dieser Bereich umfasst nicht den Bereich für die Eingabe- und Ausgabebytes. Die beiden Eingangsnummern benötigen 4 Bytes und die eine Ausgangsnummer benötigt 2 Bytes. Durch Addition der 6 Bytes für die Eingabe- und Ausgabezahlen ergibt sich der Bereich für das Programm, der bei $0212 + $6 = $0218 endet. Die Gesamtlänge des Programms beträgt 19 16 = 25 10 .

Das niedrigere Byte des Minuends sollte sich in der Adresse $0213 befinden, und das höhere Byte desselben Minuends sollte sich in der Adresse $0214 befinden – Little Endianness. Ebenso sollte sich das untere Byte des Subtrahends in der Adresse $0215 befinden und das höhere Byte desselben Subtrahends in der Adresse $0216 – Little Endianness. Das niedrigere Byte des Ergebnisses (Differenz) sollte sich in der Adresse $0217 befinden, und das höhere Byte desselben Ergebnisses sollte in der Adresse $0218 liegen – Little Endianness.

Der Opcode von 38 16 für SEC (implizite Adressierung) liegt in der $0200-Adresse. Es wird davon ausgegangen, dass alle Programme in diesem Kapitel am Speicherort $0200 beginnen und alle Programme, die sich dort befunden hätten, annullieren; sofern nicht anders angegeben. Der Opcode für „LDA $0213“, also AD 16 , für LDA (absolute Adressierung) befindet sich an der Byte-Position $0201. Das untere Byte des Minuends, das 10111111 ist, befindet sich im Speicherbyte-Speicherort $0213. Denken Sie daran, dass jeder Opcode ein Byte belegt. Die „$0213“-Adresse von „LDA $0213“ befindet sich in den Byte-Speicherorten von $0202 und $0203. Der Befehl „LDA $0213“ lädt das untere Byte des Minuenden in den Akkumulator.

Der Opcode für „SBC $0215“, also ED 16 , für SBC (absolute Adressierung) befindet sich an der Byte-Position $0204. Das untere Byte des Subtrahends, das 01101010 ist, befindet sich an der Byte-Position $0215. Die „$0215“-Adresse von „ADC $0215“ befindet sich in den Byte-Positionen von $0205 und $0206. Der Befehl „SBC $0215“ subtrahiert das untere Byte des Subtrahends vom unteren Byte des Minuends, der sich bereits im Akkumulator befindet. Dies ist die Zweierkomplement-Subtraktion. Das Ergebnis wird zurück in den Akkumulator gelegt. Das Komplement (Inversion) jedes Übertrags nach dem achten Bit wird an das Übertragsflag des Statusregisters gesendet. Dieses Übertragsflag darf nicht vor der zweiten Subtraktion mit den höheren Bytes gelöscht werden. Dieser Übertrag wird automatisch zur Subtraktion der höheren Bytes addiert.

Der Kommentar dauert die nächsten 57 10 = 3916 16 Bytes. Dies bleibt jedoch nur in der Textdatei „.asm“ bestehen. Es gelangt nicht in die Erinnerung. Es wird durch die Übersetzung entfernt, die vom Assembler (einem Programm) durchgeführt wird.

Für die nächste Anweisung, die „STA $0217“ ist, der Opcode von STA, also 8D 16 (absolute Adressierung) befindet sich im Byte-Speicherort $0207. Die „$0217“-Adresse von „STA $0217“ befindet sich in den Speicherplätzen von $0208 und $0209. Der Befehl „STA $0217“ kopiert den 8-Bit-Inhalt des Akkumulators in den Speicherort $0217.

Das höhere Byte des Minuends, das 00101010 ist, befindet sich an der Speicherstelle von $0214, und das höhere Byte des Subtrahends, das 00010101 ist, befindet sich an der Bytestelle von $0216. Der Opcode für „LDA $0214“, also AD 16 für LDA (absolute Adressierung) befindet sich an der Byte-Position $020A. Die „$0214“-Adresse von „LDA $0214“ befindet sich an den Orten $020B und $020C. Der Befehl „LDA $0214“ lädt das höhere Byte des Minuenden in den Akkumulator und löscht alles, was sich im Akkumulator befindet.

Der Opcode für „SBC $0216“, also ED 16 für SBC (absolute Adressierung) befindet sich an der Byte-Position $020D. Die „$0216“-Adresse von „SBC $0216“ befindet sich in den Byte-Positionen von $020E und $020F. Der Befehl „SBC $0216“ subtrahiert das höhere Byte des Subtrahends vom höheren Byte des Minuenden (Zweierkomplement), das sich bereits im Akkumulator befindet. Das Ergebnis wird zurück in den Akkumulator gelegt. Wenn es für diese zweite Subtraktion einen Übertrag von 1 gibt, wird sein Komplement automatisch in die Übertragszelle des Statusregisters eingefügt. Obwohl der Übertrag über das sechzehnte Bit (links) hinaus für dieses Problem nicht erforderlich ist, ist es sinnvoll, durch Überprüfen des Übertragsflags zu überprüfen, ob der Komplementübertrag auftritt.

Für die nächste und letzte Anweisung, die „STA $0218“, ist der Opcode von STA, also 8D 16 (absolute Adressierung) befindet sich im Byte-Speicherort $0210. Die „$0218“-Adresse von „STA $0218“ befindet sich in den Speicherplätzen von $0211 und $0212. Der Befehl „STA $0218“ kopiert den 8-Bit-Inhalt des Akkumulators in den Speicherort $0218. Das Ergebnis der Subtraktion mit den beiden Sechzehn-Bit-Zahlen ist 0001010101010101 mit dem unteren Byte 01010101 im Speicherort $0217 und dem höheren Byte 00010101 im Speicherort $0218 – Little Endianness.

Der 6502 µP verfügt nur über Schaltkreise für die Addition und indirekt für die Zweierkomplement-Subtraktion. Es verfügt nicht über Schaltkreise für Multiplikation und Division. Um die Multiplikation und Division durchzuführen, sollte ein Assemblerprogramm mit Details, einschließlich der Verschiebung von Teilprodukten und Teildividenden, geschrieben werden.

4.4 Logische Operationen

Im 6502 µP ist die Mnemonik für OR ORA und die Mnemonik für Exklusiv-OR EOR. Beachten Sie, dass die logischen Operationen nicht über die implizite Adressierung verfügen. Die implizite Adressierung benötigt keinen Operanden. Jeder der logischen Operatoren muss zwei Operanden annehmen. Der erste befindet sich im Akkumulator und der zweite im Speicher oder in der Anweisung. Das Ergebnis (8 Bit) wird zurück in den Akkumulator geschrieben. Der erste im Akkumulator wird entweder durch einen sofortigen Befehl dorthin gelegt oder mit absoluter Adressierung aus dem Speicher kopiert. In diesem Abschnitt wird zur Veranschaulichung nur die Zero-Page-Adressierung verwendet. Diese logischen Operatoren sind alle bitweise Operatoren.

UND
Die folgende Tabelle veranschaulicht das bitweise UND in binärer, hexadezimaler und dezimaler Form:

Alle Programme in diesem Kapitel sollten an der Speicherbyte-Position $0200 beginnen. Die Programme in diesem Abschnitt befinden sich jedoch auf Seite Null, mit dem Ziel, die Verwendung von Seite Null ohne das höhere Byte 00000000 zu veranschaulichen 2 . Die vorherige UND-Verknüpfung kann wie folgt codiert werden:

LDA #$9A ; nicht aus dem Gedächtnis – sofortige Adressierung
UND #$CD ; nicht aus dem Gedächtnis – sofortige Adressierung
STA $30; speichert 88 $ bei nullbasierten 0,030 $

ODER
Die folgende Tabelle veranschaulicht das bitweise ODER im Binär-, Hexadezimal- und Dezimalformat:

LDA #$9A ; nicht aus dem Gedächtnis – sofortige Adressierung
ORA #$CD ; nicht aus dem Gedächtnis – sofortige Adressierung
STA $30; speichert $CF bei nullbasiertem $0030

FREI
Die folgende Tabelle veranschaulicht das bitweise XOR in binärer, hexadezimaler und dezimaler Form:

LDA #$9A ; nicht aus dem Gedächtnis – sofortige Adressierung
EOR #$CD ; nicht aus dem Gedächtnis – sofortige Adressierung
STA $30; speichert 57 $ bei nullbasierten 0,030 $

4.5 Schiebe- und Drehvorgänge

Die Mnemoniken und Opcodes für die Verschiebungs- und Rotationsoperatoren sind:

ASL: Verschieben Sie den Akkumulator oder Speicherplatz um ein Bit nach links und fügen Sie 0 in die frei gewordene Zelle ganz rechts ein.

LSR: Verschieben Sie den Akkumulator oder Speicherplatz um ein Bit nach rechts und fügen Sie 0 in die frei gewordene Zelle ganz links ein.
ROL: Drehen Sie ein Bit nach links vom Akkumulator oder Speicherort und fügen Sie das Bit, das links herausgefallen ist, in die frei gewordene Zelle ganz rechts ein.
ROR: Drehen Sie ein Bit nach rechts vom Akkumulator oder Speicherort und fügen Sie das Bit, das rechts herausgefallen ist, in die frei gewordene Zelle ganz links ein.

Um eine Verschiebung oder Rotation mit dem Akku durchzuführen, lautet die Anweisung etwa so:

LSR A

Dabei wird ein anderer Adressierungsmodus verwendet, der als Akkumulator-Adressierungsmodus bezeichnet wird.

Um eine Verschiebung oder Rotation mit einem Byte-Speicherort durchzuführen, sieht die Anweisung etwa so aus:

ROR $2BCD

Wobei 2BCD der Speicherort ist.

Beachten Sie, dass es keinen unmittelbaren oder impliziten Adressierungsmodus für das Verschieben oder Drehen gibt. Es gibt keinen unmittelbaren Adressierungsmodus, da es keinen Sinn macht, eine Zahl zu verschieben oder zu drehen, die nur in der Anweisung verbleibt. Es gibt keinen impliziten Adressierungsmodus, da die Entwickler des 6502 µP nur den Inhalt des Akkumulators (A-Register) oder eine Speicherbytestelle verschieben oder rotieren möchten.

4.6 Relativer Adressierungsmodus

Der Mikroprozessor erhöht den Programmzähler (PC) stets (um 1, 2 oder 3 Einheiten), um auf den nächsten auszuführenden Befehl hinzuweisen. Der 6502 µP verfügt über einen Befehl, dessen Mnemonik BVS ist, was „Branch on Overflow Set“ bedeutet. Der PC besteht aus zwei Bytes. Dieser Befehl bewirkt, dass der PC eine andere Speicheradresse für den nächsten auszuführenden Befehl hat, der nicht aus einer normalen Inkrementierung resultiert. Dies geschieht durch Addition oder Subtraktion eines Wertes, der als Offset bezeichnet wird, zum Inhalt des PCs. Der PC verweist dann auf einen anderen (verzweigten) Speicherort, damit der Computer von dort aus die Ausführung fortsetzen kann. Der Offset ist eine Ganzzahl von -128 10 bis +127 10 (Zweierkomplement). Der Offset kann also dazu führen, dass der Sprung im Speicher voranschreitet. Ob es positiv ist oder im Gedächtnis zurückbleibt, oder ob es negativ ist.

Der BVS-Befehl benötigt nur einen Operanden, nämlich den Offset. BVS verwendet die relative Adressierung. Beachten Sie die folgende Anweisung:

BVS 7F $

In Basis zwei, 7F H ist 01111111 2 = 127 10 . Gehen Sie davon aus, dass der Inhalt im PC für die nächste Anweisung 0300 $ beträgt. Der BVS-Befehl bewirkt, dass $7F (eine positive Zahl bereits im Zweierkomplement) zu $0300 addiert wird, um $037F zu ergeben. Anstelle des nächsten Befehls, der am Speicherort $0300 ausgeführt werden soll, befindet er sich also am Speicherort $037F (ungefähr eine halbe Seitendifferenz).

Es gibt andere Verzweigungsanweisungen, aber BVS eignet sich sehr gut zur Veranschaulichung der relativen Adressierung. Bei der relativen Adressierung handelt es sich um Verzweigungsanweisungen.

4.7 Indizierte Adressierung und indirekte Adressierung getrennt

Diese Adressierungsmodi ermöglichen es dem 6502 µP, enorme Datenmengen in kurzer Zeit und mit einer reduzierten Anzahl von Befehlen zu verarbeiten. Es gibt 64-KB-Speicherplätze für den gesamten Comodore-64-Speicher. Um also auf eine beliebige Byte-Position mit 16 Bits zugreifen zu können, sind zwei Bytes erforderlich. Die einzige Ausnahme von der Notwendigkeit von zwei Bytes besteht für Seite Null, wo das höhere Byte von $00 weggelassen wird, um den von der Anweisung im Speicher belegten Platz zu sparen. Bei einem Nicht-Seite-Null-Adressierungsmodus werden sowohl die höheren als auch die niedrigeren Bytes der 16-Bit-Speicheradresse meistens irgendwie angezeigt.

Grundlegende indizierte Adressierung

Absolute Indexadressierung
Denken Sie daran, dass das X- oder Y-Register als Indexregister bezeichnet wird. Beachten Sie die folgende Anweisung:

LDA $C453,X

Nehmen Sie an, dass der Wert 6 ist H steht im X-Register. Beachten Sie, dass 6 nirgendwo in der Anweisung eingegeben wird. Diese Anweisung fügt den Wert 6H zu C453 hinzu H Dies ist Teil der typisierten Anweisung in der Textdatei, die noch zusammengesetzt werden muss – C453 H + 6 H = C459 H . LDA bedeutet, ein Byte in den Akkumulator zu laden. Das in den Akkumulator zu ladende Byte stammt von der Adresse $C459. Der $C459 ist die Summe von $C453, die mit der Anweisung eingegeben wird, und 6 H Die im X-Register gefundene Adresse wird zur effektiven Adresse, von der das in den Akkumulator zu ladende Byte stammt. Wenn 6 H im Y-Register war, wird in der Anweisung Y anstelle von X eingegeben.

In der typisierten Anweisungsanweisung ist $C453 als Basisadresse bekannt und die 6 H im X- oder Y-Register wird als Zähl- oder Indexteil für die effektive Adresse bezeichnet. Die Basisadresse kann sich auf eine beliebige Byte-Adresse im Speicher beziehen, die nächsten 256 10 Auf Adressen kann zugegriffen werden, vorausgesetzt, dass der Startindex (oder die Anzahl) im X- oder Y-Register 0 ist. Denken Sie daran, dass ein Byte einen kontinuierlichen Bereich von bis zu 256 ergeben kann 10 Zahlen (z. B. 00000000 2 bis 11111111 2 ).

Bei der absoluten Adressierung wird also alles, was bereits in das In der typisierten Anweisung werden die beiden Indexregister durch X oder Y unterschieden, die nach einem Komma eingegeben werden. Entweder X oder Y wird eingegeben; nicht beide.

Nachdem das Programm in einem Texteditor eingegeben und mit der Dateinamenerweiterung „.asm“ gespeichert wurde, muss der Assembler, der ein anderes Programm ist, das eingegebene Programm in das übersetzen, was im Speicher (geladen) ist. Der vorherige Befehl, der „LDA $C453,X“ lautet, belegt drei Byte-Speicherplätze im Speicher und nicht fünf.

Denken Sie daran, dass eine Mnemonik wie LDA mehr als einen Opcode (verschiedene Bytes) haben kann. Der Opcode für den Befehl, der das X-Register verwendet, unterscheidet sich vom Opcode, der das Y-Register verwendet. Der Assembler weiß anhand der eingegebenen Anweisung, welchen Opcode er verwenden muss. Der Ein-Byte-Opcode für „LDA $C453,X“ unterscheidet sich vom Ein-Byte-Opcode für „LDA $C453,Y“. Tatsächlich ist der Opcode für LDA in „LDA $C453,X“ BD und der Opcode für LDA in „LDA $C453,9“ ist BD.

Wenn sich der Opcode für LDA am Byte-Speicherort $0200 befindet. Dann nimmt die 16-Bit-Adresse von $C453 die nächsten Byte-Positionen im Speicher ein, die $0201 und $0202 sind. Das jeweilige Opcode-Byte gibt an, ob es sich um das X-Register oder das Y-Register handelt. Daher belegt der zusammengesetzte Sprachbefehl „LDA $C453,X“ oder „LDA $C453,Y“ drei aufeinanderfolgende Bytes im Speicher und nicht vier oder fünf.

Zero-Page-indizierte Adressierung
Die Nullseiten-Indexadressierung ähnelt der zuvor beschriebenen absoluten Indexadressierung, das Zielbyte darf sich jedoch nur auf Seite Null befinden (von $0000 bis $00FF). Wenn es nun um die Nullseite geht, ist das höhere Byte immer 00 H für die Speicherorte wird in der Regel vermieden. Daher wird normalerweise erwähnt, dass Seite Null von $00 bis FF beginnt. Die vorherige Anweisung von „LDA $C453,X“ lautet also:

LDA 53,X $

Das $C4, ein höheres Byte, das sich auf eine Seite über dem Seitennullpunkt bezieht, kann in dieser Anweisung nicht verwendet werden, da es das erwartete Zielbyte, das in das akkumulierte Byte geladen werden soll, außerhalb und über dem Seitennullpunkt platziert.

Wenn der in der Anweisung eingegebene Wert zum Wert im Indexregister addiert wird, sollte die Summe kein Ergebnis über dem Seitennullpunkt (FF) ergeben H ). Es kommt also nicht in Frage, eine Anweisung wie „LDA $FF, X“ und einen Wert wie FF zu haben H im Indexregister, weil FF H + FF H = 200 H Dabei handelt es sich um die Position des ersten Bytes ($0200) von Seite 2 (dritte Seite) im Speicher, die weit von Seite 0 entfernt ist. Bei der Nullseiten-indizierten Adressierung muss die effektive Adresse also auf Seite Null liegen.

Indirekte Adressierung

Springen Sie zur absoluten Adressierung
Bevor wir uns mit der absoluten indirekten Adressierung befassen, sollten wir uns zunächst mit der absoluten Adressierung von JMP befassen. Nehmen Sie an, dass die Adresse mit dem interessierenden Wert (Zielbyte) 8765 $ ist. Dies sind 16 Bit, die aus zwei Bytes bestehen: Das höhere Byte ist 87 H und das untere Byte ist 65 H . Daher werden die zwei Bytes für 8765 $ für den nächsten Befehl in den PC (Programmzähler) gelegt. Was in das Assembler-Programm (Datei) eingegeben wird, ist:

JMP 8765 $

Das ausführende Programm im Speicher springt von der Adresse, auf die es zugegriffen hat, zu 8765 $. Die JMP-Mnemonik hat drei Opcodes: 4C, 6C und 7C. Der Opcode für diese absolute Adressierung ist 4C. Der Opcode für die absolute indirekte JMP-Adressierung ist 6C (siehe folgende Abbildungen).

Absolute indirekte Adressierung
Dies wird nur mit der Sprunganweisung (JMP) verwendet. Nehmen Sie an, dass die Adresse mit dem interessierenden Byte (Zielbyte) 8765 $ ist. Dies sind 16 Bit, die aus zwei Bytes bestehen: Das höhere Byte ist 87 H und das untere Byte ist 65 H . Bei der absoluten indirekten Adressierung befinden sich diese beiden Bytes tatsächlich an zwei aufeinanderfolgenden Byte-Speicherorten an anderer Stelle im Speicher.

Gehen Sie davon aus, dass sie sich an den Speicherorten $0210 und $0211 befinden. Dann das untere Byte der interessierenden Adresse, das 65 ist H befindet sich in der Adresse $0210 und im höheren Byte, das 87 ist H befindet sich in der Adresse $0211. Das bedeutet, dass das niedrigere interessierende Speicherbyte an eine niedrigere aufeinanderfolgende Adresse geht und das höhere interessierende Speicherbyte an die höhere aufeinanderfolgende Adresse geht – Little Endianness.

Die 16-Bit-Adresse kann sich auf zwei aufeinanderfolgende Adressen im Speicher beziehen. In diesem Sinne bezieht sich die Adresse $0210 auf die Adressen $0210 und $0211. Das Adresspaar $0210 und $0211 enthält die endgültige Adresse (16 Bits von zwei Bytes) des Zielbytes, wobei das untere Byte 65 ist H in $0210 und dem höheren Byte von 87 H in 0211 $. Die eingegebene Sprunganweisung lautet also:

JMP (0210 $)

Die JMP-Mnemonik hat drei Opcodes: 4C, 6C und 7C. Der Opcode für die absolute indirekte Adressierung ist 6C. In die Textdatei wird „JMP ($0210)“ eingegeben. Aufgrund der Klammern verwendet der Assembler (Übersetzer) für JMP den Opcode 6C und nicht 4C oder 7C.

Bei der absoluten indirekten Adressierung gibt es tatsächlich drei Speicherbereiche. Der erste Bereich kann aus den Byte-Speicherorten $0200, $0201 und $0202 bestehen. Dies enthält die drei Bytes für die Anweisung „JMP ($0210)“. Der zweite Bereich, der nicht unbedingt neben dem ersten liegt, besteht aus den beiden aufeinanderfolgenden Byte-Speicherorten $0210 und $0211. Es ist hier das untere Byte ($0210), das in der Assembler-Programmanweisung eingegeben wird. Wenn die interessierende Adresse $8765 ist, das untere Byte von 65 H befindet sich im Byte-Speicherort $0210 und im höheren Byte von 87 H befindet sich im Byte-Speicherort $0211. Der dritte Bereich besteht aus nur einem Byte-Speicherort. Es handelt sich um die $8765-Adresse für das Zielbyte (letztes interessierende Byte). Das Paar aufeinanderfolgender Adressen, $0210 und $0211, enthält den Zeiger $8765, der die interessierende Adresse darstellt. Nach der Recheninterpretation sind es 8765 $, die in den PC (Programmzähler) fließen, um auf das Zielbyte zuzugreifen.

Indirekte Zero-Page-Adressierung
Diese Adressierung ist die gleiche wie die absolute indirekte Adressierung, der Zeiger muss sich jedoch auf Seite Null befinden. Die untere Byteadresse des Zeigerbereichs ist wie folgt in der typisierten Anweisung angegeben:

JMP (50 $)

Das höhere Byte des Zeigers befindet sich an der Byte-Position $51. Die effektive Adresse (zeigt) muss sich nicht auf Seite Null befinden.

Bei der Indexadressierung wird also der Wert in einem Indexregister zur Basisadresse addiert, die im Befehl angegeben ist, um die effektive Adresse zu erhalten. Die indirekte Adressierung verwendet einen Zeiger.

4.8 Indizierte indirekte Adressierung

Absolut indizierte indirekte Adressierung
Dieser Adressierungsmodus wird nur mit dem JMP-Befehl verwendet.
Bei der absoluten indirekten Adressierung gibt es den angezeigten Wert (Byte) mit seinen eigenen zwei aufeinanderfolgenden Byte-Adressen. Diese beiden aufeinanderfolgenden Adressen bilden den Zeiger, der im Zeigerbereich von zwei aufeinanderfolgenden Bytes im Speicher liegt. Das untere Byte des Zeigerbereichs ist das, was in der Anweisung in Klammern eingegeben wird. Der Zeiger ist die Adresse des angezeigten Werts. In der vorherigen Situation ist $8765 die Adresse des angegebenen Werts. $0210 (gefolgt von $0211) ist die Adresse, deren Inhalt $8765 ist, was den Zeiger darstellt. Beim absoluten indirekten Adressierungsmodus wird ($0210) einschließlich der Klammern in das Programm (Textdatei) eingegeben.

Beim Absolute Indexed Indirect Addressing Mode hingegen wird das untere Adressbyte für den Zeigerbereich durch Addition des Werts im X-Register zur typisierten Adresse gebildet. Befindet sich der Zeiger beispielsweise an der Adressposition von $0210, könnte die typisierte Anweisung etwa so aussehen:

JMP ($020A,X)

Wobei das X-Register den Wert 6 hat H . 020A H + 6 H = 0210 H . Das Y-Register wird bei diesem Adressierungsmodus nicht verwendet.

Nullseitenindizierte indirekte Adressierung
Dieser Adressierungsmodus verwendet das X-Register und nicht das Y-Register. Bei diesem Adressierungsmodus gibt es immer noch den angezeigten Wert und den Zeiger in seinem Zwei-Byte-Adresszeigerbereich. Für den Zeiger müssen auf der Seite Null zwei aufeinanderfolgende Bytes vorhanden sein. Die in der Anweisung eingegebene Adresse ist eine Ein-Byte-Adresse. Dieser Wert wird zum Wert im X-Register addiert und etwaige Überträge werden verworfen. Das Ergebnis zeigt auf den Zeigerbereich auf Seite 0. Wenn die interessierende (zeigte) Adresse beispielsweise $8765 ist und sie sich an den Byte-Positionen $50 und $51 von Seite 0 befindet und der Wert im X-Register $30 ist, beträgt die Die getippte Anweisung sieht etwa so aus:

LDA ($20,X)

Weil 20 $ + 30 $ = 50 $.

Indirekte indizierte Adressierung
Dieser Adressierungsmodus verwendet das Y-Register und nicht das X-Register. Bei diesem Adressierungsmodus gibt es immer noch den Zeigerwert und den Zeigerbereich, aber der Inhalt des Zeigerbereichs funktioniert anders. Für den Zeigerbereich müssen auf der Seite Null zwei aufeinanderfolgende Bytes vorhanden sein. Die untere Adresse des Zeigerbereichs wird in die Anweisung eingegeben. Diese im Zeigerbereich enthaltene Zahl (Bytepaar) wird zum Wert im Y-Register addiert, um den tatsächlichen Zeiger zu erhalten. Angenommen, die interessierende Adresse (zeigt) sei $8765, der Wert von 6H befinde sich im Y-Register und die Zahl (zwei Bytes) befinde sich an der Adresse 50 H und 51 H . Die beiden Bytes zusammen ergeben 875 F $, da 875 F $ + 6 $ = 8765 $. Die getippte Anweisung sieht etwa so aus:

LDA (50 $),Y

4.9 Anweisungen zum Inkrementieren, Dekrementieren und Testen von BITs

Die folgende Tabelle zeigt die Operationen der Inkrementierungs- und Dekrementierungsanweisungen:

INA und DEA erhöhen bzw. dekrementieren den Akkumulator. Das nennt man Akku-Adressierung. INX, DEX, INY und DEY stehen für die X- bzw. Y-Register. Sie übernehmen keinen Operanden. Sie verwenden also den impliziten Adressierungsmodus. Inkrement bedeutet das Hinzufügen von 1 zum Register- oder Speicherbyte. Dekrementieren bedeutet, 1 vom Register- oder Speicherbyte zu subtrahieren.

INC und DEC erhöhen bzw. dekrementieren ein Speicherbyte (und kein Register). Durch die Verwendung der Nullseitenadressierung anstelle der absoluten Adressierung soll der Speicher für den Befehl eingespart werden. Die Nullseitenadressierung ist ein Byte weniger als die absolute Adressierung für den Befehl im Speicher. Der Nullseiten-Adressierungsmodus wirkt sich jedoch nur auf die Seite Null aus.

Der BIT-Befehl testet die Bits eines Bytes im Speicher mit den 8 Bits im Akkumulator, ändert jedoch keines davon. Nur einige Flags des Prozessorstatusregisters „P“ sind gesetzt. Die Bits des angegebenen Speicherplatzes werden mit denen des Akkumulators logisch UND-verknüpft. Anschließend werden folgende Statusbits gesetzt:

  • N, das Bit 7 und das letzte Bit (links) des Statusregisters ist, empfängt vor der UND-Verknüpfung Bit 7 des Speicherplatzes.
  • V, das Bit 6 des Statusregisters ist, empfängt vor der UND-Verknüpfung Bit 6 des Speicherplatzes.
  • Das Z-Flag des Statusregisters wird gesetzt (auf 1 gesetzt), wenn das Ergebnis der UND-Operation Null (00000000) ist 2 ). Andernfalls wird es gelöscht (auf 0 gesetzt).

4.10 Anweisungen vergleichen

Die Vergleichsbefehlsmnemoniken für den 6502 µP sind CMP, CPX und CPY. Nach jedem Vergleich werden die N-, Z- und C-Flags des Prozessorstatusregisters „P“ beeinflusst. Das N-Flag wird gesetzt (auf 1 gesetzt), wenn das Ergebnis eine negative Zahl ist. Das Z-Flag wird gesetzt (auf 1 gesetzt), wenn das Ergebnis eine Null (000000002) ist. Das C-Flag wird gesetzt (auf 1 gesetzt), wenn es einen Übertrag vom achten zum neunten Bit gibt. Die folgende Tabelle gibt eine detaillierte Darstellung

Das bedeutet „größer als“. Damit sollte die Vergleichstabelle selbsterklärend sein.

4.11 Sprung- und Verzweigungsanweisungen

Die folgende Tabelle fasst die Sprung- und Verzweigungsanweisungen zusammen:

Der JMP-Befehl verwendet die absolute und indirekte Adressierung. Die restlichen Anweisungen in der Tabelle sind Verzweigungsanweisungen. Sie verwenden nur die relative Adressierung mit dem 6502 µP. Dadurch wird die Tabelle selbsterklärend, wenn sie von links nach rechts und von oben nach unten gelesen wird.

Beachten Sie, dass die Verzweigungen nur auf Adressen angewendet werden können, die zwischen -128 und +127 Bytes von der angegebenen Adresse entfernt liegen. Dies ist eine relative Adressierung. Sowohl bei den JMP- als auch bei den Verzweigungsanweisungen ist der Programmzähler (PC) direkt betroffen. Der 6502 µP erlaubt keine Verzweigungen zu einer absoluten Adresse, obwohl der Sprung die absolute Adressierung übernehmen kann. Der JMP-Befehl ist kein Verzweigungsbefehl.

Notiz: Die relative Adressierung wird nur bei Verzweigungsanweisungen verwendet.

4.12 Der Stapelbereich

Eine Unterroutine ist wie eines der vorherigen Kurzprogramme zum Addieren oder Subtrahieren zweier Zahlen. Der Stapelbereich im Speicher beginnt bei $0100 bis einschließlich $01FF. Dieser Bereich wird einfach Stapel genannt. Wenn der Mikroprozessor einen Sprung zur Unterprogrammanweisung (JSR – siehe folgende Diskussion) ausführt, muss er wissen, wohin er nach Abschluss zurückkehren soll. Der 6502 µP speichert diese Informationen (Rückgabeadresse) im unteren Speicher von $0100 bis $01FF (dem Stapelbereich) und verwendet den Inhalt des Stapelzeigerregisters, der im Mikroprozessor „S“ ist, als Zeiger (9 Bit) auf die zuletzt zurückgegebene Adresse der auf Seite 1 ($0100 bis $01FF) des Speichers gespeichert ist. Der Stack wächst ab $01FF und ermöglicht die Verschachtelung der Unterprogramme bis zu einer Tiefe von 128 Ebenen.

Eine andere Verwendung des Stapelzeigers besteht darin, die Interrupts zu verarbeiten. Beim 6502 µP sind die Pins mit IRQ und NMI gekennzeichnet. Es ist möglich, dass an diese Pins einige kleine elektrische Signale angelegt werden, die dazu führen, dass der 6502 µP die Ausführung eines Programms beendet und mit der Ausführung eines anderen beginnt. In diesem Fall wird das erste Programm unterbrochen. Wie Unterprogramme können die Interrupt-Codesegmente verschachtelt werden. Die Interrupt-Verarbeitung wird im nächsten Kapitel besprochen.

Notiz : Der Stapelzeiger verfügt über 8 Bits für die untere Byteadresse bei der Adressierung der Speicherorte von $0100 bis $01FF. Das höhere Byte von 00000001 2 wird angenommen.

Die folgende Tabelle enthält die Anweisungen, die den Stapelzeiger „S“ mit den A-, X-, Y- und P-Registern dem Stapelbereich im Speicher zuordnen:

4.13 Aufruf und Rückkehr eines Unterprogramms

Eine Unterroutine ist eine Reihe von Anweisungen, die ein bestimmtes Ziel erreichen. Das vorherige Additions- oder Subtraktionsprogramm ist ein sehr kurzes Unterprogramm. Unterprogramme werden manchmal einfach Routinen genannt. Die Anweisung zum Aufrufen einer Unterroutine lautet:

JSR: Zur Subroutine springen

Die Anweisung zum Zurückkehren aus einem Unterprogramm lautet:

RTS: Rückkehr vom Unterprogramm

Der Mikroprozessor hat die Tendenz, die Anweisungen im Speicher kontinuierlich nacheinander auszuführen. Nehmen Sie an, dass der Mikroprozessor gerade ein Codesegment ausführt und auf einen Sprungbefehl (JMP) stößt, um ein Codesegment auszuführen, das dahinter codiert ist und möglicherweise bereits ausgeführt wurde. Es führt das Codesegment dahinter aus und fährt mit der Ausführung aller Codesegmente (Anweisungen) fort, die auf das Codesegment dahinter folgen, bis es das aktuelle Codesegment erneut ausführt und unten fortfährt. JMP verschiebt die nächste Anweisung nicht auf den Stapel.

Im Gegensatz zu JMP schiebt JSR die Adresse des nächsten Befehls nach sich selbst vom PC (Programmzähler) auf den Stapel. Die Stapelposition dieser Adresse wird im Stapelzeiger „S“ platziert. Wenn im Unterprogramm ein RTS-Befehl angetroffen (ausgeführt) wird, wird die Adresse, die auf den Stapel geschoben wird, vom Stapel abgezogen, und das Programm wird an der abgezogenen Adresse fortgesetzt, die die nächste Befehlsadresse unmittelbar vor dem Aufruf des Unterprogramms ist. Die letzte Adresse, die vom Stapel entfernt wird, wird an den Programmzähler gesendet. Die folgende Tabelle enthält die technischen Details der JSR- und RTS-Anweisungen:

Die Verwendung von JSR und RTS finden Sie in der folgenden Abbildung:

4.14 Ein Beispiel für eine Countdown-Schleife

Das folgende Unterprogramm zählt von $FF bis $00 herunter (insgesamt 256). 10 zählt):

LDX starten #$FF ; Laden Sie X mit $FF = 255
Schleife DEX ; X = X – 1
BNE-Schleife; Wenn X nicht Null ist, gehe zur Schleife
RTS; zurückkehren

Jede Zeile hat einen Kommentar. Kommentare werden nie zur Ausführung gespeichert. Der Assembler (Übersetzer), der ein Programm zur Ausführung (Ausführung) in das umwandelt, was es im Speicher ist, entfernt immer die Kommentare. Ein Kommentar beginnt mit „;“ . „Start“ und „Schleife“ werden in diesem Programm als Labels bezeichnet. Eine Bezeichnung identifiziert (den Namen) für die Adresse der Anweisung. Wenn es sich bei der Anweisung um eine Einzelbyte-Anweisung handelt (implizite Adressierung), ist die Bezeichnung die Adresse dieser Anweisung. Wenn es sich bei der Anweisung um eine Multibyte-Anweisung handelt, identifiziert die Bezeichnung das erste Byte für die Multibyte-Anweisung. Die erste Anweisung für dieses Programm besteht aus zwei Bytes. Unter der Annahme, dass es bei der Adresse $0300 beginnt, kann die Adresse $0300 unten im Programm durch „start“ ersetzt werden. Der zweite Befehl (DEX) ist ein Einzelbyte-Befehl und sollte sich an der Adresse $0302 befinden. Dies bedeutet, dass die Adresse $0302 unten im Programm durch eine „Schleife“ ersetzt werden kann, was in der „BNE-Schleife“ tatsächlich der Fall ist.

„BNE-Schleife“ bedeutet die Verzweigung zur angegebenen Adresse, wenn das Z-Flag des Statusregisters 0 ist. Wenn der Wert im A-, X- oder Y-Register 00000000 ist 2 Aufgrund der letzten Operation ist das Z-Flag 1 (gesetzt). Während es also 0 (nicht 1) ist, werden die zweite und dritte Anweisung im Programm in dieser Reihenfolge wiederholt. In jeder wiederholten Sequenz wird der Wert (ganze Zahl) im X-Register um 1 verringert. DEX bedeutet X = X – 1. Wenn der Wert im X-Register $00 = 00000000 ist 2 , Z wird 1. An diesem Punkt gibt es keine Wiederholung der beiden Anweisungen mehr. Der letzte RTS-Befehl im Programm, bei dem es sich um einen Einzelbyte-Befehl (implizite Adressierung) handelt, kehrt vom Unterprogramm zurück. Die Wirkung dieser Anweisung besteht darin, dass die Programmzähleradresse im Stapel für den Code festgelegt wird, der vor dem Unterprogrammaufruf ausgeführt werden soll, und zum Programmzähler (PC) zurückgekehrt wird. Diese Adresse ist die Adresse des Befehls, der vor dem Aufruf des Unterprogramms ausgeführt werden soll.

Notiz: Beim Schreiben eines Assemblerprogramms für den 6502 µP darf nur ein Label am Anfang einer Zeile beginnen; Jeder andere Zeilencode muss um mindestens eine Stelle nach rechts verschoben werden.

Aufrufen einer Unterroutine
Ohne den Speicherplatz zu ignorieren, der von den vorherigen Labels belegt wird, belegt das Programm 6 Bytes aufeinanderfolgender Speicherorte (RAM) von $0300 bis $0305. In diesem Fall lautet das Programm:

LDX #$FF ; Laden Sie X mit $FF = 255
DEX; X = X – 1
BNE $0302 ; Wenn X nicht Null ist, gehe zur Schleife
RTS; zurückkehren

Ab der Adresse $0200 im Speicher kann der Aufruf des Unterprogramms erfolgen. Die Aufrufanweisung lautet:

JSR-Start; Start ist Adresse $0300, also JSR $0300

Die Unterroutine und ihr Aufruf, die ordnungsgemäß in die Texteditordatei geschrieben sind, sind:

LDX starten #$FF; Laden Sie X mit $FF = 255
Schleife DEX ; X = X – 1

BNE-Schleife; Wenn X nicht Null ist, gehe zur Schleife
RTS; zurückkehren

JSR-Start: Zur Routine springen, beginnend bei 0300 $

Nun kann es in einem langen Programm viele Unterprogramme geben. Sie können nicht alle den Namen „Start“ haben. Sie sollten unterschiedliche Namen haben. Tatsächlich dürfte keiner von ihnen den Namen „Start“ tragen. Aus didaktischen Gründen wird hier „Start“ verwendet.

4.15 Ein Programm übersetzen

Ein Programm zu übersetzen oder es zusammenzustellen bedeutet dasselbe. Betrachten Sie das folgende Programm:

LDX starten #$FF : X mit $FF = 255 laden
Schleife DEX: X = X – 1
BNE-Schleife: Wenn X nicht Null ist, gehe zur Schleife
RTS: Rückkehr
JSR-Start: Zur Routine springen, beginnend bei 0300 $

Dies ist das Programm, das zuvor geschrieben wurde. Es besteht aus dem Unterprogramm, dem Start und dem Aufruf des Unterprogramms. Das Programm zählt von 255 herunter 10 auf 0 10 . Das Programm beginnt an der Benutzeranfangsadresse $0200 (RAM). Das Programm wird in einen Texteditor eingegeben und auf der Festplatte gespeichert. Es hat einen Namen wie „sample.asm“, wobei „sample“ der vom Programmierer gewählte Name ist, die Erweiterung „.asm“ für die Assemblersprache jedoch mit dem Dateinamen verknüpft sein muss.

Das zusammengestellte Programm wird von einem anderen Programm erstellt, das als Assembler bezeichnet wird. Der Assembler wird vom Hersteller des 6502 µP oder von einem Drittanbieter geliefert. Der Assembler reproduziert das Programm so, dass es sich während der Ausführung (Run) im Speicher (RAM) befindet.

Nehmen Sie an, dass der JSR-Befehl an der Adresse $0200 beginnt und das Unterprogramm an der Adresse $0300 beginnt. Der Assembler entfernt alle Kommentare und Leerzeichen. Die Kommentare und Leerzeichen verschwenden den Speicher, der immer knapp ist. Eine mögliche Leerzeile zwischen dem vorherigen Unterprogrammcodesegment und dem Unterprogrammaufruf ist ein Beispiel für Leerzeichen. Die zusammengestellte Datei wird weiterhin auf der Festplatte gespeichert und trägt etwa den Namen „sample.exe“. „Beispiel“ ist der vom Programmierer gewählte Name, die Erweiterung „.exe“ sollte jedoch vorhanden sein, um anzuzeigen, dass es sich um eine ausführbare Datei handelt.

Das zusammengestellte Programm lässt sich wie folgt dokumentieren:

Die Erstellung eines Dokuments wie dieses bezeichnet man als manuelles Zusammenfügen. Beachten Sie, dass die Kommentare in diesem Dokument nicht im Speicher (zur Ausführung) erscheinen. Die Adressspalte in der Tabelle gibt die Startadressen der Befehle im Speicher an. Beachten Sie, dass „JSR-Start“, also „JSR $0300“, das voraussichtlich als „20 03 00“ codiert wird, tatsächlich als „20 00 03“ codiert ist, wobei die Adresse des unteren Speicherbytes das niedrigere Byte im Speicher einnimmt und das Höhere Speicherbyte-Adresse, die das höhere Byte im Speicher übernimmt – Little Endianness. Der Opcode für JSR ist 20 16 .

Beachten Sie, dass der Offset zu einem Verzweigungsbefehl wie BNE eine Zweierkomplementzahl im Bereich von 128 ist 10 bis + 127 10 . „BNE-Schleife“ bedeutet also „BNE -1“. 10 “, was eigentlich „D0 FF“ in der Codeform von FF ist 16 ist -1 im Zweierkomplement, was als = 11111111 zur Basis zwei geschrieben wird. Das Assemblerprogramm ersetzt die Beschriftungen und Felder durch tatsächliche Hexadezimalzahlen (Hexadezimalzahlen sind Binärzahlen, die in vier Bits gruppiert sind). Die tatsächlichen Adressen, an denen jeder Befehl beginnt, sind tatsächlich enthalten.

Notiz: Der „JSR-Start“-Befehl wird durch kürzere Befehle ersetzt, die den aktuellen Inhalt (High- und Low-Byte) des Programmzählers an den Stack senden, wobei der Stack-Pointer zweimal dekrementiert wird (einmal für High-Byte und einmal für Low-Byte) und Anschließend wird der PC mit der Adresse $0300 neu geladen. Der Stapelzeiger zeigt nun auf $00FD, vorausgesetzt, dass er auf $01FF initialisiert ist.

Außerdem wird der RTS-Befehl durch eine Reihe kürzerer Befehle ersetzt, die den Stapelzeiger „S“ zweimal erhöhen (einmal für Low-Byte und einmal für High-Byte) und die entsprechenden zwei Bytes der Adresse vom Stapelzeiger zum PC ziehen die nächste Anweisung.

Notiz: Ein Beschriftungstext sollte nicht mehr als 8 Zeichen lang sein.

„BNE-Schleife“ verwendet die relative Adressierung. Es bedeutet, -3 zu addieren 10 zum nächsten Programmzählerinhalt von $0305. Die Bytes für „BNE-Schleife“ sind „D0 FD“, wobei FD das Zweierkomplement von -3 ist 10 .

Hinweis: Dieses Kapitel enthält nicht alle Anweisungen für den 6502 µP. Alle Anweisungen und deren Details finden Sie im Dokument „SY6500 8-Bit Microprocessor Family“. Zu diesem Dokument gibt es eine PDF-Datei mit dem Namen „6502.pdf“, die im Internet frei verfügbar ist. Der in diesem Dokument beschriebene 6502 µP ist 65C02.

4.16 Unterbrechungen

Die Signale aller Geräte, die an die externen (vertikalen) Anschlüsse des Commodore 64 angeschlossen sind, müssen entweder die Schaltkreise (ICs) CIA 1 oder CIA 2 durchlaufen, bevor sie den Mikroprozessor 6502 erreichen. Die Signale vom Datenbus des 6502 µP müssen entweder den CIA 1- oder CIA 2-Chip durchlaufen, bevor sie ein externes Gerät erreichen. CIA steht für Complex Interface Adapter. In Abb. 4.1 „Blockdiagramm des Commodore_64-Motherboards“ stellen die Block-Eingabe-/Ausgabegeräte CIA 1 und CIA 2 dar. Wenn ein Programm ausgeführt wird, kann es unterbrochen werden, um einen anderen Code auszuführen, bevor es fortfährt. Es gibt eine Hardwareunterbrechung und eine Softwareunterbrechung. Zur Hardware-Unterbrechung gibt es zwei Eingangssignal-Pins am 6502 µP. Die Namen dieser Pins sind IRQ Und NMI . Dies sind keine µP-Datenleitungen. Die Datenleitungen für den µP sind D7, D6, D5, D4, D3, D2, D1 und D0; mit D0 für das niederwertigste Bit und D7 für das höchstwertige Bit.

IRQ steht für Interrupt ReQuest „active“ low. Diese Eingangsleitung zum µP ist normalerweise hoch und liegt bei etwa 5 Volt. Wenn es auf ungefähr 0 Volt absinkt, ist das eine Unterbrechungsanforderung, die dem µP signalisiert. Sobald der Anfrage stattgegeben wird, geht die Leitung wieder nach oben. Die Gewährung der Interrupt-Anfrage bedeutet, dass der µP zu dem Code (Unterprogramm) verzweigt, der den Interrupt verarbeitet.

NMI steht für Non-Maskable Interrupt „active“ low. Während der Code für IRQ wird ausgeführt NMI kann nach unten gehen. In diesem Fall, NMI behandelt wird (sein eigener Code wird ausgeführt). Danach wird der Code für IRQ geht weiter. Nach dem Code für IRQ endet, wird der Hauptprogrammcode fortgesetzt. Das ist, NMI unterbricht die IRQ Handler. Das Signal für NMI kann dem µP auch dann noch gegeben werden, wenn der µP inaktiv ist und nichts verarbeitet oder kein Hauptprogramm ausführt.

Notiz: Es ist eigentlich der Übergang von hoch nach niedrig NMI , das ist das NMI Signal – dazu später mehr. IRQ kommt normalerweise von CIA 1 und NMI kommt normalerweise von CIA 2. NMI , was für Non-Maskable Interrupt steht, kann als nicht stoppbarer Interrupt betrachtet werden.

Umgang mit Interrupts
Ob die Anfrage von stammt IRQ oder NMI , die aktuelle Anweisung muss abgeschlossen sein. Der 6502 verfügt nur über die A-, X- und Y-Register. Während ein Unterprogramm ausgeführt wird, verwendet es möglicherweise diese drei Register zusammen. Ein Interrupt-Handler ist immer noch eine Unterroutine, wird jedoch nicht als solche betrachtet. Nachdem der aktuelle Befehl abgeschlossen ist, werden die Inhalte der A-, X- und Y-Register für den 65C02 µP im Stapel gespeichert. Die Adresse des nächsten Befehls des Programmzählers wird ebenfalls an den Stapel gesendet. Der µP verzweigt dann zum Code für den Interrupt. Danach werden die Inhalte der A-, X- und Y-Register in der umgekehrten Reihenfolge, in der sie gesendet wurden, vom Stapel wiederhergestellt.

Beispielcodierung für einen Interrupt
Nehmen Sie der Einfachheit halber an, dass die Routine für den µP IRQ Der Interrupt dient lediglich dazu, die Zahlen $01 und $02 zu addieren und das Ergebnis von $03 an der Speicheradresse $0400 zu speichern. Der Code lautet:

ISR PHA
PHX
PHY
;
LDA #$01
ADC #$02
SIE KOSTEN 0400 $
;
PLY
PLX
PLA
RTI

ISR ist eine Bezeichnung und identifiziert die Speicheradresse, an der sich der PHA-Befehl befindet. ISR bedeutet Interrupt Service Routine. PHA, PHX und PHY senden den Inhalt der A-, X- und Y-Register an den Stapel in der Hoffnung, dass er von dem Code (Programm) benötigt wird, der unmittelbar vor der Unterbrechung ausgeführt wird. Die nächsten drei Anweisungen bilden den Kern des Interrupt-Handlers. Die Anweisungen PLY, PLX und PLA müssen in dieser Reihenfolge vorliegen und geben den Inhalt der Register Y, X und A zurück. Der letzte Befehl, RTI (ohne Operanden), gibt die Fortsetzung der Ausführung an den Code (das Programm) zurück, der vor der Unterbrechung ausgeführt wurde. RTI ruft die Adresse des nächsten Befehls des Codes, der gerade ausgeführt wird, vom Stapel zurück zum Programmzähler. RTI bedeutet ReTurn from Interrupt. Damit ist die Interrupt-Behandlung (Unterroutine) beendet.

Software-Unterbrechung
Der Hauptweg für einen Software-Interrupt für den 6502 µP ist die Verwendung des impliziten Adressbefehls BRK. Gehen Sie davon aus, dass das Hauptprogramm ausgeführt wird und auf die BRK-Anweisung stößt. Von diesem Punkt an sollte die Adresse des nächsten Befehls im PC an den Stapel gesendet werden, sobald der aktuelle Befehl abgeschlossen ist. Eine Unterroutine zur Verarbeitung der Softwareanweisung sollte „next“ heißen. Diese Interrupt-Subroutine sollte die Inhalte der A-, X- und Y-Register auf den Stapel verschieben. Nachdem der Kern des Unterprogramms ausgeführt wurde, sollten die Inhalte der A-, X- und Y-Register vom abschließenden Unterprogramm vom Stapel in ihre Register zurückgezogen werden. Die letzte Anweisung in der Routine ist RTI. Der PC-Inhalt wird aufgrund von RTI auch automatisch vom Stapel auf den PC zurückgezogen.

Vergleich und Gegenüberstellung von Subroutinen und Interrupt-Service-Routinen
In der folgenden Tabelle werden die Subroutine und die Interrupt-Service-Routine verglichen und gegenübergestellt:

4.17 Zusammenfassung der 6502-Hauptadressierungsmodi

Jede Anweisung für den 6502 besteht aus einem Byte, gefolgt von null oder mehr Operanden.

Sofortiger Adressierungsmodus
Im Direktadressierungsmodus steht nach dem Operanden der Wert und keine Speicheradresse. Dem Wert muss ein # vorangestellt werden. Wenn der Wert hexadezimal ist, muss dem „#“ ein „$“ folgen. Die unmittelbaren Adressierungsanweisungen für den 65C02 sind: ADC, AND, BIT, CMP, CPX, CPY, EOR, LDA, LDX, LDY, ORA, SBC. Der Leser sollte die Dokumentation für 65C02 µP konsultieren, um zu erfahren, wie er die hier aufgeführten Anweisungen verwendet, die in diesem Kapitel nicht erläutert werden. Eine Beispielanweisung ist:

LDA #77

Absoluter Adressierungsmodus
Im absoluten Adressierungsmodus gibt es einen Operanden. Dieser Operand ist die Adresse des Werts im Speicher (normalerweise hexadezimal oder als Label). Es sind 64K 10 = 65.536 10 Speicheradressen für den 6502 µP. Normalerweise befindet sich der Ein-Byte-Wert an einer dieser Adressen. Die absoluten Adressierungsanweisungen für den 65C02 sind: ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, JMP, JSR, LDA, LDX, LDY, LSR, ORA, ROL, ROR, SBC, STA , STX, STY, STZ, TRB, TSB. Der Leser sollte die Dokumentation für 65C02 µP konsultieren, um zu erfahren, wie die hier aufgeführten Anweisungen verwendet werden, sowie für die übrigen Adressierungsmodi, die in diesem Kapitel nicht erläutert werden. Eine Beispielanweisung ist:

SIE SIND 1234 $

Impliziter Adressierungsmodus
Im impliziten Adressierungsmodus gibt es keinen Operanden. Alle beteiligten µP-Register werden durch den Befehl impliziert. Die impliziten Adressierungsanweisungen für den 65C02 sind: BRK, CLC, CLD, CLI, CLV, DEX, DEY, INX, INY, NOP, PHA, PHP, PHX, PHY, PLA, PLP, PLX, PLY, RTI, RTS, SEC , SED, SEI, TAX, TAY, TSX, TXA, TXS, TYA. Eine Beispielanweisung ist:

DEX: Dekrementieren Sie das X-Register um eine Einheit.

Relativer Adressierungsmodus
Der relative Adressierungsmodus befasst sich nur mit Verzweigungsanweisungen. Im relativen Adressierungsmodus gibt es nur einen Operanden. Es ist ein Wert von -128 10 bis +127 10 . Dieser Wert wird als Offset bezeichnet. Basierend auf dem Vorzeichen wird dieser Wert zum nächsten Befehl des Programmzählers addiert oder davon subtrahiert, um die Adresse des beabsichtigten nächsten Befehls zu ergeben. Die relativen Adressmodusanweisungen sind: BCC, BCS, BEQ, BMI, BNE, BPL, BRA, BVC, BVS. Die Anleitungsbeispiele sind:

BNE $7F : (Verzweigung, wenn Z = 0 im Statusregister, P)

Dadurch wird 127 zum aktuellen Programmzähler (zur auszuführenden Adresse) addiert und mit der Ausführung des Befehls an dieser Adresse begonnen. Ähnlich:

BEQ $F9 : (Verzweigung wenn Z = : im Statusregister, P)

Dadurch wird ein -7 zum aktuellen Programmzähler hinzugefügt und die Ausführung an der neuen Programmzähleradresse gestartet. Der Operand ist eine Zweierkomplementzahl.

Absolut indizierte Adressierung
Bei der absoluten Indexadressierung wird der Inhalt des X- oder Y-Registers zur gegebenen absoluten Adresse addiert (irgendwo zwischen $0000 und $FFFF, also von 0). 10 bis 65536 10 ), um die tatsächliche Adresse zu erhalten. Diese gegebene absolute Adresse wird Basisadresse genannt. Wenn das X-Register verwendet wird, sieht die Assembleranweisung etwa so aus:

LDA $C453,X

Wenn das Y-Register verwendet wird, sieht es etwa so aus:

LDA $C453,Y

Der Wert für das X- oder Y-Register wird als Zähl- oder Indexwert bezeichnet und kann zwischen 0 und 00 liegen 10 ) auf $FF (250 10 ). Es wird nicht als Offset bezeichnet.

Die absoluten Indexadressierungsanweisungen sind: ADC, AND, ASL (nur X), BIT (mit Akkumulator und Speicher, nur mit X), CMP, DEC (nur Speicher und X), EOR, INC (nur Speicher und X), LDA , LDX, LDY, LSR (nur X), ORA, ROL (nur X), ROR (nur X), SBC, STA, STZ (nur X).

Absolute indirekte Adressierung
Dies wird nur mit der Sprunganweisung verwendet. Damit hat die angegebene absolute Adresse eine Zeigeradresse. Die Zeigeradresse besteht aus zwei Bytes. Der Zwei-Byte-Zeiger zeigt auf den Zielbytewert im Speicher (ist dessen Adresse). Die Assembler-Anweisung lautet also:

JMP (3456 $)

Mit den Klammern steht $13 an der Adressposition von $3456, während sich $EB an der Adressposition von $3457 befindet (= $3456 + 1). Dann ist die Zieladresse $13EB und $13EB ist der Zeiger. Der absolute Wert von 3456 $ steht in der Anweisung in Klammern, wobei 34 das niedrigere Byte und 56 das höhere Byte ist.

4.18 Erstellen eines Strings mit der 6502 µP-Assemblersprache

Wie im nächsten Kapitel gezeigt wird, kann die Datei nach dem Erstellen im Speicher auf der Festplatte gespeichert werden. Der Datei muss ein Name gegeben werden. Der Name ist ein Beispiel für eine Zeichenfolge. Es gibt viele andere Beispiele für Strings in der Programmierung.

Es gibt zwei Hauptmethoden zum Erstellen einer Zeichenfolge aus ASCII-Codes. In beiden Fällen nehmen alle ASCII-Codes (Zeichen) aufeinanderfolgende Byte-Positionen im Speicher ein. Auf eine der Arten wird dieser Bytefolge ein ganzzahliges Byte vorangestellt, das der Länge (Anzahl der Zeichen) in der Folge (Zeichenfolge) entspricht. Umgekehrt folgt (unmittelbar gefolgt) der Zeichenfolge das Nullbyte, das 00 ist 16 , also 00 $. Die Länge des Strings (Anzahl der Zeichen) wird auf diese Weise nicht angegeben. Das Nullzeichen wird in der ersten Art nicht verwendet.

Denken Sie zum Beispiel an „Ich liebe dich!“ Zeichenfolge ohne Anführungszeichen. Die Länge beträgt hier 11; Ein Leerzeichen zählt als ein ASCII-Byte (Zeichen). Gehen Sie davon aus, dass die Zeichenfolge im Speicher abgelegt werden muss, wobei sich das erste Zeichen an der Adresse $0300 befindet.

Die folgende Tabelle zeigt die String-Speichereinstellung, wenn das erste Byte 11 ist 10 = 0B 16 :

Die folgende Tabelle zeigt die String-Speichereinstellung, wenn das erste Byte „I“ und das letzte Byte Null ($00) ist:

Die folgende Anweisung kann verwendet werden, um mit der Erstellung der Zeichenfolge zu beginnen:

SIE KOSTEN 0300 $

Gehen Sie davon aus, dass sich das erste Byte im Akkumulator befindet, das an den Adressspeicherort $0300 gesendet werden soll. Diese Anweisung gilt für beide Fälle (beide Arten von Zeichenfolgen).

Nachdem alle Zeichen nacheinander in die Speicherzellen eingepasst wurden, kann die Zeichenfolge mithilfe einer Schleife gelesen werden. Im ersten Fall wird die Anzahl der Zeichen nach der Länge ausgelesen. Im zweiten Fall werden die Zeichen von „I“ gelesen, bis das Nullzeichen „Null“ erreicht wird.

4.19 Erstellen eines Arrays mit der 6502 µP-Assemblersprache

Ein Array von Einzelbyte-Ganzzahlen besteht aus aufeinanderfolgenden Speicherbyte-Positionen mit den Ganzzahlen. Dann gibt es einen Zeiger, der auf die Position der ersten Ganzzahl zeigt. Ein Array von Ganzzahlen besteht also aus zwei Teilen: dem Zeiger und der Reihe von Positionen.

Bei einem String-Array kann sich jeder String an einer anderen Stelle im Speicher befinden. Dann gibt es aufeinanderfolgende Speicherstellen mit Zeigern, wobei jeder Zeiger auf die erste Stelle jeder Zeichenfolge zeigt. Ein Zeiger besteht in diesem Fall aus zwei Bytes. Wenn eine Zeichenfolge mit ihrer Länge beginnt, zeigt der entsprechende Zeiger auf die Position dieser Länge. Wenn eine Zeichenfolge nicht mit ihrer Länge beginnt, sondern mit einem Nullzeichen endet, zeigt der entsprechende Zeiger auf die Position des ersten Zeichens der Zeichenfolge. Und es gibt einen Zeiger, der auf die untere Byteadresse des ersten Zeigers aufeinanderfolgender Zeiger zeigt. Ein String-Array besteht also aus drei Teilen: den Strings an verschiedenen Stellen im Speicher, den entsprechenden aufeinanderfolgenden Zeigern und dem Zeiger auf den ersten Zeiger der aufeinanderfolgenden Zeiger.

4.20 Probleme

Dem Leser wird empfohlen, alle Probleme in einem Kapitel zu lösen, bevor er mit dem nächsten Kapitel fortfährt.

  1. Schreiben Sie ein Assemblerprogramm, das bei $0200 für den 6502 µP beginnt und die vorzeichenlosen Zahlen von 2A94 hinzufügt H (addieren) zu 2ABF H (augend). Lassen Sie die Ein- und Ausgänge im Speicher liegen. Erstellen Sie außerdem das zusammengestellte Programmdokument von Hand.
  2. Schreiben Sie ein Assemblerprogramm, das bei 0200 $ für den 6502 µP beginnt und die vorzeichenlosen Zahlen von 1569 subtrahiert H (Subtrahend) von 2ABF H (Minuend). Lassen Sie die Ein- und Ausgänge im Speicher liegen. Erstellen Sie außerdem das zusammengestellte Programmdokument von Hand.
  3. Schreiben Sie ein Assemblerprogramm für den 6502 µP, das mithilfe einer Schleife von $00 bis $09 hochzählt. Das Programm sollte bei 0200 $ beginnen. Erstellen Sie außerdem das zusammengestellte Programmdokument von Hand.
  4. Schreiben Sie ein Assemblerprogramm, das bei 0200 $ für den 6502 µP beginnt. Das Programm verfügt über zwei Unterprogramme. Das erste Unterprogramm fügt die vorzeichenlosen Zahlen 0203 hinzu H (augend) und 0102H (addend). Das zweite Unterprogramm addiert die Summe aus dem ersten Unterprogramm, die 0305H beträgt, zu 0006 H (augend). Das Endergebnis wird im Speicher abgelegt. Rufen Sie das erste Unterprogramm FSTSUB und das zweite Unterprogramm SECSUB auf. Lassen Sie die Ein- und Ausgänge im Speicher liegen. Erstellen Sie außerdem das zusammengestellte Programmdokument für das gesamte Programm von Hand.
  5. Angesichts dessen, dass ein IRQ Der Handler addiert $02 zu $01 am Akkumulator als Kernverarbeitungs-Während NMI ausgegeben wird und das Kernhandling für NMI Addiert $05 zu $04 im Akkumulator und schreibt eine Assemblersprache für beide Handler einschließlich ihrer Aufrufe. Der Aufruf an die IRQ Der Handler sollte sich an der Adresse $0200 befinden. Der IRQ Der Handler sollte bei der Adresse $0300 beginnen. Der NMI Der Handler sollte bei der Adresse $0400 beginnen. Das Ergebnis der IRQ Der Handler sollte an der Adresse $0500 abgelegt werden und das Ergebnis des NMI Der Handler sollte auf die Adresse $0501 gesetzt werden.
  6. Erklären Sie kurz, wie der BRK-Befehl verwendet wird, um den Software-Interrupt in einem 65C02-Computer zu erzeugen.
  7. Erstellen Sie eine Tabelle, die eine normale Unterroutine mit einer Interrupt-Service-Routine vergleicht und gegenüberstellt.
  8. Erklären Sie kurz die wichtigsten Adressierungsmodi des 65C02 µP anhand der Assembler-Anweisungsbeispiele.
  9. a) Schreiben Sie ein 6502-Maschinensprachenprogramm, um das „Ich liebe dich!“ zu formulieren. Zeichenfolge von ASCII-Codes im Speicher, beginnend bei der Adresse $0300 mit der Länge der Zeichenfolge. Das Programm sollte an der Adresse $0200 starten. Holen Sie sich jedes Zeichen einzeln aus dem Akkumulator, vorausgesetzt, dass es von einer Unterroutine dorthin gesendet wird. Stellen Sie das Programm außerdem von Hand zusammen. (Wenn Sie die ASCII-Codes für „Ich liebe dich!“ kennen müssen. Hier sind sie: „I“:49 16 , Platz: 20 16 , „l“: 6C 16 , 'o':6F 16 , 'in':76 16 , 'e':65, 'y':79 16 , 'in':75 16 und „!“:21 16 (Hinweis: Jeder Code belegt 1 Byte).
    b) Schreiben Sie ein 6502-Maschinensprachenprogramm, um das „Ich liebe dich!“ zu formulieren. Zeichenfolge von ASCII-Codes im Speicher, beginnend bei der Adresse $0300 ohne die Länge der Zeichenfolge, aber endend bei 00 16 . Das Programm sollte an der Adresse $0200 starten. Erhalten Sie jedes Zeichen aus dem Akkumulator, vorausgesetzt, dass sie einzeln von einer Unterroutine dorthin gesendet werden. Stellen Sie das Programm außerdem von Hand zusammen.