Mais voilà qui est fait. Je vous l'ai annoncé, et vous allez le taper. Que les paresseux se rassurent: une copie de cette toute petite application pédagogique se trouve sur l'ARMadisque.
Car en effet nous allons, pour la première fois, en profiter pour nous taper le squelette de base d'une application Wimp!
Créez donc un nouveau dossier, que vous appelerez: « !Toto1 ». Ensuite, ouvrez-le (pour cela, vous appuyez sur la touche <shift> en même temps que vous double-cliquez sur l'icône de ce nouveau dossier).
A l'intérieur, vous allez créer pour l'instant trois fichiers: deux fichiers de type "Obey" que vous nommerez respectivement « !Boot » et « !Run », et un fichier de type "Sprite" que vous appelerez « !Sprites ».
Dans le fichier « !Boot », vous écrirez simplement la ligne suivante:
IconSprites <Obey$Dir>.!SpritesDans le fichier « !Run », vous taperez ces trois lignes:
WimpSlot -min 8k -max 8k Run <Obey$Dir>.!Boot Run <Obey$Dir>.ObjectDans le fichier « !Sprites », vous mettrez (avec l'application !Paint) un seul icone, n'importe lequel (celui qui se trouve dans le !Toto1 de l'ARMadisque n'est qu'une suggestion), mais vous devrez IMPERATIVEMENT le nommer « !Toto1 », sans quoi vous ne pourrez voir que la triste figure par défaut des Apps dans la fenêtre de votre disque dur. Et puis, comme nous réutilisons cet icone dans le programme, il vaut mieux que le Wimp puisse le localiser, sans quoi rien n'apparaîtra sur la barre de menu.
Si vous n'avez pas envie de créer tous ces fichiers, vous pouvez toujours les récupérer à partir de l'ARMadisque.
;"Mon Adorable Premier Petit Menu Wimp en Assembleur" ;(C)1996 A. VIDOVIC pour l'ARMada #smile #set lenpile=1024 ;ceci devrait suffire pour une pile (en mots) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #entry ADR R0,pile STR R13,[R0] MOV R13,R0 ;on crée une pile DB (ED) ;-------Initialisation du Wimp MOV R0,#200 ;dernière version connue de Wimp*100 MOV R1,#&4B534154 ;"TASK" ADR R2,nom_prog ;short description for Task Mgr SWI Wimp_Initialise ADR R0,task_handle STR R1,[R0] ;sauvegarder le task_handle ;-------Création de l'icone de la barre des icones ADR R1,menuicon SWI Wimp_CreateIcon ;créer l'icone de barre des icones ;-------Polling loop .je_polle MOV R0,#%0110111111 ;masque ADR R1,user_buf SWI Wimp_Poll ;=>R0: reason code... CMP R0,#6 BEQ clickation ;6: mouse click CMP R0,#9 BEQ choix ;9: menu selection ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .clickation ;Traitement du click souris ADR R10,user_buf LDR R0,[R10,#12] ;Window handle (ou -2 si iconbar) CMP R0,#-2 ;iconbar? BNE je_polle ;non: rien pour cette fois LDR R0,[R10,#8] ;mouse buttons CMP R0,#2 ;menu button? BLEQ create_menu ;oui: demander au wimp de créer le menu B je_polle ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .create_menu ;Sous-routine de création par le Wimp du menu principal ADR R1,menu_block LDR R2,[R1,#16] ;largeur des items LDR R0,[R10] ;mouse_x SUB R2,R0,R2,ASR #1 SUB R2,R2,#24 ;x du menu (cf style guide du PRM) MOV R3,#96+(1*44)+(0*24) ;y du menu (cf idem) SWI Wimp_CreateMenu MOV R15,R14 ;retour à l'appelant ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .choix ;Traitement du menu ADR R10,user_buf LDR R0,[R10] ;numéro de l'item sélectionné dans le main CMP R0,#0 ;si 0=quit: suicide du prog BNE je_polle ;sinon (pas d'autre option): retour au poll ;-------Fermeture su slot Wimp et sortie du programme ADR R0,task_handle ;récupérer le task handle LDR R0,[R0] MOV R1,#&4B534154 ;"TASK" SWI Wimp_CloseDown ADR R0,pile LDR R13,[R0] ;on restaure l'ancienne pile MOV R0,#0 SWI OS_Exit ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DBD lenpile,0 ;espace pour la pile programme .pile DBD 1,0 ;sauvegarde ancien pointeur de pile .task_handle DBD 1,0 ;espace pour contenir le handle .user_buf DBB 256,0 ;un bloc de 256 octets (nuls) de long .nom_prog DCB "Toto The Menu",0 ;nom à donner au Wimp, au début ALIGN 4 ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .menuicon ;lors de la creation de l'icone DCD -1 ;win handle (-1=iconbar right) DCD 0 ;xmin de l'icon bouding box DCD 0 ;ymin DCD 90 ;xmax DCD 90 ;ymax DCD %11000100000010 ;icon flags DCD spr_name ;ptr sur nom du sprite DCD 1 ;ptr to sprite ctrl block (1=Wimp) DCD 10 ;longueur du nom du sprite pointé spr_name ;sprite à utiliser pour la barre d'icone DCB "!toto1",0 ;en fait, le même que pour le prog (cf <!sprites>) ALIGN 4 ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .menu_block ;le menu de ce programme DCB "Toto" ;12 caractères de titre de menu DBD 2,0 DCB 7 ;title foreground and frame colour DCB 2 ;title background colour DCB 7 ;work-area foreground colour DCB 0 ;work-area background colour DCD 6*16 ;width of menu items (ici 4 car. max + 2 espaces=6) DCD 44 ;height of menu items DCD 0 ;vertical gap between menu items ;-------quit DCD %10000000 ;item flags DCD -1 DCD &07000021 ;icon flags DCB "Quit" ;12 caractères de long DBD 2,0 ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #end
Une fois ce source tapé, sauvé, compilez-le avec !ExtASM: vous devez obtenir, dans le dossier que nous avons créé en début de leçon et à côté des autres fichiers déjà créés, un fichier appelé « Object » de type "Absolute". Si jamais le nom est différent, changez-le et modifiez l'option de !ExtASM qui spécifie le nom du fichier exécutable créé après une compilation: en effet le fichier « !Run » de l'application cherche à déclencher un exécutable de ce nom et pas un autre...
Au fait: n'oubliez pas de jouer avec votre application ainsi créée, en guise de récréation. Faites durer cette récréation aussi longtemps que vous prendra la flemme de passer à la suite de l'article.
Vous l'avez noté: vous reconnaissez des instructions, voire des pans entiers de code, que nous avons déjà abordés dans l'acte précédent. Nous n'y reviendrons pas, ce qui implique qu'en cas de mauvaise compréhension de ces parties du listing, vous devez en premier lieu vous reporter au numéro précédent de ARMada news, et ensuite seulement, si vous ne comprenez toujours pas, vous pouvez joindre le bureau de l'ARMada, qui me transmettra vos doléances.
ADR R1,menuicon SWI Wimp_CreateIcon ;créer l'icone de barre des iconesC'est un appel à la fonction du Wimp "Wimp_CreateIcon" avec comme paramètre une adresse, passée dans R1, celle du bloc de données ".menuicon", défini plus bas dans le listing. Pour les détails sur la structure de cet "icon-bloc", je vous renvoie au PRM ou à StrongHelp... Quoi de particulier ici? Simplement la ligne du bloc suivante:
DCD spr_name ;ptr sur nom du spriteCeci, vous l'avez probablement intuité, stocke à cet endroit un mot, qui est une adresse, celle définie par le label ".spr_name", défini lui juste après le bloc-icone, et qui est le début d'une chaîne de caractères:
DCB "!toto1",0Et c'est le nom de l'icone contenu dans le fichier « !Sprites ».
MOV R0,#%11111111110110111111 ;masqueContrairement à la dernière fois, nous ne mettons pas zéro comme masque, mais un nombre en binaire (préfixe %) avec pour seuls bits à zéro ceux dont le numéro correspond aux seuls évênements que nous avons l'intention de traiter dans ce programme: le Wimp ne rendra la main au programme apres l'appel à la fonction "Wimp_Poll" que lorsqu'il aura quelque chose de pertinent à transmettre: ceci évite de manger le temps du processeur inutilement, en permettant au Wimp de venir nous voir sans arrêt.
Après cela, je vous renvoie à une bonne documentation sur le Wimp pour les différents "reason codes".
ADR R10,user_buf LDR R0,[R10,#12] ;Window handle (ou -2 si iconbar)Ces deux instructions mettent l'adresse du user_buf dans le registre R10, puis nous chargeons dans R0 le mot situé à l'adresse qui est la somme de l'adresse spécifiée par R10 et de 12. Autrement dit: ajouter 12 au nombre contenu par R10, puis à l'adresse ainsi obtenue chercher un mot, que l'on met dans le registre R0!
REMARQUE: le contenu du registre R10 n'est pas altéré par cette opération, que l'on appelle "pré-incrémentation". Souvenez-vous: pré-incrémentation: l'incrément AVANT le crochet fermé!
Nous verrons ultérieurement comment faire pour que R10 soit mis à jour par une telle opération.
CMP R0,#2 ;menu button? BLEQ create_menu ;oui: demander au wimp de créer le menuLa première, c'est une comparaison: on compare le contenu du registre R0 à la valeur 2.
La seconde est une instruction dans sa forme conditionnelle. L'instruction, à la base, s'écrit comme ceci:
BL label_de_sous_routineOn peut la lire "Branch with Link", ce qui ne veut pas dire grand chose, si ce n'est que son action sera celle-ci: d'abord, le contenu du registre R15 sera recopié dans le registre R14. Puis un branchement sera fait au label spécifié.
Pourquoi copier R15 dans R14? Et bien, parceque R15 est un registre un peu spécial: c'est le COMPTEUR DE PROGRAMME. C'est R15 en effet qui contient l'adresse de l'instruction en cours (en fait c'est un peu différent, mais restons imprécis pour cette fois). Si à un moment donné nous désirons faire appel à une sous-routine, il faudra que, une fois celle-ci terminée, le processeur sache où reprendre l'exécution. Nous avons besoin de connaître l'ADRESSE DE RETOUR, pour la remettre dans R15, de sorte que le processeur saura où aller chercher l'instruction suivant la fin de la sous-routine.
MOV R15,R14 ;retour à l'appelantC'est tout simple, non? Nous nous contentons de copier le contenu de R14 dans R15, ce qui implicitement la réciproque de l'opération précédente!
Nous verrons ultérieurement quelles solutions nous pouvons adopter (elles sont légion!) pour avoir droit à des sous-routines imbriquées sans perdre, à chaque étage, le contenu de R14...
SUB R2,R0,R2,ASR #1Bon, vous connaissez déjà les instructions arithmétiques, addition, etc. Je vous rappelle par exemple comment soustraire R2 à R0 et mettre le résultat dans R2:
SUB R2,R0,R2"Traduit" en basic, cela donnerait: R2=R0-R2. Mais que vient faire le petit bout qui dépasse plus haut? Et bien, on pourrait le lire "Arithmetic Shift Right by 1 bit" (Décalage Arithmétique vers la Droite de 1 bit).
En fait, juste avant d'être soustrait de R0, le contenu de R2 est décalé de 1
bit vers la droite, ce qui revient à le DIVISER PAR DEUX!
"Traduit" en basic, cela donnerait: R2=R0-(R2/2)
"Traduit" en C: R2 = R0 - (R2 >> 1);
Eh oui! Nous venons, en une seule opération, de diviser par 2 le contenu d'un registre et de le soustraire à un autre registre!
Vous pouvez comme cela, la plupart du temps, effectuer des décalages de bits, des rotations, sur les données en même temps que d'autres opérations. Les principaux opérateurs que vous pouvez rajouter sont:
LSL Logical Shift Left (Décalage Logique vers la gauche) ASL Arithmetic Shift Left (Décalage Arithmétique vers la gauche) LSR Logical Shift Right (Décalage Logique vers la droite) ASR Arithmetic Shift Right (Décalage Arithmétique vers la droite) ROR Rotate Right (Rotation vers la droite)En paramètre, vous pouvez spécifier soit un nombre (par exemple: ASR #1), soit un registre (par exemple: ASR R1), registre qui, à ce moment-là, contient le nombre qui sera pris comme paramètre, ce qui permet des possibilités intéressantes.
Il y a un autre opérateur, RRX "Rotate right with extent", sans paramètre, qui permet de faire tourner vers la droite, d'un bit seulement, et avec extension... C'est un peu compliqué à expliquer, ce n'est pas tellement utile pour le moment, alors nous en parlerons plus tard.
Alors si tel est le cas, reprenez calmement cette leçon, au besoin revoyez les précédentes... Et si ce n'est pas suffisant, écrivez-moi, au bureau de l'association ou par e-mail.
Dans tous les cas, vous avez probablement noté que nous commençons à être en mesure de faire des programmes qui commencent à avoir de la gueule... Hé hé...