ATAMON V1.3


Table des matières


Avant-propos

La documentation d'ATAMON (ATAri MONitor) reste introuvable depuis plus de 40 ans.

Ce que vous lisez est une documentation non officielle, le fruit d'heures de travail, d'essais, de décompilation et de rédaction à partir du code désassemblé d'ATAMON.

J'espère que vous l'apprécierez ;-)

Atarinside — Mars 2026

Le programme se trouve ici : https://www.atarinside.com/blog/index.php/atarinside-items/atamon/


Qu'est-ce qu'ATAMON ?

Vous venez de charger ATAMON, le moniteur langage machine d'ATARI. Mais à quoi sert un moniteur, exactement ?

Votre Atari 800XL fonctionne grâce à un processeur, le 6502, qui exécute des milliers d'instructions par seconde. Ces instructions — appelées "langage machine" — sont stockées en mémoire sous forme de nombres. ATAMON est l'outil qui vous permet de voir, modifier et exécuter directement ces instructions, sans passer par un langage intermédiaire comme le BASIC.

Concrètement, ATAMON vous permet de :

Pour qui ? ATAMON s'adresse aux programmeurs, aux passionnés qui souhaitent comprendre le fonctionnement interne de leur Atari, ou à quiconque veut explorer et modifier des programmes en langage machine. Aucun matériel supplémentaire n'est nécessaire : ATAMON fonctionne entièrement depuis votre Atari, avec votre lecteur de disquette habituel.

Comment démarrer ? Depuis le menu du DOS Atari, sélectionnez L. BINARY LOAD puis tapez D:ATAMON et appuyez sur Entrée. Le programme s'installe en mémoire à partir de l'adresse $4000, affiche sa bannière, et le curseur Atari indique qu'il est prêt à recevoir une commande. Toutes les commandes sont à une seule lettre — rapide et efficace.


Documentation technique

Moniteur langage machine pour Atari 800XL


Fichier source : Atamon - D7 - DXG 5724.PROATAMON Identification : *** ATAMON V1.3 - (c) 1983 by ATARI *** Type : Moniteur / débogueur en langage machine 6502 Taille : 4 404 octets Format : XEX Atari (segments multiples) Adresse de chargement : $4000 Adresse d'exécution (RUNAD) : $4000 Langage source : Assembleur 6502 Éditeur : Atari Deutschland GmbH (Atari Allemagne) — ATAMON est un produit Atari Allemagne, identifié par le numéro de catalogue DXG 5724 Auteur : Non identifié — le binaire ne contient aucun nom de programmeur, uniquement (c) 1983 by ATARI Outil d'assemblage probable : Atari Macro Assembler ou MAC/65 (OSS) — déduit de la structure des segments XEX de 256 octets (252 octets de code + 4 octets d'en-tête), format de sortie caractéristique des assembleurs Atari natifs de 1983


1. Présentation générale

ATAMON est un moniteur langage machine professionnel développé par ATARI en 1983. Il permet à un programmeur de :

Il appartient à la famille des moniteurs langage machine qui ont accompagné les ordinateurs 8 bits de l'époque sur de nombreuses plateformes.


2. Installation en mémoire

Occupation mémoire : environ 4,5 Ko de $4000 à $52B1. ATAMON déclare aussi MEMLO = $5300 pour protéger son code.


3. Mécanisme de démarrage

L'entrée à $4000 utilise une technique classique : le vecteur BRK ($0206-$0207).

Pourquoi cette technique ? Le BRK pousse automatiquement l'adresse de la prochaine instruction (adresse courante + 2) et le registre d'état sur la pile. ATAMON récupère ensuite ces valeurs pour construire un tableau complet de l'état du processeur au moment de l'entrée dans le moniteur.

Sauvegarde des registres ($401C)

Note sur le mécanisme d'entrée : Le handler OS Atari (ROM IRQ) pousse le registre A via PHA avant d'appeler le vecteur VBREAK. C'est pourquoi SAVE_CPU effectue 4 PLA successifs (A, P, PCL, PCH) alors que l'instruction BRK n'en pousse que 3 (P, PCL, PCH).

Zone de sauvegarde des registres ($4F3C-$4F42) :

Ce layout est confirmé par le handler G (Go) : LDA $4F3D restaure A, LDA $4F40; PHA; PLP restaure P, JMP ($4F41) saute à l'adresse $4F42:$4F41.


4. Boucle principale de commande

Après initialisation, ATAMON affiche sa bannière et entre dans la boucle de commande ($4064) :

Invite de commande et affichage des registres

ATAMON n'affiche pas de prompt explicite : l'invite de saisie est le curseur de l'éditeur écran Atari (bloc clignotant en vidéo inverse), géré automatiquement par l'OS. Quand ce curseur est visible, ATAMON attend une commande.

Les en-têtes *R, *B, *C sont des préfixes d'affichage ATAMON, pas le prompt. L'astérisque * (code $2A) est émis par ATAMON avant d'afficher les registres, suivi d'une lettre indiquant le contexte d'entrée :

Exemple d'affichage des registres (commande R ou après un BRK) :

La ligne de valeurs commence toujours par ;. Signification de chaque champ :

ChampCe que c'estValeur dans l'exemple
PCCompteur de programme : adresse de la prochaine instruction qui sera exécutée. C'est là que votre programme "est" dans la mémoire.4000 → prêt à exécuter depuis $4000
SPPointeur de pile : indique où se trouve le sommet de la pile. La pile Atari est en $0100–$01FF ; SP=FD signifie que le sommet est à $01FD, pile quasi-vide.FD → pile réinitialisée
ACAccumulateur A : registre principal du 6502, utilisé pour les calculs, les transferts, les comparaisons.00
XRRegistre X : registre d'index, souvent utilisé pour les boucles et les adresses indexées.00
YRRegistre Y : second registre d'index.00
NV\BDIZCFlags du processeur (registre P), affichés bit à bit en binaire (0 ou 1). Chaque bit indique un état particulier du dernier calcul. Voir la description détaillée dans la commande ;.00110000 → flags I et B actifs

Cette ligne se met à jour automatiquement après chaque retour de programme (suite à un BRK ou G), pour refléter l'état réel du processeur à cet instant.


5. Comment charger votre programme dans ATAMON

L'Atari stocke l'adresse de lancement automatique du dernier programme chargé dans une case mémoire bien précise, à l'adresse $02E0 (le vecteur système appelé RUNAD).

Si tu charges ton jeu, son adresse de démarrage va se loger en $02E0. Mais si tu charges ATAMON juste derrière, l'adresse de démarrage d'ATAMON ($4000) va écraser celle de ton jeu !

Pour contourner ça et utiliser ATAMON en tant que détective, on va inverser l'ordre de chargement en s'aidant d'une autre option du menu DOS (l'option M).

Voici le plan d'action de l'agent double

Étape 1 : Installer le moniteur en "sous-marin"

  1. Depuis le menu DOS, utilise L pour charger ATAMON.

  2. ATAMON s'affiche à l'écran. Tape la commande X (eXit).

  3. Tu reviens au menu DOS, mais ATAMON reste caché bien au chaud dans la mémoire (à partir de $4000).

Étape 2 : Charger ton jeu silencieusement

  1. De retour dans le DOS, utilise à nouveau L pour charger ton programme en ajoutant /N (sans espace après le nom de fichier) — exemple : MYPROG.BIN/N.

  2. Le jeu se charge en mémoire et l'OS inscrit son adresse de départ en $02E0. Comme on a mis /N, le DOS ne saute pas à cette adresse, n'exécute pas le programme chargé et te garde dans le menu.

Étape 3 : Réveiller ATAMON

  1. Dans le menu DOS, choisis l'option M (Run at address).

  2. Tape 4000 (l'adresse où dort ATAMON) et appuie sur Entrée.

  3. La bannière d'ATAMON s'affiche — te revoilà dans le moniteur !

Étape 4 : Lire l'adresse magique

  1. Dans l'invite d'ATAMON, affiche la mémoire à l'adresse $02E0 en tapant :

  1. Appuie tout de suite sur BREAK pour arrêter le défilement.

  2. Regarde les deux premiers octets de la ligne affichée.

Attention — Little Endian : l'Atari stocke les adresses « à l'envers » (octet de poids faible en premier, puis poids fort).

  • Si ATAMON affiche :02E0 00 50 ..., l'adresse de ton programme est $5000.

  • S'il affiche :02E0 00 2A ..., l'adresse est $2A00.

Et voilà ! Tu n'as plus qu'à utiliser la commande G suivie de l'adresse découverte (ex : G 5000) pour lancer ton programme, sachant qu'ATAMON est prêt à intercepter n'importe quel plantage ou point d'arrêt (BRK).

Placer des points d'arrêt dans ton programme

Attention : ATAMON ne possède pas de fonction d'interruption asynchrone garantie.

La seule méthode infaillible pour rendre la main à ATAMON au milieu d'un programme, c'est d'y insérer volontairement un point d'arrêt logiciel :

  1. Remplace temporairement un octet de ton programme par l'instruction BRK (code hexadécimal $00).

  2. Lorsque le processeur exécutera ce $00, il déclenchera une interruption logicielle.

  3. ATAMON a détourné le vecteur d'interruption du système (VBREAK en $0206$0207) lors de son chargement.

  4. Le processeur sautera directement dans les bras d'ATAMON, qui sauvegardera tous tes registres (A, X, Y, PC…) et affichera son invite avec *B pour signaler qu'il a intercepté un BRK.

En résumé : si ton programme est une boucle infinie sans instruction BRK, la touche BREAK ne te sauvera pas (sauf si ton code fait appel aux routines clavier de l'OS). Tu seras bon pour un Reset ! Pense toujours à placer tes $00 stratégiquement avant de lancer ton code avec G.


6. Liste des commandes

La table des commandes est stockée à partir de $4F9D. Les commandes s'entrent en majuscules. Quand une commande prend plusieurs arguments, ils sont séparés par des virgules (pas d'espace entre les arguments). Un espace est accepté avant le premier argument.

Conventions de syntaxe


G [aaaa] — Go (Exécuter)

Lance l'exécution du programme à l'adresse aaaa. Sans argument : repart depuis l'adresse d'exécution sauvegardée (registre PC). Restaure tous les registres CPU sauvegardés avant de faire JMP aaaa.

Attention : G aaaa saute directement à l'adresse indiquée. Si cette adresse ne contient pas un programme valide (par exemple de la RAM non initialisée avec des zéros), le 6502 exécutera n'importe quoi et le système se bloquera ou redémarrera. G seul (sans adresse) est sûr : il repart depuis le PC sauvegardé au moment du dernier BRK.

Première utilisation après le démarrage : au démarrage, le PC sauvegardé est $400B (point d'entrée de l'initialisation ATAMON). Taper G seul réexécute donc le démarrage d'ATAMON : la bannière s'affiche à nouveau, suivie de *C et de l'état des registres.

Exemples :


M aaaa — Memory (Afficher mémoire)

Affiche le contenu de la mémoire à partir de l'adresse aaaa, 8 octets par ligne en hexadécimal. ATAMON défile indéfiniment — appuyer sur BREAK pour arrêter.

Le format d'affichage commence chaque ligne par : suivi de l'adresse, des 8 octets en hexadécimal, puis une colonne ATASCII à droite (chaque octet affiché comme son caractère ATASCII correspondant).

Exemple :


E ssss[,aaaa[,nn]] — E (Lire un secteur disque)

Lit le secteur disque numéro ssss (en hexadécimal) depuis le lecteur D1: et le charge dans le buffer mémoire à l'adresse aaaa (défaut : $0680).

Arguments optionnels :

Attention : ssss est un numéro de secteur, pas une adresse mémoire. Une disquette Atari simple densité (720 secteurs) a des numéros de $0001 à $02D0. Dépasser ce nombre provoque une erreur I/O.

Pour voir le contenu du secteur chargé : taper M 0680 — ATAMON affiche les octets à partir de $0680 en défilant (appuyer BREAK pour arrêter après avoir vu les 128 premiers octets du secteur).

Exemple :


D aaaa[,bbbb] — Disassemble (Désassembler)

Désassemble le code 6502 à partir de l'adresse aaaa et affiche les mnémoniques. Utilise les tables internes à $4FF9 qui contiennent les 56 mnémoniques 6502 et les informations de décodage des modes d'adressage.

Important : l'adresse de fin bbbb est syntaxiquement acceptée mais ignorée — ATAMON désassemble indéfiniment sans s'arrêter, continue après $FFFF et repart à $0000. Appuyer sur BREAK pour arrêter.

Exemple :

Chaque ligne indique : l'adresse, les octets bruts en mémoire, puis l'instruction désassemblée.


L aaaa,bbbb,xx — Locate Non-Matching (Localiser les octets différents)

Parcourt la zone mémoire de aaaa à bbbb et affiche les adresses où l'octet trouvé est différent de xx.

En pratique : L identifie les octets qui "ne correspondent pas" à une valeur de référence. Utile pour repérer rapidement les différences entre deux zones après une copie, ou trouver des octets modifiés dans un programme.

L seul (sans argument) → erreur ? — les trois arguments sont obligatoires.

Note : ATAMON ne possède pas de commande de chargement de fichier. Les programmes doivent être chargés depuis le DOS Atari (option L. BINARY LOAD) avant de lancer ATAMON.

Exemple :


W ssss[,aaaa[,nn]] — Write (Écrire un secteur disque)

Écrit le contenu du buffer mémoire à l'adresse aaaa (défaut : $0680) sur le secteur disque numéro ssss (en hexadécimal).

Arguments optionnels : mêmes que E — buffer source et nombre de secteurs consécutifs.

Attention : écrase directement le secteur sur la disquette — opération irréversible. ssss est un numéro de secteur en hexadécimal (1 à $02D0 = 720 pour une disquette simple densité).

E et W fonctionnent en tandem : E pour lire un secteur, modifier avec M ou :, puis W pour réécrire.

Exemple :


V aaaa,bbbb,cccc — Verify (Comparer mémoire)

Compare la zone mémoire aaaabbbb avec la zone commençant à cccc (comparaison mémoire à mémoire). Signale les adresses où les octets diffèrent. Aucune modification n'est effectuée.

Utile pour vérifier qu'une copie (effectuée avec T) est conforme à l'original, ou comparer deux versions d'un programme.

Exemple :

Note : si la zone de destination n'est pas initialisée (RAM quelconque), presque toutes les adresses de la plage apparaîtront dans le résultat.


F aaaa,bbbb,bb — Fill (Remplir)

Remplit la zone mémoire aaaabbbb avec l'octet bb.

Zone sûre : ATAMON occupe $4000–$52B1. Utiliser des adresses au-delà de $5300 (ex : $6000+).

Exemple :


T aaaa,bbbb,cccc — Transfer (Transférer mémoire)

Copie le bloc mémoire de aaaa à bbbb vers la destination cccc (mémoire vers mémoire). Effectue ensuite une vérification octet par octet et signale les différences.

Zones qui se chevauchent : si la source et la destination se recoupent en mémoire, une copie naïve du début vers la fin écraserait des octets source non encore lus. ATAMON évite ce problème : si la destination est avant la source, il copie de gauche à droite (premier octet en premier) ; si la destination est après la source (chevauchement par la droite), il copie de droite à gauche (dernier octet en premier). Le résultat est toujours correct quelle que soit la configuration.

Zone sûre : ATAMON occupe $4000–$52B1. Pour les tests, utiliser une zone au-delà de $5300 (par exemple $6000–$7FFF, RAM libre).

Exemples :


H aaaa,bbbb,DrecherchéD — Hunt (Rechercher en mémoire)

Parcourt la zone mémoire de aaaa à bbbb et cherche la séquence d'octets DrecherchéD. Affiche les adresses où la séquence est trouvée, puis OK.

D est un caractère délimiteur choisi librement (ex : ", /, #…) qui encadre la séquence. Les données à l'intérieur s'expriment comme pour la commande I : octets hex deux par deux (sans espaces), ou chaîne entre guillemets simples '...'.

H est une commande de recherche uniquement. La syntaxe de remplacement DsearchD,DreplaceD ne fonctionne pas : après la recherche, ATAMON retourne au prompt et interprète tout ce qui suit comme une nouvelle commande.

H seul, H aaaa ou H aaaa,bbbb (sans troisième argument) → erreur ? — les trois arguments minimum sont obligatoires.

Les données à l'intérieur du délimiteur suivent les mêmes règles que la commande I : octets hex deux par deux, ou chaîne entre '...'. Sans les guillemets simples internes, les lettres sont interprétées comme des chiffres hex — AT = A (hex valide) + T (hex invalide) → résultat corrompu.

Exemple :


S aaaa — Scan (Moniteur binaire en temps réel)

Affiche en temps réel les 4 octets à partir de l'adresse aaaa sous forme de 8 bits binaires. La même ligne se rafraîchit continuellement (pas de défilement) : ATAMON relit et réaffiche les mêmes 4 octets en boucle, permettant de surveiller en direct l'évolution de registres matériels.

S seul (sans argument) → erreur ? — l'adresse est obligatoire.

La commande ne rend pas la main — appuyer sur BREAK (ou SYSTEM RESET) pour arrêter.

Note : ATAMON ne possède pas de commande de pas-à-pas (single-step). Pour déboguer un programme pas à pas, il faut insérer manuellement des instructions BRK aux points souhaités dans le code.

Exemple avec une adresse fixe :

Exemple avec un registre matériel en temps réel :

Particulièrement utile pour surveiller des registres matériels (POKEY, GTIA, ANTIC, horloge RTCLOK) qui changent en temps réel, ou observer l'évolution d'une variable durant l'exécution d'un programme.


C aaaa,bbbbbbbb — Code (Écrire des octets binaires en mémoire)

Écrit un ou plusieurs octets en mémoire à partir de l'adresse aaaa. Chaque octet est saisi en binaire (8 chiffres 0 ou 1), séparés par des virgules.

C seul (sans argument) → erreur ?

Note : Cette commande est buggée dans la version originale V1.3 — elle interprète la virgule comme $2C au lieu d'analyser les arguments binaires, et retourne ?. Les exemples ci-dessous décrivent le comportement de la version patchée uniquement (Atamon - D7 - DXG 5724-Patched Atarinside.atr). Voir la section Correction du bug de la commande C en fin de document.

Exemple :

Exemple avec plusieurs octets :


P [E|T] — Printer (Gestion imprimante)

Contrôle le canal imprimante (IOCB 6, device P1:).

Exemple :

Note : cette commande est utile si vous disposez d'une imprimante connectée à votre Atari. Sans imprimante, P E provoquera une erreur I/O.


R — Registers (Afficher les registres)

Affiche l'état actuel de tous les registres CPU sauvegardés. La commande affiche uniquement, sans modifier aucun registre.

Pour modifier les registres, utiliser la commande ; (chargement complet) ou modifier directement en mémoire aux adresses $4F3C–$4F42.

Exemple :


X — eXit (Quitter)

Retourne au DOS Atari via JMP DOSVEC ($000A).

Exemple :


Z nn,cc[,aaaa,llll] — IOCB (Manipulation d'un canal CIO)

Exécute une opération d'entrée/sortie de l'OS Atari sur un canal donné, en passant directement par le système CIO (Central I/O).

Le système CIO en bref

L'OS Atari organise toutes les entrées/sorties en trois niveaux :

Le CIO offre un point d'entrée unique ($E456) pour tous les appareils : que vous écriviez sur l'écran, lisiez le clavier ou accédiez à une disquette, c'est toujours la même routine OS que vous appelez. C'est le handler de périphérique (une routine spécifique en ROM ou en RAM) qui s'occupe du vrai travail.

Handlers résidents en ROM (toujours disponibles, chargés automatiquement au démarrage) :

NomPériphériqueAccèsNote
E:Éditeur écran — saisie ligne par ligne avec édition interactivelecture + écritureUtilise K: et S: en interne
K:Clavier — lecture directe des toucheslecture seuleJamais ouvert directement — utilisé en interne par E:
S:Écran graphique — accès bitmap, commandes DRAW et FILLlecture + écriture 
P:Imprimante — sur XL/XE : P1: à P8: selon le modèleécriture seule 
C:Cassettelecture + écritureN'utilise pas le protocole SIO

Handlers non-résidents (chargés en RAM au démarrage par DOS ou la ROM d'un périphérique SIO) :

NomPériphériqueAccèsChargé par
D:Disquette — gestionnaire de fichiers DOS (D1: à D8:)lecture + écritureDOS, au boot
R:Interface 850 — ports série RS-232 (R1: à R4:)lecture + écritureROM de l'interface 850, au boot
T:Modem 1030 (XM301, 835)lecture + écritureROM du modem, au boot

Ces handlers non-résidents s'ajoutent à la table des handlers ($031A) au démarrage dès que le périphérique correspondant est connecté et allumé. Si le périphérique est absent, le handler n'est pas chargé et toute tentative d'accès à D:, R: ou T: via CIO retourne une erreur "unknown device".

Les canaux IOCB

Pour communiquer avec le CIO, on utilise un IOCB (Input/Output Control Block) : une zone mémoire de 16 octets qui décrit l'opération souhaitée (quel périphérique, quelle commande, quel buffer…).

L'OS dispose de 8 canaux (IOCB #0 à #7), chacun pouvant être affecté à n'importe quel périphérique :

CanalOffset nnAdresse mémoireAffectation
000$0340–$034FE: éditeur écran — ouvert par l'OS au démarrage, toujours disponible
110$0350–$035Flibre — disponible pour tout programme
220$0360–$036Flibre — disponible pour tout programme
330$0370–$037Flibre — disponible pour tout programme
440$0380–$038Flibre — disponible pour tout programme
550$0390–$039Flibre — disponible pour tout programme
660$03A0–$03AFréservé par Atari BASIC pour S: (modes graphiques ≠ 0)
770$03B0–$03BFréservé par Atari BASIC pour P:/D:/C: (imprimante, disque, cassette)

Les canaux 1 à 5 n'ont pas d'affectation fixe — c'est voulu. Les handlers non-résidents (D:, R:, T:) ne s'ouvrent pas sur un canal dédié : c'est le programme qui choisit librement sur quel canal il ouvre chaque périphérique. K: n'a jamais besoin d'un canal IOCB car il est utilisé en interne par E:. Par exemple, un programme peut ouvrir D:FICHIER.DAT sur le canal 1, et R1: (port série) sur le canal 2, simultanément. Si BASIC est actif, éviter de toucher aux canaux 6 et 7.

Un record est une suite d'octets terminée par le caractère de fin de ligne ATASCII $9B. GET RECORD lit jusqu'au prochain $9B ; PUT RECORD écrit et ajoute $9B en fin.

Syntaxe Z

Z seul, Z 00 seul → erreur ? — la commande cc est obligatoire.

Commande ccSignification
03OPEN — ouvre un canal vers un périphérique
05GET RECORD — lit une ligne depuis le canal (jusqu'au $9B)
07GET BYTES — lit des octets (sans s'arrêter au $9B)
09PUT RECORD — écrit une ligne vers le canal (ajoute $9B)
0BPUT BYTES — écrit des octets (sans ajouter $9B)
0CCLOSE — ferme le canal
0DSTATUS — lit l'état du canal

Z copie l'IOCB actuel du canal, remplace les champs fournis (commande, adresse, longueur), appelle CIO, puis réécrit l'IOCB modifié. Aucun résultat n'est affiché — l'effet est la sortie de l'opération CIO elle-même.

Exemple — afficher du texte à l'écran via PUT RECORD sur le canal 0 (toujours ouvert sur l'éditeur écran E:) :

Pour inspecter le contenu brut d'un IOCB, utiliser M 0340 (canal 0) ou M 0350 (canal 1).


I aaaa,DdonnéesD — Input string (Saisir du texte en mémoire)

Saisit du texte ou des données mixtes directement en mémoire à partir de l'adresse aaaa.

D est un caractère délimiteur choisi librement (ex : ", ', /…) qui marque le début et la fin des données. Tout ce qui se trouve entre les deux délimiteurs est écrit octet par octet en mémoire.

⚠ Important : PAS d'espace entre la virgule et le délimiteur. La virgule sépare l'adresse des données — le délimiteur doit immédiatement suivre la virgule, sans espace. Un espace entre , et le délimiteur produit ?.

À l'intérieur des données, deux formats sont acceptés :

Attention : 'B'O'N'J'O'U'R' est incorrect — après le premier 'B', la lettre O est interprétée comme début d'un octet hex à deux chiffres, ce qui échoue immédiatement avec ?. Il faut impérativement mettre toute la chaîne entre une seule paire de guillemets simples : 'BONJOUR'.

Exemples :

Cette commande est particulièrement utile pour écrire des messages d'erreur, des chaînes ATASCII ou des patches de code directement dans la mémoire.


# — Conversion décimal → hexadécimal

Interprète l'argument comme une valeur décimale et affiche son équivalent en hexadécimal.

Utile quand on connaît une adresse ou une valeur en décimal et qu'on veut savoir ce qu'elle vaut en hexadécimal avant de l'utiliser dans une autre commande.

Exemples :


$ — Conversion hexadécimal → décimal

Interprète l'argument comme une valeur hexadécimale et affiche son équivalent en décimal (complément de #).

Exemples :

Important : $ exige exactement 4 chiffres hexadécimaux. Utiliser $ 00FF et non $ FF.


% — Entrée binaire

Permet de saisir une valeur sous forme de 8 bits (0 et 1) et l'affiche en hexadécimal.

Utile pour travailler directement avec les flags du processeur ou tout registre dont on veut contrôler bit à bit la valeur — plus lisible qu'un octet hex pour ce type de manipulation.

Exemples :


; aaaa BB BB BB BB XXXXXXXX — Set (Charger tous les registres d'un coup)

Charge l'intégralité des registres CPU en une seule ligne de commande. Syntaxe : ; PCHL SP AC XR YR XXXXXXXX

Utile pour restaurer un contexte d'exécution précis en une seule opération, par exemple pour reprendre le débogage d'un programme exactement dans l'état où il s'est arrêté.

Exemple :


! aaaa — Binary (Conversion hexadécimal → binaire)

Convertit la valeur hexadécimale aaaa en binaire sur 16 bits et l'affiche. Il ne lit pas la mémoire — il convertit l'argument lui-même.

Format : ! aaaa = bbbbbbbb bbbbbbbb (octet de poids fort puis octet de poids faible).

Utile pour visualiser les bits individuels d'une valeur (registre matériel lu au préalable, résultat d'une opération, valeur de flag…).

Exemples :


* OP aaaa,bbbb — Arithmetic (Calculateur)

Effectue une opération arithmétique ou logique entre deux valeurs 16 bits sur la même ligne de commande. L'opérateur est un symbole : + (addition), - (soustraction), A (AND logique), O (OR logique), E (EOR/XOR).

Les deux opérandes doivent être fournis ensemble, séparés par une virgule. Le résultat s'affiche au format RRRR C=b (résultat 16 bits + bit de retenue).

* + 4000 seul (un seul opérande) → erreur ? — le second opérande après la virgule est obligatoire.

Exemples :

Utile pour calculer des adresses, des offsets ou vérifier des plages mémoire sans sortir du moniteur.


: aaaa bb bb bb bb bb bb bb bb — Enter (Saisir des octets en mémoire)

Écrit 8 octets hexadécimaux en mémoire à partir de l'adresse aaaa, affiche la ligne écrite, puis propose l'adresse suivante pour continuer la saisie. BREAK pour revenir au prompt.

: aaaa seul (sans octets) → ne produit rien.

Exemple :

Pour saisir une grande zone, continuer ligne par ligne : chaque ENTRÉE avance de 8 octets. Pour saisir moins de 8 octets, utiliser la commande I.

Limitation : : vérifie chaque octet après écriture en relisant l’adresse. Cette vérification échoue sur les registres hardware (POKEY $D200–$D20F, GTIA $D000–$D01F, ANTIC $D400–$D40F, PIA $D300–$D30F) car lecture et écriture correspondent à des registres physiques différents. Pour écrire dans le hardware, placer le code machine en RAM puis l’exécuter avec G.


, aaaa bb [bb ...] — Enter with Disassembly (Saisir avec désassemblage)

Écrit des octets hexadécimaux en mémoire à partir de aaaa et affiche le désassemblage 6502 correspondant. Contrairement à :, le nombre d'octets par ligne est libre (pas limité à 8). Mode interactif continu : après chaque ligne, ATAMON affiche le désassemblage et propose l'adresse suivante. BREAK pour revenir au prompt.

Exemples :

Idéal pour entrer du code assembleur et vérifier immédiatement que les opcodes sont corrects.


7. Variables internes (page zéro)

AdresseNom localRôle
$DA-$DBPTR_STARTAdresse de début 16 bits (argument 1)
$DC-$DDPTR_ENDAdresse de fin 16 bits (argument 2)
$DE-$DFPTR_DESTAdresse de destination 16 bits (argument 3)
$E0MODE0 = mode normal, ≠0 = mode inverse
$E4TEMP_ATemporaire / sauvegarde accumulateur
$E5TEMP_BCompteur / temporaire
$E7COL_CTRCompteur de colonnes pour l'affichage hex (0-6)
$EBTEMP_CTemporaire affichage
$F2BUF_PTRPointeur dans le buffer $4E3C
$F3-$F4FP_PTRPointeur vers zone Math ROM (virgule flottante)

8. Sous-routines principales

AdresseDescription
$401CSAVE_CPU : Sauvegarde l'état du 6502 (accumulateur, X, Y, flags, adresse d'exécution, pile)
$4054PRINT_HEADER : Affiche la bannière et l'en-tête des registres
$4064CMD_LOOP : Boucle principale de lecture/dispatch des commandes
$40B5CLR_RANGE : Remet à zéro les registres d'adresse DA-DF
$40C5DUMP_8 : Affiche 8 octets en hexadécimal
$40DBFILTER_CHAR : Filtre un caractère ATASCII (affichable / non-affichable)
$4127ADD16 : Additionne A à l'adresse 16 bits DA:DB
$4133DO_CIO : Appelle CIO ($E456) avec X=numéro IOCB×16
$41DDDO_SIO_DISK : Envoie une commande SIO disque via DSKINV ($E453)
$41E8FIND_CMD : Cherche un caractère dans la table de commandes $4F8D
$41F7GET_CHAR : Lit le prochain caractère du buffer d'entrée
$422ASKIP_SP : Avance le pointeur buffer en sautant les espaces
$423DREAD_BYTE : Lit 2 chiffres hex → octet en A
$4256READ_ADDR : Lit 4 chiffres hex → adresse 16 bits en A(hi) Y(lo)
$4280READ_BIN : Lit 8 chiffres binaires → octet en A
$42C7SET_FNAME : Configure l'adresse du nom de fichier dans l'IOCB
$42CFSET_BUFADDR : Configure l'adresse du buffer dans l'IOCB
$42E9OPEN_EDITOR : Ouvre le canal 0 sur E: (éditeur écran)
$4330PRINT_HEX8 : Affiche un octet sous forme de 2 chiffres hex
$4349NEWLINE_REGS : Saut de ligne + affichage des registres
$4373NEWLINE : Envoie un retour chariot ($9B) sur E:
$4399PRINT_CHAR : Affiche un caractère ATASCII via CIO
$44A4FP_TO_STR : Conversion virgule flottante → chaîne (Math ROM IFP+FASC)
$44C5SET_FP_PTR : Initialise le pointeur zone flottante ($4D99)

9. Utilisation du système Atari

ATAMON utilise les services OS suivants :

ServiceAdresseUtilisation
CIO — Central I/O$E456 (CIOV)Lecture/écriture écran, fichiers
SIO — Serial I/O disque$E453 (DSKINV)Accès secteurs disque
Math ROM IFP$D9AAConversion entier → flottant
Math ROM FASC$D8E6Conversion flottant → ASCII
VBREAK$0206-$0207Vecteur BRK (entrée moniteur sur point d'arrêt)

Structure des IOCBs utilisés :

Structure DCB pour les accès disque ($0300-$030B) :


10. Tables de données internes

Bannière et format registres ($4F44)

La chaîne stockée en mémoire est :

ATAMON pointe sur le début de la partie PC SP AC XR YR NV\BDIZC (à $4F71) pour afficher l'en-tête de colonnes — la partie E:P1: est dans la chaîne binaire mais n'est pas affichée séparément. L'affichage à l'écran (40 colonnes) donne :

Table des chiffres hex + commandes ($4F8D)

Table de dispatch ($4FC8)

Paires d'octets (adresse - 1) (lo, hi) pour chaque handler de commande. Le dispatch utilise le trick RTS : l'adresse du handler moins 1 est poussée sur la pile (hi d'abord, puis lo), puis RTS est exécuté. Le 6502 récupère l'adresse, l'incrémente de 1 et saute au handler. Cela évite un tableau de JMP et économise quelques octets.

Exemple : commande 'G' (5e caractère dans $4F9D) → ATAMON lit les 2 octets à $4FC8 + (index × 2), les pousse en ordre inversé, et fait RTS vers le handler.

Tables du désassembleur intégré ($4FF9+)

ATAMON possède son propre mini-désassembleur (commande D). Il utilise deux tables internes :

  1. Mnémoniques 6502 : entrées de 3 lettres codées (56 mnémoniques officiels)

  2. Modes d'adressage : table des tailles et formats d'opérandes pour chaque opcode

Ces tables couvrent uniquement les opcodes officiels du 6502. Les opcodes illégaux ne sont pas reconnus par le désassembleur d'ATAMON et seraient affichés de manière incorrecte.

→ Voir Annexe B en fin de document pour la liste complète des 56 mnémoniques reconnus.

Note : dans le binaire ATAMON, les adresses $4F43–$52B1 contiennent des données (chaînes texte, tables de caractères, vecteurs). Un désassembleur linéaire interprète ces octets comme des instructions — dont beaucoup tombent dans la catégorie des opcodes non documentés du 6502 ($02 *KIL, $03 *SLO, $3A *NOP, etc.). Il s'agit de faux positifs dus à la nature des données, pas d'utilisation intentionnelle d'opcodes illégaux dans le code d'ATAMON.


11. Comment utiliser ATAMON

Lancement

Depuis le DOS Atari, sélectionner L. BINARY LOAD puis taper D:ATAMON. ATAMON affiche sa bannière (*C + registres) et le curseur Atari attend votre première commande.

Touches spéciales

ToucheEffet dans ATAMON
RETURNValide la commande en cours
BREAKInterrompt un programme en cours d'exécution et renvoie le contrôle à ATAMON (via le vecteur VBREAK/BRK)
RESETRéinitialisation matérielle de l'Atari — éviter : efface la mémoire et détruit le programme chargé
DELETE / BACK S.Efface le dernier caractère saisi
ESCPeut annuler la saisie en cours selon le contexte CIO/éditeur

Note : ATAMON repose sur CIO (éditeur écran E:) pour la lecture des commandes. Les fonctions d'édition standard de l'éditeur Atari (déplacement curseur, effacement) sont disponibles avant de valider avec RETURN.

Affichage typique au démarrage

Exemples de session


12. Notes historiques

ATAMON (abréviation de ATAri MONitor) est un moniteur langage machine commercialisé par ATARI en 1983 en Allemagne, la même année que le lancement de l'Atari 800XL.

La disquette DXG 5724 contient également :

Ces trois programmes constituent une disquette complète : DOS + utilitaires + moniteur de débogage.

L'analyse de la disquette n'a révélé aucune protection particulière. L'analyse des 720 secteurs confirme l'absence de secteurs fantômes (phantom_count = 0 pour tous les secteurs), de mauvais CRC intentionnels ou de tout autre mécanisme de protection par copie. La disquette originale d'ATAMON n'était pas protégée contre la copie.



13. Notes techniques sur le désassemblage

Opcodes illégaux connus du 6502

GroupeOpcodesDescription
*KIL$02,$12,$22,$32,$42,$52,...Bloque le CPU
*NOP$1A,$3A,$5A,$7A,$DA,$FA (1 octet)No-operation illégal
*NOP$04,$44,$64,$14,$34,$54,... (2-3 octets)NOP avec opérande ignoré
*SLO$03,$07,$0F,$13,$17,$1B,$1FASL mémoire puis ORA A
*RLA$23,$27,$2F,$33,$37,$3B,$3FROL mémoire puis AND A
*SRE$43,$47,$4F,$53,$57,$5B,$5FLSR mémoire puis EOR A
*RRA$63,$67,$6F,$73,$77,$7B,$7FROR mémoire puis ADC A
*LAX$A3,$A7,$AF,$B3,$B7,$BFCharge A et X simultanément
*SAX$83,$87,$8F,$97Stocke A AND X
*DCP$C3,$C7,$CF,$D3,$D7,$DB,$DFDEC mémoire puis CMP A
*ISC$E3,$E7,$EF,$F3,$F7,$FB,$FFINC mémoire puis SBC A
Divers$0B/$2B *ANC, $4B *ALR, $6B *ARR, $CB *SBX, $9B *TAS, $9C *SHYDiverses combinaisons

Bug JMP indirect

Le 6502 a un bug matériel : JMP (addr) lit incorrectement le byte de poids fort si addr se termine par $FF. Exemple : JMP ($10FF) lit $10FF (lo) et $1000 (hi) au lieu de $1100. Dans ATAMON, les deux JMP (ind) présents ($47BF JMP (DOSVEC) et $47E4 JMP ($4F41)) n'ont pas d'adresses se terminant par $FF — pas de bug dans ce programme. Note : JMP ($4F41) est le saut d'exécution vers l'adresse sauvegardée (PCL à $4F41, PCH à $4F42).



Annexe A — Glossaire de la page zéro ($00$FF)

La page zéro est la première tranche de 256 octets de la RAM ($00 à $FF). Sur le 6502, elle est spéciale à deux titres :

L'OS Atari et ATAMON s'en servent intensivement. Voici les emplacements les plus importants, expliqués pour un débutant :

Variables OS Atari (réservées par le système)

AdresseNom OSCe que c'est
$08COLCRSColonne du curseur (0 à 39). L'OS met à jour cette valeur chaque fois que vous tapez un caractère. Vous pouvez la modifier pour déplacer le curseur horizontalement.
$09ROWCRSLigne du curseur (0 à 24). Même principe pour la ligne.
$0B$0CSAVMSCAdresse de la mémoire écran (2 octets). Pointe vers le premier octet de l'image affichée. Modifier directement cette zone modifie l'écran en temps réel.
$14$16RTCLOKHorloge temps réel (3 octets). Incrémentée automatiquement 60 fois par seconde par l'OS (à chaque interruption verticale). Utile pour mesurer le temps ou créer des délais.
$55ATRACTÉconomiseur d'écran. L'OS incrémente ce compteur à chaque seconde d'inactivité clavier. Quand il dépasse 127, les couleurs deviennent atténuées pour protéger l'écran. Remettre à 0 désactive l'économiseur.
$6ARAMTOPLimite haute de la RAM disponible. Valeur en pages (×256). Indique jusqu'où la RAM est utilisable par les programmes. Modifiable pour réserver de la mémoire haute.
$80$9FFR0Registre flottant 0 (6 octets). Zone de travail de la Math ROM pour les calculs en virgule flottante. Écrasé à chaque appel de la Math ROM.
$A0$A5FR1Registre flottant 1 (6 octets). Second registre flottant, utilisé comme opérande dans les calculs.

Variables utilisées par ATAMON

Ces adresses sont réservées par ATAMON pendant qu'il est chargé. Les modifier avec : ou , peut perturber le fonctionnement du moniteur.

AdresseNom ATAMONCe que c'est
$DA$DBPTR_STARTAdresse de début de l'opération en cours (argument 1 des commandes M, D, F, T…).
$DC$DDPTR_ENDAdresse de fin (argument 2).
$DE$DFPTR_DESTAdresse de destination (argument 3, utilisé par T).
$E0MODEMode d'affichage : 0 = normal, ≠ 0 = mode inverse (pour M).
$E4TEMP_ATemporaire : sauvegarde de l'accumulateur entre deux opérations internes.
$E5TEMP_BCompteur temporaire (boucles internes).
$E7COL_CTRCompteur de colonnes pour l'affichage hex (0 à 6, pour aligner 8 octets par ligne).
$F2BUF_PTRPointeur dans le buffer de commande ($4E3C). Indique où en est la lecture de la ligne saisie.

Conseil : utilisez M 0000 00FF pour visualiser l'intégralité de la page zéro et observer comment ces valeurs changent selon les opérations en cours.


Documentation reconstituée par analyse du binaire XEX et désassemblage 6502. Références : De Re Atari (APX 90009), Atari 8-bit FAQ, Altirra 4.40 source, AtariWiki — 6502 Assembly Code, Unused Opcodes, OS ROM listing, Atari Custom Display Lists (Atarimania), Display Lists Simplified (Atari magazines), ANTIC registers (xmission.com/~trevin).


Annexe B — Les 56 mnémoniques officiels du 6502

Le désassembleur intégré d'ATAMON (commande D) reconnaît exactement ces 56 instructions.

Chargement / stockage

MnémoniqueNom completDescriptionExemple
LDALoad AccumulatorCharge une valeur dans l'accumulateur ALDA #$41 → A = 'A'
LDXLoad XCharge une valeur dans le registre XLDX #$00 → X = 0 (init boucle)
LDYLoad YCharge une valeur dans le registre YLDY #$08 → Y = 8 (compteur)
STAStore AccumulatorÉcrit A en mémoireSTA $D800 → envoie la couleur vers GTIA
STXStore XÉcrit X en mémoireSTX $00 → sauvegarde X en page zéro
STYStore YÉcrit Y en mémoireSTY $CB → sauvegarde Y dans une variable

Transferts entre registres

MnémoniqueNom completDescriptionExemple
TAXTransfer A to XCopie A dans XLDA #$10 / TAX → X = 16
TAYTransfer A to YCopie A dans YTAY → Y ← A (pour indexer un tableau)
TXATransfer X to ACopie X dans ATXA / CLC / ADC #$40 → calcul d'adresse
TYATransfer Y to ACopie Y dans ATYA / STA $CB → sauvegarde Y comme valeur
TSXTransfer SP to XCopie le pointeur de pile SP dans XTSX → X = valeur actuelle de la pile
TXSTransfer X to SPCopie X dans le pointeur de pile SPLDX #$FF / TXS → réinitialise la pile

Pile

MnémoniqueNom completDescriptionExemple
PHAPush AccumulatorEmpile A (sauvegarde)PHA avant JSR, pour ne pas perdre A
PLAPull AccumulatorDépile dans A (restaure)PLA après JSR, restaure A
PHPPush Processor statusEmpile le registre d'état PPHP / SEI / … / PLP : section critique
PLPPull Processor statusDépile dans PPLP restaure les flags sauvés par PHP

Arithmétique

MnémoniqueNom completDescriptionExemple
ADCAdd with CarryA ← A + opérande + CCLC / LDA #$10 / ADC #$05 → A = $15
SBCSubtract with CarryA ← A − opérande − (1−C)SEC / LDA #$10 / SBC #$03 → A = $0D

Incrémentation / décrémentation

MnémoniqueNom completDescriptionExemple
INCIncrement memory+1 à un octet en mémoireINC $0600 → incrémente le score en $0600
INXIncrement XX ← X + 1INX / CPX #$10 / BNE LOOP : boucle 16×
INYIncrement YY ← Y + 1INY / LDA (PTR),Y : avance dans un tableau
DECDecrement memory−1 à un octet en mémoireDEC $CB → décrémente un compteur de vies
DEXDecrement XX ← X − 1LDX #$08 / LOOP: DEX / BNE LOOP : attend 8×
DEYDecrement YY ← Y − 1DEY / BNE LOOP : reboucle tant que Y ≠ 0

Opérations logiques

MnémoniqueNom completDescriptionExemple
ANDLogical ANDA ← A AND opérande (bit à bit)AND #$0F → garde les 4 bits bas (nibble)
ORALogical ORA ← A OR opérande (bit à bit)ORA #$80 → force le bit 7 à 1 (inverse vidéo)
EORExclusive ORA ← A XOR opérande (bit à bit)EOR #$FF → inverse tous les bits
BITBit testZ ← A AND mem ; N,V ← bits 7,6 de memBIT $D018 → teste un registre sans modifier A

Décalages et rotations

MnémoniqueNom completDescriptionExemple
ASLArithmetic Shift LeftDécale à gauche (× 2) ; bit 7 → CASL A → A × 2
LSRLogical Shift RightDécale à droite (÷ 2) ; bit 0 → CLSR A → A ÷ 2
ROLRotate LeftRotation gauche à travers CROL A → × 2 + ancien C (multiplication 16 bits)
RORRotate RightRotation droite à travers CROR A → ÷ 2 + ancien C en bit 7

Comparaisons

MnémoniqueNom completDescriptionExemple
CMPCompare AA − opérande → N,Z,C (A non modifié)CMP #$9B / BEQ EOL → fin de ligne ATASCII ?
CPXCompare XX − opérande → N,Z,CCPX #$10 / BNE LOOP → fin à X=16
CPYCompare YY − opérande → N,Z,CCPY #$00 / BEQ DONE → fin à Y=0

Branchements conditionnels

Tous les branchements sont relatifs (déplacement signé de −128 à +127 octets depuis l'instruction suivante).

MnémoniqueNom completConditionExemple
BCCBranch if Carry ClearC = 0ADC #$01 / BCC OK → pas de retenue
BCSBranch if Carry SetC = 1CMP #$80 / BCS HIGH → A ≥ $80
BEQBranch if EqualZ = 1 (résultat nul)CMP #$41 / BEQ FOUND → trouvé 'A'
BNEBranch if Not EqualZ = 0 (résultat non nul)DEX / BNE LOOP → boucle classique
BMIBranch if MinusN = 1 (bit 7 = 1)BIT $D40B / BMI VBLANK → VBlank actif
BPLBranch if PlusN = 0 (bit 7 = 0)LDA $CB / BPL OK → valeur positive
BVCBranch if oVerflow ClearV = 0ADC #$01 / BVC OK → pas de débordement signé
BVSBranch if oVerflow SetV = 1ADC #$40 / BVS ERR → débordement signé détecté

Sauts et appels

MnémoniqueNom completDescriptionExemple
JMPJumpSaut inconditionnel (absolu ou indirect)JMP $4000 → relance ATAMON
JSRJump to SubroutineEmpile adresse retour, puis sauteJSR $E456 → appelle CIO
RTSReturn from SubroutineDépile adresse retour + 1 et y sauteRTS → fin de sous-routine
RTIReturn from InterruptDépile P puis compteur de programmeRTI → fin de handler VBI ou DLI

Interruption logicielle

MnémoniqueNom completDescriptionExemple
BRKBreakDéclenche une interruption logicielle ; empile PC+2 et P, saute via le vecteur OS ($0206/$0207). C'est le mécanisme central d'ATAMON pour les points d'arrêt.BRK → retour immédiat dans ATAMON

Gestion des flags

MnémoniqueNom completDescriptionExemple
CLCClear CarryC ← 0CLC / ADC #$01 → addition sans retenue parasite
SECSet CarryC ← 1SEC / SBC #$01 → soustraction correcte
CLDClear DecimalD ← 0 (désactive BCD)CLD au démarrage d'une routine arithmétique
SEDSet DecimalD ← 1 (active BCD)SED → rarement utile sur Atari
CLIClear Interrupt disableI ← 0 (autorise IRQ)CLI → autorise VBI, POKEY, etc.
SEISet Interrupt disableI ← 1 (masque IRQ)SEI → protège une section critique
CLVClear oVerflowV ← 0CLV → repart d'un état connu avant arithmétique signée

Divers

MnémoniqueNom completDescriptionExemple
NOPNo OperationNe fait rien ; avance le compteur de programme d'1 octet. Utilisé pour neutraliser une instruction ou combler un espace en mémoire.NOP / NOP / NOP pour remplacer un JSR $xxxx de 3 octets

Annexe C — Opcodes illégaux / non documentés du 6502

Ces opcodes n'existent pas dans la spécification officielle MOS Technology du 6502. Ils sont le résultat de combinaisons non prévues de la logique interne du processeur. Leur comportement est reproduit par le désassembleur ATAMON (commande D), qui les affiche précédés d'un *.

Attention : la plupart sont instables selon la révision du processeur ou la tension d'alimentation. À éviter en code de production ; utiles pour analyser des programmes anciens qui les exploitent.

Instructions fatales

MnémoniqueNoms alt.DescriptionOpcodes
*KILJAM, HLTBloque définitivement le CPU — le bus de données se fige, seul un RESET matériel peut relancer la machine.$02 $12 $22 $32 $42 $52 $62 $72 $92 $B2 $D2 $F2

Instructions lecture-modification-écriture combinées

Ces opcodes effectuent deux opérations en une : une modification en mémoire (ou sur l'accumulateur) puis une opération logique/arithmétique avec A.

MnémoniqueNoms alt.DescriptionModesOpcodes
*SLOASOASL sur l'octet mémoire, puis ORA avec Ainx zp abs iny zpx aby abx$03 $07 $0F $13 $17 $1B $1F
*RLAROL sur l'octet mémoire, puis AND avec Ainx zp abs iny zpx aby abx$23 $27 $2F $33 $37 $3B $3F
*SRELSELSR sur l'octet mémoire, puis EOR avec Ainx zp abs iny zpx aby abx$43 $47 $4F $53 $57 $5B $5F
*RRAROR sur l'octet mémoire, puis ADC avec Ainx zp abs iny zpx aby abx$63 $67 $6F $73 $77 $7B $7F
*DCPDCMDEC sur l'octet mémoire, puis CMP avec Ainx zp abs iny zpx aby abx$C3 $C7 $CF $D3 $D7 $DB $DF
*ISCISB, INSINC sur l'octet mémoire, puis SBC avec Ainx zp abs iny zpx aby abx$E3 $E7 $EF $F3 $F7 $FB $FF

Chargement / stockage combinés

MnémoniqueNoms alt.DescriptionModesOpcodes
*LAXCharge la même valeur simultanément dans A et X — équivalent LDA + TAX en un seul opcodeinx zp abs iny zpy aby$A3 $A7 $AF $B3 $B7 $BF
*SAXAXSÉcrit en mémoire la valeur de A AND X (sans modifier les flags)inx zp abs zpy$83 $87 $8F $97

Instructions sur l'accumulateur

MnémoniqueNoms alt.DescriptionOpcodeStabilité
*ANCAND immédiat sur A, puis copie le bit 7 dans le flag Carry (comme un ASL sans modifier la mémoire)$0B $2Bstable
*ALRASRAND immédiat sur A, puis LSR sur A (décalage logique droite)$4Bstable
*ARRAND immédiat sur A, puis ROR sur A — avec effets complexes sur C et V (pas identiques à ROR normal)$6Bstable
*SBXAXS(A AND X) - imm → X, sans emprunt (affecte C, Z, N)$CBstable
*SBCDoublon du SBC #imm officiel ($E9) — comportement identique$EBstable
*ANEXAAA = (A OR $EE) AND X AND imm — résultat dépend du processeur$8Binstable
*LXALAX #(A OR $EE) AND imm → A et X — résultat dépend du processeur$ABinstable

Instructions mémoire instables (dépendent de addr_hi)

MnémoniqueNoms alt.DescriptionOpcodeStabilité
*TASXAS, SHSSP = A AND X ; écrit SP AND (addr_hi+1) en mémoire$9Binstable
*SHYA11YÉcrit Y AND (addr_hi+1) en mémoire$9Cinstable
*SHXA11XÉcrit X AND (addr_hi+1) en mémoire$9Einstable
*SHAAXAÉcrit A AND X AND (addr_hi+1) en mémoire$93 $9Finstable
*LASLARA = X = SP = mémoire AND SP$BBinstable

NOP illégaux (multi-octets, sans effet)

Ces opcodes se comportent comme un NOP (ne font rien de visible) mais consomment 2 ou 3 octets — le CPU les lit et les ignore.

MnémoniqueModeTailleOpcodes
*NOPimp (1 octet)1$1A $3A $5A $7A $DA $FA
*NOPzp (2 octets)2$04 $44 $64
*NOPzpx (2 octets)2$14 $34 $54 $74 $D4 $F4
*NOPabs (3 octets)3$0C
*NOPabx (3 octets)3$1C $3C $5C $7C $DC $FC

Annexe D — Étiquettes Atari connues

Adresses symboliques reconnues par le désassembleur ATAMON (commande D). Elles apparaissent dans le désassemblage à la place de l'adresse hexadécimale brute.

Page zéro — Variables OS ($00$FF)

AdresseÉtiquetteDescription
$000A$000BDOSVECVecteur DOS — adresse de saut vers le DOS (2 octets lo/hi). JMP (DOSVEC) quitte le programme et retourne au DOS.
$000C$000DDOSINIVecteur d'initialisation DOS — appelé à chaque warm reset.
$0010POKMSKMasque d'activation des interruptions POKEY (IRQ). Chaque bit active un type d'IRQ (timer, série…).
$0012$0014RTCLOKHorloge temps réel (3 octets). Incrémentée 60×/s par le VBI de l'OS.
$0020$002BZIOCBIOCB zéro — copie de travail de l'IOCB du canal courant pendant un appel CIO.
$002CSTATUSCode de statut de la dernière opération SIO ou CIO.
$002E$002FBUFRLO/HIAdresse du buffer d'entrée/sortie (2 octets). Utilisé par le DCB SIO et CIO.
$0030$0031BFENLO/HIAdresse de fin du buffer (2 octets).
$0036$0037BYTLO/HINombre d'octets transférés lors du dernier appel SIO/CIO (2 octets).

Page 2 — Vecteurs d'interruption ($0200$02FF)

AdresseÉtiquetteDescription
$0200$0201VDSLSTVecteur DLI (Display List Interrupt) — appelé à chaque instruction DLI dans la display list ANTIC.
$0202$0203VPRCEDVecteur interruption "proceed" (entrée série).
$0204$0205VINTERVecteur interruption "interrupt" (entrée série).
$0206$0207VBREAKVecteur BRK — appelé quand le CPU exécute BRK. ATAMON l'installe pour capturer les points d'arrêt.
$0208$0209VKEYBDVecteur interruption clavier (touche pressée).
$020A$020BVSERINVecteur réception série (POKEY).
$020C$020DVSERORVecteur émission série (POKEY).
$020E$020FVSEROCVecteur fin d'émission série.
$0210$0211VTIMR1Vecteur timer 1 POKEY.
$0212$0213VTIMR2Vecteur timer 2 POKEY.
$0214$0215VTIMR4Vecteur timer 4 POKEY.
$0216$0217VIMIRQVecteur IRQ générique (non utilisé par l'OS).
$0222$0223VVBLKIVecteur VBI immédiat — appelé en début de blanking vertical (~3 800 cycles disponibles).
$0224$0225VVBLKDVecteur VBI différé — appelé après SYSVBV (~20 000 cycles disponibles, plus sûr).
$0226$0227CDTMA1Vecteur timer software 1 (décrémenté par le VBI).
$0228$0229CDTMA2Vecteur timer software 2.
$022ACDTMF3Flag timer software 3.
$022CCDTMF4Flag timer software 4.
$022EBRKKEYFlag touche BREAK : $00 si BREAK pressé, sinon $80.
$022FSDMCTLShadow DMACTL — copié vers $D400 (ANTIC) à chaque VBI. Contrôle la largeur de l'écran et l'activation du DMA.
$0230$0231SDLSTL/HShadow display list (lo/hi) — copié vers $D402/$D403 au VBI. Pointe vers la display list ANTIC active.
$023BATRACTCompteur économiseur d'écran. Incrémenté par l'OS chaque seconde d'inactivité clavier. Au-delà de 127, les couleurs s'atténuent. Remettre à 0 désactive l'économiseur.
$026FGPRIORShadow PRIOR — copié vers $D01B (GTIA) au VBI. Détermine la priorité d'affichage joueurs/missiles/fond.
$02C0$02C8COLPF0COLPM0Couleurs des playfields et joueurs (shadows des registres GTIA couleur).
$02C8COLBKCouleur du fond (background). Shadow du registre GTIA $D01A.
$02E0$02E1RUNADAdresse d'exécution du programme chargé (XEX). L'OS saute à cette adresse après le chargement.
$02E2$02E3INITADAdresse d'initialisation — appelée après chaque segment XEX marqué INITAD.
$02E4RAMSIZTaille de la RAM en pages (×256). Valeur lue au démarrage.
$02E5RAMTOPLimite haute de la RAM utilisable (en pages).
$02E7$02E8MEMLOLimite basse de la RAM libre (2 octets). ATAMON la positionne à $5300 pour protéger son code.
$02E9$02EAMEMTOPLimite haute de la RAM libre (2 octets).
$02F4CHBASShadow CHBASE — copié vers $D408 (ANTIC) au VBI. Sélectionne la police de caractères (page haute de l'adresse).

Page 3 — DCB SIO ($0300$035F)

AdresseÉtiquetteDescription
$0300DDEVICNuméro du périphérique SIO (ex : $31 = lecteur de disque D1:).
$0301DUNITNuméro d'unité (1 à 4 pour D1: à D4:).
$0302DCOMNDCommande SIO (ex : $52 = Read sector, $57 = Write sector).
$0303DSTATSSens : $40 = lecture, $80 = écriture, $00 = statut seul.
$0304$0305DBUFLO/HIAdresse du buffer de données (2 octets lo/hi).
$0306DTIMLOTimeout SIO en unités VBI (~1/60 s). Valeur typique : $0F (15 VBI).
$0308$0309DBYTLO/HINombre d'octets à transférer (2 octets).
$030A$030BDAUX1/2Paramètres auxiliaires (ex : numéro de secteur lo/hi pour le disque).
$0340$034FIOCB0IOCB canal 0 (éditeur écran E: — utilisé par ATAMON pour la saisie).
$0350$035FIOCB1IOCB canal 1 (libre).

Registres matériels — GTIA ($D000)

AdresseÉtiquetteDescription
$D000HPOSP0Position horizontale joueur 0 (missile).
$D001HPOSP1Position horizontale joueur 1.
$D002HPOSP2Position horizontale joueur 2.
$D003HPOSP3Position horizontale joueur 3.
$D004HPOSM0Position horizontale missile 0.
$D01BPRIORPriorité d'affichage joueurs/missiles/playfields. Bit 7 = mode GTIA spécial.
$D01DGRACTLActivation du DMA joueurs/missiles.
$D01FCONSOLTouches console (lecture) : bits 2-0 = START/SELECT/OPTION (0 = pressé). En écriture : contrôle le haut-parleur interne.

Registres matériels — POKEY ($D200)

AdresseÉtiquetteDescription
$D200AUDF1Fréquence canal audio 1 (valeur 0–255, fréquence inversement proportionnelle).
$D201AUDC1Contrôle canal 1 : bits 7-4 = volume, bits 3-0 = distorsion/waveform.
$D202AUDF2Fréquence canal audio 2.
$D203AUDC2Contrôle canal 2.
$D204AUDF3Fréquence canal audio 3.
$D205AUDC3Contrôle canal 3.
$D206AUDF4Fréquence canal audio 4.
$D207AUDC4Contrôle canal 4.
$D208AUDCTLContrôle global audio : fréquence d'horloge (64 kHz / 15 kHz / 1,79 MHz), canaux 16 bits, filtre passe-haut.
$D20ASTIMERÉcriture : remet les timers POKEY à zéro.
$D20ESEROUTSortie série (écriture).
$D20FSKCTLContrôle série POKEY : réinitialisation, mode synchronisation.

Registres matériels — PIA ($D300)

AdresseÉtiquetteDescription
$D300PORTAPort A : joystick 1 (bits 3-0) et joystick 2 (bits 7-4). Bit = 0 si direction active.
$D301PORTBPort B : sur 800XL, contrôle la banque mémoire OS ROM (bit 0) et BASIC (bit 1).
$D302PACTLContrôle port A (direction bits, interruptions).
$D303PBCTLContrôle port B.

Registres matériels — ANTIC ($D400)

AdresseÉtiquetteDescription
$D400DMACTLContrôle DMA : active/désactive le DMA, définit la largeur de l'écran (narrow/normal/wide) et le DMA joueurs/missiles.
$D401CHACTLContrôle caractères : vidéo inverse, blanking des lignes hautes/basses d'une cellule.
$D402$D403DLISTL/HAdresse de la display list (lo/hi). ANTIC lit cette liste pour construire l'image.
$D404HSCROLScrolling horizontal fin (0–15 colour clocks).
$D405VSCROLScrolling vertical fin (0–15 lignes).
$D407PMBASEBase des joueurs/missiles (octet haut de l'adresse, page de 1 Ko ou 2 Ko selon DMACTL).
$D408CHBASEBase de la police de caractères (octet haut ; la police commence à cette page × 256).
$D409WSYNCWait for sync — écriture : le CPU se bloque jusqu'à la fin de la ligne de balayage courante (synchronisation raster).
$D40BVCOUNTCompteur de ligne de balayage actuelle (lecture seule, 0–131).
$D40ENMIENActivation NMI : bit 7 = DLI, bit 6 = VBI.
$D40FNMIRESÉcriture : réinitialise les flags NMI. Lecture : identifie la source NMI (bit 7 = DLI, bit 6 = VBI).

Points d'entrée OS ROM ($E4xx)

AdresseÉtiquetteDescription
$E450DISKIVInitialisation du handler disque.
$E453DSKINVAppel SIO disque — exécute la commande décrite dans le DCB ($0300+). Utilisé par ATAMON pour les commandes E et W.
$E456CIOVCIO (Central I/O) — point d'entrée principal des entrées/sorties. Utilisé par ATAMON pour lire les commandes et écrire les résultats.
$E459SIOVSIO (Serial I/O) — transfert série bas niveau.
$E45CSETVBVInstalle un handler VBI (immédiat ou différé).
$E45FSYSVBVHandler VBI système (OS) — à appeler depuis un VBI immédiat pour chaîner le VBI différé.
$E462XITVBVSortie du VBI (fin d'un handler VBI).
$E465SIOINVInitialisation SIO.
$E474WARMSVWarm restart — réinitialise l'OS sans effacer la RAM.
$E477COLDSVCold start — réinitialisation complète (efface la RAM).

Math ROM ($D8xx)

AdresseÉtiquetteDescription
$D800AFPASCII → virgule flottante (chaîne pointée par $F3/$F4 → FR0).
$D8E6FASCVirgule flottante → ASCII (FR0 → chaîne pointée par $F3/$F4).
$D9AAIFPEntier 16 bits → virgule flottante (valeur en $D4/$D5 → FR0).
$D9D2FPIVirgule flottante → entier 16 bits (FR0 → $D4/$D5).
$DA44ZFR0Met FR0 à zéro.
$DA60FSUBSoustraction flottante : FR0 ← FR0 − FR1.
$DA66FADDAddition flottante : FR0 ← FR0 + FR1.
$DADBFMULMultiplication flottante : FR0 ← FR0 × FR1.
$DB28FDIVDivision flottante : FR0 ← FR0 / FR1.
$DD40PLYEVLÉvaluation polynomiale (pour sin, cos, exp…).
$DD89FLD0RCharge FR0 depuis l'adresse en (X,Y).
$DD98FLD1RCharge FR1 depuis l'adresse en (X,Y).
$DDA7FSTORStocke FR0 à l'adresse en (X,Y).
$DDB6FMOVEFR1 ← FR0.

Annexe E — Registres hardware Atari 800XL — référence rapide

Récapitulatif des registres matériels des quatre puces customs de l'Atari 800XL, avec leur usage typique en programmation.

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

AdresseNomR/WUsage
$D000$D003HPOSPnWPosition horizontale des 4 joueurs (sprites)
$D004$D007HPOSMnWPosition horizontale des 4 missiles
$D008$D00BSIZEPnWTaille des joueurs (1×, 2×, 4×)
$D00CSIZEMWTaille des missiles
$D00D$D010GRAFPnWForme du joueur n (8 bits = 8 pixels)
$D011GRAFMWForme des 4 missiles (2 bits chacun)
$D012$D015COLPMnWCouleur joueur n
$D016$D019COLPFnWCouleur playfield 0–3
$D01ACOLBKWCouleur fond
$D01BPRIORWPriorité joueurs/playfields, mode GTIA
$D01CVDELAYWDélai vertical missiles/joueurs (résolution fine)
$D01DGRACTLWActivation DMA joueurs/missiles
$D01EHITCLRWÉcriture : remet à zéro les registres de collision
$D01FCONSOLR/WLecture : touches START/SELECT/OPTION. Écriture : haut-parleur

POKEY — Potentiometer and Keyboard ($D200$D20F)

AdresseNomR/WUsage
$D200$D207AUDFn / AUDCnWFréquence et contrôle des 4 canaux audio (paires AUDF/AUDC)
$D208AUDCTLWContrôle global audio (horloge, canaux 16 bits, filtres)
$D209STIMERWRemet les timers à zéro
$D20ASKRESWRemet le registre de statut série à zéro
$D20BPOTGOWDémarre la conversion des potentiomètres (paddles)
$D200$D207POTnRValeur des 8 potentiomètres (paddles)
$D208ALLPOTRÉtat des conversions potentiomètres en cours
$D209KBCODERCode de la touche pressée (ATASCII interne)
$D20ARANDOMRGénérateur de nombres aléatoires (lecture seule)
$D20DSERINRDonnée reçue en série
$D20ESEROUTWDonnée à émettre en série
$D20FSKCTLWContrôle série (init, synchronisation, mode deux tons)

PIA — Peripheral Interface Adaptor ($D300$D303)

AdresseNomR/WUsage
$D300PORTAR/WJoystick 1 (bits 3-0) et joystick 2 (bits 7-4)
$D301PORTBR/WSur 800XL : banque mémoire OS (bit 0) et BASIC (bit 1)
$D302PACTLWContrôle direction bits et interruptions port A
$D303PBCTLWContrôle direction bits et interruptions port B

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

AdresseNomR/WUsage
$D400DMACTLWLargeur écran (40/48 couleurs), DMA ANTIC/joueurs actif
$D401CHACTLWInverse vidéo, blanking caractères
$D402$D403DLISTL/HWAdresse display list (lo/hi)
$D404HSCROLWScrolling horizontal fin (0–15 colour clocks)
$D405VSCROLWScrolling vertical fin (0–15 lignes)
$D407PMBASEWPage de base joueurs/missiles
$D408CHBASEWPage de base police caractères
$D409WSYNCWAttente fin de ligne raster (synchronisation CPU/vidéo)
$D40AVSCROLW(lecture VCOUNT si adresse $D40B)
$D40BVCOUNTRCompteur ligne raster courante
$D40C$D40DPENH/VRPosition crayon optique horizontal/vertical
$D40ENMIENWActivation NMI : bit 7 = DLI, bit 6 = VBI
$D40FNMIRESR/WLecture : source NMI. Écriture : reset flags NMI

Correction du bug de la commande C (patch)

Le bug

La commande C d'ATAMON V1.3 est buggée depuis sa publication en 1983. Quelle que soit la syntaxe utilisée, elle retourne toujours ? et n'écrit rien en mémoire.

Cause : Dans le code d'ATAMON, chaque commande qui prend plusieurs arguments doit, entre chaque argument, appeler la routine $43AE (SEPARATOR_CHECK). Cette routine lit et consomme la virgule , qui sépare les arguments dans la ligne de commande.

Le handler de la commande C (à l'adresse $4BE9) lit correctement l'adresse de destination via JSR $4256, mais appelle ensuite directement JSR $4280 (READ_BIN, qui lit les 8 bits) sans passer par $43AE. Résultat : READ_BIN lit la virgule , (code $2C) au lieu du premier chiffre binaire 0 ou 1. La virgule est écrite en mémoire ($2C = 44), puis le programme rencontre une erreur et affiche ?.

Toutes les autres commandes multi-arguments (F, T, V, L, H, I...) appellent correctement $43AE entre leurs arguments. C est la seule à l'omettre.

La correction

La correction consiste à ajouter l'appel manquant à $43AE sans modifier le code existant. Comme ATAMON occupe entièrement la zone $4000–$52B1, on installe un petit programme intermédiaire ("trampoline") dans le premier octet libre après le code : $52B2.

Étape 1 — Rediriger l'appel de READ_BIN

À l'adresse $4BF6, remplacer :

par :

Étape 2 — Installer le trampoline à $52B2

La boucle interne du handler C (à $4C05) appelle elle-même $43AE pour consommer la virgule entre les octets suivants. Le trampoline ne doit donc consommer la virgule qu'au premier appel (quand le compteur $E8 vaut 0), et appeler READ_BIN directement pour les appels suivants.

Sans ce test sur $E8, le trampoline essaierait de consommer une virgule déjà lue par $4C05, lirait le premier bit binaire à la place, et retournerait ? dès le deuxième octet.

Appliquer le patch

Le fichier Atamon - D7 - DXG 5724-Patched Atarinside.atr fourni avec ce document contient ATAMON avec cette correction déjà appliquée. Chargez-le dans votre émulateur ou copiez-le sur une disquette Atari à la place de l'original.

Pour regénérer le patch manuellement à partir du XEX original, le script Python patch_atamon.py automatise les deux étapes ci-dessus.


Sources documentaires

Processeur 6502

Documentation Atari 800XL

AtariWiki

Format de disque .PRO

Émulateur utilisé pour les tests