|
|
||
|
COURS
D'ASM 68000
(par le Féroce Lapin) ******************************************************************
* *
* COURS D'ASSEMBLEUR 68000 SUR ATARI ST *
* *
* par Le Féroce Lapin (from 44E) *
* *
* Seconde série *
* *
* Cours numéro 3 *
*****************************************************************
Avant de continuer à étudier ces cours, je pense qu'il est grand
temps pour vous d'étudier toutes les instructions du 68000. Vous
avez déjà suffisamment de bases pour réaliser de petits programmes
et surtout vous devez vous être habitué avec le système qui
consiste à taper seulement 2 ou 3 lignes de programmes puis à
visualiser leur fonction avec MONST.
Prenez donc l'ouvrage sur le 68000 que vous avez normalement ac-
quis, et faites le tour de toutes les instructions avec cette mé-
thode. Observez bien les résultats des opérations de décalages
(ASL, ASR etc..) Il ne s'agit pas ici de les connaître par coeur
mais au moins de savoir qu'elles existent pour pouvoir, le cas
échéant, les retrouver facilement, et surtout d'être capable de
comprendre ce qu'elles font. Le nombre d'instructions est faible
mais chacune d'elle réalise une opération bien précise qu'il
convient de connaître dans ses moindres détails. Il ne suffit pas
de savoir que ROR réalise une rotation vers la droite, il faut
également savoir que le bit éjecté d'un coté est remis de l'autre
et, qu'en plus, il est recopié dans le bit C du SR. Il faut re-
marquer aussi que ROR #4,D0 est accepté mais pas ROR #9,D0. Dans
ce cas il faut faire 2 ROR ou MOVE.W #9,D1 puis ROR D1,D0. C'est
ce genre de petits trucs qui vous bloqueront plus tard si vous
n'avez pas passé quelques heures à les décortiquer!
LES INCLUSIONS DE FICHIERS
L'un des plus gros problème de l'ASSEMBLEUR se situe au niveau de
la taille des listings. Si en BASIC une ligne suffit pour une
opération parfois très complexe, nous avons vu qu'en ASSEMBLEUR ce
n'était pas le cas. Par contre nous avons vu également que
l'écriture en ASSEMBLEUR consistait à taper le bon nombre d'ins-
truction machine, alors que le compilateur du BASIC, du C ou du
PASCAL se débrouille à faire une traduction 'qui marche' et qui
n'est donc pas forcément la plus économique au niveau taille et/ou
au niveau vitesse.
En contre partie, nos sources ASSEMBLEUR font très rapidement des
pages et des pages là, où un programmeur travaillant avec un lan-
gage 'évolué' n'aurait que quelques dizaines de lignes. Il existe
cependant quelques méthodes permettant non pas d'éviter ces
multiples pages, mais de réduire sensiblement la taille du listing
sur lequel nous travaillons.
Deux directives vont principalement nous servir. Attention, ce ne
sont pas des instructions ASSEMBLEUR, mais des ordres interprétés
par l'ASSEMBLEUR. Ce sont donc, dans notre cas, des instructions
'Devpack' et non pas des instructions '68000'.
La première, INCBIN, permet d'incorporer dans le programme un
fichier binaire. Un fichier binaire cela peut-être une image, de
la digit, des sprites etc... ou bien un morceau de programme qui a
été assemblé sous forme de fichier binaire. Voici un exemple avec
une image. (listing 1 série 2)
Tout d'abord nous transférons l'adresse de l'image en A6, nous
sautons l'en-tête de celle-ci pour pointer sur les couleurs qui
sont mises en place avec Xbios(6), nous cherchons ensuite l'adres-
se de l'écran avec la fonction Xbios(3) puis, après avoir sauté la
palette de couleurs de notre image, nous transférons cette image
sur l'écran. Un écran fait 32000 octets. Si nous transférons
long mot par long mot, nous ne devons transférer que 32000
divisé par 4 c'est à dire 8000 long mots. Comme nous utilisons
une boucle DBF qui compte jusqu'à 0 compris (la boucle s'arrête
quand le compteur atteint -1), il faut donc initialiser le
compteur à 7999. Ensuite attente d'appui sur une touche et bye
bye.
Petit exercice éducatif. Une fois ce programme assemblé, suivez le
sous MONST. Lorsque Xbios(3) aura donné l'adresse de l'écran, pla-
cez la fenêtre 3 sur cette adresse puis continuez à faire avancer
pas à pas le programme, pour voir la recopie se faire. De temps en
temps tapez sur la touche V afin de voir l'écran au lieu de MONST,
vous pourrez ainsi suivre l'affichage 'en direct'!!!
Autre petit exercice: Le ST possède la particularité d'avoir en
quelque sorte 2 écrans: l'écran sur lequel on travaille (Xbios(2))
et celui que l'on voit (Xbios(3)). Dans la plupart des cas il
s'agit du même mais il est tout à fait possible de les placer à
des endroits différents de la mémoire et ainsi de préparer un
affichage dans xbios2 tout en montrant Xbios3. Il sera ainsi
possible d'afficher rapidement Xbios2 en le transférant dans
Xbios3, et ainsi, de faire des animations rapides. Essayez donc de
changer un peu le listing et de mettre MOVE.W #2,-(SP) à la
place de 3 pour la recherche de l'écran. Débuggez le programme et
constatez!
Mais ceci nous éloigne un peu du sujet qui était l'inclusion. Pour
réaliser ceci nous avons juste fourni un label de repérage qui est
ici IMAGE puis l'instruction INCBIN suivi du chemin pour trouver
cette image. Dans l'exemple c'est une image PI3 mais rien ne vous
empêche de mettre une image PI2 ou PI1! Nous aurions très bien pu
mettre 2 images l'une à la suite de l'autre, sans mettre de label
pour repérer la seconde. Pour pointer dessus, sachant qu'une
image DEGAS fait 32066 octets, nous aurions fait:
LEA IMAGE,A6
ADDA.L #32066,A6
Je rappelle que cela se lit: load effective address IMAGE dans A6
add address long...
Petit exercice: faire un programme qui tourne en moyenne réso-
lution, passe en basse, affiche une image basse résolution, attend
un appui sur une touche puis repasse en moyenne. Sachant utiliser
les fonctions Xbios et les boucles, vous devriez être capable de
faire une routine de sauvegarde de la palette et une autre de
restitution de celle-ci.
Il est tout à fait possible d'inclure ainsi des fichiers très
divers. Il existe pourtant plusieurs problèmes. Tout d'abord la
taille du programme résultant. En effet, notre image DEGAS, de
part sa taille, a grossi notre programme de 32Ko! Bien sûr il y a
maintenant l'avantage de pouvoir empêcher les bidouilleurs de
venir y mettre leur pieds! Encore qu'une image DEGAS fait
toujours la même taille, mais il est possible d'inclure une image
compactée (en mettant bien sûr une routine de décompactage dans
notre programme!).
Autre problème, le temps! En effet, si l'affichage lui même est
plus rapide du fait qu'il n'y a pas à aller chercher l'image sur
la disquette puisque cette image est déjà en mémoire avec le
programme, c'est à l'assemblage que ça pédale!!! Il faut donc pas-
ser par des mécanismes de travail bien ordonnés. Mettre en place
un disque virtuel (de préférence résistant au Reset) recopier les
images dedans et ensuite commencer à travailler. Vous comprendrez
bien vite pourquoi les possesseurs de 520 ont tout intérêt à les
faire gonfler à un méga minimum et pourquoi un lecteur externe ou
mieux un disque dur devient vite indispensable!!!
Après avoir vu le mécanisme d'inclusion de fichiers, nous allons
nous intéresser maintenant aux inclusions de listings. Il est en
effet possible de prendre un bout de listing, de le sauver sur
disquette et de demander à l'assembleur de l'inclure lors de l'as-
semblage. Là aussi, perte de temps à l'assemblage mais gain de
temps très appréciable lors de la création de programme. Par
exemple votre routine de sauvegarde de palette: faites avec soin,
elle marche bien et en fait vous en avez besoin dans tous vos
programmes. Il faut donc à chaque fois la retaper et surtout
consommer quelques dizaines de lignes avec cette routine. Perte
de temps, possibilité d'erreur de frappe et allongement bien
inutile du listing. Lorsque vous commencerez à circuler dans 10
ou 20 pages de sources à la recherche d'une variable vous com-
mencerez à comprendre de quoi je parle, en sachant en plus que 20
pages, c'est un tout petit source assembleur...
Voyons concrètement un exemple, avec la sauvegarde de palette.
SAUVE_PALETTE
MOVEM.L D0-D4/A0-A4,-(SP)
LEA ANC_PAL,A4 ptn sur le lieu de
sauvegarde
MOVE.W #15,D4 16 couleurs
.ICI MOVE.W #-1,-(SP) demande de couleurs
MOVE.W D4,-(SP) numéro de la couleur
MOVE.W #7,-(SP) Setcolor()
TRAP #14 Xbios
ADDQ.L #6,SP
MOVE.W D0,(A4)+ sauvegarde de la couleur
DBF D4,.ICI et on passe à la suivante
MOVEM.L (SP)+,D0-D4/A0-A4
RTS
ANC_PAL DC.L 0,0,0,0,0,0,0,0
REMET_PALETTE
MOVEM.L D0-D4/A0-A4,-(SP)
LEA ANC_PAL,A4 ptn sur le lieu de
sauvegarde
MOVE.W #15,D4 16 couleurs
.ICI MOVE.W (A4)+,-(SP) demande de couleurs
MOVE.W D4,-(SP) numéro de la couleur
MOVE.W #7,-(SP) Setcolor()
TRAP #14 Xbios
ADDQ.L #6,SP
DBF D4,.ICI et on passe à la suivante
MOVEM.L (SP)+,D0-D4/A0-A4
RTS
Voici donc 2 routines. Tout d'abord sachant qu'un appel à Xbios
ne sauve pas les registres D0-D3 et A0-A3 nous utilisons D4 et A4
pour le compteur de couleur et l'adresse de sauvegarde, ce qui
explique aussi la sauvegarde sur la pile au début des deux
routines. La première sauvegarde la palette et la met à l'adresse
ANC_PAL. Nous constatons que cette adresse se trouve entre les 2
routines. En effet plusieurs solutions s'offrent à nous. D'abord
la plus économique en taille c'est de mettre cette réservation
pour la palette dans la section BSS de notre programme en faisant
ANC_PAL DS.W 16 Nous avons déjà vu que la section BSS n'occupait
pas de place sur la disquette. Cependant nous avons réalisé ces
routines avec en tête l'idée de les inclure, afin de gagner en
facilité de programmation. En plaçant cette réservation entre les
routines, elle fera partie intégrante du fichier. Il n'est
cependant pas possible de la mettre en DS nous somme donc
contraint de la mettre en DC. Le danger serait que notre
programme essaye de lire cette partie. Faire un BSR ANC_PAL par
exemple serait fatal mais nous sommes assez sérieux pour ne pas le
faire, donc pas de problème...
Une fois tapé ce petit listing, sauvez le par exemple sous le nom
SAUV_PAL.S. Ensuite modifiez le programme du listing 1 (celui que
nous venons de voir avec l'image incluse). Juste après la fin du
programme par MOVE.W #0,-(SP), TRAP #1 (donc juste avant
l'inclusion de l'image), mettez
INCLUDE "A:\SAUV_PAL.S"
Ne mettez pas d'étiquette sur le bord gauche puisque la première
étiquette c'est SAUVE_PALETTE et qu'elle est dans notre routine.
Ensuite au tout début du programme, mettez BSR SAUVE_PALETTE et à
la fin juste avant de quitter, mettez BSR REMET_PALETTE. Au niveau
taille, votre listing est donc simplement augmenté de 3 lignes:
(BSR SAUVE_PALETTE, BSR REMET_PALETTE et INCLUDE "A:\SAUV_PAL.S")
et pourtant ce sont 24 lignes qui sont ajoutées!!!
Nous sommes donc en train de nous créer une bibliothèque. C'est
une très grande partie du travail du programmeur en assembleur car
de nombreuses choses reviennent souvent: initialisation par sauve-
garde de la palette, passage en basse résolution et passage en Su-
perviseur, restitution en faisant l'inverse, décompactage des
images etc
De même, si vous êtes en train de réaliser un gros programme, en
cours de développement ce sont des pages entières qui peuvent être
incluses diminuant d'autant la taille du listing et y permettant
des déplacements nettement plus aisés.
Voyons tout de suite un autre bloc qui devra maintenant faire
partie de notre bibliothèque. Jusqu'à présent nous avons tapé pas
mal de petits programmes, sans nous soucier de la place mémoire.
Il est temps d'y penser afin de commencer à prendre conscience du
fait qu'il faut programmer proprement. Imaginons que notre
programme soit en mémoire mais qu'en même temps il y ait d'autres
programmes dans cette mémoire. Il est bien évident que chacun ne
doit s'approprier que la place mémoire dont il a besoin, afin
d'en laisser le plus possible pour ces voisins. Pour cela il faut
savoir que lors de l'assemblage sous forme de fichier exécutable,
il y a génération d'une en-tête. Grâce à cette en-tête, au lan-
cement de notre programme il va y avoir création de ce qu'on ap-
pelle la page de base. En voici un descriptif. Si vous désirez
obtenir un maximum de renseignements sur les en-têtes de programme
ou les pages de base, reportez vous aux chapitres correspondants
dans la Bible ou le Livre du Développeur. Excellent chapitre sur
ce sujet dans la doc officielle ATARI (document sur la structure
des programmes).
* Page de base
Adresse Description
$00 Adresse de début de cette page de base
$04 Adresse de fin de la mémoire libre
$08 Adresse du début de la section TEXTE
$0C Taille de la section TEXTE
$10 Adresse de début de la section DATA
$14 Taille de la section DATA
$18 Adresse de début de la section BSS
$1C Taille de la section BSS
Nous allons donc piocher ces informations, et en déduire la taille
qui devrait suffire pour notre programme. Connaissant
l'emplacement de la zone d'implantation du programme, nous
utiliserons la fonction 74 du GEMDOS (fonction Mshrink) qui
permet, en donnant la taille désirée et l'adresse de fin, de
rétrécir une zone mémoire. En effet, au lancement notre programme
a pris toute la place disponible, nous devons donc la rétrécir.
Notre programme a également besoin d'une pile. Au lieu de prendre
celle qui est déjà en place, nous allons lui substituer la notre,
dont nous pourrons régler la taille à loisir.
* ROUTINE DE DEMARRAGE DES PROGRAMMES
MOVE.L A7,A5 prélève ptn de pile pour
prendre
* les paramètres
LEA.L PILE,A7 impose notre pile
MOVE.L 4(A5),A5 adresse de la page de base
de
* l'ancienne pile
MOVE.L 12(A5),D0 taille de la section texte
ADD.L 20(A5),D0 + taille section data
ADD.L 28(A5),D0 + taille section bss
ADD.L #$100,D0 + longueur de la page de
base
*(256 bytes)
* Appel à la fonction MShrink() du GEMDOS (Memory Shrink)
MOVE.L D0,-(SP)
MOVE.L A5,-(SP)
MOVE.W #0,-(SP)
MOVE.W #74,-(SP) M_shrink()
TRAP #1
LEA 12(A7),A7
Voilà, après cette opération, notre programme n'utilise plus que
la place mémoire dont il a besoin. Il ne faut pas oublier de
définir la pile dans la section BSS par ceci:
DS.L 256
PILE DS.L 1
J'en vois qui sont surpris par cette réservation!!! Dans les
exemples fournis avec DEVPACK il est marqué "stack go backwards",
que je traduis librement par "moi j'avance la pile recule, comment
veux tu ..." Un peu de sérieux. Nous avons vu que l'utilisation de
la pile se faisait en décrémentant celle ci:
(move.w #12,-(sp) par exemple).
Il faut donc réserver de la place AVANT l'étiquette. Pour cette
raison nous notons le label et, au-dessus, la taille réellement
réservée pour la pile.
Quelle taille choisir? Cela dépend de vous! Si votre programme
est plein de subroutines s'appelant mutuellement et sauvant tous
les registres à chaque fois, il faut prévoir assez gros.
Tapez le programme suivant. Il est évident que vous devez avoir
tapé au préalable la routine de démarrage de programmes qui est un
peu plus haut dans ce cours. Elle est ici incluse au début. Pas de
branchement à y faire. Si, une fois assemblé, vous débuggez ce
programme, vous verrez au début la routine de start. Dorénavant,
cette routine sera toujours présente au début de nos programmes
mais ne sera jamais intégralement recopiée, un INCLUDE est bien
plus commode! Note: Il semble que DEVAPCK se mélange parfois les
pinceaux lorsque les inclusions sont nombreuses et font appel à
des fichiers contenus dans des dossiers. De même il existe des
problèmes avec les inclusions sur disque B lorsque celui-ci est
pris comme lecteur A dans lequel on met le disque B. (je n'ai par
contre pas rencontré de problème avec mon lecteur externe).
INCLUDE "A:\START.S"
MOVE.W #$AAAA,BIDULE
BSR TRUCMUCHE
MOVE.W BIDULE,D6
MOVE.W #0,-(SP)
TRAP #1
*-----------------------------------------------*
TRUCMUCHE MOVEM.L D0-D7/A0-A6,-(SP)
BSR MACHIN
MOVEM.L (SP)+,D0-D7/A0-A6
RTS
MACHIN MOVEM.L D0-D7/A0-A6,-(SP)
MOVE.L #$12345678,D0
MOVEM.L (SP)+,D0-D7/A0-A6
RTS
SECTION BSS
BIDULE DS.W 1
DS.B 124
PILE DS.L 1
END
Ce programme est bien sur bidon. J'espère cependant que vous
l'avez scrupuleusement tapé. Lancez le... paf 4 bombes!!!!!
Observons le à la loupe afin de comprendre pourquoi... Le start
est bien mis en place et lorsque nous débuggons il est effectué
sans incident. On place ensuite $AAAA dans la variable BIDULE.
Activons la fenêtre 3 et pointons sur BIDULE (il suffit pour cela
de faire Alternate A et de taper le nom du label en majuscule donc
ici BIDULE). Avançons pas à pas, nous voyons bien BIDULE
recevoir AAAA. Continuons à avancer: nous sautons dans TRUCMUCHE
avec au passage sauvegarde dans la pile de l'adresse de retour (à
ce propos vous pouvez faire pointer la fenêtre 3 sur PILE et
regarder au dessus l'empilage des données). Ensuite nous allons
sauter dans MACHIN mais là, stop!!!!!!! Suivez attentivement les
explications. Juste avant d'exécuter le BSR MACHIN, faites scrol-
ler la fenêtre 1 avec la touche 'flèche vers le bas'. En effet
d'après la taille du listing et celle de la fenêtre vous ne devez
pas voir BIDULE. Descendez donc de 7 lignes. Normalement, la
première ligne de la fenêtre doit maintenant être BSR MACHIN avec
la petite flèche en face indiquant que c'est cette instruction qui
va être exécutée. En bas de la fenêtre vous devez voir BIDULE
avec en face DC.W $AAAA puisque c'est ce que nous y avons déposé.
En dessous des ORI.B#0,D0 . En effet nous sommes dans une
fenêtre qui cherche à nous montrer le désassemblage de ce qu'il y
a dans le tube. Or à cette endroit il y a 0 dans le tube et cela
correspond à ORI.B #0,d0; ce qui explique ces instructions. Mais
ces ORI.B correspondent à quoi ? où sont-ils situés? eh bien, il
sont dans notre pile puisque celle-ci est constituée d'un bloc de
124 octets entre BIDULE et PILE. Alors maintenant scrutez très
attentivement BIDULE et avancez le programme d'un pas. Nous voici
maintenant sur la ligne MOVEM.L de la subroutine MACHIN. Exécutons
cette ligne...
Stupeur, BIDULE est écrasé, de même que le RTS de la subroutine
MACHIN qui est juste au dessus!!! Et maintenant, si nous
continuons, après le second MOVEM le 68000 ne va pas tomber sur
le RTS puisque celui-ci vient d'être écrasé, et notre programme va
planter! Pourquoi ? eh bien, parce que nous avons essayé d'empiler
128 octets (MOVEM de trucmuche=15 registres donc 15*4=60 octets,
idem pour le MOVEM de machin, auquel il faut ajouter l'adresse de
retour pour trucmuche et celle de machin, total 128 octets!) alors
que nous n'avions prévu qu'une pile de 124 octets.
Pour que ce programme marche sans problème, il faut donc mettre au
minimum une pile de 128 octets. Faites très attention à ça, car si
nous avions mis une pile de 124 octets, le programme ne se
serait pas planté car il n'y aurait pas eu écrasement du RTS mais
il y aurait eu écrasement de BIDULE et je suis certain que vous
auriez cherché bien longtemps en vous disant " mais qu'est ce qui
peut bien écraser BIDULE " surtout que cet écrasement survient à
un moment où, justement, on n'utilise pas BIDULE!!!
Gardez donc toujours présent à l'esprit le principe du tube
mémoire, sans oublier qu'il est plein d'instructions, de contenus
de variables et que rien n'empêche de les écraser!
Encore une petite remarque sur le Start. Il est tout à fait
possible de tester D0 en retour du Mshrink(). Si celui-ci est
négatif, c'est qu'il y a eu erreur. Si vous savez que systémati-
quement vous mettez le label BYE_BYE en face du GEMDOS(0) qui ter-
mine votre programme, vous pouvez rajouter à la fin du start:
TST.W D0
BMI BYE_BYE
Une dernière précision sur les inclusions. Il existe d'autres
moyens de réaliser de telles choses, par exemple d'assembler les
morceaux puis de les lier avec un LINKER. Cette solution est
intéressante lorsque les programmes commencent à prendre des pro-
portions gigantesques.
Sinon, il s'agit plus d'embêtements qu'autre chose!!!! Même si
certains puristes préfèrent linker:
j'édite, j'assemble, je quitte, je linke, je lance, ça plante, je
débugge, j'édite etc...)
je préfère, quant à moi, la méthode de l' "include". Elle permet
éventuellement d'avoir accès directement au source. Par exemple,
si votre routine de sauvegarde palette plante, placer le curseur
de GENST sur la ligne INCLUDE "A:\SAUV_PAL.S" puis choisissez
l'option Insert File dans le menu fichier. Votre routine est
maintenant sous vos yeux. Une fois que ce bloc est au point,
délimitez le avec F1 et F2 puis sauver le avec F3, hop le tour est
joué!
Fin du cours sur les inclusions! Commencez à fabriquez votre
bibliothèque et n'hésitez pas à en faire des copies de sécurité,
et méfiez vous des virus! Sur cette disquette il y a IMUN.PRG
Vous le mettez en dossier Auto sur votre disquette de boot, et il
vérifié toutes les disquettes que vous introduisez dans le
lecteur!
|
||