COURS203.TXT/fr
****************************************************************** * * * 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!
Back to ASM_Tutorial