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/
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:
In den Speicher schauen: Zeigen Sie beliebige Bereiche des RAM Ihres Atari Byte für Byte an.
Speicher verändern: Ändern Sie Werte direkt, korrigieren Sie einen Fehler in einem Programm oder passen Sie ein Spiel nach Ihren Wünschen an.
Ein Programm disassemblieren: ATAMON übersetzt rohe Maschinensprache in lesbare Mnemoniken (wie LDA, JMP, STA…), sodass Sie verstehen können, wie ein Programm funktioniert.
Ausführen und debuggen: Starten Sie ein Programm und übernehmen Sie an jedem BRK-Haltepunkt wieder die Kontrolle — unerlässlich für die Fehlersuche.
Sektoren sichern: Lesen und schreiben Sie Diskettensektoren direkt (über die Befehle E und W).
Rechnen: Führen Sie Additionen, Subtraktionen, logisches UND und ODER direkt in Hexadezimal oder Binär durch.
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.
Quelldatei: Atamon - D7 - DXG 5724.PRO → ATAMON
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
ATAMON ist ein professioneller Maschinensprachemonitor, der 1983 von ATARI entwickelt wurde. Er ermöglicht einem Programmierer:
RAM zu untersuchen und zu verändern
6502-Register anzuzeigen und zu verändern (Programmzähler, Stapelzeiger, Akkumulator, X, Y, Flags)
6502-Code direkt im Speicher zu disassemblieren
Code auszuführen und an jedem BRK-Haltepunkt die Kontrolle zurückzugewinnen
Diskettensektoren zu lesen und zu schreiben
Speicherbereiche zu überprüfen und zu übertragen
Hexadezimalberechnungen durchzuführen
ATAMON gehört zur Familie der Maschinensprachemonitore, die in den 1980er Jahren 8-Bit-Computern auf vielen Plattformen beilagen.
Adresse Inhalt--------- --------------------------------$4000 Haupteinsprungpunkt (RUNAD)$4000-$52B1 ATAMON-Code und -Daten$4F3C-$4F42 CPU-Registersicherungsbereich$4E3C Tastatureingabepuffer (Befehlszeile)$4F44 ASCII-Banner + Registeranzeigeformat$4F8D Hex-Zifferntabelle + Befehlszeichen$4F9D Befehlsdispatch-Tabelle$4FC8 Handler-Adresstabelle (Vektoren)$4FF9+ Interne 6502-Disassembler-Tabellen
Speicherbedarf: ca. 4,5 KB von $4000 bis $52B1.
ATAMON setzt außerdem MEMLO = $5300, um seinen Code zu schützen.
Der Einsprungpunkt bei $4000 nutzt eine klassische Technik: den BRK-Vektor ($0206–$0207).
xxxxxxxxxx$4000 LDA #$40 ; BRK-Handler installieren$4002 STA $0207 ; VBREAK hi = $40$4005 LDA #$0B$4007 STA $0206 ; VBREAK lo = $0B → Handler bei $400B$400A BRK ; BRK absichtlich auslösen; === Der 6502 legt (aktuelle Adresse + 2) und Flags auf den Stapel, springt über $0206 ===$400B LDA #$40 ; VBREAK für zukünftige Verwendung neu konfigurieren$400D STA $0207$4010 LDA #$1A$4012 STA $0206 ; Neuer VBREAK = $401A$4015 LDA #$43 ; 'C' = Kennzeichen "Eintritt über Start"$4017 JMP $401C ; → CPU-Zustand sichern
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.
xxxxxxxxxx$401C STA $E4 ; Eintrittskennzeichen sichern (vom Aufrufer übergeben)$401E PLA ; A zurückholen (vom OS-Handler vor BRK per PHA gesichert)$401F STA $4F3D ; A sichern$4022 STY $4F3F ; Y sichern$4025 STX $4F3E ; X sichern$4028 PLA ; P (Flags, vom BRK-Stapel) zurückholen$4029 STA $4F40 ; P sichern$402C CLC$402F PLA ; PCL (niederwertiges Adressbyte, vom BRK-Stapel) zurückholen$4030 ADC #$FF ; 1 subtrahieren (16-Bit: BRK legt addr+1 ab, wir kehren zur echten Adresse zurück)$4032 STA $4F41 ; bereinigtes PCL sichern$4035 PLA ; PCH (höherwertiges Adressbyte, vom BRK-Stapel) zurückholen$4036 ADC #$FF ; 16-Bit-Subtraktion mit Übertrag fortsetzen$4038 STA $4F42 ; bereinigtes PCH sichern$403B TSX$403C STX $4F3C ; SP sichern$403F LDX #$FD$4041 TXS ; Stapel auf $FD zurücksetzen
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):
xxxxxxxxxx$4F3C SP Stapelzeiger$4F3D A Akkumulator$4F3E X X-Register$4F3F Y Y-Register$4F40 P Statusregister (Flags NV\BDIZC)$4F41 PCL Niederwertiges Byte der nächsten Befehlsadresse (angepasst -1)$4F42 PCH Höherwertiges Byte der nächsten Befehlsadresse
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.
Nach der Initialisierung zeigt ATAMON sein Banner an und tritt in die Befehlsschleife ($4064) ein:
xxxxxxxxxx1. Stapel auf $FD zurücksetzen2. Eingabepuffer leeren ($4E3C ← $9B)3. Kanal E: (Bildschirmeditor) über CIO öffnen4. Zeile über CIO (IOCB 0) lesen5. Erstes Nicht-Leerzeichen suchen6. Dieses Zeichen in Tabelle $4F9D nachschlagen7. Wenn gefunden → Handler-Adresse aus $4FC8/$4FC9 laden8. Handler über indirektes RTS ausführen (hi-1 / lo-1 ablegen, RTS)9. Zu Schritt 1 zurückkehren
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:
*C — Eintritt über Start oder G
*R — Befehl R
*B — Rückkehr nach BREAK (Unterbrechung eines Programms)
Beispiel einer Registeranzeige (nach dem Befehl R oder nach einem BRK):
xxxxxxxxxx*RPC SP AC XR YR NV\BDIZC; 400B FB 0B 20 01 00110001
Die Wertzeile beginnt immer mit ;. Bedeutung der einzelnen Felder:
| Feld | Was es ist | Wert im Beispiel |
|---|---|---|
PC | Programmzähler: Adresse des nächsten auszuführenden Befehls. Hier befindet sich Ihr Programm im Speicher. | 4000 → bereit zur Ausführung ab $4000 |
SP | Stapelzeiger: 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 |
AC | Akkumulator A: Hauptregister des 6502, verwendet für Berechnungen, Übertragungen, Vergleiche. | 00 |
XR | X-Register: Indexregister, häufig für Schleifen und indizierte Adressierung. | 00 |
YR | Y-Register: zweites Indexregister. | 00 |
NV\BDIZC | Prozessor-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.
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).
Schritt 1: Den Monitor „verdeckt" installieren
Wählen Sie im DOS-Menü L, um ATAMON zu laden.
ATAMON erscheint auf dem Bildschirm. Geben Sie den Befehl X (eXit) ein.
Sie kehren zum DOS-Menü zurück, aber ATAMON bleibt unsichtbar im Speicher (ab $4000).
Schritt 2: Ihr Spiel lautlos laden
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.
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
Wählen Sie im DOS-Menü die Option M (Run at address).
Geben Sie 4000 (die Adresse, wo ATAMON schläft) ein und drücken Sie die Eingabetaste.
Das ATAMON-Banner erscheint — Sie sind wieder im Monitor!
Schritt 4: Die magische Adresse lesen
Zeigen Sie in ATAMON den Speicher bei $02E0 an:
xxxxxxxxxxEingabe:M 02E0
Drücken Sie sofort BREAK, um das Scrollen anzuhalten.
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.
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:
Ersetzen Sie ein Byte Ihres Programms vorübergehend durch den BRK-Befehl (Hexcode $00).
Wenn der Prozessor dieses $00 ausführt, löst er einen Software-Interrupt aus.
ATAMON hat den System-Interruptvektor (VBREAK bei $0206–$0207) beim Laden umgeleitet.
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 mitGstarten.
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.
aaaa = 16-Bit-Adresse in Hexadezimal (z. B. 4000)
bb = 8-Bit-Byte in Hexadezimal (z. B. FF)
[...] = optionales Argument
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:
xEingabe:G*** ATAMON V1.3 - (c) 1983 by ATARI ****CPC SP AC XR YR NV\BDIZC; 400B FD 00 00 00 00110000Eingabe:G 4000; Startet Ausführung bei $4000 — ATAMON tritt zurück, solange Ihr Programm läuft.; Kontrolle erst zurück, wenn das Programm BRK ausführt.
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:
xxxxxxxxxxEingabe:M 4000Ergebnis (scrollt endlos — BREAK zum Anhalten)::4000 A9 40 8D 07 02 A9 0B 8D ©@♦ ©.♦:4008 06 02 A9 43 4C 1C 40 48 . ©CL @H:4010 68 48 8C 3F 4F A8 B9 40 hH♦?O¨¹@; ... (läuft automatisch weiter)
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:
aaaa: Zieladresse des Puffers (Standard: $0680)
nn: Anzahl aufeinanderfolgender Sektoren (Standard: 01) — Puffer rückt pro Sektor um $80 (128 Byte) vor
ssss ist eine Sektornummer (keine Speicheradresse). Atari-Diskette einfacher Dichte: $0001–$02D0.
xxxxxxxxxxEingabe:E 0168Ergebnis:OKEingabe:E 0001,0700Ergebnis:OK; Sektor 1 in $0700 geladen (statt Standard $0680)Eingabe:E 0001,0700,02Ergebnis:OK; Sektor 1 → $0700, Sektor 2 → $0780Eingabe:E 0001Ergebnis bei Fehler:I/O ERROR #138
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.
xxxxxxxxxxEingabe:D 4000,400CErgebnis (scrollt endlos — BREAK zum Anhalten):4000 A9 40 LDA #$404002 8D 07 02 STA $02074005 A9 0B LDA #$0B4007 8D 06 02 STA $0206400A A9 43 LDA #$43400C 4C 1C 40 JMP $401C; ... (läuft automatisch weiter)
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).
xxxxxxxxxxEingabe:F 6000,60FF,EA ; ($6000–$60FF mit $EA füllen)Eingabe:: 6000 A9 FF 8D 00 D0 4C 00 40 ; (einige Bytes bei $6000 ändern)Eingabe:L 6000,60FF,EA ; Durchsucht $6000–$60FF und zeigt Adressen an, wo Byte ≠ $EAErgebnis (7 Adressen pro Zeile — BREAK drücken zum Anhalten, zeigt *B):6000 6001 6002 6003 6004 6005 60066007*B; → Adressen $6000–$6007 enthalten Bytes ≠ $EA; Adressen, wo das Byte genau $EA ist, werden NICHT angezeigt
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.
xxxxxxxxxxEingabe:E 0001 ; 1. Sektor 1 in den Puffer lesen ($0680); (Puffer ggf. mit : 0680 A9 FF ... ändern)Eingabe:W 0001 ; 2. Puffer auf Sektor 1 zurückschreibenErgebnis: OK; Bei Fehler: I/O ERROR #xxx
V aaaa,bbbb,cccc — Verify (Speicher vergleichen)Vergleicht den Speicherbereich aaaa→bbbb 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.
xxxxxxxxxxEingabe:T 6000,600F,6100 ; ($6000–$600F nach $6100 kopieren)Eingabe:V 6000,600F,6100 ; $6000–$600F mit $6100–$610F vergleichenErgebnis wenn alles übereinstimmt:OK; Um Unterschiede zu sehen, ein Byte vor dem Vergleich ändern:Eingabe:: 6100 FF FF 00 00 00 00 00 00Eingabe:V 6000,600F,6100 ; $6100 und $6101 geändert → ATAMON meldet $6000 und $6001Ergebnis (7 Adressen pro Zeile):6000 6001; Nur die QUELL-Adressen mit abweichenden Bytes werden angezeigt — nicht die Werte.
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 aaaa→bbbb mit Byte bb.
Sicherer Bereich: ATAMON belegt $4000–$52B1. Adressen ab $5300 verwenden (z. B. $6000+).
xxxxxxxxxxEingabe:F 6000,60FF,EAErgebnis:OK; ATAMON zeigt „OK" an und kehrt zum Prompt zurück; $6000 bis $60FF (256 Bytes) enthält jetzt $EA (NOP-Opcode); Nützlich, um einen Bereich zu „bereinigen" oder vor dem Patchen NOPs zu schreiben; Zur Überprüfung, dass die NOPs geschrieben wurden:Eingabe:M 6000Ergebnis::6000 EA EA EA EA EA EA EA EA nnnnnnn:6008 EA EA EA EA EA EA EA EA nnnnnnn; ... (BREAK drücken zum Anhalten); Rechte Spalte = ATASCII von $EA (Zeichen 'n' in inversem ATASCII)
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).
xxxxxxxxxxEingabe:T 6000,60FF,6100 ; $6000–$60FF nach $6100 kopierenErgebnis: OKEingabe:T 6000,6008,6004 ; Überlappungsfall: ATAMON kopiert rückwärts, um die Quelle nicht zu überschreiben; Ergebnis: (kein Anzeigetext — korrekt behandelt)
H aaaa,bbbb,DsuchfolgeD — Hunt (Speicher durchsuchen)Durchsucht aaaa–bbbb 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 → ?).
xxxxxxxxxxEingabe:H 4000,52B0,"'ATARI'"Ergebnis:4D99 4E4A 4F62OKEingabe:H 4000,52B0,"4154415249"Ergebnis:4D99 4F62OK; Hex-Form liefert 2 Treffer (kein Selbsttreffer); Form mit Anführungszeichen 3 (Eingabepuffer-Treffer).
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:
xxxxxxxxxxEingabe:S 4000Ergebnis (eine einzige Zeile aktualisiert sich in einer Schleife):10101001 01000000 10001101 00000111; Die 4 Bytes an $4000–$4003 werden kontinuierlich angezeigt und aktualisiert; BREAK drücken, um zum Prompt zurückzukehren
Beispiel mit einem Hardware-Register in Echtzeit:
xxxxxxxxxxEingabe:S 0014 ; RTCLOK ($0014–$0017) überwachen — Atari-Uhr, 60× pro Sekunde inkrementiertErgebnis (Zeile ändert sich sichtbar):00000000 00000001 01001100 0000000000000000 00000001 01001101 00000000; Das Byte bei $0016 wird kontinuierlich inkrementiert — Beweis, dass der Atari läuft; BREAK drücken zum Anhalten
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.
xxxxxxxxxxEingabe:C 6000,10110001 ; Schreibt $B1 (10110001 binär) an Adresse $6000Ergebnis:; (keine Anzeige — der Atari-Cursor erscheint wieder); Überprüfung:Eingabe:M 6000Ergebnis::6000 B1 xx xx xx xx xx xx xx [...]; → $B1 wurde korrekt nach $6000 geschrieben (BREAK drücken, um das Scrollen zu stoppen)
Beispiel mit mehreren Bytes:
xxxxxxxxxxEingabe:C 6000,01001100,00000000,01100000 ; Schreibt $4C, $00, $60 ab $6000 (= JMP $6000 in Maschinensprache)
P [E|T] — Printer (Druckerverwaltung)Steuert den Druckerkanal (IOCB 6, Gerät P1:).
P allein: Kanal schließen → zeigt AUS an
P E: Echo-Modus öffnen → zeigt EIN an (alle Ausgaben werden auch gedruckt)
P T: Datenübertragung zum Drucker (nicht getestet)
xxxxxxxxxxEingabe:PErgebnis: P AUSEingabe:P EErgebnis: EIN; Echo-Betrieb ist aktiviert (EIN = „ein" = „on" auf Deutsch); Alle ATAMON-Ausgaben werden auch gedrucktEingabe:P ; (zum Deaktivieren des Echos)Ergebnis: P AUS
Hinweis: Dieser Befehl ist nützlich, wenn ein Drucker an Ihren Atari angeschlossen ist. Ohne Drucker verursacht
P Eeinen 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.
xxxxxxxxxxEingabe:RErgebnis:*RPC SP AC XR YR NV\BDIZC; 4000 FD 00 00 00 00110000
X — eXit (Beenden)Kehrt über JMP DOSVEC ($000A) zum Atari-DOS zurück.
xxxxxxxxxxEingabe:X ; ATAMON beendet — der Atari-DOS-Bildschirm erscheint wieder
Z nn,cc[,aaaa,llll] — IOCB (CIO-Kanal-Operation)Führt eine OS-E/A-Operation über das CIO-System (Central I/O) aus.
xxxxxxxxxxIhr Programm| (über IOCB)CIO -- Central I/O <- einziger Einsprungpunkt| (über ZIOCB)Gerätetreiber| (über DCB)SIO -- Serial I/O
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):
| Name | Gerät | Zugriff | Hinweis |
|---|---|---|---|
E: | Bildschirmeditor — zeilenweise Eingabe mit interaktiver Bearbeitung | lesen+schreiben | Verwendet intern K: und S: |
K: | Tastatur — direkte Tastaturabfrage | nur lesen | Nie direkt geöffnet — intern von E: verwendet |
S: | Grafikbildschirm — Bitmap-Zugriff, DRAW- und FILL-Befehle | lesen+schreiben | |
P: | Drucker — auf XL/XE: P1: bis P8: je nach Modell | nur schreiben | |
C: | Kassette | lesen+schreiben | Verwendet nicht das SIO-Protokoll |
Nicht-residiente Treiber (beim Booten durch DOS oder Peripherie-ROM geladen):
| Name | Gerät | Zugriff | Geladen von |
|---|---|---|---|
D: | Diskette — DOS-Dateiverwaltung (D1:–D8:) | lesen+schreiben | DOS, beim Booten |
R: | 850-Schnittstelle — RS-232-Ports (R1:–R4:) | lesen+schreiben | ROM der 850-Schnittstelle, beim Booten |
T: | 1030-Modem (XM301, 835) | lesen+schreiben | ROM 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.
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:
| Kanal | Offset nn | Speicheradresse | Belegung |
|---|---|---|---|
| 0 | 00 | $0340–$034F | E: Bildschirmeditor — vom OS beim Booten geöffnet, immer verfügbar |
| 1 | 10 | $0350–$035F | frei — für jedes Programm verfügbar |
| 2 | 20 | $0360–$036F | frei — für jedes Programm verfügbar |
| 3 | 30 | $0370–$037F | frei — für jedes Programm verfügbar |
| 4 | 40 | $0380–$038F | frei — für jedes Programm verfügbar |
| 5 | 50 | $0390–$039F | frei — für jedes Programm verfügbar |
| 6 | 60 | $03A0–$03AF | von Atari BASIC für S: reserviert (Grafikmodi ≠ 0) |
| 7 | 70 | $03B0–$03BF | von 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.
nn = Kanal-Offset (2 Hex-Stellen), cc = CIO-Befehl (2 Hex-Stellen).
aaaa = Adresse des Datenpuffers (optional, nur für GET/PUT BYTES und OPEN)
llll = Länge der Daten in Bytes (optional, nur für GET/PUT BYTES)
Z allein oder Z nn allein → ? — cc ist erforderlich.
cc | Befehl |
|---|---|
03 | OPEN (Öffnen) |
05 | GET RECORD (Zeile bis $9B lesen) |
07 | GET BYTES (Bytes lesen) |
09 | PUT RECORD (Zeile schreiben + $9B) |
0B | PUT BYTES (Bytes schreiben) |
0C | CLOSE (Schließen) |
0D | STATUS |
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):
xxxxxxxxxx; Schritt 1: "ATARI!!" + $9B (ATASCII-Zeilenende) nach $6000 schreibenEingabe:: 6000 41 54 41 52 49 21 21 9B; Schritt 2: 8 Bytes von $6000 via CIO auf den Bildschirm sendenEingabe:Z 00,09,6000,0008Ergebnis:ATARI!!; → der Text wird direkt angezeigt, dann erscheint der Atari-Cursor wieder
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:
Hexadezimale Bytes: 2-stellige Paare (z. B. 9B, 4F)
Zeichenkette: ein Paar einfacher Anführungszeichen '...' umschließt eine vollständige Zeichenkette — 'HALLO' nicht 'H'A'L'L'O'
xxxxxxxxxx; ⚠ Unbedingt $6000+ verwenden — ATAMON belegt $4000–$52B1Eingabe:I 6000,"'HALLO'9B" ; KEIN Leerzeichen zwischen , und " — Trennzeichen muss direkt nach dem Komma folgen; 'HALLO' = vollständige ATASCII-Zeichenkette, 9B = Zeilenende-Byte; Überprüfung:Eingabe:M 6000Ergebnis::6000 48 41 4C 4C 4F 9B xx xx [HALLO.xx]; (BREAK zum Anhalten)Eingabe:I 6010,/FF 00 4C 00 40/ ; 5 Hex-Bytes, durch Leerzeichen getrennt; Überprüfung:Eingabe:M 6010Ergebnis::6010 FF 00 4C 00 40 xx xx xx [..L.@...]; (BREAK zum Anhalten)Eingabe:I 6020,"'ATARI'9B" ; ATASCII-Zeichenkette + Zeilenende-Byte; Überprüfung:Eingabe:M 6020Ergebnis::6020 41 54 41 52 49 9B xx xx [ATARI.xx]; (BREAK zum Anhalten)
Dieser Befehl ist besonders nützlich zum Schreiben von Fehlermeldungen, ATASCII-Zeichenketten oder Code-Patches direkt in den Speicher.
# — Dezimal → Hexadezimal-UmrechnungInterpretiert 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.
xxxxxxxxxxEingabe:# 4000Ergebnis:# 4000 = 0FA0; 4000 in Dezimal = $0FA0 in HexadezimalEingabe:# 255Ergebnis:# 255 = 00FF; 255 in Dezimal = $FF in Hexadezimal
$ — Hexadezimal → Dezimal-UmrechnungInterpretiert das Argument als Hexadezimalwert und zeigt das Dezimaläquivalent an (Komplement von #).
xxxxxxxxxxEingabe:$ 1638Ergebnis:$ 1638 = 5688; $1638 in Hexadezimal = 5688 in DezimalEingabe:$ 00FFErgebnis:$ 00FF = 0255; $FF = 255 in Dezimal — ATAMON erfordert genau 4 Hex-Stellen; $ FF (nur 2 Stellen) → Fehler ?
Wichtig: $ erfordert genau 4 Hexadezimalstellen. $ 00FF verwenden, nicht $ FF.
% — BinäreingabeErmö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.
xxxxxxxxxxEingabe:% 11001000Ergebnis:C8; $C8 = Hexadezimalwert von 11001000 binär (= 200 in Dezimal)Eingabe:% 00110000Ergebnis:30; $30 = Flags I+B gesetzt (typischer Zustand beim Starten)
; 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
PCHL : 4 Hex-Stellen = PC-Ausführungsadresse (z. B. 5000)
SP : Stapelzeiger (z. B. FD)
AC : Akkumulator
XR : X-Register
YR : Y-Register
XXXXXXXX : 8 Binärbits = Flags P in der Reihenfolge N V \ B D I Z C
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):
| Bit | Buchst. | Name | Gesetzt wenn... |
|---|---|---|---|
| 7 | N | Negative | Bit 7 des letzten Ergebnisses = 1 |
| 6 | V | oVerflow | Vorzeichenbehafteter Überlauf |
| 5 | ** | (unbenutzt) | Immer 1 |
| 4 | B | Break | Eintritt über BRK-Befehl |
| 3 | D | Decimal | BCD-Modus (am Atari-6502 nicht funktional) |
| 2 | I | Interrupt disable | IRQ-Interrupts maskiert |
| 1 | Z | Zero | Letztes Ergebnis = 0 |
| 0 | C | Carry | Ü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).
xxxxxxxxxxEingabe:; 5000 FD 00 00 00 00110100Ergebnis: ATAMON überschreibt die eingegebene Zeile mit dem `;`-Format, ohne eine neue Zeile hinzuzufügen.Der angezeigte Inhalt ist identisch mit der Eingabe — der Befehl erscheint lautlos.; 5000 FD 00 00 00 00110100Überprüfung:Eingabe:RErgebnis:*RPC SP AC XR YR NV\BDIZC; 5000 FD 00 00 00 00110100
! 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…).
xxxxxxxxxxEingabe:! 4000 ; Konvertiert $4000 in Binär: $40=01000000, $00=00000000Ergebnis:! 4000 = 01000000 00000000Eingabe:! 00FF ; Konvertiert $00FF: $00=00000000, $FF=11111111Ergebnis:! 00FF = 00000000 11111111Eingabe:! D01F ; Konvertiert den Wert $D01F (Adresse des CONSOL-Registers) — um die Bits eines Hardware-Registers zu sehen, zuerst seinen Wert mit M lesen, dann mit ! konvertierenErgebnis:! D01F = 11010000 00011111
* 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.
xxxxxxxxxxEingabe:* + 4000,0100Ergebnis:* + 4000,0100 = 4100 C= 0; $4000 + $0100 = $4100, Übertrag = 0Eingabe:* - 5000,0200Ergebnis:* - 5000,0200 = 4E00 C= 1; $5000 - $0200 = $4E00, C=1 = kein Borgeübertrag (positives Ergebnis)Beim 6502 ist der Übertrag bei der Subtraktion im Vergleich zur Addition invertiert: C=1 = Ergebnis ≥ 0 (kein Borgeübertrag), C=0 = negatives Ergebnis (Überlauf). Das ist das Gegenteil von dem, was man intuitiv erwartet.Eingabe:* A FF00,0FF0Ergebnis:* A FF00,0FF0 = 0F00; $FF00 AND $0FF0 = $0F00Eingabe:* O 4000,0001Ergebnis:* O 4000,0001 = 4001; $4000 OR $0001 = $4001
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.
xxxxxxxxxxEingabe:: 6000 A9 FF 8D 00 D0 4C 00 40Ergebnis::6000 A9 FF 8D 00 D0 4C 00 40 ) PL @:6008; ATAMON schlägt die nächste Adresse vor — man kann 8 neue Bytes eingeben; oder BREAK drücken, um zum Prompt zurückzukehren
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.
xxxxxxxxxxEingabe:, 6000 A9 00Ergebnis:, 6000 A9 00 LDA #$00, 6002; ATAMON zeigt die Bytes + die Disassemblierung an, dann schlägt er die Fortsetzung mit `,` vor; Weiter durch Eingabe der nächsten Bytes, BREAK zum Zurückkehren zum PromptEingabe:, 6002 4C 00 60Ergebnis:, 6002 4C 00 60 JMP $6000, 6005; 3 Bytes geschrieben — JMP $6000 (Sprung nach $6000); Fortfahren oder BREAK drücken
Ideal für die Eingabe von Assembler-Code und sofortige Überprüfung, dass die Opcodes korrekt sind.
| Adresse | Lokaler Name | Funktion |
|---|---|---|
$DA-$DB | PTR_START | 16-Bit-Startadresse (Argument 1) |
$DC-$DD | PTR_END | 16-Bit-Endadresse (Argument 2) |
$DE-$DF | PTR_DEST | 16-Bit-Zieladresse (Argument 3) |
$E0 | MODE | 0 = Normalmodus, ≠0 = Umkehrmodus |
$E4 | TEMP_A | Zwischenspeicher / Akkumulatorsicherung |
$E5 | TEMP_B | Zähler / Zwischenspeicher |
$E7 | COL_CTR | Spaltenzähler für Hex-Anzeige (0–6) |
$EB | TEMP_C | Anzeige-Zwischenspeicher |
$F2 | BUF_PTR | Zeiger in Puffer $4E3C |
$F3-$F4 | FP_PTR | Zeiger auf Math-ROM-Gleitkommabereich |
| Adresse | Beschreibung |
|---|---|
| $401C | SAVE_CPU: Sichert 6502-Zustand (Akkumulator, X, Y, Flags, Programmzähler, Stapel) |
| $4054 | PRINT_HEADER: Zeigt Banner und Registerüberschrift an |
| $4064 | CMD_LOOP: Hauptschleife zum Einlesen/Verteilen von Befehlen |
| $40B5 | CLR_RANGE: Setzt Adressregister DA–DF auf Null |
| $40C5 | DUMP_8: Zeigt 8 Bytes hexadezimal an |
| $40DB | FILTER_CHAR: Filtert ein ATASCII-Zeichen (druckbar / nicht druckbar) |
| $4127 | ADD16: Addiert A zur 16-Bit-Adresse DA:DB |
| $4133 | DO_CIO: Ruft CIO ($E456) mit X=IOCB-Nummer×16 auf |
| $41DD | DO_SIO_DISK: Sendet einen SIO-Diskettenbefehl über DSKINV ($E453) |
| $41E8 | FIND_CMD: Sucht ein Zeichen in der Befehlstabelle $4F8D |
| $41F7 | GET_CHAR: Liest das nächste Zeichen aus dem Eingabepuffer |
| $422A | SKIP_SP: Bewegt Pufferzeiger über Leerzeichen hinweg |
| $423D | READ_BYTE: Liest 2 Hex-Stellen → Byte in A |
| $4256 | READ_ADDR: Liest 4 Hex-Stellen → 16-Bit-Adresse in A(hi) Y(lo) |
| $4280 | READ_BIN: Liest 8 Binärziffern → Byte in A |
| $42C7 | SET_FNAME: Setzt Dateinamenadresse im IOCB |
| $42CF | SET_BUFADDR: Setzt Pufferadresse im IOCB |
| $42E9 | OPEN_EDITOR: Öffnet Kanal 0 auf E: (Bildschirmeditor) |
| $4330 | PRINT_HEX8: Zeigt ein Byte als 2 Hex-Stellen an |
| $4349 | NEWLINE_REGS: Zeilenvorschub + Registeranzeige |
| $4373 | NEWLINE: Sendet Wagenrücklauf ($9B) auf E: |
| $4399 | PRINT_CHAR: Zeigt ein ATASCII-Zeichen über CIO an |
| $44A4 | FP_TO_STR: Gleitkomma-zu-Zeichenkette-Umwandlung (Math-ROM IFP+FASC) |
| $44C5 | SET_FP_PTR: Initialisiert Gleitkommazeiger ($4D99) |
ATAMON verwendet folgende OS-Dienste:
| Dienst | Adresse | Verwendung |
|---|---|---|
| CIO — Central I/O | $E456 (CIOV) | Bildschirm lesen/schreiben, Dateien |
| SIO — Serial I/O Diskette | $E453 (DSKINV) | Diskettensektorzugriff |
| Math-ROM IFP | $D9AA | Ganzzahl → Gleitkomma-Umwandlung |
| Math-ROM FASC | $D8E6 | Gleitkomma → ASCII-Umwandlung |
| VBREAK | $0206–$0207 | BRK-Vektor (Monitor-Eintritt bei Haltepunkt) |
Verwendete IOCBs:
IOCB 0 ($0340): Hauptkanal zu E: (Editor/Bildschirm) für alle Benutzereingaben/-ausgaben.
Das IOCB wird dynamisch durch SET_FNAME / SET_BUFADDR / DO_CIO konfiguriert.
DCB-Struktur für Diskettenzugriffe ($0300–$030B):
$0300 DDEVIC = $31 ('1') — Diskettengerät D1:
$0301 DUNIT = 1
$0302 DCOMND = SIO-Befehl ('R'=$52 Lesen, 'W'=$57 Schreiben)
$0303 DSTATS = Richtung ($40 = Lesen, $80 = Schreiben)
$0304–$0305 DBUFLO/HI = Pufferadresse
$030A–$030B DAUX1/2 = Sektornummer
Die im Speicher gespeicherte Zeichenkette lautet:
xxxxxxxxxx*** ATAMON V1.3 - (c) 1983 by ATARI ***E:P1: PC SP AC XR YR NV\BDIZC<$9B>
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:
xxxxxxxxxx*** ATAMON V1.3 - (c) 1983 by ATARI ***PC SP AC XR YR NV\BDIZC; 4000 FD 00 00 00 00110000
xxxxxxxxxx$4F8D "0123456789ABCDEF" <- Hex-Ziffern (Index 0–15)$4F9D "RX;GM:EWFVTH#$%!I*PCSD,LZ" <- Befehlszeichen
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.
ATAMON besitzt einen eigenen Mini-Disassembler (Befehl D). Er verwendet zwei interne Tabellen:
6502-Mnemoniken: 3-Buchstaben-kodierte Einträge (56 offizielle Mnemoniken)
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.
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.
| Taste | Wirkung in ATAMON |
|---|---|
RETURN | Bestätigt den aktuellen Befehl |
BREAK | Unterbricht ein laufendes Programm und gibt die Kontrolle an ATAMON zurück (über VBREAK/BRK-Vektor) |
RESET | Hardware-Reset — vermeiden: löscht den Speicher und zerstört das geladene Programm |
DELETE / BACK S. | Löscht das zuletzt eingegebene Zeichen |
ESC | Kann 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
RETURNbestätigt wird.
xxxxxxxxxx*** ATAMON V1.3 - (c) 1983 by ATARI ****CPC SP AC XR YR NV\BDIZC; 4000 FD 00 00 00 00110000
xxxxxxxxxx; Speicher ab $4000 anzeigenM 4000; 8 Bytes bei $6000 ändern (freier Bereich): 6000 A9 FF 8D 00 D0 4C 00 60; Disassemblieren ab $4000D 4000; Programm bei $4000 startenG 4000; $4000-$40FF nach $6000 kopieren, dann prüfenT 4000,40FF,6000V 4000,40FF,6000; $6000-$60FF mit NOPs ($EA) füllen — freier Bereich außerhalb ATAMONF 6000,60FF,EA; Diskettensektor 1 in Puffer ($0680) lesenE 0001; Puffer auf Sektor 1 zurückschreibenW 0001; $4000 + $0100 berechnen* + 4000,0100; Zu DOS beendenX
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:
DOS.SYS: das Atari-DOS-2.x-Diskettenbetriebssystem (39 Sektoren)
DUP.SYS: das Diskettenverwaltungsprogramm (42 Sektoren)
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.
| Gruppe | Opcodes | Beschreibung |
|---|---|---|
*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,$1F | ASL Speicher, dann ORA A |
*RLA | $23,$27,$2F,$33,$37,$3B,$3F | ROL Speicher, dann AND A |
*SRE | $43,$47,$4F,$53,$57,$5B,$5F | LSR Speicher, dann EOR A |
*RRA | $63,$67,$6F,$73,$77,$7B,$7F | ROR Speicher, dann ADC A |
*LAX | $A3,$A7,$AF,$B3,$B7,$BF | Lädt A und X gleichzeitig |
*SAX | $83,$87,$8F,$97 | Speichert A UND X |
*DCP | $C3,$C7,$CF,$D3,$D7,$DB,$DF | DEC Speicher, dann CMP A |
*ISC | $E3,$E7,$EF,$F3,$F7,$FB,$FF | INC Speicher, dann SBC A |
| Sonst. | $0B/$2B *ANC, $4B *ALR, $6B *ARR, $CB *SBX, $9B *TAS, $9C *SHY | Verschiedene Kombinationen |
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).
$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:
Befehle, die auf sie zugreifen, verwenden nur ein Adressbyte statt zwei → sie sind kürzer und schneller.
Der 6502 kann sie als Bereich „zusätzlicher Register" nutzen: 16-Bit-Zeiger, Zähler, temporäre Variablen.
Das Atari-Betriebssystem und ATAMON machen davon intensiv Gebrauch. Hier die wichtigsten Stellen:
| Adresse | OS-Name | Bedeutung |
|---|---|---|
| $08 | COLCRS | Cursorspalte (0 bis 39). Das OS aktualisiert diesen Wert bei jeder Tasteneingabe. Änderbar, um den Cursor horizontal zu verschieben. |
| $09 | ROWCRS | Cursorreihe (0 bis 24). Gleiches Prinzip für die Zeile. |
$0B–$0C | SAVMSC | Bildschirmspeicheradresse (2 Bytes). Zeigt auf das erste Byte des angezeigten Bildes. Direkte Änderung verändert den Bildschirm in Echtzeit. |
$14–$16 | RTCLOK | Echtzeituhr (3 Bytes). Wird vom OS automatisch 60-mal pro Sekunde inkrementiert (bei jedem vertikalen Interrupt). Nützlich zur Zeitmessung oder für Verzögerungen. |
$55 | ATRACT | Bildschirmschoner. 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. |
$6A | RAMTOP | Obergrenze des verfügbaren RAM. Wert in Seiten (×256). Gibt an, bis wohin RAM von Programmen nutzbar ist. Änderbar, um oberen Speicher zu reservieren. |
$80–$9F | FR0 | Gleitkommaregister 0 (6 Bytes). Arbeitsbereich des Math-ROM für Gleitkommaberechnungen. Wird bei jedem Math-ROM-Aufruf überschrieben. |
$A0–$A5 | FR1 | Gleitkommaregister 1 (6 Bytes). Zweites Gleitkommaregister, als Operand in Berechnungen verwendet. |
Diese Adressen sind von ATAMON während des Betriebs reserviert. Eine Änderung mit : oder , kann den Monitor stören.
| Adresse | ATAMON-Name | Bedeutung |
|---|---|---|
$DA–$DB | PTR_START | Startadresse der aktuellen Operation (Argument 1 der Befehle M, D, F, T...). |
$DC–$DD | PTR_END | Endadresse (Argument 2). |
$DE–$DF | PTR_DEST | Zieladresse (Argument 3, von T genutzt). |
| $E0 | MODE | Anzeigemodus: 0 = normal, ≠ 0 = invertiert (für M). |
| $E4 | TEMP_A | Zwischenspeicher: Akkumulatorsicherung zwischen zwei internen Operationen. |
| $E5 | TEMP_B | Temporärer Zähler (interne Schleifen). |
| $E7 | COL_CTR | Spaltenzähler für Hex-Anzeige (0 bis 6, zur Ausrichtung von 8 Bytes pro Zeile). |
| $F2 | BUF_PTR | Befehlspufferzeiger ($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.
Der eingebaute Disassembler von ATAMON (Befehl D) erkennt genau diese 56 Befehle.
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
LDA | Load Accumulator | Lädt einen Wert in den Akkumulator A | LDA #$41 → A = 'A' |
LDX | Load X | Lädt einen Wert in Register X | LDX #$00 → X = 0 (Schleifen-Init) |
LDY | Load Y | Lädt einen Wert in Register Y | LDY #$08 → Y = 8 (Zähler) |
STA | Store Accumulator | Schreibt A in den Speicher | STA $D800 → sendet Farbe an GTIA |
STX | Store X | Schreibt X in den Speicher | STX $00 → sichert X in Zeropage |
STY | Store Y | Schreibt Y in den Speicher | STY $CB → sichert Y in Variable |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
TAX | Transfer A to X | Kopiert A nach X | LDA #$10 / TAX → X = 16 |
TAY | Transfer A to Y | Kopiert A nach Y | TAY → Y ← A (zur Tabellenindizierung) |
TXA | Transfer X to A | Kopiert X nach A | TXA / CLC / ADC #$40 → Adressberechnung |
TYA | Transfer Y to A | Kopiert Y nach A | TYA / STA $CB → sichert Y als Wert |
TSX | Transfer SP to X | Kopiert Stapelzeiger SP nach X | TSX → X = aktueller Stapelwert |
TXS | Transfer X to SP | Kopiert X in Stapelzeiger SP | LDX #$FF / TXS → setzt Stapel zurück |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
PHA | Push Accumulator | Legt A auf den Stapel (sichern) | PHA vor JSR, um A nicht zu verlieren |
PLA | Pull Accumulator | Holt A vom Stapel (wiederherstellen) | PLA nach JSR, stellt A wieder her |
PHP | Push Processor status | Legt Statusregister P auf den Stapel | PHP / SEI / … / PLP: kritischer Abschnitt |
PLP | Pull Processor status | Holt P vom Stapel | PLP stellt durch PHP gesicherte Flags wieder her |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
ADC | Add with Carry | A ← A + Operand + C | CLC / LDA #$10 / ADC #$05 → A = $15 |
SBC | Subtract with Carry | A ← A − Operand − (1−C) | SEC / LDA #$10 / SBC #$03 → A = $0D |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
INC | Increment memory | +1 zu einem Speicherbyte | INC $0600 → erhöht Punktestand in $0600 |
INX | Increment X | X ← X + 1 | INX / CPX #$10 / BNE LOOP: 16×-Schleife |
INY | Increment Y | Y ← Y + 1 | INY / LDA (PTR),Y: schreitet durch Tabelle |
DEC | Decrement memory | −1 zu einem Speicherbyte | DEC $CB → verringert Lebenszähler |
DEX | Decrement X | X ← X − 1 | LDX #$08 / LOOP: DEX / BNE LOOP: wartet 8× |
DEY | Decrement Y | Y ← Y − 1 | DEY / BNE LOOP: Schleife solange Y ≠ 0 |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
AND | Logical AND | A ← A UND Operand (bitweise) | AND #$0F → behält untere 4 Bits (Nibble) |
ORA | Logical OR | A ← A ODER Operand (bitweise) | ORA #$80 → setzt Bit 7 auf 1 (Invertbild) |
EOR | Exclusive OR | A ← A XOR Operand (bitweise) | EOR #$FF → invertiert alle Bits |
BIT | Bit test | Z ← A UND Speicher; N,V ← Bits 7,6 d. Speichers | BIT $D018 → testet Register ohne A zu ändern |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
ASL | Arithmetic Shift Left | Links schieben (× 2); Bit 7 → C | ASL A → A × 2 |
LSR | Logical Shift Right | Rechts schieben (÷ 2); Bit 0 → C | LSR A → A ÷ 2 |
ROL | Rotate Left | Linksrotation durch C | ROL A → × 2 + altes C (16-Bit-Multiplikation) |
ROR | Rotate Right | Rechtsrotation durch C | ROR A → ÷ 2 + altes C in Bit 7 |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
CMP | Compare A | A − Operand → N,Z,C (A unverändert) | CMP #$9B / BEQ EOL → ATASCII-Zeilenende? |
CPX | Compare X | X − Operand → N,Z,C | CPX #$10 / BNE LOOP → Ende bei X=16 |
CPY | Compare Y | Y − Operand → N,Z,C | CPY #$00 / BEQ DONE → Ende bei Y=0 |
Alle Sprünge sind relativ (vorzeichenbehafteter Offset von −128 bis +127 Bytes ab dem nächsten Befehl).
| Mnemonic | Vollständiger Name | Bedingung | Beispiel |
|---|---|---|---|
BCC | Branch if Carry Clear | C = 0 | ADC #$01 / BCC OK → kein Übertrag |
BCS | Branch if Carry Set | C = 1 | CMP #$80 / BCS HIGH → A ≥ $80 |
BEQ | Branch if Equal | Z = 1 (Ergebnis null) | CMP #$41 / BEQ FOUND → 'A' gefunden |
BNE | Branch if Not Equal | Z = 0 (Ergebnis nicht null) | DEX / BNE LOOP → klassische Schleife |
BMI | Branch if Minus | N = 1 (Bit 7 = 1) | BIT $D40B / BMI VBLANK → VBlank aktiv |
BPL | Branch if Plus | N = 0 (Bit 7 = 0) | LDA $CB / BPL OK → positiver Wert |
BVC | Branch if oVerflow Clear | V = 0 | ADC #$01 / BVC OK → kein Vorzeichenüberlauf |
BVS | Branch if oVerflow Set | V = 1 | ADC #$40 / BVS ERR → Vorzeichenüberlauf |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
JMP | Jump | Unbedingter Sprung (absolut oder indirekt) | JMP $4000 → startet ATAMON neu |
JSR | Jump to Subroutine | Legt Rücksprungadresse ab, dann Sprung | JSR $E456 → ruft CIO auf |
RTS | Return from Subroutine | Holt Rücksprungadresse+1 und springt dorthin | RTS → Ende eines Unterprogramms |
RTI | Return from Interrupt | Holt P, dann Programmzähler vom Stapel | RTI → Ende eines VBI- oder DLI-Handlers |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
BRK | Break | Lö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 |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
CLC | Clear Carry | C ← 0 | CLC / ADC #$01 → Addition ohne alten Übertrag |
SEC | Set Carry | C ← 1 | SEC / SBC #$01 → korrekte Subtraktion |
CLD | Clear Decimal | D ← 0 (BCD deaktivieren) | CLD zu Beginn einer Rechenroutine |
SED | Set Decimal | D ← 1 (BCD aktivieren) | SED → am Atari selten nützlich |
CLI | Clear Interrupt disable | I ← 0 (IRQ erlauben) | CLI → aktiviert VBI, POKEY usw. |
SEI | Set Interrupt disable | I ← 1 (IRQ maskieren) | SEI → schützt kritischen Abschnitt |
CLV | Clear oVerflow | V ← 0 | CLV → bekannter Ausgangszustand vor vorzeichenbehafteter Arithmetik |
| Mnemonic | Vollständiger Name | Beschreibung | Beispiel |
|---|---|---|---|
NOP | No Operation | Tut 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 |
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.
| Mnemonic | Alt.-Namen | Beschreibung | Opcodes |
|---|---|---|---|
*KIL | JAM, HLT | Sperrt 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 |
Diese Opcodes führen zwei Operationen in einer aus: eine Änderung im Speicher dann eine logische/arithmetische Operation mit A.
| Mnemonic | Alt.-Namen | Beschreibung | Modi | Opcodes |
|---|---|---|---|---|
*SLO | ASO | ASL auf Speicherbyte, dann ORA mit A | inx zp abs iny zpx aby abx | $03 $07 $0F $13 $17 $1B $1F |
*RLA | — | ROL auf Speicherbyte, dann AND mit A | inx zp abs iny zpx aby abx | $23 $27 $2F $33 $37 $3B $3F |
*SRE | LSE | LSR auf Speicherbyte, dann EOR mit A | inx zp abs iny zpx aby abx | $43 $47 $4F $53 $57 $5B $5F |
*RRA | — | ROR auf Speicherbyte, dann ADC mit A | inx zp abs iny zpx aby abx | $63 $67 $6F $73 $77 $7B $7F |
*DCP | DCM | DEC auf Speicherbyte, dann CMP mit A | inx zp abs iny zpx aby abx | $C3 $C7 $CF $D3 $D7 $DB $DF |
*ISC | ISB, INS | INC auf Speicherbyte, dann SBC mit A | inx zp abs iny zpx aby abx | $E3 $E7 $EF $F3 $F7 $FB $FF |
| Mnemonic | Alt.-Namen | Beschreibung | Modi | Opcodes |
|---|---|---|---|---|
*LAX | — | Lädt denselben Wert gleichzeitig in A und X — entspricht LDA + TAX in einem Opcode | inx zp abs iny zpy aby | $A3 $A7 $AF $B3 $B7 $BF |
*SAX | AXS | Schreibt A UND X in den Speicher (ohne Flags zu ändern) | inx zp abs zpy | $83 $87 $8F $97 |
| Mnemonic | Alt.-Namen | Beschreibung | Opcode | Stabilität |
|---|---|---|---|---|
*ANC | — | Sofort-AND mit A, dann Bit 7 in Carry kopieren (wie ASL ohne Speicheränderung) | $0B $2B | stabil |
*ALR | ASR | Sofort-AND mit A, dann LSR auf A (logische Rechtsverschiebung) | $4B | stabil |
*ARR | — | Sofort-AND mit A, dann ROR auf A — mit komplexen Effekten auf C und V | $6B | stabil |
*SBX | AXS | (A UND X) − Imm → X, ohne Borge (beeinflusst C, Z, N) | $CB | stabil |
*SBC | — | Duplikat des offiziellen SBC #imm ($E9) — identisches Verhalten | $EB | stabil |
*ANE | XAA | A = (A ODER $EE) UND X UND Imm — Ergebnis prozessorabhängig | $8B | instabil |
*LXA | LAX # | (A ODER $EE) UND Imm → A und X — Ergebnis prozessorabhängig | $AB | instabil |
| Mnemonic | Alt.-Namen | Beschreibung | Opcode | Stabilität |
|---|---|---|---|---|
*TAS | XAS, SHS | SP = A UND X; schreibt SP UND (addr_hi+1) in Speicher | $9B | instabil |
*SHY | A11Y | Schreibt Y UND (addr_hi+1) in Speicher | $9C | instabil |
*SHX | A11X | Schreibt X UND (addr_hi+1) in Speicher | $9E | instabil |
*SHA | AXA | Schreibt A UND X UND (addr_hi+1) in Speicher | $93 $9F | instabil |
*LAS | LAR | A = X = SP = Speicher UND SP | $BB | instabil |
Diese Opcodes verhalten sich wie NOP (tun nichts Sichtbares), verbrauchen aber 2 oder 3 Bytes.
| Mnemonic | Modus | Größe | Opcodes |
|---|---|---|---|
*NOP | imp (1 Byte) | 1 | $1A $3A $5A $7A $DA $FA |
*NOP | zp (2 Bytes) | 2 | $04 $44 $64 |
*NOP | zpx (2 Bytes) | 2 | $14 $34 $54 $74 $D4 $F4 |
*NOP | abs (3 Bytes) | 3 | $0C |
*NOP | abx (3 Bytes) | 3 | $1C $3C $5C $7C $DC $FC |
Symbolische Adressen, die der ATAMON-Disassembler (Befehl D) erkennt. Sie erscheinen im Disassemblat anstelle der reinen Hexadresse.
$00–$FF)| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$000A–$000B | DOSVEC | DOS-Vektor — Sprungadresse zum DOS (2 Bytes lo/hi). JMP (DOSVEC) verlässt das Programm und kehrt zum DOS zurück. |
$000C–$000D | DOSINI | DOS-Initialisierungsvektor — bei jedem Warm-Reset aufgerufen. |
$0010 | POKMSK | POKEY-IRQ-Aktivierungsmaske. Jedes Bit aktiviert einen IRQ-Typ (Timer, Seriell…). |
$0012–$0014 | RTCLOK | Echtzeituhr (3 Bytes). 60×/s vom OS-VBI inkrementiert. |
$0020–$002B | ZIOCB | IOCB Null — Arbeitskopie des aktuellen Kanal-IOCB während eines CIO-Aufrufs. |
$002C | STATUS | Statuscode der letzten SIO- oder CIO-Operation. |
$002E–$002F | BUFRLO/HI | Adresse des Ein-/Ausgabepuffers (2 Bytes). Von SIO DCB und CIO verwendet. |
$0030–$0031 | BFENLO/HI | Puffer-Endadresse (2 Bytes). |
$0036–$0037 | BYTLO/HI | Anzahl der beim letzten SIO/CIO-Aufruf übertragenen Bytes (2 Bytes). |
$0200–$02FF)| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$0200–$0201 | VDSLST | DLI-Vektor (Display-List-Interrupt) — bei jeder DLI-Anweisung in der ANTIC-Display-List aufgerufen. |
$0202–$0203 | VPRCED | Interrupt-Vektor „proceed" (serielle Eingabe). |
$0204–$0205 | VINTER | Interrupt-Vektor „interrupt" (serielle Eingabe). |
$0206–$0207 | VBREAK | BRK-Vektor — aufgerufen wenn die CPU BRK ausführt. ATAMON installiert ihn, um Haltepunkte abzufangen. |
$0208–$0209 | VKEYBD | Tastatur-Interrupt-Vektor (Taste gedrückt). |
$020A–$020B | VSERIN | Serieller Empfangsvektor (POKEY). |
$020C–$020D | VSEROR | Serieller Sendevektor (POKEY). |
$020E–$020F | VSEROC | Vektor Ende serieller Sendung. |
$0210–$0211 | VTIMR1 | POKEY-Timer-1-Vektor. |
$0212–$0213 | VTIMR2 | POKEY-Timer-2-Vektor. |
$0214–$0215 | VTIMR4 | POKEY-Timer-4-Vektor. |
$0216–$0217 | VIMIRQ | Generischer IRQ-Vektor (vom OS nicht verwendet). |
$0222–$0223 | VVBLKI | Sofortiger VBI-Vektor — zu Beginn des vertikalen Blanking aufgerufen (~3 800 Zyklen verfügbar). |
$0224–$0225 | VVBLKD | Verzögerter VBI-Vektor — nach SYSVBV aufgerufen (~20 000 Zyklen verfügbar, sicherer). |
$0226–$0227 | CDTMA1 | Software-Timer-1-Vektor (vom VBI dekrementiert). |
$0228–$0229 | CDTMA2 | Software-Timer-2-Vektor. |
$022A | CDTMF3 | Software-Timer-3-Flag. |
$022C | CDTMF4 | Software-Timer-4-Flag. |
$022E | BRKKEY | BREAK-Taste-Flag: $00 wenn BREAK gedrückt, sonst $80. |
$022F | SDMCTL | Schatten DMACTL — beim VBI nach $D400 (ANTIC) kopiert. Steuert Bildschirmbreite und DMA-Aktivierung. |
$0230–$0231 | SDLSTL/H | Schatten Display-List (lo/hi) — beim VBI nach $D402/$D403 kopiert. Zeigt auf aktive ANTIC-Display-List. |
$023B | ATRACT | Bildschirmschoner-Zähler. Vom OS jede Sekunde Tastaturinaktivität inkrementiert. Über 127 → Farben gedämpft. Zurücksetzen auf 0 deaktiviert den Schoner. |
$026F | GPRIOR | Schatten PRIOR — beim VBI nach $D01B (GTIA) kopiert. Bestimmt Anzeige-Priorität Spieler/Missiles/Hintergrund. |
$02C0–$02C8 | COLPF0…COLPM0 | Farben der Playfields und Spieler (Schatten der GTIA-Farbregister). |
$02C8 | COLBK | Hintergrundfarbe. Schatten des GTIA-Registers $D01A. |
$02E0–$02E1 | RUNAD | Ausführungsadresse des geladenen Programms (XEX). Das OS springt nach dem Laden zu dieser Adresse. |
$02E2–$02E3 | INITAD | Initialisierungsadresse — nach jedem mit INITAD markierten XEX-Segment aufgerufen. |
$02E4 | RAMSIZ | RAM-Größe in Seiten (×256). Beim Start gelesen. |
$02E5 | RAMTOP | Obere RAM-Nutzungsgrenze (in Seiten). |
$02E7–$02E8 | MEMLO | Untere RAM-Grenze (2 Bytes). ATAMON setzt sie auf $5300, um seinen Code zu schützen. |
$02E9–$02EA | MEMTOP | Obere RAM-Grenze (2 Bytes). |
$02F4 | CHBAS | Schatten CHBASE — beim VBI nach $D408 (ANTIC) kopiert. Wählt den Zeichensatz. |
$0300–$035F)| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$0300 | DDEVIC | SIO-Gerätenummer (z. B. $31 = Diskette D1:). |
$0301 | DUNIT | Einheitennummer (1 bis 4 für D1: bis D4:). |
$0302 | DCOMND | SIO-Befehl (z. B. $52 = Read sector, $57 = Write sector). |
$0303 | DSTATS | Richtung: $40 = Lesen, $80 = Schreiben, $00 = nur Status. |
$0304–$0305 | DBUFLO/HI | Pufferadresse (2 Bytes lo/hi). |
$0306 | DTIMLO | SIO-Timeout in VBI-Einheiten (~1/60 s). Typischer Wert: $0F (15 VBI). |
$0308–$0309 | DBYTLO/HI | Anzahl zu übertragender Bytes (2 Bytes). |
$030A–$030B | DAUX1/2 | Hilfsparameter (z. B. Sektornummer lo/hi für Diskette). |
$0340–$034F | IOCB0 | IOCB Kanal 0 (Bildschirmeditor E: — von ATAMON für die Eingabe verwendet). |
$0350–$035F | IOCB1 | IOCB Kanal 1 (frei). |
| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$D000 | HPOSP0 | Horizontalposition Spieler 0. |
$D001 | HPOSP1 | Horizontalposition Spieler 1. |
$D002 | HPOSP2 | Horizontalposition Spieler 2. |
$D003 | HPOSP3 | Horizontalposition Spieler 3. |
$D004 | HPOSM0 | Horizontalposition Munition 0. |
$D01B | PRIOR | Anzeige-Priorität Spieler/Munition/Playfields. Bit 7 = spezieller GTIA-Modus. |
$D01D | GRACTL | Aktivierung DMA Spieler/Munition. |
$D01F | CONSOL | Konsolentasten (Lesen): Bits 2-0 = START/SELECT/OPTION (0 = gedrückt). Schreiben: Lautsprecher-Steuerung. |
| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$D200 | AUDF1 | Frequenzteiler Audiokanal 1 (Wert 0–255, Frequenz umgekehrt proportional). |
$D201 | AUDC1 | Steuerung Kanal 1: Bits 7-4 = Lautstärke, Bits 3-0 = Verzerrung/Wellenform. |
$D202 | AUDF2 | Frequenzteiler Audiokanal 2. |
$D203 | AUDC2 | Steuerung Kanal 2. |
$D204 | AUDF3 | Frequenzteiler Audiokanal 3. |
$D205 | AUDC3 | Steuerung Kanal 3. |
$D206 | AUDF4 | Frequenzteiler Audiokanal 4. |
$D207 | AUDC4 | Steuerung Kanal 4. |
$D208 | AUDCTL | Globale Audio-Steuerung: Taktfrequenz (64 kHz/15 kHz/1,79 MHz), 16-Bit-Kanäle, Hochpassfilter. |
$D20A | STIMER | Schreiben: POKEY-Timer auf Null zurücksetzen. |
$D20E | SEROUT | Serieller Ausgang (Schreiben). |
$D20F | SKCTL | POKEY-Serien-Steuerung: Reset, Synchronisationsmodus. |
| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$D300 | PORTA | Port A: Joystick 1 (Bits 3-0) und Joystick 2 (Bits 7-4). Bit = 0 wenn Richtung aktiv. |
$D301 | PORTB | Port B: auf dem 800XL Steuerung der OS-ROM-Bank (Bit 0) und BASIC (Bit 1). |
$D302 | PACTL | Steuerung Port A (Richtungsbits, Interrupts). |
$D303 | PBCTL | Steuerung Port B. |
| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$D400 | DMACTL | DMA-Steuerung: aktiviert/deaktiviert DMA, definiert Bildschirmbreite (narrow/normal/wide) und Spieler/Munition-DMA. |
$D401 | CHACTL | Zeichen-Steuerung: invertiertes Video, Blanking oberer/unterer Zeilenränder einer Zelle. |
$D402–$D403 | DLISTL/H | Display-List-Adresse (lo/hi). ANTIC liest diese Liste für den Bildaufbau. |
$D404 | HSCROL | Feines horizontales Scrolling (0–15 Farbtakte). |
$D405 | VSCROL | Feines vertikales Scrolling (0–15 Zeilen). |
$D407 | PMBASE | Basisadresse Spieler/Munition (oberes Byte der Adresse, 1-KB- oder 2-KB-Seite je nach DMACTL). |
$D408 | CHBASE | Basisadresse Zeichensatz (oberes Byte; Zeichensatz beginnt bei dieser Seite × 256). |
$D409 | WSYNC | Wait for sync — Schreiben: CPU wartet bis Ende der aktuellen Rasterzeile (Raster-Synchronisation). |
$D40B | VCOUNT | Aktueller Rasterzeilen-Zähler (nur Lesen, 0–131). |
$D40E | NMIEN | NMI-Aktivierung: Bit 7 = DLI, Bit 6 = VBI. |
$D40F | NMIRES | Schreiben: NMI-Flags zurücksetzen. Lesen: NMI-Quelle identifizieren (Bit 7 = DLI, Bit 6 = VBI). |
$E4xx)| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$E450 | DISKIV | Initialisierung des Disketten-Handlers. |
$E453 | DSKINV | SIO-Diskettenaufruf — führt den im DCB ($0300+) beschriebenen Befehl aus. Von ATAMON für die Befehle E und W verwendet. |
$E456 | CIOV | CIO (Central I/O) — Haupt-Einsprungpunkt für Ein-/Ausgabe. Von ATAMON zum Lesen von Befehlen und Schreiben von Ergebnissen verwendet. |
$E459 | SIOV | SIO (Serial I/O) — niederstufiger serieller Transfer. |
$E45C | SETVBV | Installiert einen VBI-Handler (sofort oder verzögert). |
$E45F | SYSVBV | System-VBI-Handler (OS) — aus einem sofortigen VBI aufzurufen, um den verzögerten VBI zu verketten. |
$E462 | XITVBV | VBI-Austritt (Ende eines VBI-Handlers). |
$E465 | SIOINV | SIO-Initialisierung. |
$E474 | WARMSV | Warm-Restart — setzt das OS zurück ohne RAM zu löschen. |
$E477 | COLDSV | Kalt-Start — vollständige Neuinitialisierung (löscht RAM). |
$D8xx)| Adresse | Bezeichner | Beschreibung |
|---|---|---|
$D800 | AFP | ASCII → Gleitkomma (Zeichenkette bei $F3/$F4 → FR0). |
$D8E6 | FASC | Gleitkomma → ASCII (FR0 → Zeichenkette bei $F3/$F4). |
$D9AA | IFP | 16-Bit-Ganzzahl → Gleitkomma (Wert in $D4/$D5 → FR0). |
$D9D2 | FPI | Gleitkomma → 16-Bit-Ganzzahl (FR0 → $D4/$D5). |
$DA44 | ZFR0 | FR0 auf Null setzen. |
$DA60 | FSUB | Gleitkomma-Subtraktion: FR0 ← FR0 − FR1. |
$DA66 | FADD | Gleitkomma-Addition: FR0 ← FR0 + FR1. |
$DADB | FMUL | Gleitkomma-Multiplikation: FR0 ← FR0 × FR1. |
$DB28 | FDIV | Gleitkomma-Division: FR0 ← FR0 / FR1. |
$DD40 | PLYEVL | Polynomauswertung (für sin, cos, exp…). |
$DD89 | FLD0R | FR0 von der Adresse in (X,Y) laden. |
$DD98 | FLD1R | FR1 von der Adresse in (X,Y) laden. |
$DDA7 | FSTOR | FR0 an der Adresse in (X,Y) speichern. |
$DDB6 | FMOVE | FR1 ← FR0. |
Übersicht der Hardware-Register der vier Custom-Chips des Atari 800XL, mit ihrer typischen Verwendung in der Programmierung.
$D000–$D01F)| Adresse | Bezeichner | Richtung | Beschreibung |
|---|---|---|---|
$D000 | HPOSP0 | W | Horizontalposition Spieler 0 |
$D001 | HPOSP1 | W | Horizontalposition Spieler 1 |
$D002 | HPOSP2 | W | Horizontalposition Spieler 2 |
$D003 | HPOSP3 | W | Horizontalposition Spieler 3 |
$D004 | HPOSM0 | W | Horizontalposition Munition 0 |
$D005 | HPOSM1 | W | Horizontalposition Munition 1 |
$D006 | HPOSM2 | W | Horizontalposition Munition 2 |
$D007 | HPOSM3 | W | Horizontalposition Munition 3 |
$D008–$D00B | SIZEPx | W | Spielerbreite (0–3) |
$D00C | SIZEM | W | Munitionsbreite (Bits 0–7, je 2 pro Munition) |
$D00D–$D010 | GRAPx | W | Spieler-/Munitionsgrafik (1 Byte = 1 Pixelzeile) |
$D011 | GRAFM | W | Munitionsgrafik (4 × 2 Bits) |
$D012–$D015 | COLPMx | W | Spieler/Munition-Farbe 0–3 |
$D016–$D019 | COLPFx | W | Spielfeld-Farbe 0–3 |
$D01A | COLBK | W | Hintergrundfarbe |
$D01B | PRIOR | W | Kollisions-/Prioritäts-Steuerung |
$D01C | VDELAY | W | Vertikale Verzögerung für Spieler/Munition |
$D01D | GRACTL | W | Grafik-Steuerregister (Spieler/Munition ein/aus) |
$D01E | HITCLR | W | Kollisionszähler zurücksetzen |
$D01F | CONSOL | R/W | Konsolentasten (START/SELECT/OPTION lesen), Lautsprecher |
$D000–$D007 | M0PF–P3PF | R | Kollision Spieler/Munition mit Spielfeld |
$D008–$D00F | M0PL–P3PL | R | Kollision Munition/Spieler untereinander |
$D010–$D017 | P0PF–P3PF | R | Kollision Spieler mit Spielfeld |
$D018–$D01F | P0PL–P3PL | R | Kollision Spieler untereinander |
$D200–$D20F)| Adresse | Bezeichner | Richtung | Beschreibung |
|---|---|---|---|
$D200 | AUDF1 | W | Tondivider Kanal 1 (Frequenz) |
$D201 | AUDC1 | W | Tonsteuerung Kanal 1 (Distortion, Lautstärke) |
$D202 | AUDF2 | W | Tondivider Kanal 2 |
$D203 | AUDC2 | W | Tonsteuerung Kanal 2 |
$D204 | AUDF3 | W | Tondivider Kanal 3 |
$D205 | AUDC3 | W | Tonsteuerung Kanal 3 |
$D206 | AUDF4 | W | Tondivider Kanal 4 |
$D207 | AUDC4 | W | Tonsteuerung Kanal 4 |
$D208 | AUDCTL | W | Audiosteuerung (Kanalverknüpfung, Taktbasis) |
$D209 | STIMER | W | Timer-Neustart |
$D20A | SKRES | W | SKSTAT zurücksetzen |
$D20B | POTGO | W | Potentiometer-Ablesung starten |
$D20E | IRQEN | W | IRQ-Freigabe |
$D20F | SKCTL | W | Serielles Port-Steuerregister |
$D200–$D207 | POT0–POT7 | R | Potentiometer-Werte |
$D208 | ALLPOT | R | Potentiometer-Status (Bit = 1 = noch nicht bereit) |
$D209 | KBCODE | R | Tastaturcode |
$D20A | RANDOM | R | Pseudozufallszahl |
$D20D | SERIN | R | Empfangenes Byte (seriell) |
$D20E | IRQST | R | IRQ-Status |
$D20F | SKSTAT | R | Serieller Port-Status |
$D300–$D303)| Adresse | Bezeichner | Richtung | Beschreibung |
|---|---|---|---|
$D300 | PORTA | R/W | Joystick-Port 1+2 (Richtungen als Bits) |
$D301 | PORTB | R/W | Bankswitching (XL/XE), Port B |
$D302 | PACTL | W | Port A-Steuerregister |
$D303 | PBCTL | W | Port B-Steuerregister |
$D400–$D40F)| Adresse | Bezeichner | Richtung | Beschreibung |
|---|---|---|---|
$D400 | DMACTL | W | DMA-Steuerung (Spielfeldbreite, Spieler-DMA, ...) |
$D401 | CHACTL | W | Zeichen-Steuerung (Spiegelung, ...) |
$D402–$D403 | DLISTL/H | W | Anzeigenlistenzeiger (lo/hi) |
$D404 | HSCROL | W | Horizontales Fine-Scrolling |
$D405 | VSCROL | W | Vertikales Fine-Scrolling |
$D407 | PMBASE | W | Basis-Adresse Spieler/Munition-DMA |
$D408 | CHBASE | W | Basis-Adresse Zeichensatz |
$D409 | WSYNC | W | Warte auf horizontale Synchronisation |
$D40A | VSCROL | W | (Lesen von VCOUNT bei Adresse $D40B) |
$D40B | VCOUNT | R | Aktueller vertikaler Zeilenzähler |
$D40C | PENH | R | Lichtstift-Horizontalposition |
$D40D | PENV | R | Lichtstift-Vertikalposition |
$D40E | NMIEN | W | NMI-Freigabe (VBI, DLI) |
$D40F | NMIRES/NMIST | W/R | NMI zurücksetzen / NMI-Status |
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 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:
xxxxxxxxxx20 80 42 JSR $4280 ; READ_BIN (direkter Aufruf — Fehler)
durch:
xxxxxxxxxx20 B2 52 JSR $52B2 ; → Trampolin
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.
xxxxxxxxxx$52B2: A5 E8 LDA $E8 ; Byte-Zähler (0 = erster Aufruf)$52B4: D0 08 BNE $52BE ; wenn 2. Byte oder mehr → direkt READ_BIN$52B6: 20 AE 43 JSR $43AE ; 1. Byte: Komma adresse,data konsumieren$52B9: 90 03 BCC $52BE ; Komma gefunden (C=0) → READ_BIN$52BB: 4C EC 4B JMP $4BEC ; kein Komma (C=1) → Fehler ?$52BE: 4C 80 42 JMP $4280 ; READ_BIN 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.
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.
ATAMON V1.3 — Original-Binärprogramm auf der Diskette DXG-5724 (Atari Deutschland GmbH, 1983). Analysiert mittels Altirra-Emulator und eigenem Disassembler-Skript.
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 400/800 Operating System Source Listing — Atari Inc., 1979. Offizielle kommentierte Quelltextliste des Atari-Betriebssystems.
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).
Atari System Reference Manual (OSRM) — Atari Inc., 1983. Offizielle Referenz für alle Betriebssystemvektoren, -variablen und -routinen.
Compute!'s First Book of Atari — Compute! Publications. Einführung in die Atari-Hardwareprogrammierung.
MOS Technology 6502 Microprocessor Datasheet — MOS Technology Inc., 1975. Offizielles Datenblatt des 6502-Prozessors.
6502 Assembly Language Programming — Lance Leventhal, Osborne/McGraw-Hill, 1979. Standardreferenz für 6502-Assemblerprogrammierung.
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
Atari PRO Disk Image Format Specification — Atari Preservation Project. Quelle: a8preservation.com
ATR (Atari Disk Image) Format — Diverse Community-Dokumentation. Beschreibung des 16-Byte-ATR-Headers und der Sektorstruktur.
XEX / DOS BINARY Load Format — Atari-DOS-Dokumentation. Beschreibung der Segmentstruktur ($FFFF-Header, Startadresse, Endadresse, Daten, RUNAD).
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
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.
AtariWiki — Community-Wiki zur Atari-8-Bit-Plattform (Hardware, Software, Geschichte). Quelle: atariwiki.org
AtariAge Forums — Aktive Community-Foren für Atari-8-Bit-Programmierung, Hardware-Mods und Softwareentwicklung. Quelle: atariage.com
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