HOME LINK CONTACT
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.