HOME             LINK               CONTACT

 

PROGRAMMATION INFORMATIQUE

 

PROGRAMMATION DE L’AMIGA

 

 

I- Introduction :

 

 

Dans cette partie, nous passerons en revue toutes les concepts que nous devons savoir pour commencer à programmer l’Amiga. Si la plupart utiliserons un compilateur C ou assembleur quelconque, je parts toujours du principe que nous n’avons rien et que parfois, le programmeur préfère développer ces propres outils plus aptes a répondre a ses besoins. C’est pourquoi tous les programmes seront listés à leur niveau le plus primitif (Aucunes bibliothèques externes). Ensuite le lecteur est libre de choisir le moyen le plus approprier à ses besoins. Nous utiliserons, pour les listings, la syntaxe officielle de l’assembleur du processeur Motorola 68000. Pour plus d’informations sur ce processeur voir les liens proposés.

 

 

1)      Aperçu

 

L’Amiga est un micro-ordinateur 16/32 bits tournant autour d’un processeur Motorola 68000 cadencé a environ 7,09 MHZ (PAL). Le M68000 est un faux processeur 32 bits. Les registres internes font effectivement 32 bits mais sont bus de données n’est que de 16 bits. En revanche le processeur adresse 16 Mo de mémoire grâce à son bus de 24 bits. L’architecture de l’Amiga est construite autour de 3 circuits spécialisés appelés « Customs Chips ». Le processeur travaille en collaboration avec ces trois circuits. Chacun, de ces derniers, est chargé de taches particulières. Agnus contrôle la mémoire chip et les canaux DMA, fournit le signal d’horloge aux autres circuits, contient le coprocesseur Cooper et le Blitter. Denise est chargé de fournir en sortie le signal vidéo (en réalité, il envoie des données dans un circuit hybride qui génère ensuite le signal vidéo), elle contrôle également les sprites. Enfin Paula contrôle l’audio et les interfaces comme le lecteur de disquettes, le clavier, l’interface série et parallèle. Ces Custom Chip peuvent avoir un accès direct en mémoire par DMA, nous y reviendrons. A cela s’ajoute d’autres circuits, similaire à ce que l’on pouvait trouver a l’époque : Gary (contrôleur de bus, d’adressage et de décodage), CIA (8250 pour les ports et un compteur), un circuit vidéo Hybride etc…

 

Revenons sur les Custom Chip et leur accès en mémoire par DMA. Ces derniers n’ont accès qu’a de la mémoire dit « Chip »  alors que le M68000 possède, en plus de l’accès au CHIP, un accès sa propre extension de mémoire dit « Fast ». Pourquoi « Fast », et bien tous simplement parce que seul le processeur aura accès à cette mémoire et ne sera donc pas oblige d’attendre qu’un Custom Chip termine son boulot dans la mémoire « Chip ».  Et oui, un inconvénient de la mémoire CHIP est que la concurrence peut y être dure. Le circuit Gary (contrôleur de la logique du bus) arbitre les accès en mémoire « Chip » entre le M68000 et Agnus. Dans le meilleur des mondes cela ne devrait pas poser de problèmes : Le processeur accède au bus de mémoire 1 cycle sur 2, les Customs Chip y accèdent donc lorsque le processeur n’y accède pas, lui permettant ainsi de fonctionner a sa pleine vitesse. Mais il arrive souvent que le coprocesseur Cooper, le Blitter ou Paula bloque la mémoire « Chip obligeant ainsi le processeur à attendre. Il est évident que de la mémoire « Fast » peut apporter beaucoup.

Viennent les problèmes de la quantité de la mémoire chip selon les Amiga, les problèmes car je trouve que des références contradictoires mais possédant un Amiga 500 et un Amiga 600 j’ai pu le vérifier par moi-même :

 

L’Amiga 1000 possède 256 KO de Ram Chip non extensible car le bus mémoire de la puce Agnus est de 18 bits.

L’Amiga 500 d’origine possède 512 Ko de Ram Chip non extensible, d’après les plans je ne compte que 19 bits pour le bus d’adresse de la puce Fat Agnus.

La puce Fat Agnus de certain Amiga 500 et de l’Amiga 500+ (ECS) permet l’adressage de 1 Mo de Ram Chip.

La puce Agnus de l’Amiga 600 (nommé Super Agnus) possède la faculté d’adresser 2 Mo de Ram Chip.

 

2)      Le ROM

 

L’Amiga étant beaucoup plus complexe que ses contemporains, ses concepteurs l’ont doté d’un système d’exploitation en ROM très sophistiquée. Le ROM fournit un OS multitâche préemptif, des bibliothèques de fonctions très fournis et variées (Gestion I/O, système de fichier, allocation de la mémoire, utilisation des circuits spécialisés etc.). L’OS de l’Amiga fournit, également, une interface utilisateur fenêtrée appelle « Intuition » avec lequel on peut créer des programmes type « Window » très proche de ce que l’on a aujourd’hui avec MS Windows et Linux sur PC. Nous étudierons Intuition v34 (d’origine sur l’Amiga 500) dans la prochaine section. Les lecteurs familiarisés avec la programmation type « Window » ne seront pas dépaysés : tous les concepts y sont déjà et tous ça des 1985 !

Contrairement aux ordinateurs contemporains de l’Amiga, il n’y a pas de mappage mémoire absolue. En effet, L’Amiga est doté d’un système d’exploitation multi-tâches et donc le mappage absolue n’a pas lieu d’être, et de plus, il peut varier d’une version du ROM à un autre. Les seules exceptions à la règle sont :

-         L’adresse 0x00000004 qui contient un pointeur vers Exec qui est le cœur du système d’exploitation. (En fait, ça devrait être la seule exception)

-         BFE000-BFE001   les registres du CIA (pour la programmation hardware)

-         F00000-FFFFFF l’emplacement du ROM (commence en F80000 pour les Amiga 500/600/1000/2000)

-         DEF000-DFFFFF les registres Custom Chip (pour la programmation hardware)

 

Les adresses doivent être obtenues en appelant les fonctions du ROM. Bien sur, il est possible d’ignorer cette précaution repérer le mappage et travailler en adresse absolue mais se sera au détriment de la compatibilité. Donc je pars du principe que l’on fera de la programmation propre.

Les versions du ROM sont nombreuses, nous étudierons que les versions 33 (Kickstart v 1.2) de l’Amiga 1000 et 34 (Kickstart v 1.3) pour les Amiga 500/2000. La version 36 (v 2.0) est apparut sur l’Amiga 3000 et l’Amiga 500+, la version 37(2.04) sur l’Amiga 600 et enfin les versions 3 sur les Amiga 1200 et 4000. Ces versions (a partir de la version 2.0) apportent de nombreuses améliorations, mais nostalgie oblige, je ne cible que l’Amiga 500 (pour l’instant) et donc les versions v33-34.

Le numéro de version de la ROM se trouve en BASE+$10 sur 2 octets et le numéro de révision en BASE+$12 toujours sur 2 octets.

 

Le ROM fournit deux sortes de fonctions, les fonctions de bibliothèques (Library) et les fonctions des contextes de périphériques (Device). Nous étudierons ici ceux de la librairie. Les fonctions Device peuvent nous apporter une aide précieuse pour la manipulation des périphériques bien que, pour beaucoup de périphériques, il vaille mieux passer par le hardware directement surtout lorsqu’elles ne nous apportent que trop peu et nous compliquant même parfois la tache. Je trouve, en fait, leurs utilisations justifiées surtout pour le lecteur de disquette et la « Console Device ». Elles seront abordées lors de la section consacrée à EXEC (OS de l’Amiga).

 

       

3)                Exec, cœur du system d’exploitation de l’Amiga

 

Comme nous l’avons vu plus haut, la seule adresse absolue est l’adresse 4 qui contient un pointeur vers Exec qui est le moteur du système d’exploitation. Grâce à lui vous pouvez (et devez) :

-         Allouer de la mémoire

-         Ouvrir un Device (Un périphérique)

-         Ouvrir une Library (Dos, Graphics, Intuition)

-         Gérer le multitâches (Gestion des Task/process, Signaux et Activation/désactivation du multitâches)

-         Gérer les interruptions

-         Une foule d’autres choses

 

Les sections II et III seront consacrées en partie à Exec. Nous verrons quelques trucs de base à savoir.

Dans cette partie, on va pas mal rabacher concernant l’appelle de fonction OpenLibrary() avec Exec. Ca devrait être claire à la fin.

 

 

4)                Aperçu de l’assembleur M68000

 

Je n’ai pas l’intention d’écrire une section sur l’assembleur M68000 car la documentation sur le net afflue donc je ne vois pas ce que j’apporterais de plus. De plus même si au début pour les habitués d’autre assembleur c’est un peu déroutant on s’y fait très vite et il n’y a pas de problème majeur je dirais même plus grâce a la présence de 8 registres de données (D0-D7) et 8 d’adresses (A0-A7) ainsi que la présence de 13 modes d’adressage, l’assembleur M68000 et, je trouve, plus facile que le x86. En tous cas rien a voir avec le MOS6009 (processeur 8 bis des machines Commodore antérieur à l’Amiga dont le légendaire C64) par exemple (ceux qui l’ont essayé me comprendrons).

On va quand même passe en revue les principales manipulations avec cet assembleur sous l’Amiga.

Tout d’abords le processeur est en BIG-ENDIAN c’est quand même plus pratique que l’horrible LITTLE-ENDIAN du x86.

Le processeur M68000 possède deux modes de fonctionnement : Le superviseur et l’utilisateur.

Dans le mode utilisateur, certaines instructions ne sont pas permises. La présence de ces deux modes facilite l’implémentation d’un OS plus sur où un programme ne peut faire n’importe quoi. Mais le M68000 ne possède pas de mécanisme d’adressage virtuel d’où l’absence de protection de mémoire.

 

L’instruction MOVE.B/W/L  est, bien sur, la plus utilisée. La syntaxe est MOVE.T Source, Destination où T peut-être B(8 bits), W(16 bits) ou L (32 bits). On peut avec:

 

Copier directement la valeur de registre entre eux :

            MOVE.B        D0,D1             ; Copie 8 bits de D0 dans D1 exemple: D0=$12345678, D1=$0 => D1=$00000078

            MOVE.W       D1,A1             ; Copie 16 bits de D1 dans A1 exemple: D0=$12345678, D1=$0 => D1=$00005678

            MOVE.L        A1,D1             ; Copie 32 bits ou tout le registre A1 dans D1

 

Charger des Valeur direct dans les registre :

            Les valeur direct sont indique par le caractère #

            MOVE.L        #$8766,D0      ; Copie la valeur de $8766 dans D0  exemple D0=$1234568 => D0=$00008766

            MOVE.W       #$8766,D0      ; Copie 16 bits  $8766 dans D0         exemple D0=$1234568 => D0=$12348766           (remarquez la nuance)

            MOVE.L        #$8766,A1      ; Marche aussi avec les registres d’adresse

 

Lire ou écrire dans la mémoire ave les registres : 

            L’absence du caractère # nos indique que l’on manipule un adresse. Ici il y a une petite nuance lorsque l’on fait une copie de 16/8bit

            Supposons que l’adresse $8766 contiennent sur 4 octets la valeur $00 01 20 80          

            MOVE.L        $8766,D0        ; Copie la valeur se trouvant a l’adresse $8766 dans D0 => D0=$00012080

            MOVE.W       $8766,D0        ; Copie 16 bits de la valeur se trouvant a l’adresse $8766 dans D0 => D0=$00000001

            MOVE.L        $8766,A0        ; Copie la valeur se trouvant a l’adresse $8766 dans A0

            MOVE.W       $8766,A0        ; Copie 16 bits de la valeur se trouvant a l’adresse $8766 dans A0

            Pour l’écriture il suffit juste d’inverser l’ordre des opérateurs.

 

Lire ou écrire dans la mémoire par les registres d’adresse :

            Les registres d’adresse sont utilise comme pointeur, on met entre parenthèse le registre d’adresse pour spécifier que l’on s’en sert comme pointeur.

            MOVE.L        (A1),D1           ; Copie la valeur se trouvant a l’adresse indique par A1 dans D1

            MOVE.L        (A1)+,D1         ; Même chose mais incrémente ensuite A1 de 4 octets

            MOVE.W       (A1)+,D1         ; Même chose mais copie 2 octets et incrémente ensuite A1 de 2 octets

MOVE.B        (A1)+,D1         ; Même chose mais copie 1 octet et donc incrémente ensuite A1 de 1 octet

            MOVE.L        -(A1),D1          ; Décrémente A1 et ensuite copie la valeur            

            MOVE.L        4(A1),D1         ; Copie la valeur pointer par (A1 + 4)

            MOVE.L        (A1,D2),D1     ; Copie la valeur pointer par (A1 + D2)

            MOVE.L        4(A1,D2),D1   ; Copie la valeur pointer par (A1 + D2 + 4)

Pour l’écriture il suffit juste d’inverser l’ordre des opérateurs.

 

Différence entre instruction LEA/MOVE et adressage relatif :

            L’instruction LEA (Load effective adress) prend obligatoirement un registre An comme opérateur de destination.

L’adressage relatif s’écrit OFFSET(PC) bien sur avec un compilateur on peut écrire le nom de la variable a la place de l’offset.

            Un code avec que des adresses relatives peut-être reloger partout. Nous reviendrons sur les problèmes d’adresse absolue.

            Supposons que la variable DOSNAME se trouve a l’adresse $534BC et contient $646F732E (« dos. »)

            MOVE.L        #DOSNAME(PC),A1            ; A1 contient l’adresse $534BC

MOVE.L        DOSNAME(PC),A1              ; A1 contient la valeur a l’adresse $534BC c'est-à-dire $646F732E

            LEA                DOSNAME(PC),A1              ; A1 contient l’adresse $534BC.       LEA #DOSNAME(PC),An n’est pas permis.

            LEA                #DOSNAME,A1                    ; A1 contient la valeur a l’adresse $534BC c'est-à-dire $646F732E

ATTENTION ! Les instructions avec adressage relatif ne sont pas permises en écriture :

MOVE.L        A1,DOSNAME(PC)              ; INSTRUCTION NON PREMISE

           

 

Gestion de la pile :

            Il n’y a pas d’instruction explicite push et pop. On se sert d’un registre d’adresse et on effectue les opérations suivantes :

            MOVE.L        D0,-(A1)                                  ; PUSH D0

            MOVE.L        (A1)+,D0                                 ; POP  D0

            Le registre A7 est utilisé comme pile et la plupart des compilateurs acceptent le registre SP qui équivaut à A7

Lorsque l’on veut empiler plusieurs registres, une instruction bien utile est MOVEM. Elle permet de transférer plusieurs registres à la fois. Voici des exemples :

MOVEM.L    D0/D2/A0/A1,-(SP)                ; Transfère les registres D0,D2 A0 et A1 dans la pile.

MOVEM.L    (SP)+, D0/D2/A0/A1              ; Dépile les registres ci-dessus.

MOVEM.L    D0-D7/A1-A6, -(SP)               ; Transfère tous les registre excepté A7 dans la pile

MOVEM.L    (SP)+,D0-D7/A1-A6               ; Dépile les registres ci-dessus

           

Branchement :

Le registre CCR sur 8 bits contient les flags suivant : X, N, Z, C et V. Les utilisation des branchements sont sans surprise avec les instructions comme TST (effectue un AND sans sauver le résultat), CMP (Effectue une soustraction sans sauver le résultat) et autre opérateurs. Les branchement sont relatif : BCC.S et BCC.W pour les sauts signe de 1 et 2 octets respectivement.

ATTENTION ! BCC.L n’est pas accepté par le Processeur M68000 et M68010. On l’ignorera car nous ciblons l’Amiga 500 avec le processeur M68000.

Voici la liste des instructions principales de branchements relatifs :

BCC    (C=0 =>Carry Clear)

BCS     (C=1 => Carry Set)

BEQ    (Z=1 => EQUAL 0)

BNE    (Z=0 => NOT EQUAL 0)

BGT     (N=0 => GREATER THAN)

BLT     (N=1 => LESS THAN)

BGE     (N=0 C=1 GREATER OR EQUAL)

BLE     (N=1 C=1 LESS OR EQUAL)

BVC    (V=0 OVERFLOW CLEAR)

BVS     (V=1 OVERFLOW SET)

            BRA    (ANY)

            Bien sur l’inévitable instruction JMP (branchement inconditionnel) qui accepte tous les types d’adressages vus.

 

Fonction :

            L’instruction BSR.S/W sauve le PC dans la pile et effectue un saut relatif dans une routine qui doit se terminer par RTS.

JSR sauve le PC dans la pile et effectue un saut avec n’importe quelle type d’adressages vus avec l’instruction MOVE. Par exemple: JSR OFFSET(A6) sera très souvent employer pour l’appel d’une fonction du ROM.

 

Opération :

Le processeur possède toutes les instructions auquel on peut s’attendre je vous laisserez le soin de les découvrir, ils sont sans surprise et se combinent avec quasi tous les modes d’adressage vus.

Juste se rappeler que la syntaxe est toujours OPE SRC, DST et produit DST=> DST OPE SRC. (OPE est bien sur l’instruction d’opération). Les suffixes b, w et l s’appliquent pour la plupart sans problème.

Exemples :

            MOVEQ         #50,D0

            MOVEQ         #25,D1

            SUB.L             D1,D0             ; D0=D0-D1 => D0=50-25=25

            MOVE.L        #$AA8F,D1

            ROL.B            #4,D1              ; Rotation de 4 bits sur le premier octet du registre D1 => $AAF8 

 

Une remarque pour les instructions MOVEQ, ADDQ et SUBQ.

MOVEQ utilise des valeurs directs sur 8bits et effectuent donc leur opération plus vites que son pendant : MOVE. Mais il ne s’applique MOVEQ ne s’applique qu’à un registre Dn.

En revanche ADDQ et SUBQ s’appliquent à n’import quel registre mais sur 3 bits avec des valeurs de 1 a 8. Les instructions ADDQ # 1,Dn et SUBQ #1,Dn remplacent les inc et dec des processeur x86.

Exemple :

MOVEQ         #0,D0

ADDQ            #4,A1

SUBQ             #8,A2

 

Instructions utiles :

            L’instruction DBRA Dn,Label décrémente Dn et se branche au Label tant que Dn est différent de 0.

            L’instruction CLR efface registre ou mémoire. Attention, mieux vaut faire MOVEQ #0,D0 que CLR.L D0 (4 cycles contre 6).

 

Optimisation :

La règle d’or est de se rappeler que nous avons affaire avec un processeur dons le bus de données est de 16 bits et dépourvu de cache d’instruction. Donc la longueur d’une instruction influe sur la performance car le processeur doit d’abord precharger les instructions avec son bus de 16 bits. Par exemple, l’instruction MOVEQ et plus rapide que MOVE.L car la taille de l’instruction est de 2 octets contre 6 ! Donc pour MOVE.L #DATA, il y a 3 cycle pour le prechargement contre un seul pour MOVEQ #DATA

Bon les conclusions est que l’on doit utiliser un maximum les registres, on en a vraiment un paquet. Et bien sur éviter le plus possible les écritures/lecture en mémoire quand cela n’est pas vraiment nécessaire. Ne pas hésiter à utiliser tous les modes d’adressage pour faire n pierres d’un coup. Utiliser un maximum les instructions MOVEQ, ADDQ et SUBQ.

Bon, toutes ces remarques sont évidentes et révèle du bon sens. Je connais mal l’Amiga et son hardware compliqué fait que l’optimisation est sûrement plus complexe qu’un bête comptage de cycle.

 

Remarque avec l’Amiga :

Etant donnes que le processeur et Agnus se partage la mémoire chip, chacun d’eu a accès au bus d’adresse tous les 2 cycles. De ce fait l’instruction TAS est a éviter car cette instruction ne s’adapte pas au cycle 1 sur 2.

L’instruction MOVE SR est privilégie pour les processeur a partir du M680020, donc il faut par conséquence utilise la fonction d’Exec GETCC().

Les adresses doivent être tous considéré comme 32 bits. (Même si l’Amiga ignore les bits supérieurs b31-b28).

Les adresses doivent être obligatoirement alignées sur 16 bits c'est-à-dire être paire. Fait attention à ce détail lorsque vous utiliser de la mémoire statique en programme et penser a ce que votre compilateur possède la directive EVEN ou bien alors que le compilateur aligne automatiquement les pointeurs statiques. (Par exemple DEVPAC le fait pour nous et possède aussi la directive EVEN, ASMONE signal le non alignement à la compilation).

Voici un petit lien dans lequel l’auteur fait une petite récapitulation des choses à faire et à ne pas faire avec l’Amiga : http://www.mways.co.uk/amiga/howtocode/text/generalguidelines.php

En tous cas, ne trouvez vous pas que le M68000 est merveilleux !? Tous ces modes d’adressages et pour la plupart utilisables quelques soient l’instruction ! 16 registres de 32 bits !

Moi il m’a vraiment séduit.

 

L’Amiga 1200 utilise un processeur 680020H et il y a beaucoup d’amélioration. D’abord le bus de données passe à 32 bits ! Et la fréquence est doublée. Résultat une puissance multipliée par 4: les opérations d’écriture deviennent plus rapides que le Blitter. C’est un presque vrai processeur 32 bits, mais presque car le bus d’adresse reste a 24 bits. De plus le M680020 possède un cache d’instruction de 256 octets. Le « self-modifying » code n’est donc plus permis. (D’ailleurs même avec un M68000 il n’y a vraiment que peu d’intérêt). Les bidouilles d’optimisation avec ce processeur sont quasi sans limite. Mais attention pour pouvoir profiter la toute puissance de ce processeur, de la RAM FAST est obligatoire. Sinon il passe la majeur partie de son temps a attendre que la chip se libère : un vrai gâchis.

Mais je ne parlerai pas de l’Amiga 1200 (enfin pas encore).

 

 

5)                Ouverture d’une LIBRARY

 

La syntaxe utilisée est conforme à la syntaxe officielle du M68000. Dans les exemples de cette section, j’ai utilisé un cross compilateur sous Windows : x68k (D’où le END START a la fin).

Plus tard on supposera que nous sommes sous le DevPac v2.

Pour ouvrir une bibliothèque, on doit avoir ceci.

           

            ABSEXECBASE                  EQU        4

                LVS_OPENLIBRARY       EQU        -552

                LVS_CLOSELIBRARY     EQU        -414

               

                START

                                MOVE.L                ABSEXECBASE,A6                           ; On copie le contenu de la mémoire pointer en $0000 0004 dans A6

                                ; C'est-à-dire la base de EXEC

                                LEA                        DOSNAME(PC),A1                            ; A1 pointe sur DOSNAME              

                                MOVE.L                #33,D0                                   ; D0 doit contenir le numéro de version. Ici 33, pour assurer la compatibilité avec WB1.2

                                                                                                                                ; Si 0 alors le système nous retourne la dernière version

                                JSR                        LVS_OPENLIBRARY(A6)

                ; La fonction retourne la base de la bibliothèque en D0. Si D0 est nulle, l’ouverture a échouée

                ; **************************************************************************

                ; Fermeture de la bibliothèque

                                MOVE.L                D0,A1

                                JSR                        LVS_CLOSELIBRARY(A6)

                ; On quitte

MOVE.L                #0,D0

                                RTS

               

                DOSNAME           DC.B      « dos.library »,0 

                END START        

 

Dans cette exemple, on ouvre la bibliothèque « dos.library » cette dernière nous fournit toutes les fonctions pour la gestion de fichiers et la gestion de la console de base.

Pour ouvrir une Library, on doit se servir de la fonction OPENLIBRARY de Exec (offset -552) par l’utilisation de jsr offset(A6) ou A6 (registre 32 bits d’adresse du M68000) doit contenir l’adresse de Exec. Comme nous l’avons déjà vu, cette adresse se trouve en 0x04. Avant d’appeler OPENLIBRARY, on doit s’assurer que le registre A1 pointe sur la chaîne de caractère contenant le nom de la Library à ouvrir (ici dos.library) et doit se terminer par 0. Le registre D0 doit contenir la version désirée. La fonction nous retourne en D0 le pointeur de la Library. En cas d’erreur, D0 sera nulle.

Ensuite lorsque on n’a plus besoin de la Library, il faut la fermer via la fonction CLOSELIBRARY de Exec (offset -414) où A1 doit contenir le pointeur sur la Library à fermer.

 

La documentation indispensable se trouve ici. Dans le fichier LVO.offs se trouve tous les fonctions avec leur offset et dans le fichier STRUCTURE.offs les structures (ouaa) utilisées pas l’OS de l’Amiga.

La description des fonctions se trouve dans les fichiers « .Doc » relatifs. Cette documentation est le minimum absolu au niveau Software. Avec elle, vous pouvez absolument tout faire avec l’Amiga pour peu que vous ne passiez pas directement par le Hardware. Donc je redonne le lien : Indispensable. (Merci Gege de AmigaMuseumTitan ).       

Ce trouve également les fichiers include officiels de pré-compliation contenant notamment la valeur de différents attributs utilisés par les fonctions du ROM et quelques macros et fonctions utiles mais j’avoue que je ne m’en sert pas car je préfère utilise mes propres fichier include et écrire mes propres fonctions. (Ne jamais présumer que des sources officielles fonctionnent a 100% si vous ne me croyiez pas, jetez un coup d’œil sur la routine ConvBin2Str officielle. Ecrivez vous même vos fonctions, rien de pire qu’un truc qui fonctionne pas car il y a un bug dans un bidule externe. Si vous faites tous vous même, au moins vous avez le contrôle sur tout et que si quelque chose foire c’est forcement de votre faute. C’est valable pour mes listings qui sont bourrés de défaut et ne sont la que pour illustrer les points aborder.)

Rappelez vous que l’auteur de cette article est un authentique débutant avec l’AMIGA. 

 

 

4)      Les offsets des structures et des fonctions du ROM

 

Pour programmer proprement l’Amiga, on doit se servir le plus possible des fonctions du ROM. Comme nous l’avons vu, il n’existe qu’un seul adresse absolue : $04 où se trouve l’adresse de base de EXEC. Tous le reste, doit être accéder via des appelles au bibliothèque. Chaque bibliothèque est organisée de manière similaire. Elle possède toute une adresse de base fournit par la fonction OPENLIBRARY de EXEC. Les fonctions possèdent des offsets absolues par rapport à leur base. Par exemple pour appeler la fonction OPENLIBRARY, on récupère la base en $04 et on utilise l’offset -552 ($0FDD8 en hexadécimale). Les paramètres des fonctions sont passés dans les registres D et A (en général Dn pour des valeurs et An pour des pointeurs) ces paramètres varient bien sur en fonction des fonctions appelées. Les fonctions retourne toujours en D0. En général une valeur de 0 indique une erreur. Les registres A0, A1, D0 et D1 sont altérées : ceci est TRÈS IMPORTANT et est sujet a de nombreuses erreurs au début (j’en sais quelque chose J).

Récapitulons une dernière fois  pour l’ouverture de la Library « intuition.library ».

OPENLIBRARY prend en paramètres A0 pointeur d’un texte contenant le nom de la librairie que l’on veut ouvrir et D0 le numéro de version (on utilisera 33 pour la compatibilité maximal). Donc pour ouvrir et récupérer la base de INTUITION on doit avoir ceci :

 

            EXECBASE                          EQU        4

                EXEC_OPENLIBARY        EQU        -552

                ……………………………………………

                move.l                     EXECBASE,A6                                    ; copie le contenu en $04, l’adresse de EXEC, dans A6

                move.l                     #INTNAME,A0                                    ; A0 pointe sur INTNAME

                move.l                     #33,D0                                                   ; copie 33 dans D0

                jsr                           EXEC_OPENLIBRARY(A6)             ; Appelle de OPENLIBRARY : sauvegarde des contextes et saut en mémoire a l’adresse A6 offset -552

                tst.l                         D0                                                           ; D0 doit contenir l’adresse de base d’intuition

                ……………………………………………

                INTNAME             DC.B      « intuition.library »,0 

 

Remarquez la différence entre move.l EXECBASE, A6 et move.l #INTNAME, A0. Le caractère # est primordiale. La première instruction  copie 4 octets (long) du contenue de la mémoire pointe en $04 (Valeur de EXECBASE) dans A6, alors que la deuxième instruction copie l’adresse de INTNAME dans A0.

Dans l’exemple ci-dessus, l’adressage absolue est utilise avec:   MOVE.L #INTNAME, A0

L’adressage relatif qui permet de reloger du code n’importe où  est utilisée avec:            LEA INTNAME(PC),D0  ou bien MOVE.L #INTNAME(PC),D0

On peut ainsi reloger ce code n’ importe où sans avoir à connaître au départ l’adresse de INTNAME c'est-à-dire l’adresse du code.

Bien sur l’adressage absolue et plus pratique car plus lisible mais surtout il est, parfois, indispensable lorsque les offsets sont supérieures à 32 KO (ça peut arriver !) et surtout lorsque une partie du code est en Chip l’autre en Fast et donc deux blocs qui peuvent être séparer de facilement plus de 32 KO. Car le processeur Motorola 68000 ne permet des déplacements relatifs que de 2 octets signés. Comment cela se passe, alors que l’on ne connaît pas l’adresse de départ de notre programme, mais qu’une valeur absolue est indispensable ??

En faite, un programme Amiga démarré à partir du DOS doit respecter une certaine structure où, entre autre, l’adressage absolu y est résolu.

 

 

 

5)      Le format des exécutables

 

Un exécutable AmigaDos valide doit être structure de façon particulière. Les Hunks sont des blocs de données pouvant contenir du code et des données. Les exécutables doivent être composés de Hunks. Au moins un Hunk avec dedans un Hunk Code et éventuellement des Hunk_reloc32 nous allons y venir. 

On va faire simple avec un exemple, supposons le code suivant :

 

EXECBASE                          EQU        4

LVS_OPENLIBRARY       EQU        -552

LVS_CLOSELIBRARY     EQU        -414

               

code.      

                MOVE.L                EXECBASE,A6                                    ; EXECBASE dans A6

                MOVE.L                #DOSNAME,A1                                  ; Name: Dos          PREMIER ADRESSE ABSOLUE

                MOVE.L                #33,D0                                                   ; Version: Compatible WB 1.2

                JSR                        LVS_OPENLIBRARY(a6)                ; Call OpenLibrary

                TST.l                      D0

                BEQ.S                    failed

                MOVE.l                 D0,DOSPTR                                        ; DEUXIEME ADRESSE ABSOLUE

                MOVE.l                 DOSPTR,A1                                        ; TROIXIEME ADRESSE ABSOLUE

                MOVE.L                EXECBASE,A6                                    ; EXECLIBRARY dans A6

                JSR                        LVS_CLOSELIBRARY(a6)              ; Call CloseLibrary

                MOVEQ                #0,D0                                                     ; Return Code

                RTS                                                                                        ; Exit

failed

                MOVE.L                #20,D0                                                   ; Code d’erreur

                RTS                                                                                        ; Exit

 

DOSPTR                                               DC.L      0

DOSNAME                                           DC.B      'dos.library',0

                         

Voici le résultat du Fichier Objet (exécutable):

DESCRIPTION                                                                                               BINAIRE

HUNK_HEADER                                                                                           00 00 03 f3

N1=NOMBRE DE CARACTERE POUR LE NOM (ici pas de Nom)            00 00 00 00

NOMBRE DE HUNK (ici un seul)                                                                  00 00 00 01

PREMIER HUNK                                                                                           00 00 00 00

DERNIER HUNK                                                                                           00 00 00 00

TAILLE DU PREMIER HUNK                                                                       00 00 00 13

HUNK_CODE                                                                                                00 00 03 e9

TAILLE DE HUNK                                                                                         00 00 00 13

DONNEES CODE :

$00                  MOVE.L         4,A6                                                                2c 79 00 00 00 04                                          

$06                  MOVE.L         #DOSNAME,A1                                             22 7c 00 00 00 40                                          

$0C                 MOVE.L         #$21,D0                                                          20 3c 00 00 00 21                                          

$12                  JSR                  $FDD8(A6)                                                     4e ae fd d8                                                      

$16                  TST.L              D0                                                                   4a 80                                                              

$18                  BEQ.S             $1A                                                                 67 1a                                                              

$1A                 MOVE.L         D0,DOSPTR                                                   23 c0 00 00 00 3c                                           

$20                  MOVE.L         DOSPTR,A1                                                   22 79 00 00 00 3c                                          

$26                  MOVE.L         4,A6                                                                2c 79 00 00 00 04                                          

$2C                 JSR                  $FE62(A6)                                                      4e ae fe 62                                                      

$30                  MOVEQ          #0,D0                                                              70 00                                                              

$32                  RTS                                                                                         4e 75                                                              

$34                  MOVE.L         #$14,D0                                                          20 3c 00 00 00 14                                          

$3A                 RTS                                                                                         4e 75                                                              

DONNEES

$3C                 DOSPTR                                                                                00 00 00 00                                                    

$40                  «dos.library »,0                                                                      64 6f 73 2e 6c 69 62 72 61 72 79 00              

HUNK_REALOC32                                                                                       00 00 03 ec

NOMBRE DE REALOC A EFFECTUER                                                       00 00 00 03

DANS LE HUNK                                                                                           00 00 00 00

PREMIER                                                                                                        00 00 00 08

DEUXIME                                                                                                       00 00 00 1c

TROIXIEME                                                                                                   00 00 00 22

FIN (ZERO)                                                                                                    00 00 00 00

HUNK_END                                                                                                   00 00 03 f2

 

En gras les endroits concerne par la réallocation. Donc si vous utiliser un cross compilateur ne pas oublier en linkant d’indiquer a quelle endroit nous avons des adressage absolues dans le HUNK de realoc32.

Par exemple imaginons que le programme démarre à l’adresse $60000, les variables auront les adresses suivantes :

$6003C                       DOSPTR                                                                                00 00 00 00                                                    

$60040                        «dos.library»,0                                                                       64 6f 73 2e 6c 69 62 72 61 72 79 00       

Et les partie a « relocer » seront effecteur en ajoutant $60000. D’où le résultat suivant :

$60000                        MOVE.L         4,A6                                                                2c 79 00 00 00 04                                          

$60006                        MOVE.L         #DOSNAME,A1                                             22 7c 00 06 00 40                                          

$6000C                       MOVE.L         #$21,D0                                                          20 3c 00 00 00 21                                          

$60012                        JSR                  $FDD8(A6)                                                     4e ae fd d8                                                      

$60016                        TST.L              D0                                                                   4a 80                                                              

$60018                        BEQ.S             $1A                                                                 67 1a                                                              

$6001A                       MOVE.L         D0,DOSPTR                                                   23 c0 00 06 00 3c                                           

$60020                        MOVE.L         DOSPTR,A1                                                   22 79 00 06 00 3c                                          

$60026                        MOVE.L         4,A6                                                                2c 79 00 00 00 04                                          

$6002C                       JSR                  $FE62(A6)                                                      4e ae fe 62                                                      

$60030                        MOVEQ          #0,D0                                                              70 00                                                              

$60032                        RTS                                                                                         4e 75                                                              

$60034                        MOVE.L         #$14,D0                                                          20 3c 00 00 00 14                                          

$6003A                       RTS                                                                                         4e 75                                                              

 

Merci à CybFree pour son explication.

Bon la plupart d’entre nous utiliserons un environnement comme DEVPAC ou ASMONE et n’aurons pas à se soucier de ces détails.

 

 

6)      Quelques Exemples Simples

 

Avant de commencer, signalons rapidement qu’un programme standard Amiga peut-être de deux types : Soit lancer depuis le CLI, soit lancer depuis le Workbench. On reviendra sur le Workbench dans la partie consacre a Intuition (la différence est minime mais importante). Pour l’instant tous nos programmes sont lancés à partir CLI. Cela signifie qu’aucun process n’est créer : le CLI saute directement a notre programme par un appel de fonction, notre programme se lance au sein du process du CLI. Notre programme peut emprunter au CLI la console (fonction Output/Input).

 

Comme nous l’avons maintes et maintes fois vus, on ouvre d’abord la Library dont on veut utilise les fonctions. La fonction OpenLibrary nous retourne la base de la Library en D0.

Ensuite a partir de cette base, nous utilisons les offset des fonctions pour sauter a la fonction souhaiter par jsr offset(BASE).

Avant de commencer, voici la liste des fonctions utilisées, dans ces exemples, avec leur offset et leurs paramètres entre parenthèse.

 

Exec

414 $fe62 -$019e CloseLibrary(library)(A1)

552 $fdd8 -$0228 OpenLibrary(libName,version)(A1,D0)

 

Dos.Library

48 $ffd0 -$0030 Write(file,buffer,length)(D1/D2/D3)

60 $ffc4 -$003c Output()

 

Intuition.library

96 $ffa0 -$0060 DisplayBeep(Screen)(A0)

 

Cela permettra une compréhension plus facile du code fortement commenté. Comme rien ne vaut la pratique vous pouvez essayer quelques autres exemples pour vous entraîner et vous familiariser.

 

Display Beep

Comme premier exemple, nous allons afficher le célèbre « beep » jaune. Pour ce faire nous utilisons la fonction DisplayBeep()  (offset -96) de la librairie Intuition. C’est l’exemple officiel de Commodore dans ses références (Appelée « EasyASM »  J).

 

AbsExecBase                                                        EQU        4

LVS_OPENLIBRARY                                       EQU        -552

LVS_CLOSELIBRARY                                     EQU        -414

LVS_INTIUTION_DISPLAYBEEP                 EQU        -96

               

start      

                MOVE.L                AbsExecBase,A6                                                 ; EXECLIBRARYBASE

                LEA                        INTUITIONNAME(PC),A1                                ; Name: Intuition

                MOVEQ                #33,D0                                                                   ; Version: Compatible WB 1.2

                JSR                        LVS_OPENLIBRARY(a6)                                ; Call OpenLibrary

*              On verifie que tous est en ordre=> d0 !=0

                TST.l                      d0

                BEQ.S    failed                                                                                      ; Si D0=0, L’ouverture de la Library a echouer

continue1

                MOVE.L                d0,A6                                                                     ; Mettre D0(Intuition) dans A6

                MOVEQ                #0,A0                                                                     ; Pointeur Screen est null

                JSR                        LVS_INTIUTION_DISPLAYBEEP(a6)          ; BEEP JAUNE !!

               

                MOVE.L                A6,A1                                                                    ; Intuition dans A1

                MOVE.L                AbsExecBase,A6                                                 ; EXECLIBRARY dans A6

                JSR                        LVS_CLOSELIBRARY(a6)                              ; Call CloseLibrary

                MOVEQ                #0,D0                                                                     ; Return Code

                RTS                                                                                                        ; Exit

failed

                MOVEQ                #20,D0                                                                   ; Fail Code

                RTS                                                                                                        ; Exit

 

INTUITIONNAME                               DC.B 'intuition.library',0

 

 

Hello Word

Pour afficher du texte en console on écrit dans le output du DOS que l’on récupère grâce à DOS_OUTPUT().

 

AbsExecBase                                                        EQU        4

LVS_OPENLIBRARY                                       EQU        -552

LVS_CLOSELIBRARY                                     EQU        -414

DOS_OUTPUT                                                    EQU        -60

DOS_WRITE                                                       EQU        -48

               

start      

                MOVE.L                AbsExecBase,A6                                                 ; EXECLIBRARYBASE

                LEA                        DOSNAME(PC),A1                                            ; Name: Dos

                MOVE.L                #33,D0                                                                   ; Version: Compatible WB 1.2

                JSR                        LVS_OPENLIBRARY(a6)                                ; Call OpenLibrary

                TST.l      d0

                BEQ.S    failed

continue

                MOVE.L                d0,A6                                                                     ; Mettre D0(Dos) dans A6

                JSR                        DOS_OUTPUT(a6)                                             ; D0= CurrOutput

                MOVE.L                D0,D1                                                                    ; D1 contient le output

                LEA                        MYTEXT(PC),A3                                                ; Charge le pointeur de MYTEXT dans A3

                MOVE.L                A3,D2                                                                    ; D2=Pointeur vers MYTEXT

                MOVE.L                #13,D3                                                                   ; Longueur du Texte

                JSR                        DOS_WRITE(a6)                                                ; On Affiche le texte

                MOVE.L                A6,A1                                                                    ; Dos dans A1

                MOVE.L                AbsExecBase,A6                                                 ; EXECLIBRARY dans A6

                JSR                        LVS_CLOSELIBRARY(a6)                              ; Call CloseLibrary

                MOVEQ                #0,D0                                                                     ; Return Code

                RTS                                                                                                        ; Exit

failed

                MOVEQ                #20,D0

                RTS

 

DOSNAME                                           DC.B 'dos.library',0

MYTEXT                                               DC.B 'Hello Word !',$0A,0

 

 

MonEcho

La ligne de commande d’un programme CLI est placée en A0 et D0 contient la longueur du tampon. A partir de la, il est très simple de réécrire un Echo.

 

AbsExecBase                                                        EQU        4

LVS_OPENLIBRARY                                       EQU        -552

LVS_CLOSELIBRARY                                     EQU        -414

DOS_OUTPUT                                                    EQU        -60

DOS_WRITE                                                       EQU        -48

               

start      

; On récupère les paramètres en A0 (Adresse de l'argument) et D0 (Longeur du buffer)

                LEA                        DOSCMDLEN(PC),A3

                MOVE.L                D0,(A3)

                LEA                        DOSCMDBUFF(PC),A3

                MOVE.L                A0,(A3)

                MOVE.L                AbsExecBase,A6                                                 ; EXECLIBRARYBASE

                LEA                        DOSNAME(PC),A1                                            ; Name: Dos

                MOVEQ                #33,D0                                                                   ; Version: Compatible WB 1.2

                JSR                        LVS_OPENLIBRARY(a6)                                ; Call OpenLibrary

                TST.l                      d0

                BEQ.S    failed

continue

                MOVE.L                d0,A6                                                                     ; Mettre D0(Dos) dans A6

                JSR                        DOS_OUTPUT(a6)                                             ; D0= CurrOutput

                MOVE.L                D0,D1                                                                    ; D1 contient le output

                LEA                        DOSCMDBUFF(PC),A3                                    ; Charge le pointeur de texte dans A3

                MOVE.L                (A3),D2                                                                  ; D2=Pointeur vers le texte

                LEA                        DOSCMDLEN(PC),A3                                       ; Charge la pointeur de la longueur dans A3

                MOVE.L                (A3),D3                                                                  ; D3=Longueur du texte

                JSR                        DOS_WRITE(a6)                                                ; On Affiche le texte

                MOVE.L                A6,A1                                                                    ; Dos dans A1

                MOVE.L                AbsExecBase,A6                                                 ; EXECLIBRARY dans A6

                JSR                        LVS_CLOSELIBRARY(a6)                              ; Call CloseLibrary

                MOVEQ                #0,D0                                                                     ; Return Code

                RTS                                                                                                        ; Exit

failed

                MOVEQ                #20,D0

                RTS

 

DOSNAME                           DC.B 'dos.library',0

DOSCMDLEN                     DC.L 0

DOSCMDBUFF                   DC.L 0

 

 

 

            7)      Gestion de la mémoire

 

Comme nous l’avons vu, l’Amiga ne possède pas de mappage statique et absolue car le mappage peut varier d’une version et d’un modèle d’Amiga à un autre. On ne devrait jamais s’attribuer des adresses absolues mais toujours se servir d’Exec pour l’allocation de la mémoire. Ci-dessous la liste des fonctions pour la gestion de la mémoire.

 

Disponibilité de la mémoire :

216 $ff28 -$00d8 AvailMem(requirements)(D1)=>D0

 

Allocation/Libération de la mémoire :

198 $ff3a -$00c6 AllocMem(byteSize,requirements)(D0/D1)

210 $ff2e -$00d2 FreeMem(memoryBlock,byteSize)(A1,D0)

 

Fonctions de copie de la mémoire :

624 $fd90 -$0270 CopyMem(source,dest,size)(A0/A1,D0)

630 $fd8a -$0276 CopyMemQuick(source,dest,size)(A0/A1,D0)

 

Attributs pour l’allocation : (requirements)

#define MEMF_PUBLIC         ; $0001            Priorité a la FAST si disponible sinon CHIP.    

#define MEMF_CHIP              ; $0002            Explicitement en CHIP

#define MEMF_FAST             ; $0004            Explicitement en FAST

#define MEMF_CLEAR          ; $010000        ZeroMemory

#define MEMF_LARGEST      ; $020000        Pour la fonction AvailMem uniquement.

 

 

Ci-dessous, un exemple complet de deux routines, une qui alloue 4 Ko de mémoire Chip sauve les informations dans des pointeurs et l’autres qui, à partir de ces pointeurs, restitue la mémoire allouée.

 

LVS_ALLOCATEMEM     EQU        -198

LVS_FREEMEM                  EQU        -210

 

AllocateMemory

                move.l     EXECBASE,A6

                move.l     #4096,D0                                              ; 4 Ko

                move.l     D0,BUFFERLEN                                  ; Copie la taille dans bufferlen

                move.l     #$010002,D1                                       ; Mémoire Chip avec l’espace initialise a 0

                jsr           LVS_ALLOCATEMEM(A6)             ; Allocate Mem

                move.l     D0,BUFFERPTR                                  ; Sauve le pointeur dans BUFFERPTR

                rts

 

FreeMemory

                move.l     BUFFERPTR,D0                                  ; pointeur du tampon a effacer en D0

                tst.l         D0                                                           ; Test D0, on vérifie que le pointeur n’est pas nul

                beq.s       EndFreeMemory                                  ; On saute si le pointeur est nul

                move.l     EXECBASE,A6                                   

                move.l     D0,A1                                                    ; A1 contient le pointeur du tampon a effacer

                move.l     BUFFERLEN,D0                                  ; D0 la taille du tampon

                jsr           LVS_FREEMEM(A6)                          ; FreeMem

EndFreeMemory

                rts

 

BUFFERPTR                        DC.L      0

BUFFERLEN                        DC.L      0

 

Ci dessous un programme complet affichant la mémoire Chip disponible en utilisant la fonction AvailMem().

Les conventions de nom diffère par rapport au premier exemple, c’est celle-ci que j’utiliserai à partir de maintenant.

MyCheckMem.asm :

 

EXECBASE                          EQU        4

EXEC_OPENLIB                 EQU        -552

EXEC_CLOSELIB              EQU        -414

EXEC_AVAILMEM            EQU        -216

DOS_OUTPUT                    EQU        -60         

DOS_WRITE                       EQU        -48

DOS_DELAY                       EQU        -198

 

code.

                ; OPENLIB DOS

                move.l     EXECBASE,A6

                lea           DOSNAME(PC),A1

                moveq     #33,D0

                jsr           EXEC_OPENLIB(A6)

                tst.l         D0

                beq.w      ExitErrorLab

                lea           DOSPTR(PC),A0

                move.l     D0,(A0)                                                  ; SAVE DOS

               

                ; CHECK MEMORY

                ; CHIP

                move.l     #$00002,D1                                         ; Attribut en D1 CHIP

                jsr           EXEC_AVAILMEM(A6)                   

                lea           CHIPMEM(PC),A2

                move.l     D0,(A2)                                                  ; Copie la valeur retourne en D0 par AVAILMEM dans CHIPMEM

               

               

; REPORT

                move.l     #STRBUFFER,A2              

                ; CHIP

                move.l     #MSGSTR1,D2

                bsr.w      PrintfSimpleFunct

                move.l     A2,A0

                move.l     CHIPMEM(PC),D0

                bsr.w      ConvUnsignedBin2Dec

                move.l     A2,D2

                bsr.w      PrintfSimpleFunct

                move.l     #MSGSTR4,D2

                bsr.w      PrintfSimpleFunct

; END REPORT  

               

ExitDoneLab

                bsr.w      CleanExitFunct

                moveq     #0,D0

                rts

 

ExitErrorLab

                bsr.w      CleanExitFunct

                moveq     #20,D0

                rts

 

; Fonction de Nettoyage

CleanExitFunct   

                move.l     EXECBASE,A6   

CleanExitFunctDos

                Move.l    DOSPTR(PC),D0

                tst.l         D0

                beq.s       CleanExitFunctDosEnd

                jsr           EXEC_CLOSELIB(A6)

CleanExitFunctDosEnd

CleanExitFunctEnd

                rts

               

; FONCTIONS AVEC DOS              

; Notre fonction qui affiche une chaîne de caractère se terminant par 0

PrintfSimpleFunct              ; IN D2=>Text

                movem.l D0-D4/A0/A1/A6,-(SP)

                move.l     DOSPTR(PC),A6

                jsr           DOS_OUTPUT(A6)

                tst.l         D0

                beq.s       PrintfSimpleFunctEnd

                move.l  D0,D4                                       ; Sauve le output dans D4

                ; Calcul la Longueur de la Chaîne de caractère pointée par D2

                Move.l    D2,A1                                    ; A1 pointe sur la chaîne de caractère

                Moveq     #0,D3                                     ; Longueur de la Chaîne   

                Moveq     #0,D0                                     ; Pour la comparaison

.Loop

                Addq       #1,D3                                     ; incrémente D3

                Move.b    (A1)+,D0                               ; Caractère dans D0

                Tst.w      D0                          

                Bne.w     .Loop                                      ; si 0 on a finit

                ; D3 contient maintenant la longueur de la chaîne et D2 pointe sur la chaîne

                move.l                     D4,D1                    ; Récupère le output

                jsr                           DOS_WRITE(A6)               ; Et Affiche

PrintfSimpleFunctEnd

                movem.l (SP)+,D0-D4/A0/A1/A6

                rts

 

; Notre fonction qui convertie la valeur non signée en D0 en valeur Décimal Texte dans un buffer pointer par  A0

ConvUnsignedBin2Dec      ; IN: D0 Value to Convert, A0=>String to fill Dec. OUT=>A0=Ao(in) FILL

                movem.l D0-D3/A0/A1/A6,-(SP)

                lea           POWER10DIM(PC),A1

                move.l     D0,D1                                    ; Travail avec D1 on conserve D0 même si ça sert a rien

                moveq     #0,D3                                     ; D3 est un drapeau pour dire si A0 est remplit

.NextPower10

                move.b    #'0',(A0)                                ; Met a '0'

                move.l     (A1)+,D2                               ; LOAD NEXT POWER10

                beq.w      .Finish                                   ; POWER 0 is finish

                cmp.l      D1,D2                                    ; D2-D1 ? POWERTEN-Cur

                ble.w       .CurP10                                ; D2<=D1 (exemple: 100-101)

                ;Sinon on verifie D3

                tst.l         D3

                beq.w      .NextPower10                       ; Encore rien

                addq        #1,A0                                     ; Sinon next String

                bra.w      .NextPower10                       ; on boucle

.CurP10

                moveq     #1,D3                                     ; Flag Fill String

                move.b    #'1',(A0)                                ; 1 minimum                        

.BoucleNumber10

                sub.l       D2,D1                                    ; D1-power 10 (exemple: 101-100 -201-100)

                cmp.l      D2,D1                                    ; Reste < p10 ? (exemple : 1<100 donc oui next - 101<100 non on ajoute )

                blt.w        .PrepareToNext                   ; Oui next power10

                add.b       #1,(A0)                                  ; Sinon +1 to char

                bra.w      .BoucleNumber10

.PrepareToNext

                addq        #1,A0

                bra.w      .NextPower10

.Finish

                ;TEST 0

                tst.l         D3

                bne.w      .Terminate

                addq        #1,A0                                     ; next string for print ‘0’

.Terminate

                move.b    #0,(A0)                                  ; Terminate string

                movem.l (SP)+,D0-D3/A0/A1/A6    

                rts          

; Table des puissances de 10 jusqu'a 100 millions

POWER10DIM    DC.L      100000000,10000000,1000000,100000,10000,1000,100,10,1,0

 

; LIBRARY NAME AND COMMON              

DOSNAME                           DC.B      "dos.library",0

DOSPTR                               DC.L      0

; FOR MEM PROG

CHIPMEM                            DC.L      0

STRBUFFER                        DC.L      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

                                                DC.L      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

                                                DC.L      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

                                                DC.L      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

MSGSTR1                            DC.B      "Memoire Chip disponible: ",0

MSGSTR2                            DC.B      " Octets",$0A,0,0

 

 

8)      Conclusion

 

A présent, je pense que nous avons vu les points essentiels pour aborder la programmation de l’Amiga en toute sérénité. Je vais donc parler de l’environnement de travail. Les éditeurs/compilateurs/linkers/debugger sont nombreux : DevPac2/3, ASMONE, ASMPro, Maxon et même les compilateurs C et C++. C’est une question de goûts. Mais on supposera que nous utilisons le DevPac2 qui fonctionne avec l’Amiga 500 et qui est vraiment excellent.

A l’heure où j’écris ces lignes, je ne connais pas encore grand-chose de l’Amiga et j’aurais bien aimé tomber sur une page comme celle la quand j’ai commencer : cela m’aurait éviter de ramer pendant 3 semaines.

La prochaine section est consacre au Dos et à Exec.