ATAMON V1.3


Inhaltsverzeichnis


Vorwort

Die Dokumentation von ATAMON (ATAri MONitor) ist seit über 40 Jahren unauffindbar.

Was Sie hier lesen, ist eine inoffizielle Dokumentation — das Ergebnis stundenlanger Arbeit, Versuche, Dekompilierung und Abfassung auf Basis des disassemblierten ATAMON-Codes.

Ich hoffe, Sie finden Gefallen daran ;-)

Atarinside — März 2026

Das Programm ist hier zu finden: https://www.atarinside.com/blog/index.php/atarinside-items/atamon/


Was ist ATAMON?

Sie haben soeben ATAMON, den Maschinensprachemonitor von ATARI, geladen. Aber wozu dient ein Monitor eigentlich?

Ihr Atari 800XL wird von einem Prozessor angetrieben — dem 6502 — der Tausende von Befehlen pro Sekunde ausführt. Diese Befehle — auch „Maschinensprache" genannt — sind als Zahlen im Speicher abgelegt. ATAMON ist das Werkzeug, mit dem Sie diese Befehle direkt ansehen, ändern und ausführen können, ohne eine Zwischensprache wie BASIC zu benötigen.

Konkret ermöglicht ATAMON Folgendes:

Für wen? ATAMON richtet sich an Programmierer und Enthusiasten, die das Innenleben ihres Atari verstehen wollen, oder an alle, die Maschinenprogramme untersuchen und verändern möchten. Keine zusätzliche Hardware erforderlich: ATAMON läuft vollständig auf Ihrem Atari mit dem normalen Diskettenlaufwerk.

Wie fangen Sie an? Wählen Sie im Atari-DOS-Menü L. BINARY LOAD, tippen Sie D:ATAMON und drücken Sie die Eingabetaste. Das Programm lädt sich ab Adresse $4000 in den Speicher, zeigt sein Banner an, und der Atari-Cursor signalisiert die Bereitschaft zur Befehlseingabe. Alle Befehle bestehen aus einem einzigen Buchstaben — schnell und effizient.


Technische Dokumentation

Maschinensprachemonitor für den Atari 800XL


Quelldatei: Atamon - D7 - DXG 5724.PROATAMON Kennung: *** ATAMON V1.3 - (c) 1983 by ATARI *** Typ: 6502-Maschinensprache-Monitor / Debugger Größe: 4.404 Byte Format: Atari XEX (mehrere Segmente) Ladeadresse: $4000 Startadresse (RUNAD): $4000 Quellsprache: 6502-Assembler Herausgeber: Atari Deutschland GmbH — ATAMON ist ein Produkt von Atari Deutschland, Katalognummer DXG 5724 Autor: Nicht identifiziert — die Binärdatei enthält keinen Programmierernamen, nur (c) 1983 by ATARI Wahrscheinliches Assembler-Werkzeug: Atari Macro Assembler oder MAC/65 (OSS) — aus der Struktur der 256-Byte-XEX-Segmente (252 Byte Code + 4-Byte-Header) erschlossen


1. Allgemeine Übersicht

ATAMON ist ein professioneller Maschinensprachemonitor, der 1983 von ATARI entwickelt wurde. Er ermöglicht einem Programmierer:

ATAMON gehört zur Familie der Maschinensprachemonitore, die in den 1980er Jahren 8-Bit-Computern auf vielen Plattformen beilagen.


2. Speicherbelegung

Speicherbedarf: ca. 4,5 KB von $4000 bis $52B1. ATAMON setzt außerdem MEMLO = $5300, um seinen Code zu schützen.


3. Startmechanismus

Der Einsprungpunkt bei $4000 nutzt eine klassische Technik: den BRK-Vektor ($0206–$0207).

Warum diese Technik? Der BRK-Befehl legt automatisch die Adresse des nächsten Befehls (aktuelle Adresse + 2) sowie das Statusregister auf den Stapel. ATAMON liest diese Werte anschließend aus, um eine vollständige Momentaufnahme des Prozessorzustands beim Eintritt in den Monitor zu erstellen.

Registersicherung ($401C)

Hinweis zum Eintrittsmechanismus: Der Atari-OS-Handler (ROM-IRQ) legt Register A per PHA auf den Stapel, bevor er den VBREAK-Vektor aufruft. Deshalb führt SAVE_CPU vier aufeinanderfolgende PLAs aus (A, P, PCL, PCH), obwohl der BRK-Befehl selbst nur drei ablegt (P, PCL, PCH).

Registersicherungsbereich ($4F3C–$4F42):

Dieses Layout wird durch den G-Handler (Go) bestätigt: LDA $4F3D stellt A wieder her, LDA $4F40; PHA; PLP stellt P wieder her, JMP ($4F41) springt zur Adresse $4F42:$4F41.


4. Hauptbefehlsschleife

Nach der Initialisierung zeigt ATAMON sein Banner an und tritt in die Befehlsschleife ($4064) ein:

Eingabeaufforderung und Registeranzeige

ATAMON zeigt keine explizite Eingabeaufforderung an: Die Eingabeaufforderung ist der Atari-Bildschirmeditor-Cursor (blinkender Inversionsblock), der automatisch vom Betriebssystem verwaltet wird. Wenn dieser Cursor sichtbar ist, wartet ATAMON auf einen Befehl.

Die Kopfzeilen *R, *B, *C sind ATAMON-Anzeigevorspänne, kein Prompt. Das Sternchen * (Code $2A) wird von ATAMON vor der Registeranzeige ausgegeben, gefolgt von einem Buchstaben, der den Eintragskontext anzeigt:

Beispiel einer Registeranzeige (nach dem Befehl R oder nach einem BRK):

Die Wertzeile beginnt immer mit ;. Bedeutung der einzelnen Felder:

FeldWas es istWert im Beispiel
PCProgrammzähler: Adresse des nächsten auszuführenden Befehls. Hier befindet sich Ihr Programm im Speicher.4000 → bereit zur Ausführung ab $4000
SPStapelzeiger: zeigt die aktuelle Stapelspitze an. Der Atari-Stapel liegt bei $0100–$01FF; SP=FD bedeutet, die Spitze liegt bei $01FD, Stapel nahezu leer.FD → Stapel zurückgesetzt
ACAkkumulator A: Hauptregister des 6502, verwendet für Berechnungen, Übertragungen, Vergleiche.00
XRX-Register: Indexregister, häufig für Schleifen und indizierte Adressierung.00
YRY-Register: zweites Indexregister.00
NV\BDIZCProzessor-Flags (Register P), binär Bit für Bit angezeigt (0 oder 1). Jedes Bit zeigt einen bestimmten Zustand der letzten Berechnung an. Detaillierte Beschreibung beim Befehl ;.00110000 → Flags I und B gesetzt

Diese Zeile wird nach jeder Programmrückkehr (nach einem BRK oder G) automatisch aktualisiert, um den tatsächlichen Prozessorzustand zu diesem Zeitpunkt widerzuspiegeln.


5. Programm in ATAMON laden

Der Atari speichert die automatische Startadresse des zuletzt geladenen Programms an einer bestimmten Speicherstelle bei Adresse $02E0 (dem Systemvektor namens RUNAD).

Wenn Sie Ihr Spiel laden, wird seine Startadresse in $02E0 eingetragen. Laden Sie danach ATAMON, überschreibt ATAMONs Startadresse ($4000) die Ihres Spiels!

Um dies zu umgehen und ATAMON als Werkzeug zu nutzen, kehren wir die Ladereihenfolge um — mit Hilfe einer anderen DOS-Menüoption (M).

Der Doppelagenten-Plan

Schritt 1: Den Monitor „verdeckt" installieren

  1. Wählen Sie im DOS-Menü L, um ATAMON zu laden.

  2. ATAMON erscheint auf dem Bildschirm. Geben Sie den Befehl X (eXit) ein.

  3. Sie kehren zum DOS-Menü zurück, aber ATAMON bleibt unsichtbar im Speicher (ab $4000).

Schritt 2: Ihr Spiel lautlos laden

  1. Zurück im DOS, laden Sie Ihr Programm erneut mit L und hängen /N an (kein Leerzeichen nach dem Dateinamen) — Beispiel: MYPROG.BIN/N.

  2. Das Spiel lädt sich in den Speicher, und das Betriebssystem schreibt seine Startadresse in $02E0. Da wir /N verwendet haben, springt DOS nicht zu dieser Adresse, führt das geladene Programm nicht aus und bleibt im Menü.

Schritt 3: ATAMON aufwecken

  1. Wählen Sie im DOS-Menü die Option M (Run at address).

  2. Geben Sie 4000 (die Adresse, wo ATAMON schläft) ein und drücken Sie die Eingabetaste.

  3. Das ATAMON-Banner erscheint — Sie sind wieder im Monitor!

Schritt 4: Die magische Adresse lesen

  1. Zeigen Sie in ATAMON den Speicher bei $02E0 an:

  1. Drücken Sie sofort BREAK, um das Scrollen anzuhalten.

  2. Schauen Sie sich die ersten zwei Bytes der angezeigten Zeile an.

Achtung — Little Endian: Der Atari speichert Adressen „verkehrt herum" (niederwertiges Byte zuerst, dann höherwertiges).

  • Zeigt ATAMON :02E0 00 50 ..., ist die Adresse Ihres Programms $5000.

  • Zeigt er :02E0 00 2A ..., ist die Adresse $2A00.

Das war's! Verwenden Sie nun den G-Befehl mit der gefundenen Adresse (z. B. G 5000), um Ihr Programm zu starten — ATAMON ist bereit, jeden Absturz oder Haltepunkt (BRK) abzufangen.

Haltepunkte im Programm setzen

Warnung: ATAMON verfügt über keine garantierte asynchrone Unterbrechungsfunktion.

Die einzige zuverlässige Methode, um die Kontrolle mitten in einem Programm an ATAMON zurückzugeben, ist das bewusste Einfügen eines Software-Haltepunkts:

  1. Ersetzen Sie ein Byte Ihres Programms vorübergehend durch den BRK-Befehl (Hexcode $00).

  2. Wenn der Prozessor dieses $00 ausführt, löst er einen Software-Interrupt aus.

  3. ATAMON hat den System-Interruptvektor (VBREAK bei $0206$0207) beim Laden umgeleitet.

  4. Der Prozessor springt direkt zu ATAMON, das alle Register (A, X, Y, PC...) sichert und mit *B anzeigt, dass es einen BRK abgefangen hat.

Zusammenfassung: Wenn Ihr Programm eine Endlosschleife ohne BRK-Befehl ist, hilft Ihnen die BREAK-Taste nicht weiter (außer Ihr Code ruft OS-Tastaturprogramme auf). Ein Reset wird notwendig! Setzen Sie Ihre $00-Haltepunkte immer strategisch, bevor Sie Ihren Code mit G starten.


6. Befehlsreferenz

Die Befehlstabelle beginnt bei $4F9D. Befehle werden in Großbuchstaben eingegeben. Wenn ein Befehl mehrere Argumente hat, werden sie durch Kommas getrennt (kein Leerzeichen zwischen Argumenten). Vor dem ersten Argument ist ein Leerzeichen erlaubt.

Syntaxkonventionen


G [aaaa] — Go (Ausführen)

Startet die Programmausführung bei Adresse aaaa. Ohne Argument: setzt ab dem gesicherten Programmzähler (PC-Register) fort. Stellt alle gesicherten CPU-Register wieder her, bevor JMP aaaa ausgeführt wird.

Warnung: G aaaa springt direkt zur angegebenen Adresse. Enthält diese kein gültiges Programm (z. B. uninitialiserter RAM mit Nullen), führt der 6502 beliebige Befehle aus und das System hängt sich auf. G allein (ohne Adresse) ist sicher: Es setzt ab dem beim letzten BRK gesicherten PC fort.

Erste Verwendung nach dem Start: Beim Start ist der gesicherte PC $400B (ATAMON-Initialisierungs-Einsprungpunkt). G allein führt daher den ATAMON-Start neu aus: Das Banner erscheint erneut, gefolgt von *C und dem Registerzustand.

Beispiele:


M aaaa — Memory (Speicher anzeigen)

Zeigt den Speicherinhalt ab Adresse aaaa an, 8 Byte pro Zeile in Hexadezimal. ATAMON scrollt unbegrenzt — BREAK drücken zum Anhalten.

Format: : + Adresse + 8 Hex-Bytes + ATASCII-Spalte rechts.

Beispiel:


E ssss[,aaaa[,nn]] — E (Diskettensektor lesen)

Liest Diskettensektor ssss (hexadezimal) von Laufwerk D1: in den Puffer bei aaaa (Standard: $0680). Zeigt OK bei Erfolg an.

Optionale Argumente:

ssss ist eine Sektornummer (keine Speicheradresse). Atari-Diskette einfacher Dichte: $0001–$02D0.


D aaaa[,bbbb] — Disassemble (Disassemblieren)

Disassembliert 6502-Code ab Adresse aaaa und zeigt die Mnemoniken an. Verwendet die internen Tabellen bei $4FF9, die die 56 6502-Mnemoniken und Adressierungsmodusdekodierungsinformationen enthalten.

Wichtig: Die Endadresse bbbb wird syntaktisch akzeptiert, aber ignoriert — ATAMON disassembliert unbegrenzt, überschreitet $FFFF und beginnt bei $0000 neu. BREAK drücken zum Anhalten.

Jede Zeile enthält: die Adresse, die rohen Bytes im Speicher, dann den disassemblierten Befehl.


L aaaa,bbbb,xx — Locate Non-Matching (Abweichende Bytes finden)

Durchsucht den Speicherbereich von aaaa bis bbbb und zeigt Adressen an, wo das Byte ungleich xx ist.

In der Praxis: L ermittelt Bytes, die einem Referenzwert „nicht entsprechen". Nützlich, um nach einer Kopie schnell Unterschiede zwischen zwei Bereichen zu erkennen oder veränderte Bytes in einem Programm zu finden.

L allein (ohne Argument) → Fehler ? — alle drei Argumente sind erforderlich.

Hinweis: ATAMON besitzt keinen Befehl zum Laden von Dateien. Programme müssen vor dem Start von ATAMON über das Atari-DOS geladen werden (Option L. BINARY LOAD).


W ssss[,aaaa[,nn]] — Write (Diskettensektor schreiben)

Schreibt den Speicherpuffer bei Adresse aaaa (Standard: $0680) auf Diskettensektor ssss (hexadezimal).

Optionale Argumente: identisch mit E — Quelladresse des Puffers und Sektoranzahl.

Achtung: überschreibt den Sektor auf der Diskette direkt — nicht rückgängig zu machen. ssss ist eine Sektornummer in Hexadezimal (1 bis $02D0 = 720 bei einer Diskette einfacher Dichte).

E und W arbeiten zusammen: E zum Lesen eines Sektors, Änderungen mit M oder :, dann W zum Zurückschreiben.


V aaaa,bbbb,cccc — Verify (Speicher vergleichen)

Vergleicht den Speicherbereich aaaabbbb mit dem Bereich ab cccc (Speicher-zu-Speicher-Vergleich). Meldet Adressen, an denen die Bytes abweichen. Es werden keine Änderungen vorgenommen.

Nützlich, um zu prüfen, ob eine mit T erstellte Kopie mit dem Original übereinstimmt, oder um zwei Programmversionen zu vergleichen.

Hinweis: Wenn der Zielbereich nicht initialisiert ist (beliebiger RAM), erscheinen nahezu alle Adressen des Bereichs im Ergebnis.


F aaaa,bbbb,bb — Fill (Speicher füllen)

Füllt den Speicherbereich aaaabbbb mit Byte bb.

Sicherer Bereich: ATAMON belegt $4000–$52B1. Adressen ab $5300 verwenden (z. B. $6000+).


T aaaa,bbbb,cccc — Transfer (Speicher kopieren)

Kopiert den Speicherblock von aaaa bis bbbb zum Ziel cccc (Speicher-zu-Speicher). Führt danach eine byteweise Überprüfung durch und meldet Unterschiede.

Überlappende Bereiche: Wenn Quelle und Ziel sich im Speicher überschneiden, würde eine naive Kopie von Anfang bis Ende noch nicht gelesene Quell-Bytes überschreiben. ATAMON vermeidet das: Liegt das Ziel vor der Quelle, wird von links nach rechts kopiert (erstes Byte zuerst); liegt das Ziel nach der Quelle (Überlappung rechts), wird von rechts nach links kopiert (letztes Byte zuerst). Das Ergebnis ist immer korrekt, unabhängig von der Konstellation.

Sicherer Bereich: ATAMON belegt $4000–$52B1. Für Tests einen Bereich ab $5300 verwenden (z. B. $6000–$7FFF, freier RAM).


H aaaa,bbbb,DsuchfolgeD — Hunt (Speicher durchsuchen)

Durchsucht aaaabbbb nach Bytefolge DsuchfolgeD. Zeigt gefundene Adressen an, dann OK.

D = beliebiges Trennzeichen (", /...). Daten: Hex-Paare oder 'Zeichenkette' in einfachen Anführungszeichen.

Nur Suche — kein Ersetzen. Mindestens drei Argumente erforderlich (H oder H aaaa,bbbb?).


S aaaa — Scan (Binär-Echtzeitmonitor)

Zeigt in Echtzeit die 4 Bytes ab Adresse aaaa als 8-Bit-Binärwerte an. Dieselbe Zeile wird kontinuierlich aktualisiert (kein Scrollen): ATAMON liest und zeigt dieselben 4 Bytes in einer Schleife an, um das Verhalten von Hardware-Registern in Echtzeit zu beobachten.

S allein (ohne Argument) → Fehler ? — Adresse ist erforderlich.

Der Befehl gibt die Kontrolle nicht zurück — BREAK (oder SYSTEM RESET) drücken zum Anhalten.

Hinweis: ATAMON besitzt keinen Einzelschrittmodus (Single-Step). Um ein Programm schrittweise zu debuggen, muss man manuell BRK-Befehle an den gewünschten Stellen im Code einfügen.

Beispiel mit fester Adresse:

Beispiel mit einem Hardware-Register in Echtzeit:

Besonders nützlich zum Überwachen von Hardware-Registern (POKEY, GTIA, ANTIC, RTCLOK-Uhr), die sich in Echtzeit ändern, oder um die Entwicklung einer Variable während der Programmausführung zu beobachten.


C aaaa,bbbbbbbb — Code (Binärbytes in Speicher schreiben)

Schreibt Bytes ab aaaa. Jedes Byte = 8 Binärziffern (0 oder 1), durch Kommas getrennt.

C allein → ?

Hinweis: Dieser Befehl ist in der Original-V1.3 fehlerhaft — er schreibt $2C (Komma) statt die Binärargumente zu interpretieren und liefert ?. Die folgenden Beispiele beschreiben das Verhalten der gepatchten Version (Atamon - D7 - DXG 5724-Patched Atarinside.atr). Siehe Korrektur des C-Befehls-Fehlers.

Beispiel mit mehreren Bytes:


P [E|T] — Printer (Druckerverwaltung)

Steuert den Druckerkanal (IOCB 6, Gerät P1:).

Hinweis: Dieser Befehl ist nützlich, wenn ein Drucker an Ihren Atari angeschlossen ist. Ohne Drucker verursacht P E einen I/O-Fehler.


R — Registers (Register anzeigen)

Zeigt den aktuellen Zustand aller gesicherten CPU-Register an. Der Befehl zeigt nur an, ohne Register zu ändern.

Zum Ändern der Register Befehl ; verwenden oder direkt in $4F3C–$4F42 schreiben.


X — eXit (Beenden)

Kehrt über JMP DOSVEC ($000A) zum Atari-DOS zurück.


Z nn,cc[,aaaa,llll] — IOCB (CIO-Kanal-Operation)

Führt eine OS-E/A-Operation über das CIO-System (Central I/O) aus.

Das CIO-System kurz erklärt

Das CIO bietet einen einzigen Einsprungpunkt ($E456) für alle Geräte: ob Sie auf den Bildschirm schreiben, die Tastatur lesen oder auf eine Diskette zugreifen — es ist immer dieselbe OS-Routine, die Sie aufrufen. Der Gerätetreiber (eine spezifische Routine in ROM oder RAM) erledigt die eigentliche Arbeit.

ROM-residiente Treiber (immer verfügbar, beim Booten automatisch geladen):

NameGerätZugriffHinweis
E:Bildschirmeditor — zeilenweise Eingabe mit interaktiver Bearbeitunglesen+schreibenVerwendet intern K: und S:
K:Tastatur — direkte Tastaturabfragenur lesenNie direkt geöffnet — intern von E: verwendet
S:Grafikbildschirm — Bitmap-Zugriff, DRAW- und FILL-Befehlelesen+schreiben 
P:Drucker — auf XL/XE: P1: bis P8: je nach Modellnur schreiben 
C:Kassettelesen+schreibenVerwendet nicht das SIO-Protokoll

Nicht-residiente Treiber (beim Booten durch DOS oder Peripherie-ROM geladen):

NameGerätZugriffGeladen von
D:Diskette — DOS-Dateiverwaltung (D1:–D8:)lesen+schreibenDOS, beim Booten
R:850-Schnittstelle — RS-232-Ports (R1:–R4:)lesen+schreibenROM der 850-Schnittstelle, beim Booten
T:1030-Modem (XM301, 835)lesen+schreibenROM des Modems, beim Booten

Diese nicht-residenten Treiber werden beim Booten in die Handler-Tabelle ($031A) eingetragen, sobald das entsprechende Gerät angeschlossen und eingeschaltet ist. Fehlt das Gerät, wird der Treiber nicht geladen, und jeder Zugriffsversuch auf D:, R: oder T: via CIO gibt einen Fehler „unknown device" zurück.

IOCB-Kanäle

Um mit dem CIO zu kommunizieren, verwendet man einen IOCB (Input/Output Control Block): einen 16-Byte-Speicherbereich, der die gewünschte Operation beschreibt (welches Gerät, welcher Befehl, welcher Puffer…).

Das OS stellt 8 Kanäle bereit (IOCB #0 bis #7), die jedem Gerät zugewiesen werden können:

KanalOffset nnSpeicheradresseBelegung
000$0340–$034FE: Bildschirmeditor — vom OS beim Booten geöffnet, immer verfügbar
110$0350–$035Ffrei — für jedes Programm verfügbar
220$0360–$036Ffrei — für jedes Programm verfügbar
330$0370–$037Ffrei — für jedes Programm verfügbar
440$0380–$038Ffrei — für jedes Programm verfügbar
550$0390–$039Ffrei — für jedes Programm verfügbar
660$03A0–$03AFvon Atari BASIC für S: reserviert (Grafikmodi ≠ 0)
770$03B0–$03BFvon Atari BASIC für P:/D:/C: reserviert

Die Kanäle 1 bis 5 haben keine feste Zuweisung — das ist so gewollt. Die nicht-residenten Treiber (D:, R:, T:) öffnen sich nicht auf einem festen Kanal: das Programm wählt frei, auf welchem Kanal es jedes Gerät öffnet. Wenn BASIC aktiv ist, sollte man Kanäle 6 und 7 nicht anfassen.

Ein Datensatz ist eine Bytefolge, die mit dem ATASCII-Zeilenende-Zeichen $9B abgeschlossen wird. GET RECORD liest bis zum nächsten $9B; PUT RECORD schreibt und fügt $9B am Ende hinzu.

Z-Syntax

nn = Kanal-Offset (2 Hex-Stellen), cc = CIO-Befehl (2 Hex-Stellen).

Z allein oder Z nn allein → ?cc ist erforderlich.

ccBefehl
03OPEN (Öffnen)
05GET RECORD (Zeile bis $9B lesen)
07GET BYTES (Bytes lesen)
09PUT RECORD (Zeile schreiben + $9B)
0BPUT BYTES (Bytes schreiben)
0CCLOSE (Schließen)
0DSTATUS

Z kopiert den aktuellen IOCB des Kanals, ersetzt die angegebenen Felder (Befehl, Adresse, Länge), ruft CIO auf und schreibt den geänderten IOCB zurück. Es wird kein Ergebnis angezeigt — die Wirkung ist die Ausgabe der CIO-Operation selbst.

Beispiel — Text auf dem Bildschirm ausgeben via PUT RECORD auf Kanal 0 (immer auf Bildschirmeditor E: geöffnet):

Um den Rohinhalt eines IOCB zu inspizieren, M 0340 (Kanal 0) oder M 0350 (Kanal 1) verwenden.


I aaaa,DdatenD — Input String (Text in Speicher schreiben)

Schreibt Text oder gemischte Daten direkt in den Speicher ab Adresse aaaa.

D ist ein frei wählbares Trennzeichen (z. B. ", ', /…), das Anfang und Ende der Daten markiert. Alles zwischen den zwei Trennzeichen wird Byte für Byte in den Speicher geschrieben.

⚠ Wichtig: KEIN Leerzeichen zwischen Komma und Trennzeichen. Das Komma trennt die Adresse von den Daten — das Trennzeichen muss unmittelbar auf das Komma folgen, ohne Leerzeichen. Ein Leerzeichen zwischen , und dem Trennzeichen ergibt ?.

Innerhalb der Daten werden zwei Formate akzeptiert:

Dieser Befehl ist besonders nützlich zum Schreiben von Fehlermeldungen, ATASCII-Zeichenketten oder Code-Patches direkt in den Speicher.


# — Dezimal → Hexadezimal-Umrechnung

Interpretiert das Argument als Dezimalwert und zeigt das Hexadezimaläquivalent an.

Nützlich, wenn man eine Adresse oder einen Wert in Dezimal kennt und wissen möchte, was er in Hexadezimal entspricht, bevor man ihn in einem anderen Befehl verwendet.


$ — Hexadezimal → Dezimal-Umrechnung

Interpretiert das Argument als Hexadezimalwert und zeigt das Dezimaläquivalent an (Komplement von #).

Wichtig: $ erfordert genau 4 Hexadezimalstellen. $ 00FF verwenden, nicht $ FF.


% — Binäreingabe

Ermöglicht die Eingabe eines Werts als 8 Bits (0 und 1) und zeigt ihn hexadezimal an.

Nützlich für die direkte Arbeit mit Prozessor-Flags oder jedem Register, dessen Wert bitweise kontrolliert werden soll — lesbarer als ein Hex-Byte für diese Art der Manipulation.


; aaaa BB BB BB BB XXXXXXXX — Set (Alle Register auf einmal laden)

Lädt alle CPU-Register in einer einzigen Befehlszeile. Syntax: ; PCHL SP AC XR YR XXXXXXXX

Nützlich, um einen genauen Ausführungskontext in einer einzigen Operation wiederherzustellen, zum Beispiel um das Debuggen eines Programms genau in dem Zustand fortzusetzen, in dem es angehalten wurde.

Bedeutung der 8 Flag-Bits (von links nach rechts):

BitBuchst.NameGesetzt wenn...
7NNegativeBit 7 des letzten Ergebnisses = 1
6VoVerflowVorzeichenbehafteter Überlauf
5**(unbenutzt)Immer 1
4BBreakEintritt über BRK-Befehl
3DDecimalBCD-Modus (am Atari-6502 nicht funktional)
2IInterrupt disableIRQ-Interrupts maskiert
1ZZeroLetztes Ergebnis = 0
0CCarryÜbertrag / negativer Borgeübertrag

Beispiel: 00110100 = Bits N=0, V=0, \=1, B=1, D=0, I=1, Z=0, C=0 — typischer Zustand beim Starten (I=1 : Interrupts deaktiviert).


! aaaa — Binary (Hexadezimal → Binär-Umrechnung)

Wandelt den Hexadezimalwert aaaa in 16-Bit-Binär um und zeigt ihn an. Es wird kein Speicher gelesen — das Argument selbst wird konvertiert.

Format: ! aaaa = bbbbbbbb bbbbbbbb (höherwertiges Byte dann niederwertiges Byte).

Nützlich zur Visualisierung der einzelnen Bits eines Werts (zuvor gelesenes Hardware-Register, Ergebnis einer Operation, Flag-Wert…).


* OP aaaa,bbbb — Arithmetic (Rechenwerk)

Arithmetische oder logische Operation mit zwei 16-Bit-Werten. Ergebnis: RRRR C=b.

Operatoren: + - A (UND) O (ODER) E (XOR).

* + 4000 allein → ? — beide Operanden erforderlich.

Nützlich zur Berechnung von Adressen, Offsets oder zur Überprüfung von Speicherbereichen ohne den Monitor zu verlassen.


: aaaa bb bb bb bb bb bb bb bb — Enter (Bytes in Speicher eingeben)

Schreibt 8 Hex-Bytes ab aaaa, zeigt die Zeile an, schlägt nächste Adresse vor. BREAK zum Beenden.

: aaaa allein → keine Ausgabe.

Um einen großen Bereich einzugeben, Zeile für Zeile fortfahren: jede EINGABE-Taste rückt um 8 Bytes vor. Um weniger als 8 Bytes einzugeben, den Befehl I verwenden.

Einschränkung: : prüft jeden geschriebenen Byte durch erneutes Lesen der Adresse. Diese Prüfung schlägt bei Hardwareregistern (POKEY $D200–$D20F, GTIA $D000–$D01F, ANTIC $D400–$D40F, PIA $D300–$D30F) fehl, da Lese- und Schreibadressen auf unterschiedliche physische Register zeigen. Um Hardware zu beschreiben, Maschinencode in den RAM schreiben und mit G ausführen.


, aaaa bb [bb ...] — Enter with Disassembly (Eingabe mit Disassemblierung)

Schreibt Hex-Bytes ab aaaa und zeigt die entsprechende 6502-Disassemblierung. Beliebige Byte-Anzahl pro Zeile. BREAK zum Beenden.

Ideal für die Eingabe von Assembler-Code und sofortige Überprüfung, dass die Opcodes korrekt sind.


7. Interne Variablen (Zeropage)

AdresseLokaler NameFunktion
$DA-$DBPTR_START16-Bit-Startadresse (Argument 1)
$DC-$DDPTR_END16-Bit-Endadresse (Argument 2)
$DE-$DFPTR_DEST16-Bit-Zieladresse (Argument 3)
$E0MODE0 = Normalmodus, ≠0 = Umkehrmodus
$E4TEMP_AZwischenspeicher / Akkumulatorsicherung
$E5TEMP_BZähler / Zwischenspeicher
$E7COL_CTRSpaltenzähler für Hex-Anzeige (0–6)
$EBTEMP_CAnzeige-Zwischenspeicher
$F2BUF_PTRZeiger in Puffer $4E3C
$F3-$F4FP_PTRZeiger auf Math-ROM-Gleitkommabereich

8. Wichtigste Unterprogramme

AdresseBeschreibung
$401CSAVE_CPU: Sichert 6502-Zustand (Akkumulator, X, Y, Flags, Programmzähler, Stapel)
$4054PRINT_HEADER: Zeigt Banner und Registerüberschrift an
$4064CMD_LOOP: Hauptschleife zum Einlesen/Verteilen von Befehlen
$40B5CLR_RANGE: Setzt Adressregister DA–DF auf Null
$40C5DUMP_8: Zeigt 8 Bytes hexadezimal an
$40DBFILTER_CHAR: Filtert ein ATASCII-Zeichen (druckbar / nicht druckbar)
$4127ADD16: Addiert A zur 16-Bit-Adresse DA:DB
$4133DO_CIO: Ruft CIO ($E456) mit X=IOCB-Nummer×16 auf
$41DDDO_SIO_DISK: Sendet einen SIO-Diskettenbefehl über DSKINV ($E453)
$41E8FIND_CMD: Sucht ein Zeichen in der Befehlstabelle $4F8D
$41F7GET_CHAR: Liest das nächste Zeichen aus dem Eingabepuffer
$422ASKIP_SP: Bewegt Pufferzeiger über Leerzeichen hinweg
$423DREAD_BYTE: Liest 2 Hex-Stellen → Byte in A
$4256READ_ADDR: Liest 4 Hex-Stellen → 16-Bit-Adresse in A(hi) Y(lo)
$4280READ_BIN: Liest 8 Binärziffern → Byte in A
$42C7SET_FNAME: Setzt Dateinamenadresse im IOCB
$42CFSET_BUFADDR: Setzt Pufferadresse im IOCB
$42E9OPEN_EDITOR: Öffnet Kanal 0 auf E: (Bildschirmeditor)
$4330PRINT_HEX8: Zeigt ein Byte als 2 Hex-Stellen an
$4349NEWLINE_REGS: Zeilenvorschub + Registeranzeige
$4373NEWLINE: Sendet Wagenrücklauf ($9B) auf E:
$4399PRINT_CHAR: Zeigt ein ATASCII-Zeichen über CIO an
$44A4FP_TO_STR: Gleitkomma-zu-Zeichenkette-Umwandlung (Math-ROM IFP+FASC)
$44C5SET_FP_PTR: Initialisiert Gleitkommazeiger ($4D99)

9. Nutzung des Atari-Betriebssystems

ATAMON verwendet folgende OS-Dienste:

DienstAdresseVerwendung
CIO — Central I/O$E456 (CIOV)Bildschirm lesen/schreiben, Dateien
SIO — Serial I/O Diskette$E453 (DSKINV)Diskettensektorzugriff
Math-ROM IFP$D9AAGanzzahl → Gleitkomma-Umwandlung
Math-ROM FASC$D8E6Gleitkomma → ASCII-Umwandlung
VBREAK$0206–$0207BRK-Vektor (Monitor-Eintritt bei Haltepunkt)

Verwendete IOCBs:

DCB-Struktur für Diskettenzugriffe ($0300–$030B):


10. Interne Datentabellen

Die im Speicher gespeicherte Zeichenkette lautet:

ATAMON zeigt auf den Beginn des Teils PC SP AC XR YR NV\BDIZC (bei $4F71), um die Spaltenüberschrift anzuzeigen — der Teil E:P1: ist in der Binärzeichenkette enthalten, wird aber nicht separat angezeigt. Die Bildschirmausgabe (40 Spalten) ergibt:

Hex-Ziffern + Befehlstabelle ($4F8D)

Dispatch-Tabelle ($4FC8)

Bytepaare (Adresse - 1) (lo, hi) für jeden Befehls-Handler. Die Verteilung nutzt den RTS-Trick: Die Handler-Adresse minus 1 wird auf den Stapel gelegt (hi zuerst, dann lo), dann wird RTS ausgeführt. Der 6502 liest die Adresse, erhöht sie um 1 und springt zum Handler. Das vermeidet eine JMP-Tabelle und spart einige Bytes.

Beispiel: Befehl 'G' (5. Zeichen in $4F9D) → ATAMON liest die 2 Bytes bei $4FC8 + (Index × 2), legt sie in umgekehrter Reihenfolge auf den Stapel und macht RTS zum Handler.

Interne Disassembler-Tabellen ($4FF9+)

ATAMON besitzt einen eigenen Mini-Disassembler (Befehl D). Er verwendet zwei interne Tabellen:

  1. 6502-Mnemoniken: 3-Buchstaben-kodierte Einträge (56 offizielle Mnemoniken)

  2. Adressierungsmodi: Tabelle der Operandengrößen und -formate für jeden Opcode

Diese Tabellen decken nur die offiziellen 6502-Opcodes ab. Illegale Opcodes werden vom ATAMON-Disassembler nicht erkannt und würden fehlerhaft angezeigt.

→ Siehe Anhang B am Ende des Dokuments für die vollständige Liste der 56 erkannten Mnemoniken.

Hinweis: Im ATAMON-Binärcode enthalten die Adressen $4F43–$52B1 Daten (Textzeichenketten, Zeichentabellen, Vektoren). Ein linearer Disassembler interpretiert diese Bytes als Befehle — von denen viele in die Kategorie undokumentierter 6502-Opcodes fallen ($02 *KIL, $03 *SLO, $3A *NOP usw.). Dies sind Fehlalarme aufgrund der Datennatur, keine absichtliche Verwendung illegaler Opcodes im ATAMON-Code.


11. ATAMON benutzen

Start

Wählen Sie im Atari-DOS L. BINARY LOAD, dann D:ATAMON eingeben. ATAMON zeigt sein Banner (*C + Register) an, und der Atari-Cursor wartet auf den ersten Befehl.

Sondertasten

TasteWirkung in ATAMON
RETURNBestätigt den aktuellen Befehl
BREAKUnterbricht ein laufendes Programm und gibt die Kontrolle an ATAMON zurück (über VBREAK/BRK-Vektor)
RESETHardware-Reset — vermeiden: löscht den Speicher und zerstört das geladene Programm
DELETE / BACK S.Löscht das zuletzt eingegebene Zeichen
ESCKann die aktuelle Eingabe je nach CIO/Editor-Kontext abbrechen

Hinweis: ATAMON stützt sich auf CIO (Bildschirmeditor E:) für das Einlesen von Befehlen. Die Standardbearbeitungsfunktionen des Atari-Editors (Cursorbewegung, Löschen) sind verfügbar, bevor mit RETURN bestätigt wird.

Typische Startanzeige

Beispielsitzung


12. Historische Anmerkungen

ATAMON (Abkürzung für ATAri MONitor) ist ein Maschinensprachemonitor, der 1983 von ATARI in Deutschland vermarktet wurde — im selben Jahr wie die Markteinführung des Atari 800XL.

Die DXG-5724-Diskette enthält außerdem:

Diese drei Programme bilden eine vollständige Diskette: DOS + Dienstprogramme + Debugging-Monitor.

Die Analyse der Diskette ergab keinen besonderen Kopierschutz. Die Analyse aller 720 Sektoren bestätigte das Fehlen von Phantomsektoren (phantom_count = 0 für alle Sektoren), absichtlich fehlerhafter CRCs oder anderer Kopierschutzmechanismen. Die Original-ATAMON-Diskette war nicht kopiergeschützt.


13. Technische Hinweise zur Disassemblierung

Bekannte illegale 6502-Opcodes

GruppeOpcodesBeschreibung
*KIL$02,$12,$22,$32,$42,$52,...Sperrt die CPU dauerhaft
*NOP$1A,$3A,$5A,$7A,$DA,$FA (1 Byte)Illegaler Leerbefehl
*NOP$04,$44,$64,$14,$34,$54,... (2–3 Bytes)NOP mit ignoriertem Operanden
*SLO$03,$07,$0F,$13,$17,$1B,$1FASL Speicher, dann ORA A
*RLA$23,$27,$2F,$33,$37,$3B,$3FROL Speicher, dann AND A
*SRE$43,$47,$4F,$53,$57,$5B,$5FLSR Speicher, dann EOR A
*RRA$63,$67,$6F,$73,$77,$7B,$7FROR Speicher, dann ADC A
*LAX$A3,$A7,$AF,$B3,$B7,$BFLädt A und X gleichzeitig
*SAX$83,$87,$8F,$97Speichert A UND X
*DCP$C3,$C7,$CF,$D3,$D7,$DB,$DFDEC Speicher, dann CMP A
*ISC$E3,$E7,$EF,$F3,$F7,$FB,$FFINC Speicher, dann SBC A
Sonst.$0B/$2B *ANC, $4B *ALR, $6B *ARR, $CB *SBX, $9B *TAS, $9C *SHYVerschiedene Kombinationen

JMP-Indirect-Fehler

Der 6502 hat einen Hardware-Fehler: JMP (addr) liest das höherwertige Byte falsch, wenn addr auf $FF endet. Beispiel: JMP ($10FF) liest $10FF (lo) und $1000 (hi) statt $1100. In ATAMON enden die beiden vorhandenen JMP (ind) ($47BF JMP (DOSVEC) und $47E4 JMP ($4F41)) nicht auf $FF — kein Fehler in diesem Programm. Hinweis: JMP ($4F41) ist der Ausführungssprung zur gesicherten Adresse (PCL bei $4F41, PCH bei $4F42).


Anhang A — Zeropage-Glossar ($00$FF)

Die Zeropage ist der erste 256-Byte-Block des RAM ($00 bis $FF). Auf dem 6502 ist sie aus zwei Gründen besonders:

Das Atari-Betriebssystem und ATAMON machen davon intensiv Gebrauch. Hier die wichtigsten Stellen:

Atari-OS-Variablen (vom System reserviert)

AdresseOS-NameBedeutung
$08COLCRSCursorspalte (0 bis 39). Das OS aktualisiert diesen Wert bei jeder Tasteneingabe. Änderbar, um den Cursor horizontal zu verschieben.
$09ROWCRSCursorreihe (0 bis 24). Gleiches Prinzip für die Zeile.
$0B$0CSAVMSCBildschirmspeicheradresse (2 Bytes). Zeigt auf das erste Byte des angezeigten Bildes. Direkte Änderung verändert den Bildschirm in Echtzeit.
$14$16RTCLOKEchtzeituhr (3 Bytes). Wird vom OS automatisch 60-mal pro Sekunde inkrementiert (bei jedem vertikalen Interrupt). Nützlich zur Zeitmessung oder für Verzögerungen.
$55ATRACTBildschirmschoner. Das OS erhöht diesen Zähler jede Sekunde der Tastaturinaktivität. Überschreitet er 127, werden die Farben zum Bildschirmschutz gedämpft. Zurücksetzen auf 0 deaktiviert den Schoner.
$6ARAMTOPObergrenze des verfügbaren RAM. Wert in Seiten (×256). Gibt an, bis wohin RAM von Programmen nutzbar ist. Änderbar, um oberen Speicher zu reservieren.
$80$9FFR0Gleitkommaregister 0 (6 Bytes). Arbeitsbereich des Math-ROM für Gleitkommaberechnungen. Wird bei jedem Math-ROM-Aufruf überschrieben.
$A0$A5FR1Gleitkommaregister 1 (6 Bytes). Zweites Gleitkommaregister, als Operand in Berechnungen verwendet.

Von ATAMON verwendete Variablen

Diese Adressen sind von ATAMON während des Betriebs reserviert. Eine Änderung mit : oder , kann den Monitor stören.

AdresseATAMON-NameBedeutung
$DA$DBPTR_STARTStartadresse der aktuellen Operation (Argument 1 der Befehle M, D, F, T...).
$DC$DDPTR_ENDEndadresse (Argument 2).
$DE$DFPTR_DESTZieladresse (Argument 3, von T genutzt).
$E0MODEAnzeigemodus: 0 = normal, ≠ 0 = invertiert (für M).
$E4TEMP_AZwischenspeicher: Akkumulatorsicherung zwischen zwei internen Operationen.
$E5TEMP_BTemporärer Zähler (interne Schleifen).
$E7COL_CTRSpaltenzähler für Hex-Anzeige (0 bis 6, zur Ausrichtung von 8 Bytes pro Zeile).
$F2BUF_PTRBefehlspufferzeiger ($4E3C). Zeigt an, wie weit die Eingabezeile gelesen wurde.

Tipp: Verwenden Sie M 0000 00FF, um die gesamte Zeropage anzuzeigen und zu beobachten, wie sich diese Werte bei verschiedenen Operationen ändern.


Inoffizielle Dokumentation, rekonstruiert durch Binäranalyse der XEX-Datei und 6502-Disassemblierung. Referenzen: De Re Atari (APX 90009), Atari 8-bit FAQ, Altirra 4.40 Quellcode, AtariWiki — 6502 Assembly Code, Unused Opcodes, OS-ROM-Quellliste, Atari Custom Display Lists (Atarimania), Display Lists Simplified (Atari magazines), ANTIC registers (xmission.com/~trevin), Mapping the Atari.


Anhang B — Die 56 offiziellen 6502-Mnemoniken

Der eingebaute Disassembler von ATAMON (Befehl D) erkennt genau diese 56 Befehle.

Laden / Speichern

MnemonicVollständiger NameBeschreibungBeispiel
LDALoad AccumulatorLädt einen Wert in den Akkumulator ALDA #$41 → A = 'A'
LDXLoad XLädt einen Wert in Register XLDX #$00 → X = 0 (Schleifen-Init)
LDYLoad YLädt einen Wert in Register YLDY #$08 → Y = 8 (Zähler)
STAStore AccumulatorSchreibt A in den SpeicherSTA $D800 → sendet Farbe an GTIA
STXStore XSchreibt X in den SpeicherSTX $00 → sichert X in Zeropage
STYStore YSchreibt Y in den SpeicherSTY $CB → sichert Y in Variable

Registertransfers

MnemonicVollständiger NameBeschreibungBeispiel
TAXTransfer A to XKopiert A nach XLDA #$10 / TAX → X = 16
TAYTransfer A to YKopiert A nach YTAY → Y ← A (zur Tabellenindizierung)
TXATransfer X to AKopiert X nach ATXA / CLC / ADC #$40 → Adressberechnung
TYATransfer Y to AKopiert Y nach ATYA / STA $CB → sichert Y als Wert
TSXTransfer SP to XKopiert Stapelzeiger SP nach XTSX → X = aktueller Stapelwert
TXSTransfer X to SPKopiert X in Stapelzeiger SPLDX #$FF / TXS → setzt Stapel zurück

Stapel

MnemonicVollständiger NameBeschreibungBeispiel
PHAPush AccumulatorLegt A auf den Stapel (sichern)PHA vor JSR, um A nicht zu verlieren
PLAPull AccumulatorHolt A vom Stapel (wiederherstellen)PLA nach JSR, stellt A wieder her
PHPPush Processor statusLegt Statusregister P auf den StapelPHP / SEI / … / PLP: kritischer Abschnitt
PLPPull Processor statusHolt P vom StapelPLP stellt durch PHP gesicherte Flags wieder her

Arithmetik

MnemonicVollständiger NameBeschreibungBeispiel
ADCAdd with CarryA ← A + Operand + CCLC / LDA #$10 / ADC #$05 → A = $15
SBCSubtract with CarryA ← A − Operand − (1−C)SEC / LDA #$10 / SBC #$03 → A = $0D

Inkrementieren / Dekrementieren

MnemonicVollständiger NameBeschreibungBeispiel
INCIncrement memory+1 zu einem SpeicherbyteINC $0600 → erhöht Punktestand in $0600
INXIncrement XX ← X + 1INX / CPX #$10 / BNE LOOP: 16×-Schleife
INYIncrement YY ← Y + 1INY / LDA (PTR),Y: schreitet durch Tabelle
DECDecrement memory−1 zu einem SpeicherbyteDEC $CB → verringert Lebenszähler
DEXDecrement XX ← X − 1LDX #$08 / LOOP: DEX / BNE LOOP: wartet 8×
DEYDecrement YY ← Y − 1DEY / BNE LOOP: Schleife solange Y ≠ 0

Logische Operationen

MnemonicVollständiger NameBeschreibungBeispiel
ANDLogical ANDA ← A UND Operand (bitweise)AND #$0F → behält untere 4 Bits (Nibble)
ORALogical ORA ← A ODER Operand (bitweise)ORA #$80 → setzt Bit 7 auf 1 (Invertbild)
EORExclusive ORA ← A XOR Operand (bitweise)EOR #$FF → invertiert alle Bits
BITBit testZ ← A UND Speicher; N,V ← Bits 7,6 d. SpeichersBIT $D018 → testet Register ohne A zu ändern

Schieben und Rotieren

MnemonicVollständiger NameBeschreibungBeispiel
ASLArithmetic Shift LeftLinks schieben (× 2); Bit 7 → CASL A → A × 2
LSRLogical Shift RightRechts schieben (÷ 2); Bit 0 → CLSR A → A ÷ 2
ROLRotate LeftLinksrotation durch CROL A → × 2 + altes C (16-Bit-Multiplikation)
RORRotate RightRechtsrotation durch CROR A → ÷ 2 + altes C in Bit 7

Vergleiche

MnemonicVollständiger NameBeschreibungBeispiel
CMPCompare AA − Operand → N,Z,C (A unverändert)CMP #$9B / BEQ EOL → ATASCII-Zeilenende?
CPXCompare XX − Operand → N,Z,CCPX #$10 / BNE LOOP → Ende bei X=16
CPYCompare YY − Operand → N,Z,CCPY #$00 / BEQ DONE → Ende bei Y=0

Bedingte Sprünge

Alle Sprünge sind relativ (vorzeichenbehafteter Offset von −128 bis +127 Bytes ab dem nächsten Befehl).

MnemonicVollständiger NameBedingungBeispiel
BCCBranch if Carry ClearC = 0ADC #$01 / BCC OK → kein Übertrag
BCSBranch if Carry SetC = 1CMP #$80 / BCS HIGH → A ≥ $80
BEQBranch if EqualZ = 1 (Ergebnis null)CMP #$41 / BEQ FOUND → 'A' gefunden
BNEBranch if Not EqualZ = 0 (Ergebnis nicht null)DEX / BNE LOOP → klassische Schleife
BMIBranch if MinusN = 1 (Bit 7 = 1)BIT $D40B / BMI VBLANK → VBlank aktiv
BPLBranch if PlusN = 0 (Bit 7 = 0)LDA $CB / BPL OK → positiver Wert
BVCBranch if oVerflow ClearV = 0ADC #$01 / BVC OK → kein Vorzeichenüberlauf
BVSBranch if oVerflow SetV = 1ADC #$40 / BVS ERR → Vorzeichenüberlauf

Sprünge und Aufrufe

MnemonicVollständiger NameBeschreibungBeispiel
JMPJumpUnbedingter Sprung (absolut oder indirekt)JMP $4000 → startet ATAMON neu
JSRJump to SubroutineLegt Rücksprungadresse ab, dann SprungJSR $E456 → ruft CIO auf
RTSReturn from SubroutineHolt Rücksprungadresse+1 und springt dorthinRTS → Ende eines Unterprogramms
RTIReturn from InterruptHolt P, dann Programmzähler vom StapelRTI → Ende eines VBI- oder DLI-Handlers

Software-Interrupt

MnemonicVollständiger NameBeschreibungBeispiel
BRKBreakLöst Software-Interrupt aus; legt PC+2 und P ab, springt über OS-Vektor ($0206/$0207). Zentraler ATAMON-Haltepunktmechanismus.BRK → sofortige Rückkehr zu ATAMON

Flag-Operationen

MnemonicVollständiger NameBeschreibungBeispiel
CLCClear CarryC ← 0CLC / ADC #$01 → Addition ohne alten Übertrag
SECSet CarryC ← 1SEC / SBC #$01 → korrekte Subtraktion
CLDClear DecimalD ← 0 (BCD deaktivieren)CLD zu Beginn einer Rechenroutine
SEDSet DecimalD ← 1 (BCD aktivieren)SED → am Atari selten nützlich
CLIClear Interrupt disableI ← 0 (IRQ erlauben)CLI → aktiviert VBI, POKEY usw.
SEISet Interrupt disableI ← 1 (IRQ maskieren)SEI → schützt kritischen Abschnitt
CLVClear oVerflowV ← 0CLV → bekannter Ausgangszustand vor vorzeichenbehafteter Arithmetik

Sonstiges

MnemonicVollständiger NameBeschreibungBeispiel
NOPNo OperationTut nichts; rückt Programmzähler um 1 Byte weiter. Zum Neutralisieren eines Befehls oder zum Auffüllen von Speicher.NOP / NOP / NOP ersetzt ein 3-Byte-JSR $xxxx

Anhang C — Illegale / undokumentierte 6502-Opcodes

Diese Opcodes existieren nicht in der offiziellen MOS-Technology-6502-Spezifikation. Sie entstehen durch unbeabsichtigte Kombinationen der internen Prozessorlogik. Ihr Verhalten wird vom ATAMON-Disassembler (Befehl D) wiedergegeben, der sie mit einem vorangestellten * anzeigt.

Warnung: Die meisten sind je nach Prozessorrevision oder Versorgungsspannung instabil. Im Produktionscode vermeiden; nützlich zur Analyse alter Programme, die sie nutzen.

Fatale Befehle

MnemonicAlt.-NamenBeschreibungOpcodes
*KILJAM, HLTSperrt die CPU dauerhaft — der Datenbus friert ein, nur ein Hardware-Reset kann die Maschine neu starten.$02 $12 $22 $32 $42 $52 $62 $72 $92 $B2 $D2 $F2

Kombinierte Lese-Modifizier-Schreib-Befehle

Diese Opcodes führen zwei Operationen in einer aus: eine Änderung im Speicher dann eine logische/arithmetische Operation mit A.

MnemonicAlt.-NamenBeschreibungModiOpcodes
*SLOASOASL auf Speicherbyte, dann ORA mit Ainx zp abs iny zpx aby abx$03 $07 $0F $13 $17 $1B $1F
*RLAROL auf Speicherbyte, dann AND mit Ainx zp abs iny zpx aby abx$23 $27 $2F $33 $37 $3B $3F
*SRELSELSR auf Speicherbyte, dann EOR mit Ainx zp abs iny zpx aby abx$43 $47 $4F $53 $57 $5B $5F
*RRAROR auf Speicherbyte, dann ADC mit Ainx zp abs iny zpx aby abx$63 $67 $6F $73 $77 $7B $7F
*DCPDCMDEC auf Speicherbyte, dann CMP mit Ainx zp abs iny zpx aby abx$C3 $C7 $CF $D3 $D7 $DB $DF
*ISCISB, INSINC auf Speicherbyte, dann SBC mit Ainx zp abs iny zpx aby abx$E3 $E7 $EF $F3 $F7 $FB $FF

Kombiniertes Laden / Speichern

MnemonicAlt.-NamenBeschreibungModiOpcodes
*LAXLädt denselben Wert gleichzeitig in A und X — entspricht LDA + TAX in einem Opcodeinx zp abs iny zpy aby$A3 $A7 $AF $B3 $B7 $BF
*SAXAXSSchreibt A UND X in den Speicher (ohne Flags zu ändern)inx zp abs zpy$83 $87 $8F $97

Akkumulator-Befehle

MnemonicAlt.-NamenBeschreibungOpcodeStabilität
*ANCSofort-AND mit A, dann Bit 7 in Carry kopieren (wie ASL ohne Speicheränderung)$0B $2Bstabil
*ALRASRSofort-AND mit A, dann LSR auf A (logische Rechtsverschiebung)$4Bstabil
*ARRSofort-AND mit A, dann ROR auf A — mit komplexen Effekten auf C und V$6Bstabil
*SBXAXS(A UND X) − Imm → X, ohne Borge (beeinflusst C, Z, N)$CBstabil
*SBCDuplikat des offiziellen SBC #imm ($E9) — identisches Verhalten$EBstabil
*ANEXAAA = (A ODER $EE) UND X UND Imm — Ergebnis prozessorabhängig$8Binstabil
*LXALAX #(A ODER $EE) UND Imm → A und X — Ergebnis prozessorabhängig$ABinstabil

Instabile Speicherbefehle (abhängig von addr_hi)

MnemonicAlt.-NamenBeschreibungOpcodeStabilität
*TASXAS, SHSSP = A UND X; schreibt SP UND (addr_hi+1) in Speicher$9Binstabil
*SHYA11YSchreibt Y UND (addr_hi+1) in Speicher$9Cinstabil
*SHXA11XSchreibt X UND (addr_hi+1) in Speicher$9Einstabil
*SHAAXASchreibt A UND X UND (addr_hi+1) in Speicher$93 $9Finstabil
*LASLARA = X = SP = Speicher UND SP$BBinstabil

Illegale NOPs (mehrere Bytes, kein Effekt)

Diese Opcodes verhalten sich wie NOP (tun nichts Sichtbares), verbrauchen aber 2 oder 3 Bytes.

MnemonicModusGrößeOpcodes
*NOPimp (1 Byte)1$1A $3A $5A $7A $DA $FA
*NOPzp (2 Bytes)2$04 $44 $64
*NOPzpx (2 Bytes)2$14 $34 $54 $74 $D4 $F4
*NOPabs (3 Bytes)3$0C
*NOPabx (3 Bytes)3$1C $3C $5C $7C $DC $FC


Anhang D — Bekannte Atari-Bezeichner

Symbolische Adressen, die der ATAMON-Disassembler (Befehl D) erkennt. Sie erscheinen im Disassemblat anstelle der reinen Hexadresse.

Zeropage — OS-Variablen ($00$FF)

AdresseBezeichnerBeschreibung
$000A$000BDOSVECDOS-Vektor — Sprungadresse zum DOS (2 Bytes lo/hi). JMP (DOSVEC) verlässt das Programm und kehrt zum DOS zurück.
$000C$000DDOSINIDOS-Initialisierungsvektor — bei jedem Warm-Reset aufgerufen.
$0010POKMSKPOKEY-IRQ-Aktivierungsmaske. Jedes Bit aktiviert einen IRQ-Typ (Timer, Seriell…).
$0012$0014RTCLOKEchtzeituhr (3 Bytes). 60×/s vom OS-VBI inkrementiert.
$0020$002BZIOCBIOCB Null — Arbeitskopie des aktuellen Kanal-IOCB während eines CIO-Aufrufs.
$002CSTATUSStatuscode der letzten SIO- oder CIO-Operation.
$002E$002FBUFRLO/HIAdresse des Ein-/Ausgabepuffers (2 Bytes). Von SIO DCB und CIO verwendet.
$0030$0031BFENLO/HIPuffer-Endadresse (2 Bytes).
$0036$0037BYTLO/HIAnzahl der beim letzten SIO/CIO-Aufruf übertragenen Bytes (2 Bytes).

Seite 2 — Interrupt-Vektoren ($0200$02FF)

AdresseBezeichnerBeschreibung
$0200$0201VDSLSTDLI-Vektor (Display-List-Interrupt) — bei jeder DLI-Anweisung in der ANTIC-Display-List aufgerufen.
$0202$0203VPRCEDInterrupt-Vektor „proceed" (serielle Eingabe).
$0204$0205VINTERInterrupt-Vektor „interrupt" (serielle Eingabe).
$0206$0207VBREAKBRK-Vektor — aufgerufen wenn die CPU BRK ausführt. ATAMON installiert ihn, um Haltepunkte abzufangen.
$0208$0209VKEYBDTastatur-Interrupt-Vektor (Taste gedrückt).
$020A$020BVSERINSerieller Empfangsvektor (POKEY).
$020C$020DVSERORSerieller Sendevektor (POKEY).
$020E$020FVSEROCVektor Ende serieller Sendung.
$0210$0211VTIMR1POKEY-Timer-1-Vektor.
$0212$0213VTIMR2POKEY-Timer-2-Vektor.
$0214$0215VTIMR4POKEY-Timer-4-Vektor.
$0216$0217VIMIRQGenerischer IRQ-Vektor (vom OS nicht verwendet).
$0222$0223VVBLKISofortiger VBI-Vektor — zu Beginn des vertikalen Blanking aufgerufen (~3 800 Zyklen verfügbar).
$0224$0225VVBLKDVerzögerter VBI-Vektor — nach SYSVBV aufgerufen (~20 000 Zyklen verfügbar, sicherer).
$0226$0227CDTMA1Software-Timer-1-Vektor (vom VBI dekrementiert).
$0228$0229CDTMA2Software-Timer-2-Vektor.
$022ACDTMF3Software-Timer-3-Flag.
$022CCDTMF4Software-Timer-4-Flag.
$022EBRKKEYBREAK-Taste-Flag: $00 wenn BREAK gedrückt, sonst $80.
$022FSDMCTLSchatten DMACTL — beim VBI nach $D400 (ANTIC) kopiert. Steuert Bildschirmbreite und DMA-Aktivierung.
$0230$0231SDLSTL/HSchatten Display-List (lo/hi) — beim VBI nach $D402/$D403 kopiert. Zeigt auf aktive ANTIC-Display-List.
$023BATRACTBildschirmschoner-Zähler. Vom OS jede Sekunde Tastaturinaktivität inkrementiert. Über 127 → Farben gedämpft. Zurücksetzen auf 0 deaktiviert den Schoner.
$026FGPRIORSchatten PRIOR — beim VBI nach $D01B (GTIA) kopiert. Bestimmt Anzeige-Priorität Spieler/Missiles/Hintergrund.
$02C0$02C8COLPF0COLPM0Farben der Playfields und Spieler (Schatten der GTIA-Farbregister).
$02C8COLBKHintergrundfarbe. Schatten des GTIA-Registers $D01A.
$02E0$02E1RUNADAusführungsadresse des geladenen Programms (XEX). Das OS springt nach dem Laden zu dieser Adresse.
$02E2$02E3INITADInitialisierungsadresse — nach jedem mit INITAD markierten XEX-Segment aufgerufen.
$02E4RAMSIZRAM-Größe in Seiten (×256). Beim Start gelesen.
$02E5RAMTOPObere RAM-Nutzungsgrenze (in Seiten).
$02E7$02E8MEMLOUntere RAM-Grenze (2 Bytes). ATAMON setzt sie auf $5300, um seinen Code zu schützen.
$02E9$02EAMEMTOPObere RAM-Grenze (2 Bytes).
$02F4CHBASSchatten CHBASE — beim VBI nach $D408 (ANTIC) kopiert. Wählt den Zeichensatz.

Seite 3 — SIO-DCB ($0300$035F)

AdresseBezeichnerBeschreibung
$0300DDEVICSIO-Gerätenummer (z. B. $31 = Diskette D1:).
$0301DUNITEinheitennummer (1 bis 4 für D1: bis D4:).
$0302DCOMNDSIO-Befehl (z. B. $52 = Read sector, $57 = Write sector).
$0303DSTATSRichtung: $40 = Lesen, $80 = Schreiben, $00 = nur Status.
$0304$0305DBUFLO/HIPufferadresse (2 Bytes lo/hi).
$0306DTIMLOSIO-Timeout in VBI-Einheiten (~1/60 s). Typischer Wert: $0F (15 VBI).
$0308$0309DBYTLO/HIAnzahl zu übertragender Bytes (2 Bytes).
$030A$030BDAUX1/2Hilfsparameter (z. B. Sektornummer lo/hi für Diskette).
$0340$034FIOCB0IOCB Kanal 0 (Bildschirmeditor E: — von ATAMON für die Eingabe verwendet).
$0350$035FIOCB1IOCB Kanal 1 (frei).

Hardwareregister — GTIA ($D000)

AdresseBezeichnerBeschreibung
$D000HPOSP0Horizontalposition Spieler 0.
$D001HPOSP1Horizontalposition Spieler 1.
$D002HPOSP2Horizontalposition Spieler 2.
$D003HPOSP3Horizontalposition Spieler 3.
$D004HPOSM0Horizontalposition Munition 0.
$D01BPRIORAnzeige-Priorität Spieler/Munition/Playfields. Bit 7 = spezieller GTIA-Modus.
$D01DGRACTLAktivierung DMA Spieler/Munition.
$D01FCONSOLKonsolentasten (Lesen): Bits 2-0 = START/SELECT/OPTION (0 = gedrückt). Schreiben: Lautsprecher-Steuerung.

Hardwareregister — POKEY ($D200)

AdresseBezeichnerBeschreibung
$D200AUDF1Frequenzteiler Audiokanal 1 (Wert 0–255, Frequenz umgekehrt proportional).
$D201AUDC1Steuerung Kanal 1: Bits 7-4 = Lautstärke, Bits 3-0 = Verzerrung/Wellenform.
$D202AUDF2Frequenzteiler Audiokanal 2.
$D203AUDC2Steuerung Kanal 2.
$D204AUDF3Frequenzteiler Audiokanal 3.
$D205AUDC3Steuerung Kanal 3.
$D206AUDF4Frequenzteiler Audiokanal 4.
$D207AUDC4Steuerung Kanal 4.
$D208AUDCTLGlobale Audio-Steuerung: Taktfrequenz (64 kHz/15 kHz/1,79 MHz), 16-Bit-Kanäle, Hochpassfilter.
$D20ASTIMERSchreiben: POKEY-Timer auf Null zurücksetzen.
$D20ESEROUTSerieller Ausgang (Schreiben).
$D20FSKCTLPOKEY-Serien-Steuerung: Reset, Synchronisationsmodus.

Hardwareregister — PIA ($D300)

AdresseBezeichnerBeschreibung
$D300PORTAPort A: Joystick 1 (Bits 3-0) und Joystick 2 (Bits 7-4). Bit = 0 wenn Richtung aktiv.
$D301PORTBPort B: auf dem 800XL Steuerung der OS-ROM-Bank (Bit 0) und BASIC (Bit 1).
$D302PACTLSteuerung Port A (Richtungsbits, Interrupts).
$D303PBCTLSteuerung Port B.

Hardwareregister — ANTIC ($D400)

AdresseBezeichnerBeschreibung
$D400DMACTLDMA-Steuerung: aktiviert/deaktiviert DMA, definiert Bildschirmbreite (narrow/normal/wide) und Spieler/Munition-DMA.
$D401CHACTLZeichen-Steuerung: invertiertes Video, Blanking oberer/unterer Zeilenränder einer Zelle.
$D402$D403DLISTL/HDisplay-List-Adresse (lo/hi). ANTIC liest diese Liste für den Bildaufbau.
$D404HSCROLFeines horizontales Scrolling (0–15 Farbtakte).
$D405VSCROLFeines vertikales Scrolling (0–15 Zeilen).
$D407PMBASEBasisadresse Spieler/Munition (oberes Byte der Adresse, 1-KB- oder 2-KB-Seite je nach DMACTL).
$D408CHBASEBasisadresse Zeichensatz (oberes Byte; Zeichensatz beginnt bei dieser Seite × 256).
$D409WSYNCWait for sync — Schreiben: CPU wartet bis Ende der aktuellen Rasterzeile (Raster-Synchronisation).
$D40BVCOUNTAktueller Rasterzeilen-Zähler (nur Lesen, 0–131).
$D40ENMIENNMI-Aktivierung: Bit 7 = DLI, Bit 6 = VBI.
$D40FNMIRESSchreiben: NMI-Flags zurücksetzen. Lesen: NMI-Quelle identifizieren (Bit 7 = DLI, Bit 6 = VBI).

OS-ROM-Einsprungpunkte ($E4xx)

AdresseBezeichnerBeschreibung
$E450DISKIVInitialisierung des Disketten-Handlers.
$E453DSKINVSIO-Diskettenaufruf — führt den im DCB ($0300+) beschriebenen Befehl aus. Von ATAMON für die Befehle E und W verwendet.
$E456CIOVCIO (Central I/O) — Haupt-Einsprungpunkt für Ein-/Ausgabe. Von ATAMON zum Lesen von Befehlen und Schreiben von Ergebnissen verwendet.
$E459SIOVSIO (Serial I/O) — niederstufiger serieller Transfer.
$E45CSETVBVInstalliert einen VBI-Handler (sofort oder verzögert).
$E45FSYSVBVSystem-VBI-Handler (OS) — aus einem sofortigen VBI aufzurufen, um den verzögerten VBI zu verketten.
$E462XITVBVVBI-Austritt (Ende eines VBI-Handlers).
$E465SIOINVSIO-Initialisierung.
$E474WARMSVWarm-Restart — setzt das OS zurück ohne RAM zu löschen.
$E477COLDSVKalt-Start — vollständige Neuinitialisierung (löscht RAM).

Math-ROM ($D8xx)

AdresseBezeichnerBeschreibung
$D800AFPASCII → Gleitkomma (Zeichenkette bei $F3/$F4 → FR0).
$D8E6FASCGleitkomma → ASCII (FR0 → Zeichenkette bei $F3/$F4).
$D9AAIFP16-Bit-Ganzzahl → Gleitkomma (Wert in $D4/$D5 → FR0).
$D9D2FPIGleitkomma → 16-Bit-Ganzzahl (FR0 → $D4/$D5).
$DA44ZFR0FR0 auf Null setzen.
$DA60FSUBGleitkomma-Subtraktion: FR0 ← FR0 − FR1.
$DA66FADDGleitkomma-Addition: FR0 ← FR0 + FR1.
$DADBFMULGleitkomma-Multiplikation: FR0 ← FR0 × FR1.
$DB28FDIVGleitkomma-Division: FR0 ← FR0 / FR1.
$DD40PLYEVLPolynomauswertung (für sin, cos, exp…).
$DD89FLD0RFR0 von der Adresse in (X,Y) laden.
$DD98FLD1RFR1 von der Adresse in (X,Y) laden.
$DDA7FSTORFR0 an der Adresse in (X,Y) speichern.
$DDB6FMOVEFR1 ← FR0.

Anhang E — Atari 800XL Hardwareregister — Kurzübersicht

Übersicht der Hardware-Register der vier Custom-Chips des Atari 800XL, mit ihrer typischen Verwendung in der Programmierung.

GTIA — Graphic Television Interface Adaptor ($D000$D01F)

AdresseBezeichnerRichtungBeschreibung
$D000HPOSP0WHorizontalposition Spieler 0
$D001HPOSP1WHorizontalposition Spieler 1
$D002HPOSP2WHorizontalposition Spieler 2
$D003HPOSP3WHorizontalposition Spieler 3
$D004HPOSM0WHorizontalposition Munition 0
$D005HPOSM1WHorizontalposition Munition 1
$D006HPOSM2WHorizontalposition Munition 2
$D007HPOSM3WHorizontalposition Munition 3
$D008$D00BSIZEPxWSpielerbreite (0–3)
$D00CSIZEMWMunitionsbreite (Bits 0–7, je 2 pro Munition)
$D00D$D010GRAPxWSpieler-/Munitionsgrafik (1 Byte = 1 Pixelzeile)
$D011GRAFMWMunitionsgrafik (4 × 2 Bits)
$D012$D015COLPMxWSpieler/Munition-Farbe 0–3
$D016$D019COLPFxWSpielfeld-Farbe 0–3
$D01ACOLBKWHintergrundfarbe
$D01BPRIORWKollisions-/Prioritäts-Steuerung
$D01CVDELAYWVertikale Verzögerung für Spieler/Munition
$D01DGRACTLWGrafik-Steuerregister (Spieler/Munition ein/aus)
$D01EHITCLRWKollisionszähler zurücksetzen
$D01FCONSOLR/WKonsolentasten (START/SELECT/OPTION lesen), Lautsprecher
$D000$D007M0PF–P3PFRKollision Spieler/Munition mit Spielfeld
$D008$D00FM0PL–P3PLRKollision Munition/Spieler untereinander
$D010$D017P0PF–P3PFRKollision Spieler mit Spielfeld
$D018$D01FP0PL–P3PLRKollision Spieler untereinander

POKEY — Potentiometer and Keyboard ($D200$D20F)

AdresseBezeichnerRichtungBeschreibung
$D200AUDF1WTondivider Kanal 1 (Frequenz)
$D201AUDC1WTonsteuerung Kanal 1 (Distortion, Lautstärke)
$D202AUDF2WTondivider Kanal 2
$D203AUDC2WTonsteuerung Kanal 2
$D204AUDF3WTondivider Kanal 3
$D205AUDC3WTonsteuerung Kanal 3
$D206AUDF4WTondivider Kanal 4
$D207AUDC4WTonsteuerung Kanal 4
$D208AUDCTLWAudiosteuerung (Kanalverknüpfung, Taktbasis)
$D209STIMERWTimer-Neustart
$D20ASKRESWSKSTAT zurücksetzen
$D20BPOTGOWPotentiometer-Ablesung starten
$D20EIRQENWIRQ-Freigabe
$D20FSKCTLWSerielles Port-Steuerregister
$D200$D207POT0–POT7RPotentiometer-Werte
$D208ALLPOTRPotentiometer-Status (Bit = 1 = noch nicht bereit)
$D209KBCODERTastaturcode
$D20ARANDOMRPseudozufallszahl
$D20DSERINREmpfangenes Byte (seriell)
$D20EIRQSTRIRQ-Status
$D20FSKSTATRSerieller Port-Status

PIA — Peripheral Interface Adaptor ($D300$D303)

AdresseBezeichnerRichtungBeschreibung
$D300PORTAR/WJoystick-Port 1+2 (Richtungen als Bits)
$D301PORTBR/WBankswitching (XL/XE), Port B
$D302PACTLWPort A-Steuerregister
$D303PBCTLWPort B-Steuerregister

ANTIC — Alphanumeric Television Interface Circuit ($D400$D40F)

AdresseBezeichnerRichtungBeschreibung
$D400DMACTLWDMA-Steuerung (Spielfeldbreite, Spieler-DMA, ...)
$D401CHACTLWZeichen-Steuerung (Spiegelung, ...)
$D402$D403DLISTL/HWAnzeigenlistenzeiger (lo/hi)
$D404HSCROLWHorizontales Fine-Scrolling
$D405VSCROLWVertikales Fine-Scrolling
$D407PMBASEWBasis-Adresse Spieler/Munition-DMA
$D408CHBASEWBasis-Adresse Zeichensatz
$D409WSYNCWWarte auf horizontale Synchronisation
$D40AVSCROLW(Lesen von VCOUNT bei Adresse $D40B)
$D40BVCOUNTRAktueller vertikaler Zeilenzähler
$D40CPENHRLichtstift-Horizontalposition
$D40DPENVRLichtstift-Vertikalposition
$D40ENMIENWNMI-Freigabe (VBI, DLI)
$D40FNMIRES/NMISTW/RNMI zurücksetzen / NMI-Status

Korrektur des C-Befehls-Fehlers (Patch)

Der Fehler

Der Befehl C von ATAMON V1.3 ist seit seiner Veröffentlichung 1983 fehlerhaft. Unabhängig von der verwendeten Syntax gibt er immer ? zurück und schreibt nichts in den Speicher.

Ursache: Im ATAMON-Code muss jeder Befehl, der mehrere Argumente verarbeitet, zwischen jedem Argument die Routine $43AE (SEPARATOR_CHECK) aufrufen. Diese Routine liest und konsumiert das Komma ,, das die Argumente in der Befehlszeile trennt.

Der Handler des C-Befehls (an Adresse $4BE9) liest korrekt die Zieladresse via JSR $4256, ruft dann aber direkt JSR $4280 auf (READ_BIN, der die 8 Bits liest) ohne $43AE aufzurufen. Ergebnis: READ_BIN liest das Komma , (Code $2C) statt der ersten Binärziffer 0 oder 1. Das Komma wird in den Speicher geschrieben ($2C = 44), dann trifft das Programm auf einen Fehler und zeigt ? an.

Alle anderen Multi-Argument-Befehle (F, T, V, L, H, I...) rufen $43AE korrekt zwischen ihren Argumenten auf. C ist der einzige, der es weglässt.

Die Korrektur

Die Korrektur besteht darin, den fehlenden $43AE-Aufruf hinzuzufügen, ohne den bestehenden Code zu verändern. Da ATAMON den Bereich $4000–$52B1 vollständig belegt, wird ein kleines Zwischenprogramm ("Trampolin") im ersten freien Byte nach dem Code installiert: $52B2.

Schritt 1 — READ_BIN-Aufruf umleiten

An Adresse $4BF6 ersetzen:

durch:

Schritt 2 — Trampolin bei $52B2 installieren

Die interne Schleife des C-Handlers (bei $4C05) ruft selbst $43AE auf, um das Komma zwischen den folgenden Bytes zu konsumieren. Das Trampolin muss daher das Komma nur beim ersten Aufruf konsumieren (wenn der Zähler $E8 = 0 ist), und READ_BIN für folgende Aufrufe direkt aufrufen.

Ohne diesen Test auf $E8 würde das Trampolin versuchen, ein bereits von $4C05 gelesenes Komma zu konsumieren, stattdessen die erste Binärziffer lesen, und beim zweiten Byte ? zurückgeben.

Patch anwenden

Die Datei Atamon - D7 - DXG 5724-Patched Atarinside.atr, die diesem Dokument beiliegt, enthält ATAMON mit dieser bereits angewendeten Korrektur. Laden Sie sie in Ihren Emulator oder kopieren Sie sie auf eine Atari-Diskette an Stelle des Originals.

Um den Patch manuell aus dem originalen XEX zu erzeugen, automatisiert das Python-Skript patch_atamon.py die beiden oben genannten Schritte.


Quellenverzeichnis

Originaldokumente und Software

  1. ATAMON V1.3 — Original-Binärprogramm auf der Diskette DXG-5724 (Atari Deutschland GmbH, 1983). Analysiert mittels Altirra-Emulator und eigenem Disassembler-Skript.

  2. disasm_atamon.py — Eigenes Python-Disassembler-Skript (dieses Projekt) zur vollständigen Dekompilierung des ATAMON-Binärcodes. Erzeugt .lst-Datei mit Adressen, Bytes und Mnemoniken.

Atari-Hardware- und Betriebssystemdokumentation

  1. Atari 400/800 Operating System Source Listing — Atari Inc., 1979. Offizielle kommentierte Quelltextliste des Atari-Betriebssystems.

  2. De Re Atari — Chris Crawford et al., Atari Inc., 1981. Umfassende Programmierreferenz für die Atari 8-Bit-Rechner (ANTIC, GTIA, POKEY, PIA, CIO, SIO).

  3. Atari System Reference Manual (OSRM) — Atari Inc., 1983. Offizielle Referenz für alle Betriebssystemvektoren, -variablen und -routinen.

  4. Compute!'s First Book of Atari — Compute! Publications. Einführung in die Atari-Hardwareprogrammierung.

6502-Prozessordokumentation

  1. MOS Technology 6502 Microprocessor Datasheet — MOS Technology Inc., 1975. Offizielles Datenblatt des 6502-Prozessors.

  2. 6502 Assembly Language Programming — Lance Leventhal, Osborne/McGraw-Hill, 1979. Standardreferenz für 6502-Assemblerprogrammierung.

  3. 6502 Illegal Opcodes Reference — Diverse Autoren (Demoszene/Community-Dokumentation). Vollständige Dokumentation der undokumentierten 6502-Opcodes einschließlich *KIL, *SLO, *LAX etc. Quelle: AtariWiki — 6502 Assembly Code

Disketten- und Dateiformatdokumentation

  1. Atari PRO Disk Image Format Specification — Atari Preservation Project. Quelle: a8preservation.com

  2. ATR (Atari Disk Image) Format — Diverse Community-Dokumentation. Beschreibung des 16-Byte-ATR-Headers und der Sektorstruktur.

  3. XEX / DOS BINARY Load Format — Atari-DOS-Dokumentation. Beschreibung der Segmentstruktur ($FFFF-Header, Startadresse, Endadresse, Daten, RUNAD).

Emulation und Werkzeuge

  1. Altirra — Avery Lee (phaeron). Hochpräziser Atari-8-Bit-Emulator für Windows. Verwendet für die Verhaltensverifikation und den Test von ATAMON-Befehlen in dieser Dokumentation. Quelle: virtualdub.org/altirra

  2. MADS (Macro Assembler DS) — Tomasz Biela (Fox/DLT). Moderner Cross-Assembler für den 6502/65C02 mit Atari-Unterstützung. Kompatibel mit dem hier verwendeten Assembler-Quellformat.

Weiterführende Literatur

  1. AtariWiki — Community-Wiki zur Atari-8-Bit-Plattform (Hardware, Software, Geschichte). Quelle: atariwiki.org

  2. AtariAge Forums — Aktive Community-Foren für Atari-8-Bit-Programmierung, Hardware-Mods und Softwareentwicklung. Quelle: atariage.com

  3. NMOS 6502 Opcodes — John Pickens / Graham — Detaillierte Tabelle aller 256 6502-Opcodes (offizielle und undokumentierte), Zykluszeiten und Adressierungsmodi.


Dokumentation erstellt auf Basis der vollständigen Disassemblierung von ATAMON V1.3 (Diskette DXG-5724, Atari Deutschland GmbH, 1983). Alle Adressen, Mnemoniken und Verhaltensangaben wurden durch Analyse des Binärcodes und Tests im Altirra-Emulator verifiziert.

Version dieser Dokumentation: März 2026