L aaaa,bbbb,xx — Locate Non-Matching (Localiser les octets différents)
C aaaa,bbbbbbbb — Code (Écrire des octets binaires en mémoire)
I aaaa,DdonnéesD — Input string (Saisir du texte en mémoire)
; aaaa BB BB BB BB XXXXXXXX — Set (Charger tous les registres d'un coup)
: aaaa bb bb bb bb bb bb bb bb — Enter (Saisir des octets en mémoire)
, aaaa bb [bb ...] — Enter with Disassembly (Saisir avec désassemblage)
Annexe E — Registres hardware Atari 800XL — référence rapide
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/
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 :
Regarder dans la mémoire : affichez n'importe quelle zone de la RAM de votre Atari, octet par octet, pour voir ce qu'elle contient.
Modifier la mémoire : changez des valeurs directement, corrigez un bug dans un programme, ou personnalisez un jeu à votre guise.
Désassembler un programme : ATAMON traduit le langage machine brut en mnémoniques lisibles (comme LDA, JMP, STA…), ce qui vous permet de comprendre comment un programme fonctionne.
Exécuter et déboguer : lancez un programme et reprenez la main à chaque point d'arrêt BRK, en observant l'état du processeur — indispensable pour trouver un bug.
Sauvegarder des secteurs : lisez et réécrivez directement des secteurs du disque (via les commandes E et W).
Calculer : effectuez des additions, soustractions, ET logique, OU logique directement en hexadécimal ou en binaire.
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.
Fichier source : Atamon - D7 - DXG 5724.PRO → ATAMON
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
ATAMON est un moniteur langage machine professionnel développé par ATARI en 1983. Il permet à un programmeur de :
Examiner et modifier la mémoire vive (RAM)
Afficher et modifier les registres du 6502 (adresse d'exécution, pointeur de pile, accumulateur, X, Y, flags)
Désassembler le code 6502 directement en mémoire
Exécuter du code et reprendre la main sur chaque point d'arrêt BRK
Lire et réécrire des secteurs disque
Vérifier et transférer des zones mémoire
Effectuer des calculs hexadécimaux
Il appartient à la famille des moniteurs langage machine qui ont accompagné les ordinateurs 8 bits de l'époque sur de nombreuses plateformes.
xxxxxxxxxxAdresse Contenu--------- --------------------------------$4000 Point d'entrée principal (RUNAD)$4000-$52B1 Code et données ATAMON$4F3C-$4F42 Zone de sauvegarde des registres CPU$4E3C Buffer d'entrée clavier (ligne de commande)$4F44 Bannière ASCII + format affichage registres$4F8D Table des chiffres hex + caractères de commande$4F9D Table de dispatch des commandes$4FC8 Table des adresses des handlers (vecteurs)$4FF9+ Tables internes du désassembleur 6502
Occupation mémoire : environ 4,5 Ko de $4000 à $52B1.
ATAMON déclare aussi MEMLO = $5300 pour protéger son code.
L'entrée à $4000 utilise une technique classique : le vecteur BRK ($0206-$0207).
xxxxxxxxxx$4000 LDA #$40 ; Installe le handler BRK$4002 STA $0207 ; VBREAK hi = $40$4005 LDA #$0B$4007 STA $0206 ; VBREAK lo = $0B → handler à $400B$400A BRK ; Déclenche volontairement BRK; === Le 6502 pousse (adresse courante + 2) et les flags sur la pile, saute via $0206 ===$400B LDA #$40 ; Reconfigure VBREAK pour usage futur$400D STA $0207$4010 LDA #$1A$4012 STA $0206 ; Nouveau VBREAK = $401A$4015 LDA #$43 ; 'C' = indicateur "entrée par démarrage"$4017 JMP $401C ; → Sauvegarder l'état CPU
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.
xxxxxxxxxx$401C STA $E4 ; Sauvegarde l'indicateur d'entrée (passé par l'appelant)$401E PLA ; Récupère A (poussé par le handler OS avant BRK)$401F STA $4F3D ; Sauvegarde A$4022 STY $4F3F ; Sauvegarde Y$4025 STX $4F3E ; Sauvegarde X$4028 PLA ; Récupère P (flags, depuis la pile BRK)$4029 STA $4F40 ; Sauvegarde P$402C CLC$402F PLA ; Récupère PCL (adresse basse, depuis la pile BRK)$4030 ADC #$FF ; Soustrait 1 (16 bits : BRK pousse addr+1, on revient à l'adresse réelle)$4032 STA $4F41 ; Sauvegarde PCL ajusté$4035 PLA ; Récupère PCH (adresse haute, depuis la pile BRK)$4036 ADC #$FF ; Continue la soustraction 16 bits avec la retenue$4038 STA $4F42 ; Sauvegarde PCH ajusté$403B TSX$403C STX $4F3C ; Sauvegarde SP$403F LDX #$FD$4041 TXS ; Réinitialise la pile à $FD
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) :
xxxxxxxxxx$4F3C SP Pointeur de pile$4F3D A Accumulateur$4F3E X Registre X$4F3F Y Registre Y$4F40 P Registre d'état (flags NV\BDIZC)$4F41 PCL Adresse basse de la prochaine instruction (ajustée -1)$4F42 PCH Adresse haute de la prochaine instruction
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.
Après initialisation, ATAMON affiche sa bannière et entre dans la boucle de commande ($4064) :
xxxxxxxxxx1. Réinitialise la pile à $FD2. Efface le buffer d'entrée ($4E3C ← $9B)3. Ouvre le canal E: (éditeur écran) via CIO4. Lit une ligne via CIO (IOCB 0)5. Cherche le premier caractère non-espace6. Recherche ce caractère dans la table $4F9D7. Si trouvé → charge l'adresse du handler depuis $4FC8/$4FC98. Exécute le handler via un RTS indirect (push hi-1 / lo-1, RTS)9. Retourne à l'étape 1
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 :
*C — entrée par démarrage ou G
*R — commande R
*B — retour sur BREAK (interruption d'un programme)
Exemple d'affichage des registres (commande R ou après un BRK) :
*RPC SP AC XR YR NV\BDIZC; 400B FB 0B 20 01 00110001
La ligne de valeurs commence toujours par ;. Signification de chaque champ :
| Champ | Ce que c'est | Valeur dans l'exemple |
|---|---|---|
PC | Compteur 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 |
SP | Pointeur 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 |
AC | Accumulateur A : registre principal du 6502, utilisé pour les calculs, les transferts, les comparaisons. | 00 |
XR | Registre X : registre d'index, souvent utilisé pour les boucles et les adresses indexées. | 00 |
YR | Registre Y : second registre d'index. | 00 |
NV\BDIZC | Flags 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.
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).
Étape 1 : Installer le moniteur en "sous-marin"
Depuis le menu DOS, utilise L pour charger ATAMON.
ATAMON s'affiche à l'écran. Tape la commande X (eXit).
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
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.
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
Dans le menu DOS, choisis l'option M (Run at address).
Tape 4000 (l'adresse où dort ATAMON) et appuie sur Entrée.
La bannière d'ATAMON s'affiche — te revoilà dans le moniteur !
Étape 4 : Lire l'adresse magique
Dans l'invite d'ATAMON, affiche la mémoire à l'adresse $02E0 en tapant :
xxxxxxxxxxEntrée :M 02E0
Appuie tout de suite sur BREAK pour arrêter le défilement.
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).
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 :
Remplace temporairement un octet de ton programme par l'instruction BRK (code hexadécimal $00).
Lorsque le processeur exécutera ce $00, il déclenchera une interruption logicielle.
ATAMON a détourné le vecteur d'interruption du système (VBREAK en $0206–$0207) lors de son chargement.
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$00stratégiquement avant de lancer ton code avecG.
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.
aaaa = adresse 16 bits en hexadécimal (ex : 4000)
bb = octet 8 bits en hexadécimal (ex : FF)
[...] = argument optionnel
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 :
xxxxxxxxxxEntrée :G ; Au premier lancement, réexécute l'init ATAMON :*** ATAMON V1.3 - (c) 1983 by ATARI ****CPC SP AC XR YR NV\BDIZC; 400B FD 00 00 00 00110000; Après un BRK dans votre propre programme, reprend l'exécution depuis le PC sauvegardéEntrée :G 4000 ; Lance l'exécution à $4000 — ATAMON disparaît le temps que votre programme tourne.; Il ne reprend la main que si le programme exécute un BRK (point d'arrêt).
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 :
xxxxxxxxxxEntrée :M 4000Résultat (défile sans fin — appuyer BREAK pour arrêter) ::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¨¹@; ... (continue automatiquement)
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 :
aaaa : adresse du buffer de destination (défaut : $0680)
nn : nombre de secteurs consécutifs à lire (défaut : 01) — le buffer avance de $80 (128 octets) par secteur
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 :
xxxxxxxxxxEntrée :E 0168 ; Lit le secteur 360 ($0168) = secteur VTOC du DOS 2.xRésultat :OK; ATAMON affiche "OK" — le secteur est maintenant en $0680Entrée :E 0001,0700 ; Lit le secteur 1 dans $0700 (buffer custom)Résultat :OKEntrée :E 0001,0700,02 ; Lit les secteurs 1 et 2 → $0700 (sect. 1) et $0780 (sect. 2)Résultat :OKEntrée :E 0001 ; Lit le secteur de boot (secteur 1)Résultat en cas d'erreur (secteur inexistant) :I/O ERROR #138
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 :
xxxxxxxxxxEntrée :D 4000,400CRésultat (défile sans fin — appuyer BREAK pour arrêter) :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; ... (continue automatiquement)
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 :
xxxxxxxxxxEntrée :F 6000,60FF,EA ; (remplit $6000–$60FF de $EA)Entrée :: 6000 A9 FF 8D 00 D0 4C 00 40 ; (modifie quelques octets en $6000)Entrée :L 6000,60FF,EA ; Parcourt $6000–$60FF et affiche les adresses où l'octet ≠ $EARésultat (7 adresses par ligne — appuyer BREAK pour arrêter, affiche *B) :6000 6001 6002 6003 6004 6005 60066007*B; → les adresses $6000–$6007 contiennent des octets ≠ $EA; Les adresses où l'octet vaut exactement $EA ne sont PAS affichées
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 :
xxxxxxxxxxEntrée :E 0001 ; 1. Lit le secteur 1 dans le buffer ($0680); (modifier éventuellement le buffer avec : 0680 A9 FF ...)Entrée :W 0001 ; 2. Réécrit le buffer sur le secteur 1Résultat : OK; En cas d'erreur : I/O ERROR #xxx
V aaaa,bbbb,cccc — Verify (Comparer mémoire)Compare la zone mémoire aaaa→bbbb 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 :
xxxxxxxxxxEntrée :T 6000,600F,6100 ; (copie $6000-$600F vers $6100)Entrée :V 6000,600F,6100 ; Compare $6000-$600F avec $6100-$610FRésultat si tout correspond :OK; Pour voir des différences, modifier un octet avant la comparaison :Entrée :: 6100 FF FF 00 00 00 00 00 00Entrée :V 6000,600F,6100 ; $6100 et $6101 ont été modifiés → ATAMON signale $6000 et $6001Résultat (7 adresses par ligne) :6000 6001; Seules les adresses SOURCE où les octets diffèrent sont affichées — pas les valeurs.
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 aaaa→bbbb avec l'octet bb.
Zone sûre : ATAMON occupe $4000–$52B1. Utiliser des adresses au-delà de $5300 (ex : $6000+).
Exemple :
xxxxxxxxxxEntrée :F 6000,60FF,EARésultat :OK; ATAMON affiche "OK" puis revient au prompt; $6000 à $60FF (256 octets) contient maintenant $EA (opcode NOP); Utile pour "nettoyer" une zone ou y écrire des NOP avant de patcher du code; Pour vérifier que les NOP ont bien été écrits :Entrée :M 6000Résultat ::6000 EA EA EA EA EA EA EA EA nnnnnnn:6008 EA EA EA EA EA EA EA EA nnnnnnn; ... (appuyer BREAK pour arrêter); La colonne droite = ATASCII de $EA (caractère 'n' en ATASCII inverse)
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 :
xxxxxxxxxxEntrée :T 6000,60FF,6100 ; Copie $6000-$60FF vers $6100Résultat : OKEntrée :T 6000,6008,6004 ; Cas de chevauchement : ATAMON copie à rebours pour éviter d'écraser la source; Résultat : (idem — silencieux si succès)
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 :
xxxxxxxxxxEntrée :H 4000,52B0,"'ATARI'" ; Cherche la chaîne "ATARI" dans le code ATAMON; Note : 'ATARI' (guillemets simples internes) = mode chaîne ATASCIIRésultat :4D99 4E4A 4F62OK; La chaîne ATARI apparaît 3 fois dans ATAMON (dans les tables et la bannière); ATAMON affiche les adresses trouvées, puis "OK" à la finEntrée :H 4000,52B0,"4154415249" ; Même recherche en hex : A=$41 T=$54 A=$41 R=$52 I=$49; (les espaces entre paires hex sont ignorés — "4154415249" et "41 54 41 52 49" sont équivalents)Résultat :4D99 4F62OK; Seulement 2 résultats — car la commande elle-même ne contient pas le motif dans le buffer.; Pourquoi 'ATARI' trouve 3 résultats mais "4154415249" seulement 2 ?; Le buffer d'entrée ATAMON est à $4E3C. Quand on tape H 4000,52B0,"'ATARI'",; le mot "ATARI" est présent dans le buffer vers $4E4A → H se trouve lui-même !; La version hex n'a pas ce problème (la commande ne contient pas les octets ATARI en clair).; Les 2 occurrences réelles dans le binaire ATAMON : $4D99 et $4F62.
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 :
xxxxxxxxxxEntrée :S 4000Résultat (une seule ligne se rafraîchit en boucle) :10101001 01000000 10001101 00000111; Les 4 octets à $4000-$4003 s'affichent et se mettent à jour en continu; Appuyer BREAK pour revenir au prompt
Exemple avec un registre matériel en temps réel :
xxxxxxxxxxEntrée :S 0014 ; Surveille RTCLOK ($0014-$0017) — horloge Atari incrémentée 60× par secondeRésultat (la ligne change visible à l'œil nu) :00000000 00000001 01001100 0000000000000000 00000001 01001101 00000000; L'octet en $0016 s'incrémente continuellement — preuve que l'Atari tourne; Appuyer BREAK pour arrêter
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
$2Cau 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 :
xxxxxxxxxxEntrée :C 6000,10110001 ; Écrit $B1 (10110001 en binaire) à l'adresse $6000Résultat :; (aucun affichage — le curseur Atari réapparaît); Vérification :Entrée :M 6000Résultat ::6000 B1 xx xx xx xx xx xx xx [...]; → $B1 bien écrit en $6000 (BREAK pour arrêter le défilement)
Exemple avec plusieurs octets :
xxxxxxxxxxEntrée :C 6000,01001100,00000000,01100000 ; Écrit $4C, $00, $60 à partir de $6000 (= JMP $6000 en langage machine)
P [E|T] — Printer (Gestion imprimante)Contrôle le canal imprimante (IOCB 6, device P1:).
P seul : ferme le canal imprimante et affiche son état (AUS = désactivé en allemand)
P E : ouvre le canal imprimante P1: en mode écho (tout l'affichage est dupliqué sur l'imprimante) → affiche EIN (= activé en allemand)
P T : transfert de données vers l'imprimante (non testé)
Exemple :
xxxxxxxxxxEntrée :PRésultat :P AUS; Le canal imprimante est actuellement fermé (AUS = "aus" = "off" en allemand)Entrée :P ERésultat :EIN; L'écho imprimante est activé (EIN = "ein" = "on" en allemand); Tout l'affichage ATAMON sera aussi impriméEntrée :P ; (pour désactiver l'écho)P AUS
Note : cette commande est utile si vous disposez d'une imprimante connectée à votre Atari. Sans imprimante,
P Eprovoquera 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 :
xxxxxxxxxxEntrée :RRésultat :*RPC SP AC XR YR NV\BDIZC; 4000 FD 00 00 00 00110000
X — eXit (Quitter)Retourne au DOS Atari via JMP DOSVEC ($000A).
Exemple :
xxxxxxxxxxEntrée :X ; ATAMON quitte — l'écran du DOS Atari réapparaît
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).
L'OS Atari organise toutes les entrées/sorties en trois niveaux :
xxxxxxxxxxVotre programme↓ (via IOCB)CIO — Central I/O ← point d'entrée unique pour tous les périphériques↓ (via ZIOCB)Handlers de périphériques ← routines spécifiques à chaque appareil↓ (via DCB)SIO — Serial I/O ← bus série (disquette, imprimante SIO…)
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) :
| Nom | Périphérique | Accès | Note |
|---|---|---|---|
E: | Éditeur écran — saisie ligne par ligne avec édition interactive | lecture + écriture | Utilise K: et S: en interne |
K: | Clavier — lecture directe des touches | lecture seule | Jamais ouvert directement — utilisé en interne par E: |
S: | Écran graphique — accès bitmap, commandes DRAW et FILL | lecture + écriture | |
P: | Imprimante — sur XL/XE : P1: à P8: selon le modèle | écriture seule | |
C: | Cassette | lecture + écriture | N'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) :
| Nom | Périphérique | Accès | Chargé par |
|---|---|---|---|
D: | Disquette — gestionnaire de fichiers DOS (D1: à D8:) | lecture + écriture | DOS, au boot |
R: | Interface 850 — ports série RS-232 (R1: à R4:) | lecture + écriture | ROM de l'interface 850, au boot |
T: | Modem 1030 (XM301, 835) | lecture + écriture | ROM 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".
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 :
| Canal | Offset nn | Adresse mémoire | Affectation |
|---|---|---|---|
| 0 | 00 | $0340–$034F | E: éditeur écran — ouvert par l'OS au démarrage, toujours disponible |
| 1 | 10 | $0350–$035F | libre — disponible pour tout programme |
| 2 | 20 | $0360–$036F | libre — disponible pour tout programme |
| 3 | 30 | $0370–$037F | libre — disponible pour tout programme |
| 4 | 40 | $0380–$038F | libre — disponible pour tout programme |
| 5 | 50 | $0390–$039F | libre — disponible pour tout programme |
| 6 | 60 | $03A0–$03AF | réservé par Atari BASIC pour S: (modes graphiques ≠ 0) |
| 7 | 70 | $03B0–$03BF | ré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.
nn — offset du canal en hex sur 2 chiffres : 00=canal 0, 10=canal 1… 70=canal 7
cc — commande CIO en hex sur 2 chiffres
aaaa — adresse du buffer en mémoire (4 chiffres, optionnel selon la commande)
llll — longueur du buffer en octets (4 chiffres, optionnel)
Z seul, Z 00 seul → erreur ? — la commande cc est obligatoire.
Commande cc | Signification |
|---|---|
03 | OPEN — ouvre un canal vers un périphérique |
05 | GET RECORD — lit une ligne depuis le canal (jusqu'au $9B) |
07 | GET BYTES — lit des octets (sans s'arrêter au $9B) |
09 | PUT RECORD — écrit une ligne vers le canal (ajoute $9B) |
0B | PUT BYTES — écrit des octets (sans ajouter $9B) |
0C | CLOSE — ferme le canal |
0D | STATUS — 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:) :
xxxxxxxxxx; Étape 1 : écrire "ATARI!!" + $9B (fin de ligne ATASCII) en $6000Entrée :: 6000 41 54 41 52 49 21 21 9B; Étape 2 : envoyer 8 octets de $6000 vers l'écran via CIOEntrée :Z 00,09,6000,0008Résultat :ATARI!!; → le texte s'affiche directement, puis le curseur Atari réapparaît
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 :
Octets hexadécimaux : deux chiffres hex (ex : 9B, 4F)
Chaîne littérale : une paire de guillemets simples '...' encadre une chaîne entière — tous les caractères entre les deux ' sont convertis en ATASCII (ex : 'BONJOUR' = 7 octets $42 $4F $4E $4A $4F $55 $52)
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 :
xxxxxxxxxx; ⚠ Utiliser impérativement $6000+ — ATAMON occupe $4000–$52B1Entrée :I 6000,"'BONJOUR'9B" ; PAS d'espace entre , et " — le délimiteur doit être collé à la virgule; 'BONJOUR' = chaîne ATASCII complète, 9B = octet fin de ligne; Vérification :Entrée :M 6000Résultat ::6000 42 4F 4E 4A 4F 55 52 9B [BONJOUR.]; (BREAK pour arrêter)Entrée :I 6010,/FF 00 4C 00 40/ ; 5 octets hex séparés par des espaces; Vérification :Entrée :M 6010Résultat ::6010 FF 00 4C 00 40 xx xx xx [..L.@...]; (BREAK pour arrêter)Entrée :I 6020,"'ATARI'9B" ; Chaîne ATASCII + octet fin de ligne; Vérification :Entrée :M 6020Résultat ::6020 41 54 41 52 49 9B xx xx [ATARI.xx]; (BREAK pour arrêter)
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écimalInterprè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 :
xxxxxxxxxxEntrée :# 4000Résultat :# 4000 = 0FA0; 4000 en décimal = $0FA0 en hexadécimalEntrée :# 255Résultat :# 255 = 00FF; 255 en décimal = $FF en hexadécimal
$ — Conversion hexadécimal → décimalInterprète l'argument comme une valeur hexadécimale et affiche son équivalent en décimal (complément de #).
Exemples :
xxxxxxxxxxEntrée :$ 1638Résultat :$ 1638 = 5688; $1638 en hexadécimal = 5688 en décimalEntrée :$ 00FFRésultat :$ 00FF = 0255; $FF = 255 en décimal — ATAMON exige exactement 4 chiffres hex; $ FF (seulement 2 chiffres) → erreur ?
Important : $ exige exactement 4 chiffres hexadécimaux. Utiliser $ 00FF et non $ FF.
% — Entrée binairePermet 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 :
xxxxxxxxxxEntrée :% 11001000Résultat :C8; $C8 = valeur hexadécimale de 11001000 binaire (= 200 en décimal)Entrée :% 00110000Résultat :30; $30 = flags I+B actifs (état typique au démarrage)
; 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
PCHL : 4 chiffres hex = adresse d'exécution PC (ex : 5000)
SP : pointeur de pile (ex : FD)
AC : accumulateur
XR : registre X
YR : registre Y
XXXXXXXX : 8 bits binaires = flags P dans l'ordre N V \ B D I Z C
Signification de chaque bit (de gauche à droite) :
| Bit | Lettre | Nom | Vaut 1 quand… |
|---|---|---|---|
| 7 | N | Negative | Le dernier résultat avait le bit 7 à 1 (valeur "négative" en signé) |
| 6 | V | oVerflow | Débordement en arithmétique signée (ex : 127 + 1 → −128) |
| 5 | \ | (non utilisé) | Toujours à 1 — ce bit n'est pas un flag réel du 6502 |
| 4 | B | Break | L'entrée dans le moniteur s'est faite via une instruction BRK |
| 3 | D | Decimal | Mode BCD activé — non fonctionnel sur le 6502 de l'Atari |
| 2 | I | Interrupt disable | Les interruptions IRQ sont masquées (ignorées) |
| 1 | Z | Zero | Le dernier résultat était exactement zéro |
| 0 | C | Carry | Retenue d'une addition, ou emprunt inverse d'une soustraction |
Exemple : 00110100 = bits N=0, V=0, \=1, B=1, D=0, I=1, Z=0, C=0 — état typique au démarrage (I=1 : interruptions désactivées).
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 :
xxxxxxxxxxEntrée :; 5000 FD 00 00 00 00110100Résultat : ATAMON réécrit la ligne saisie en place au format `;`, sans ajouter de nouvelle ligne.Le contenu affiché est identique à la saisie — la commande paraît silencieuse.; 5000 FD 00 00 00 00110100; Vérification :Entrée :RRésultat :*RPC SP AC XR YR NV\BDIZC; 5000 FD 00 00 00 00110100; → PC bien à $5000, flags identiques à ceux saisis
! 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 :
xxxxxxxxxxEntrée :! 4000 ; Convertit $4000 en binaire : $40=01000000, $00=00000000Résultat :! 4000 = 01000000 00000000Entrée :! 00FF ; Convertit $00FF : $00=00000000, $FF=11111111Résultat :! 00FF = 00000000 11111111Entrée :! D01F ; Convertit la valeur $D01F (adresse du registre CONSOL) — pour voir les bits; d'un registre matériel, lire d'abord sa valeur avec M, puis convertir avec !Résultat :! D01F = 11010000 00011111
* 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 :
xxxxxxxxxxEntrée :* + 4000,0100Résultat :* + 4000,0100 = 4100 C= 0; $4000 + $0100 = $4100, retenue = 0Entrée :* - 5000,0200Résultat :* - 5000,0200 = 4E00 C= 1; $5000 - $0200 = $4E00, C=1 = pas d'emprunt (résultat positif)En 6502, pour la soustraction le carry est inversé par rapport à l'addition : C=1 = résultat ≥ 0 (pas d'emprunt), C=0 = résultat négatif (dépassement). C'est l'opposé de ce qu'on attend intuitivement.Entrée :* A FF00,0FF0Résultat :* A FF00,0FF0 = 0F00; $FF00 AND $0FF0 = $0F00Entrée :* O 4000,0001Résultat :* O 4000,0001 = 4001; $4000 OR $0001 = $4001
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 :
xEntrée :: 6000 A9 FF 8D 00 D0 4C 00 40Résultat ::6000 A9 FF 8D 00 D0 4C 00 40 ) PL @:6008; ATAMON propose l'adresse suivante — on peut saisir 8 nouveaux octets; ou appuyer sur BREAK pour revenir au prompt
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 :
xxxxxxxxxxEntrée :, 6000 A9 00Résultat :, 6000 A9 00 LDA #$00, 6002; ATAMON affiche les octets + le désassemblage, puis propose la suite avec `,`; Continuer en saisissant les octets suivants, BREAK pour revenir au promptEntrée :, 6002 4C 00 60Résultat :, 6002 4C 00 60 JMP $6000, 6005; 3 octets écrits — JMP $6000 (saut vers $6000); On peut continuer ou appuyer sur BREAK
Idéal pour entrer du code assembleur et vérifier immédiatement que les opcodes sont corrects.
| Adresse | Nom local | Rôle |
|---|---|---|
$DA-$DB | PTR_START | Adresse de début 16 bits (argument 1) |
$DC-$DD | PTR_END | Adresse de fin 16 bits (argument 2) |
$DE-$DF | PTR_DEST | Adresse de destination 16 bits (argument 3) |
$E0 | MODE | 0 = mode normal, ≠0 = mode inverse |
$E4 | TEMP_A | Temporaire / sauvegarde accumulateur |
$E5 | TEMP_B | Compteur / temporaire |
$E7 | COL_CTR | Compteur de colonnes pour l'affichage hex (0-6) |
$EB | TEMP_C | Temporaire affichage |
$F2 | BUF_PTR | Pointeur dans le buffer $4E3C |
$F3-$F4 | FP_PTR | Pointeur vers zone Math ROM (virgule flottante) |
| Adresse | Description |
|---|---|
| $401C | SAVE_CPU : Sauvegarde l'état du 6502 (accumulateur, X, Y, flags, adresse d'exécution, pile) |
| $4054 | PRINT_HEADER : Affiche la bannière et l'en-tête des registres |
| $4064 | CMD_LOOP : Boucle principale de lecture/dispatch des commandes |
| $40B5 | CLR_RANGE : Remet à zéro les registres d'adresse DA-DF |
| $40C5 | DUMP_8 : Affiche 8 octets en hexadécimal |
| $40DB | FILTER_CHAR : Filtre un caractère ATASCII (affichable / non-affichable) |
| $4127 | ADD16 : Additionne A à l'adresse 16 bits DA:DB |
| $4133 | DO_CIO : Appelle CIO ($E456) avec X=numéro IOCB×16 |
| $41DD | DO_SIO_DISK : Envoie une commande SIO disque via DSKINV ($E453) |
| $41E8 | FIND_CMD : Cherche un caractère dans la table de commandes $4F8D |
| $41F7 | GET_CHAR : Lit le prochain caractère du buffer d'entrée |
| $422A | SKIP_SP : Avance le pointeur buffer en sautant les espaces |
| $423D | READ_BYTE : Lit 2 chiffres hex → octet en A |
| $4256 | READ_ADDR : Lit 4 chiffres hex → adresse 16 bits en A(hi) Y(lo) |
| $4280 | READ_BIN : Lit 8 chiffres binaires → octet en A |
| $42C7 | SET_FNAME : Configure l'adresse du nom de fichier dans l'IOCB |
| $42CF | SET_BUFADDR : Configure l'adresse du buffer dans l'IOCB |
| $42E9 | OPEN_EDITOR : Ouvre le canal 0 sur E: (éditeur écran) |
| $4330 | PRINT_HEX8 : Affiche un octet sous forme de 2 chiffres hex |
| $4349 | NEWLINE_REGS : Saut de ligne + affichage des registres |
| $4373 | NEWLINE : Envoie un retour chariot ($9B) sur E: |
| $4399 | PRINT_CHAR : Affiche un caractère ATASCII via CIO |
| $44A4 | FP_TO_STR : Conversion virgule flottante → chaîne (Math ROM IFP+FASC) |
| $44C5 | SET_FP_PTR : Initialise le pointeur zone flottante ($4D99) |
ATAMON utilise les services OS suivants :
| Service | Adresse | Utilisation |
|---|---|---|
| CIO — Central I/O | $E456 (CIOV) | Lecture/écriture écran, fichiers |
| SIO — Serial I/O disque | $E453 (DSKINV) | Accès secteurs disque |
| Math ROM IFP | $D9AA | Conversion entier → flottant |
| Math ROM FASC | $D8E6 | Conversion flottant → ASCII |
| VBREAK | $0206-$0207 | Vecteur BRK (entrée moniteur sur point d'arrêt) |
Structure des IOCBs utilisés :
IOCB 0 ($0340) : Canal principal vers E: (éditeur/écran) pour toutes les entrées/sorties utilisateur.
L'IOCB est configuré dynamiquement par les fonctions SET_FNAME / SET_BUFADDR / DO_CIO.
Structure DCB pour les accès disque ($0300-$030B) :
$0300 DDEVIC = $31 ('1') — périphérique disque D1:
$0301 DUNIT = 1
$0302 DCOMND = commande SIO ('R'=$52 lecture, 'W'=$57 écriture)
$0303 DSTATS = direction ($40 = lecture, $80 = écriture)
$0304-$0305 DBUFLO/HI = adresse du buffer
$030A-$030B DAUX1/2 = numéro de secteur
La chaîne stockée en mémoire est :
xxxxxxxxxx*** ATAMON V1.3 - (c) 1983 by ATARI ***E:P1: PC SP AC XR YR NV\BDIZC<$9B>
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 :
xxxxxxxxxx*** ATAMON V1.3 - (c) 1983 by ATARI ***PC SP AC XR YR NV\BDIZC; 4000 FD 00 00 00 00110000
xxxxxxxxxx$4F8D "0123456789ABCDEF" ← chiffres hexa (index 0-15)$4F9D "RX;GM:EWFVTH#$%!I*PCSD,LZ" ← caractères de commande
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.
ATAMON possède son propre mini-désassembleur (commande D). Il utilise deux tables internes :
Mnémoniques 6502 : entrées de 3 lettres codées (56 mnémoniques officiels)
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.
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.
| Touche | Effet dans ATAMON |
|---|---|
RETURN | Valide la commande en cours |
BREAK | Interrompt un programme en cours d'exécution et renvoie le contrôle à ATAMON (via le vecteur VBREAK/BRK) |
RESET | Ré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 |
ESC | Peut 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.
xxxxxxxxxx*** ATAMON V1.3 - (c) 1983 by ATARI ****CPC SP AC XR YR NV\BDIZC; 4000 FD 00 00 00 00110000
xxxxxxxxxx; Afficher la mémoire depuis $4000M 4000; Modifier 8 octets à $6000 (zone libre): 6000 A9 FF 8D 00 D0 4C 00 60; Désassembler depuis $4000D 4000; Lancer le programme à $4000G 4000; Copier $4000-$40FF vers $6000, puis vérifierT 4000,40FF,6000V 4000,40FF,6000; Remplir $6000-$60FF avec des NOP ($EA) — zone libre, hors ATAMONF 6000,60FF,EA; Lire le secteur 1 du disque dans le buffer ($0680)E 0001; Réécrire le buffer sur le secteur 1W 0001; Calculer $4000 + $0100* + 4000,0100; Quitter vers DOSX
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 :
DOS.SYS : le système d'exploitation disque Atari DOS 2.x (39 secteurs)
DUP.SYS : l'utilitaire de gestion de disquette (42 secteurs)
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.
| Groupe | Opcodes | Description |
|---|---|---|
*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,$1F | ASL mémoire puis ORA A |
*RLA | $23,$27,$2F,$33,$37,$3B,$3F | ROL mémoire puis AND A |
*SRE | $43,$47,$4F,$53,$57,$5B,$5F | LSR mémoire puis EOR A |
*RRA | $63,$67,$6F,$73,$77,$7B,$7F | ROR mémoire puis ADC A |
*LAX | $A3,$A7,$AF,$B3,$B7,$BF | Charge A et X simultanément |
*SAX | $83,$87,$8F,$97 | Stocke A AND X |
*DCP | $C3,$C7,$CF,$D3,$D7,$DB,$DF | DEC mémoire puis CMP A |
*ISC | $E3,$E7,$EF,$F3,$F7,$FB,$FF | INC mémoire puis SBC A |
| Divers | $0B/$2B *ANC, $4B *ALR, $6B *ARR, $CB *SBX, $9B *TAS, $9C *SHY | Diverses combinaisons |
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).
$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 :
Les instructions qui y accèdent n'utilisent qu'un seul octet d'adresse au lieu de deux → elles sont plus courtes et plus rapides.
Le 6502 peut l'utiliser comme zone de "registres supplémentaires" : pointeurs 16 bits, compteurs, variables temporaires.
L'OS Atari et ATAMON s'en servent intensivement. Voici les emplacements les plus importants, expliqués pour un débutant :
| Adresse | Nom OS | Ce que c'est |
|---|---|---|
| $08 | COLCRS | Colonne 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. |
| $09 | ROWCRS | Ligne du curseur (0 à 24). Même principe pour la ligne. |
$0B–$0C | SAVMSC | Adresse 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–$16 | RTCLOK | Horloge 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. |
$55 | ATRACT | É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. |
$6A | RAMTOP | Limite 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–$9F | FR0 | Registre 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–$A5 | FR1 | Registre flottant 1 (6 octets). Second registre flottant, utilisé comme opérande dans les calculs. |
Ces adresses sont réservées par ATAMON pendant qu'il est chargé. Les modifier avec : ou , peut perturber le fonctionnement du moniteur.
| Adresse | Nom ATAMON | Ce que c'est |
|---|---|---|
$DA–$DB | PTR_START | Adresse de début de l'opération en cours (argument 1 des commandes M, D, F, T…). |
$DC–$DD | PTR_END | Adresse de fin (argument 2). |
$DE–$DF | PTR_DEST | Adresse de destination (argument 3, utilisé par T). |
| $E0 | MODE | Mode d'affichage : 0 = normal, ≠ 0 = mode inverse (pour M). |
| $E4 | TEMP_A | Temporaire : sauvegarde de l'accumulateur entre deux opérations internes. |
| $E5 | TEMP_B | Compteur temporaire (boucles internes). |
| $E7 | COL_CTR | Compteur de colonnes pour l'affichage hex (0 à 6, pour aligner 8 octets par ligne). |
| $F2 | BUF_PTR | Pointeur dans le buffer de commande ($4E3C). Indique où en est la lecture de la ligne saisie. |
Conseil : utilisez
M 0000 00FFpour 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).
Le désassembleur intégré d'ATAMON (commande D) reconnaît exactement ces 56 instructions.
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
LDA | Load Accumulator | Charge une valeur dans l'accumulateur A | LDA #$41 → A = 'A' |
LDX | Load X | Charge une valeur dans le registre X | LDX #$00 → X = 0 (init boucle) |
LDY | Load Y | Charge une valeur dans le registre Y | LDY #$08 → Y = 8 (compteur) |
STA | Store Accumulator | Écrit A en mémoire | STA $D800 → envoie la couleur vers GTIA |
STX | Store X | Écrit X en mémoire | STX $00 → sauvegarde X en page zéro |
STY | Store Y | Écrit Y en mémoire | STY $CB → sauvegarde Y dans une variable |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
TAX | Transfer A to X | Copie A dans X | LDA #$10 / TAX → X = 16 |
TAY | Transfer A to Y | Copie A dans Y | TAY → Y ← A (pour indexer un tableau) |
TXA | Transfer X to A | Copie X dans A | TXA / CLC / ADC #$40 → calcul d'adresse |
TYA | Transfer Y to A | Copie Y dans A | TYA / STA $CB → sauvegarde Y comme valeur |
TSX | Transfer SP to X | Copie le pointeur de pile SP dans X | TSX → X = valeur actuelle de la pile |
TXS | Transfer X to SP | Copie X dans le pointeur de pile SP | LDX #$FF / TXS → réinitialise la pile |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
PHA | Push Accumulator | Empile A (sauvegarde) | PHA avant JSR, pour ne pas perdre A |
PLA | Pull Accumulator | Dépile dans A (restaure) | PLA après JSR, restaure A |
PHP | Push Processor status | Empile le registre d'état P | PHP / SEI / … / PLP : section critique |
PLP | Pull Processor status | Dépile dans P | PLP restaure les flags sauvés par PHP |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
ADC | Add with Carry | A ← A + opérande + C | CLC / LDA #$10 / ADC #$05 → A = $15 |
SBC | Subtract with Carry | A ← A − opérande − (1−C) | SEC / LDA #$10 / SBC #$03 → A = $0D |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
INC | Increment memory | +1 à un octet en mémoire | INC $0600 → incrémente le score en $0600 |
INX | Increment X | X ← X + 1 | INX / CPX #$10 / BNE LOOP : boucle 16× |
INY | Increment Y | Y ← Y + 1 | INY / LDA (PTR),Y : avance dans un tableau |
DEC | Decrement memory | −1 à un octet en mémoire | DEC $CB → décrémente un compteur de vies |
DEX | Decrement X | X ← X − 1 | LDX #$08 / LOOP: DEX / BNE LOOP : attend 8× |
DEY | Decrement Y | Y ← Y − 1 | DEY / BNE LOOP : reboucle tant que Y ≠ 0 |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
AND | Logical AND | A ← A AND opérande (bit à bit) | AND #$0F → garde les 4 bits bas (nibble) |
ORA | Logical OR | A ← A OR opérande (bit à bit) | ORA #$80 → force le bit 7 à 1 (inverse vidéo) |
EOR | Exclusive OR | A ← A XOR opérande (bit à bit) | EOR #$FF → inverse tous les bits |
BIT | Bit test | Z ← A AND mem ; N,V ← bits 7,6 de mem | BIT $D018 → teste un registre sans modifier A |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
ASL | Arithmetic Shift Left | Décale à gauche (× 2) ; bit 7 → C | ASL A → A × 2 |
LSR | Logical Shift Right | Décale à droite (÷ 2) ; bit 0 → C | LSR A → A ÷ 2 |
ROL | Rotate Left | Rotation gauche à travers C | ROL A → × 2 + ancien C (multiplication 16 bits) |
ROR | Rotate Right | Rotation droite à travers C | ROR A → ÷ 2 + ancien C en bit 7 |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
CMP | Compare A | A − opérande → N,Z,C (A non modifié) | CMP #$9B / BEQ EOL → fin de ligne ATASCII ? |
CPX | Compare X | X − opérande → N,Z,C | CPX #$10 / BNE LOOP → fin à X=16 |
CPY | Compare Y | Y − opérande → N,Z,C | CPY #$00 / BEQ DONE → fin à Y=0 |
Tous les branchements sont relatifs (déplacement signé de −128 à +127 octets depuis l'instruction suivante).
| Mnémonique | Nom complet | Condition | Exemple |
|---|---|---|---|
BCC | Branch if Carry Clear | C = 0 | ADC #$01 / BCC OK → pas de retenue |
BCS | Branch if Carry Set | C = 1 | CMP #$80 / BCS HIGH → A ≥ $80 |
BEQ | Branch if Equal | Z = 1 (résultat nul) | CMP #$41 / BEQ FOUND → trouvé 'A' |
BNE | Branch if Not Equal | Z = 0 (résultat non nul) | DEX / BNE LOOP → boucle classique |
BMI | Branch if Minus | N = 1 (bit 7 = 1) | BIT $D40B / BMI VBLANK → VBlank actif |
BPL | Branch if Plus | N = 0 (bit 7 = 0) | LDA $CB / BPL OK → valeur positive |
BVC | Branch if oVerflow Clear | V = 0 | ADC #$01 / BVC OK → pas de débordement signé |
BVS | Branch if oVerflow Set | V = 1 | ADC #$40 / BVS ERR → débordement signé détecté |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
JMP | Jump | Saut inconditionnel (absolu ou indirect) | JMP $4000 → relance ATAMON |
JSR | Jump to Subroutine | Empile adresse retour, puis saute | JSR $E456 → appelle CIO |
RTS | Return from Subroutine | Dépile adresse retour + 1 et y saute | RTS → fin de sous-routine |
RTI | Return from Interrupt | Dépile P puis compteur de programme | RTI → fin de handler VBI ou DLI |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
BRK | Break | Dé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 |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
CLC | Clear Carry | C ← 0 | CLC / ADC #$01 → addition sans retenue parasite |
SEC | Set Carry | C ← 1 | SEC / SBC #$01 → soustraction correcte |
CLD | Clear Decimal | D ← 0 (désactive BCD) | CLD au démarrage d'une routine arithmétique |
SED | Set Decimal | D ← 1 (active BCD) | SED → rarement utile sur Atari |
CLI | Clear Interrupt disable | I ← 0 (autorise IRQ) | CLI → autorise VBI, POKEY, etc. |
SEI | Set Interrupt disable | I ← 1 (masque IRQ) | SEI → protège une section critique |
CLV | Clear oVerflow | V ← 0 | CLV → repart d'un état connu avant arithmétique signée |
| Mnémonique | Nom complet | Description | Exemple |
|---|---|---|---|
NOP | No Operation | Ne 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 |
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.
| Mnémonique | Noms alt. | Description | Opcodes |
|---|---|---|---|
*KIL | JAM, HLT | Bloque 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 |
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émonique | Noms alt. | Description | Modes | Opcodes |
|---|---|---|---|---|
*SLO | ASO | ASL sur l'octet mémoire, puis ORA avec A | inx zp abs iny zpx aby abx | $03 $07 $0F $13 $17 $1B $1F |
*RLA | — | ROL sur l'octet mémoire, puis AND avec A | inx zp abs iny zpx aby abx | $23 $27 $2F $33 $37 $3B $3F |
*SRE | LSE | LSR sur l'octet mémoire, puis EOR avec A | inx zp abs iny zpx aby abx | $43 $47 $4F $53 $57 $5B $5F |
*RRA | — | ROR sur l'octet mémoire, puis ADC avec A | inx zp abs iny zpx aby abx | $63 $67 $6F $73 $77 $7B $7F |
*DCP | DCM | DEC sur l'octet mémoire, puis CMP avec A | inx zp abs iny zpx aby abx | $C3 $C7 $CF $D3 $D7 $DB $DF |
*ISC | ISB, INS | INC sur l'octet mémoire, puis SBC avec A | inx zp abs iny zpx aby abx | $E3 $E7 $EF $F3 $F7 $FB $FF |
| Mnémonique | Noms alt. | Description | Modes | Opcodes |
|---|---|---|---|---|
*LAX | — | Charge la même valeur simultanément dans A et X — équivalent LDA + TAX en un seul opcode | inx zp abs iny zpy aby | $A3 $A7 $AF $B3 $B7 $BF |
*SAX | AXS | Écrit en mémoire la valeur de A AND X (sans modifier les flags) | inx zp abs zpy | $83 $87 $8F $97 |
| Mnémonique | Noms alt. | Description | Opcode | Stabilité |
|---|---|---|---|---|
*ANC | — | AND immédiat sur A, puis copie le bit 7 dans le flag Carry (comme un ASL sans modifier la mémoire) | $0B $2B | stable |
*ALR | ASR | AND immédiat sur A, puis LSR sur A (décalage logique droite) | $4B | stable |
*ARR | — | AND immédiat sur A, puis ROR sur A — avec effets complexes sur C et V (pas identiques à ROR normal) | $6B | stable |
*SBX | AXS | (A AND X) - imm → X, sans emprunt (affecte C, Z, N) | $CB | stable |
*SBC | — | Doublon du SBC #imm officiel ($E9) — comportement identique | $EB | stable |
*ANE | XAA | A = (A OR $EE) AND X AND imm — résultat dépend du processeur | $8B | instable |
*LXA | LAX # | (A OR $EE) AND imm → A et X — résultat dépend du processeur | $AB | instable |
| Mnémonique | Noms alt. | Description | Opcode | Stabilité |
|---|---|---|---|---|
*TAS | XAS, SHS | SP = A AND X ; écrit SP AND (addr_hi+1) en mémoire | $9B | instable |
*SHY | A11Y | Écrit Y AND (addr_hi+1) en mémoire | $9C | instable |
*SHX | A11X | Écrit X AND (addr_hi+1) en mémoire | $9E | instable |
*SHA | AXA | Écrit A AND X AND (addr_hi+1) en mémoire | $93 $9F | instable |
*LAS | LAR | A = X = SP = mémoire AND SP | $BB | instable |
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émonique | Mode | Taille | Opcodes |
|---|---|---|---|
*NOP | imp (1 octet) | 1 | $1A $3A $5A $7A $DA $FA |
*NOP | zp (2 octets) | 2 | $04 $44 $64 |
*NOP | zpx (2 octets) | 2 | $14 $34 $54 $74 $D4 $F4 |
*NOP | abs (3 octets) | 3 | $0C |
*NOP | abx (3 octets) | 3 | $1C $3C $5C $7C $DC $FC |
Adresses symboliques reconnues par le désassembleur ATAMON (commande D). Elles apparaissent dans le désassemblage à la place de l'adresse hexadécimale brute.
$00–$FF)| Adresse | Étiquette | Description |
|---|---|---|
$000A–$000B | DOSVEC | Vecteur DOS — adresse de saut vers le DOS (2 octets lo/hi). JMP (DOSVEC) quitte le programme et retourne au DOS. |
$000C–$000D | DOSINI | Vecteur d'initialisation DOS — appelé à chaque warm reset. |
$0010 | POKMSK | Masque d'activation des interruptions POKEY (IRQ). Chaque bit active un type d'IRQ (timer, série…). |
$0012–$0014 | RTCLOK | Horloge temps réel (3 octets). Incrémentée 60×/s par le VBI de l'OS. |
$0020–$002B | ZIOCB | IOCB zéro — copie de travail de l'IOCB du canal courant pendant un appel CIO. |
$002C | STATUS | Code de statut de la dernière opération SIO ou CIO. |
$002E–$002F | BUFRLO/HI | Adresse du buffer d'entrée/sortie (2 octets). Utilisé par le DCB SIO et CIO. |
$0030–$0031 | BFENLO/HI | Adresse de fin du buffer (2 octets). |
$0036–$0037 | BYTLO/HI | Nombre d'octets transférés lors du dernier appel SIO/CIO (2 octets). |
$0200–$02FF)| Adresse | Étiquette | Description |
|---|---|---|
$0200–$0201 | VDSLST | Vecteur DLI (Display List Interrupt) — appelé à chaque instruction DLI dans la display list ANTIC. |
$0202–$0203 | VPRCED | Vecteur interruption "proceed" (entrée série). |
$0204–$0205 | VINTER | Vecteur interruption "interrupt" (entrée série). |
$0206–$0207 | VBREAK | Vecteur BRK — appelé quand le CPU exécute BRK. ATAMON l'installe pour capturer les points d'arrêt. |
$0208–$0209 | VKEYBD | Vecteur interruption clavier (touche pressée). |
$020A–$020B | VSERIN | Vecteur réception série (POKEY). |
$020C–$020D | VSEROR | Vecteur émission série (POKEY). |
$020E–$020F | VSEROC | Vecteur fin d'émission série. |
$0210–$0211 | VTIMR1 | Vecteur timer 1 POKEY. |
$0212–$0213 | VTIMR2 | Vecteur timer 2 POKEY. |
$0214–$0215 | VTIMR4 | Vecteur timer 4 POKEY. |
$0216–$0217 | VIMIRQ | Vecteur IRQ générique (non utilisé par l'OS). |
$0222–$0223 | VVBLKI | Vecteur VBI immédiat — appelé en début de blanking vertical (~3 800 cycles disponibles). |
$0224–$0225 | VVBLKD | Vecteur VBI différé — appelé après SYSVBV (~20 000 cycles disponibles, plus sûr). |
$0226–$0227 | CDTMA1 | Vecteur timer software 1 (décrémenté par le VBI). |
$0228–$0229 | CDTMA2 | Vecteur timer software 2. |
$022A | CDTMF3 | Flag timer software 3. |
$022C | CDTMF4 | Flag timer software 4. |
$022E | BRKKEY | Flag touche BREAK : $00 si BREAK pressé, sinon $80. |
$022F | SDMCTL | Shadow DMACTL — copié vers $D400 (ANTIC) à chaque VBI. Contrôle la largeur de l'écran et l'activation du DMA. |
$0230–$0231 | SDLSTL/H | Shadow display list (lo/hi) — copié vers $D402/$D403 au VBI. Pointe vers la display list ANTIC active. |
$023B | ATRACT | Compteur é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. |
$026F | GPRIOR | Shadow PRIOR — copié vers $D01B (GTIA) au VBI. Détermine la priorité d'affichage joueurs/missiles/fond. |
$02C0–$02C8 | COLPF0…COLPM0 | Couleurs des playfields et joueurs (shadows des registres GTIA couleur). |
$02C8 | COLBK | Couleur du fond (background). Shadow du registre GTIA $D01A. |
$02E0–$02E1 | RUNAD | Adresse d'exécution du programme chargé (XEX). L'OS saute à cette adresse après le chargement. |
$02E2–$02E3 | INITAD | Adresse d'initialisation — appelée après chaque segment XEX marqué INITAD. |
$02E4 | RAMSIZ | Taille de la RAM en pages (×256). Valeur lue au démarrage. |
$02E5 | RAMTOP | Limite haute de la RAM utilisable (en pages). |
$02E7–$02E8 | MEMLO | Limite basse de la RAM libre (2 octets). ATAMON la positionne à $5300 pour protéger son code. |
$02E9–$02EA | MEMTOP | Limite haute de la RAM libre (2 octets). |
$02F4 | CHBAS | Shadow CHBASE — copié vers $D408 (ANTIC) au VBI. Sélectionne la police de caractères (page haute de l'adresse). |
$0300–$035F)| Adresse | Étiquette | Description |
|---|---|---|
$0300 | DDEVIC | Numéro du périphérique SIO (ex : $31 = lecteur de disque D1:). |
$0301 | DUNIT | Numéro d'unité (1 à 4 pour D1: à D4:). |
$0302 | DCOMND | Commande SIO (ex : $52 = Read sector, $57 = Write sector). |
$0303 | DSTATS | Sens : $40 = lecture, $80 = écriture, $00 = statut seul. |
$0304–$0305 | DBUFLO/HI | Adresse du buffer de données (2 octets lo/hi). |
$0306 | DTIMLO | Timeout SIO en unités VBI (~1/60 s). Valeur typique : $0F (15 VBI). |
$0308–$0309 | DBYTLO/HI | Nombre d'octets à transférer (2 octets). |
$030A–$030B | DAUX1/2 | Paramètres auxiliaires (ex : numéro de secteur lo/hi pour le disque). |
$0340–$034F | IOCB0 | IOCB canal 0 (éditeur écran E: — utilisé par ATAMON pour la saisie). |
$0350–$035F | IOCB1 | IOCB canal 1 (libre). |
| Adresse | Étiquette | Description |
|---|---|---|
$D000 | HPOSP0 | Position horizontale joueur 0 (missile). |
$D001 | HPOSP1 | Position horizontale joueur 1. |
$D002 | HPOSP2 | Position horizontale joueur 2. |
$D003 | HPOSP3 | Position horizontale joueur 3. |
$D004 | HPOSM0 | Position horizontale missile 0. |
$D01B | PRIOR | Priorité d'affichage joueurs/missiles/playfields. Bit 7 = mode GTIA spécial. |
$D01D | GRACTL | Activation du DMA joueurs/missiles. |
$D01F | CONSOL | Touches console (lecture) : bits 2-0 = START/SELECT/OPTION (0 = pressé). En écriture : contrôle le haut-parleur interne. |
| Adresse | Étiquette | Description |
|---|---|---|
$D200 | AUDF1 | Fréquence canal audio 1 (valeur 0–255, fréquence inversement proportionnelle). |
$D201 | AUDC1 | Contrôle canal 1 : bits 7-4 = volume, bits 3-0 = distorsion/waveform. |
$D202 | AUDF2 | Fréquence canal audio 2. |
$D203 | AUDC2 | Contrôle canal 2. |
$D204 | AUDF3 | Fréquence canal audio 3. |
$D205 | AUDC3 | Contrôle canal 3. |
$D206 | AUDF4 | Fréquence canal audio 4. |
$D207 | AUDC4 | Contrôle canal 4. |
$D208 | AUDCTL | Contrôle global audio : fréquence d'horloge (64 kHz / 15 kHz / 1,79 MHz), canaux 16 bits, filtre passe-haut. |
$D20A | STIMER | Écriture : remet les timers POKEY à zéro. |
$D20E | SEROUT | Sortie série (écriture). |
$D20F | SKCTL | Contrôle série POKEY : réinitialisation, mode synchronisation. |
| Adresse | Étiquette | Description |
|---|---|---|
$D300 | PORTA | Port A : joystick 1 (bits 3-0) et joystick 2 (bits 7-4). Bit = 0 si direction active. |
$D301 | PORTB | Port B : sur 800XL, contrôle la banque mémoire OS ROM (bit 0) et BASIC (bit 1). |
$D302 | PACTL | Contrôle port A (direction bits, interruptions). |
$D303 | PBCTL | Contrôle port B. |
| Adresse | Étiquette | Description |
|---|---|---|
$D400 | DMACTL | Contrôle DMA : active/désactive le DMA, définit la largeur de l'écran (narrow/normal/wide) et le DMA joueurs/missiles. |
$D401 | CHACTL | Contrôle caractères : vidéo inverse, blanking des lignes hautes/basses d'une cellule. |
$D402–$D403 | DLISTL/H | Adresse de la display list (lo/hi). ANTIC lit cette liste pour construire l'image. |
$D404 | HSCROL | Scrolling horizontal fin (0–15 colour clocks). |
$D405 | VSCROL | Scrolling vertical fin (0–15 lignes). |
$D407 | PMBASE | Base des joueurs/missiles (octet haut de l'adresse, page de 1 Ko ou 2 Ko selon DMACTL). |
$D408 | CHBASE | Base de la police de caractères (octet haut ; la police commence à cette page × 256). |
$D409 | WSYNC | Wait for sync — écriture : le CPU se bloque jusqu'à la fin de la ligne de balayage courante (synchronisation raster). |
$D40B | VCOUNT | Compteur de ligne de balayage actuelle (lecture seule, 0–131). |
$D40E | NMIEN | Activation NMI : bit 7 = DLI, bit 6 = VBI. |
$D40F | NMIRES | Écriture : réinitialise les flags NMI. Lecture : identifie la source NMI (bit 7 = DLI, bit 6 = VBI). |
| Adresse | Étiquette | Description |
|---|---|---|
$E450 | DISKIV | Initialisation du handler disque. |
$E453 | DSKINV | Appel SIO disque — exécute la commande décrite dans le DCB ($0300+). Utilisé par ATAMON pour les commandes E et W. |
$E456 | CIOV | CIO (Central I/O) — point d'entrée principal des entrées/sorties. Utilisé par ATAMON pour lire les commandes et écrire les résultats. |
$E459 | SIOV | SIO (Serial I/O) — transfert série bas niveau. |
$E45C | SETVBV | Installe un handler VBI (immédiat ou différé). |
$E45F | SYSVBV | Handler VBI système (OS) — à appeler depuis un VBI immédiat pour chaîner le VBI différé. |
$E462 | XITVBV | Sortie du VBI (fin d'un handler VBI). |
$E465 | SIOINV | Initialisation SIO. |
$E474 | WARMSV | Warm restart — réinitialise l'OS sans effacer la RAM. |
$E477 | COLDSV | Cold start — réinitialisation complète (efface la RAM). |
| Adresse | Étiquette | Description |
|---|---|---|
$D800 | AFP | ASCII → virgule flottante (chaîne pointée par $F3/$F4 → FR0). |
$D8E6 | FASC | Virgule flottante → ASCII (FR0 → chaîne pointée par $F3/$F4). |
$D9AA | IFP | Entier 16 bits → virgule flottante (valeur en $D4/$D5 → FR0). |
$D9D2 | FPI | Virgule flottante → entier 16 bits (FR0 → $D4/$D5). |
$DA44 | ZFR0 | Met FR0 à zéro. |
$DA60 | FSUB | Soustraction flottante : FR0 ← FR0 − FR1. |
$DA66 | FADD | Addition flottante : FR0 ← FR0 + FR1. |
$DADB | FMUL | Multiplication flottante : FR0 ← FR0 × FR1. |
$DB28 | FDIV | Division flottante : FR0 ← FR0 / FR1. |
$DD40 | PLYEVL | Évaluation polynomiale (pour sin, cos, exp…). |
$DD89 | FLD0R | Charge FR0 depuis l'adresse en (X,Y). |
$DD98 | FLD1R | Charge FR1 depuis l'adresse en (X,Y). |
$DDA7 | FSTOR | Stocke FR0 à l'adresse en (X,Y). |
$DDB6 | FMOVE | FR1 ← FR0. |
Récapitulatif des registres matériels des quatre puces customs de l'Atari 800XL, avec leur usage typique en programmation.
$D000–$D01F)| Adresse | Nom | R/W | Usage |
|---|---|---|---|
$D000–$D003 | HPOSPn | W | Position horizontale des 4 joueurs (sprites) |
$D004–$D007 | HPOSMn | W | Position horizontale des 4 missiles |
$D008–$D00B | SIZEPn | W | Taille des joueurs (1×, 2×, 4×) |
$D00C | SIZEM | W | Taille des missiles |
$D00D–$D010 | GRAFPn | W | Forme du joueur n (8 bits = 8 pixels) |
$D011 | GRAFM | W | Forme des 4 missiles (2 bits chacun) |
$D012–$D015 | COLPMn | W | Couleur joueur n |
$D016–$D019 | COLPFn | W | Couleur playfield 0–3 |
$D01A | COLBK | W | Couleur fond |
$D01B | PRIOR | W | Priorité joueurs/playfields, mode GTIA |
$D01C | VDELAY | W | Délai vertical missiles/joueurs (résolution fine) |
$D01D | GRACTL | W | Activation DMA joueurs/missiles |
$D01E | HITCLR | W | Écriture : remet à zéro les registres de collision |
$D01F | CONSOL | R/W | Lecture : touches START/SELECT/OPTION. Écriture : haut-parleur |
$D200–$D20F)| Adresse | Nom | R/W | Usage |
|---|---|---|---|
$D200–$D207 | AUDFn / AUDCn | W | Fréquence et contrôle des 4 canaux audio (paires AUDF/AUDC) |
$D208 | AUDCTL | W | Contrôle global audio (horloge, canaux 16 bits, filtres) |
$D209 | STIMER | W | Remet les timers à zéro |
$D20A | SKRES | W | Remet le registre de statut série à zéro |
$D20B | POTGO | W | Démarre la conversion des potentiomètres (paddles) |
$D200–$D207 | POTn | R | Valeur des 8 potentiomètres (paddles) |
$D208 | ALLPOT | R | État des conversions potentiomètres en cours |
$D209 | KBCODE | R | Code de la touche pressée (ATASCII interne) |
$D20A | RANDOM | R | Générateur de nombres aléatoires (lecture seule) |
$D20D | SERIN | R | Donnée reçue en série |
$D20E | SEROUT | W | Donnée à émettre en série |
$D20F | SKCTL | W | Contrôle série (init, synchronisation, mode deux tons) |
$D300–$D303)| Adresse | Nom | R/W | Usage |
|---|---|---|---|
$D300 | PORTA | R/W | Joystick 1 (bits 3-0) et joystick 2 (bits 7-4) |
$D301 | PORTB | R/W | Sur 800XL : banque mémoire OS (bit 0) et BASIC (bit 1) |
$D302 | PACTL | W | Contrôle direction bits et interruptions port A |
$D303 | PBCTL | W | Contrôle direction bits et interruptions port B |
$D400–$D40F)| Adresse | Nom | R/W | Usage |
|---|---|---|---|
$D400 | DMACTL | W | Largeur écran (40/48 couleurs), DMA ANTIC/joueurs actif |
$D401 | CHACTL | W | Inverse vidéo, blanking caractères |
$D402–$D403 | DLISTL/H | W | Adresse display list (lo/hi) |
$D404 | HSCROL | W | Scrolling horizontal fin (0–15 colour clocks) |
$D405 | VSCROL | W | Scrolling vertical fin (0–15 lignes) |
$D407 | PMBASE | W | Page de base joueurs/missiles |
$D408 | CHBASE | W | Page de base police caractères |
$D409 | WSYNC | W | Attente fin de ligne raster (synchronisation CPU/vidéo) |
$D40A | VSCROL | W | (lecture VCOUNT si adresse $D40B) |
$D40B | VCOUNT | R | Compteur ligne raster courante |
$D40C–$D40D | PENH/V | R | Position crayon optique horizontal/vertical |
$D40E | NMIEN | W | Activation NMI : bit 7 = DLI, bit 6 = VBI |
$D40F | NMIRES | R/W | Lecture : source NMI. Écriture : reset flags NMI |
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 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 :
xxxxxxxxxx20 80 42 JSR $4280 ; READ_BIN (appel direct — bug)
par :
xxxxxxxxxx20 B2 52 JSR $52B2 ; → trampoline
É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.
xxxxxxxxxx$52B2: A5 E8 LDA $E8 ; compteur d'octets (0 = premier appel)$52B4: D0 08 BNE $52BE ; si 2e octet ou plus → READ_BIN directement$52B6: 20 AE 43 JSR $43AE ; 1er octet : consomme la virgule adresse,data$52B9: 90 03 BCC $52BE ; virgule trouvée (C=0) → READ_BIN$52BB: 4C EC 4B JMP $4BEC ; pas de virgule (C=1) → erreur ?$52BE: 4C 80 42 JMP $4280 ; appel READ_BIN
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.
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.
MOS Technology 6502 Microprocessor Data Sheet — MOS Technology Inc., 1975. Référence officielle des 56 instructions officielles, modes d'adressage et registres.
6502.org — Reference : http://www.6502.org/tutorials/6502opcodes.html — description détaillée des opcodes officiels avec cycles et flags.
Extra Instructions Of The 65XX Series CPU ("The Illegal Opcodes") — documentation communautaire des opcodes non documentés du 6502, notamment KIL, SLO, RLA, SRE, RRA, DCP, ISC, LAX, SAX, ANC, ALR, ARR, ANE, LXA, SBX, TAS, SHA, SHY, SHX, LAS. Consultable sur https://www.oxyron.de/html/opcodes02.html.
De Re Atari — Atari Inc., 1982. APX 90009 - Par Chris Crawford, Lane Winner, Jim Cox, Amy Chen, Jim Dunion, Kathleen Pitta, Bob Fraser, Gus Makreas - Référence technique fondamentale couvrant l'architecture hardware, les chips customs (GTIA, POKEY, PIA, ANTIC), le système d'exploitation et les routines ROM. Disponible sur AtariWiki : https://atariwiki.org/wiki/Wiki.jsp?page=De%20Re%20Atari et Atarinside (français) : https://www.atarinside.com/blog/index.php/books/de-re-atari-francais/
Mapping the Atari — Ian Chadwick, COMPUTE! Publications, 1983. Cartographie exhaustive de la mémoire Atari : page zéro, page 2, ROM OS, ROM Math, registres hardware. Disponible sur AtariWiki : https://atariwiki.org/wiki/Wiki.jsp?page=Mapping+the+Atari
Atari OS Source Listing — Atari Inc. Liste des sources de l'OS Atari 400/800/XL, avec étiquettes et commentaires. Consultable sur https://archive.org/details/atarioperatingsystemsourcelisting/mode/2up et https://www.atarimania.com/documents/atari-400-800-operating-system-source-listing.pdf
AtariWiki : https://atariwiki.org/wiki/Wiki.jsp?page=6502%20Assembly%20Code — encyclopédie communautaire couvrant le hardware, l'OS, le DOS, les formats de fichiers et les outils de développement Atari.
.PROAtari Preservation Project — Format PRO (P2/P3) : https://www.a8preservation.com/#/guides/pro/explorer — documentation du format d'image disque .PRO utilisé pour préserver les disquettes Atari avec leurs protections (secteurs fantômes, statuts FDC).
Altirra — émulateur Atari 8-bit par Avery Lee. https://www.virtualdub.org/altirra.html — utilisé pour vérifier empiriquement le comportement de chaque commande ATAMON décrit dans ce document.