Bienvenue aux nouveaux arrivants sur FantasPic !

- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.

--- L’équipe FantasPic ---
Forum général sur l'Assembleur !

Modérateur : mazertoc

La boucle while dans MPASM
JJE
Passioné
Passioné
Messages : 399
Âge : 83
Enregistré en : novembre 2017
Localisation : Picardie

#1 Message par JJE » mar. 19 juin 2018 17:40

Bonjour à tous,
Bien que cette directive ne soit certainement pas la plus utilisée, en ayant eu besoin récemment et ayant trébuché sur quelques difficultés, je tente de vous faire partager mon expérience.
Une description, plutôt sommaire est donnée dans l'aide :
    Menu de MPLAB Help/Topics...,
    sélectionner MPASM Assembler
    dans l'onglet développer Directives
    et dans la liste sélectionner while (la dernière)
Grosso modo, elle demande à l'assembleur de répéter une séquence de code tant qu'un condition est vraie plutôt que d'avoir à réécrire cette séquence dans le code source.
par exemple, à l'analyse de

Code : Tout sélectionner

   variable V =   0
   while V != .3   
   nop
   nop
   nop
V+=1
   endw   


l'assembleur va générer 9 nop comme en témoigne le fichier .lst généré :

Code : Tout sélectionner

MPASM  5.51                TESTMACROTEST3.ASM   6-19-2018  14:58:09         PAGE 9


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

  0000                00082         variable V =    0
                      00083         while V != .3   
0008   0000           00084         nop
0009   0000           00085         nop
000A   0000           00086         nop
  00000001            00087 V+=1
000B   0000           00084         nop
000C   0000           00085         nop
000D   0000           00086         nop
  00000002            00087 V+=1
000E   0000           00084         nop
000F   0000           00085         nop
0010   0000           00086         nop
  00000003            00087 V+=1
                      00088         endw   


Imaginons que ce traitement, plutôt que d'être composé de trois nop peu utiles nécessite une boucle à répéter un certain nombre de fois, sept par exemple.

Le source suivant donne une idée de ce que ce pourrait être :

Code : Tout sélectionner

   variable V =   0
   movlw   .7
   movwf   Cmpt1
   while V != 3
; début de traitement
   nop
Test1_1
; corps du traitement
   nop
   nop
   decf   Cmpt1,f
   btfss    STATUS,Z
   goto   Test1_1
   ; sortie du traitement
   nop
V+=1
   endw


L'assembleur déclare une erreur (deux fois)

Error[116] E:\DOCUMENTS DE JJ\MES PROJETS MPLAB\TEST-MACROSTEST\BYTE\V3\TESTMACROTEST3.ASM 89 : Address label duplicated or different in second pass (Test1_1)


On aurait pu s'y attendre, le préprocesseur de l'assembleur répétant trois fois le corps de la boucle while, il répété aussi l'étiquette Test1_1 d'où les deux erreurs.
Si on examine le fichier .lst généré :

Code : Tout sélectionner

MPASM  5.51                TESTMACROTEST3.ASM   6-19-2018  15:22:06         PAGE 10


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

  0000                00083         variable V =    0
0008   3007           00084         movlw   .7
0009   00A2           00085         movwf   Cmpt1
                      00086         while V != 3
                      00087 ; début de traitement
000A   0000           00088         nop
000B                  00089 Test1_1
                      00091 ; corps du traitement
000B   0000           00092         nop
000C   0000           00093         nop
000D   0000           00097         nop
0011   03A2           00103         decf    Cmpt1,f
0012   1D03           00104         btfss   STATUS,Z
0013   280B           00105         goto    Test1_1
                      00107         ; sortie du traitement
0014   0000           00108         nop
  00000001            00109 V+=1
                      00087 ; début de traitement
0015   0000           00088         nop
Error[116]  : Address label duplicated or different in second pass (Test1_1)
0016                  00089 Test1_1
                      00091 ; corps du traitement
0016   0000           00092         nop
0017   0000           00093         nop
0018   0000           00097         nop
001C   03A2           00103        decf    Cmpt1,f
001D   1D03           00104        btfss   STATUS,Z
001E   280B           00105        goto    Test1_1
                      00107         ; sortie du traitement
001F   0000           00108         nop
  00000002            00109 V+=1
                      00087 ; début de traitement
0020   0000           00088         nop
Error[116]  : Address label duplicated or different in second pass (Test1_1)
0021                  00089 Test1_1
                      00091 ; corps du traitement
0021   0000           00092         nop
0022   0000           00093         nop
0023   0000           00097         nop
0027   03A2           00103         decf    Cmpt1,f
0028   1D03           00104         btfss   STATUS,Z
0029   280B           00105         goto    Test1_1
                      00107         ; sortie du traitement
002A   0000           00108         nop
  00000003            00109 V+=1
                      00110         endw   


On constate que l'assembleur généré en 001E un 280B alors qu'on espérait un 2816 et en 0029 un 280B alors qu'on attendait un 2821. Il garde la première valeur attribuée à Test1_1, ce qui n'est pas scandaleux. De toute façon, pas de .hex généré, il faut donc modifier le source.
J'avais vu une directive "local" (voir dans l'aide) qui, bien qu'elle soit présentée comme permettant de manipuler des variables locales à une macro correspondait bien à la situation. Je tente ma chance

Code : Tout sélectionner

   variable V =   0
   movlw   .7
   movwf   Cmpt1
   while V != 3
; début de traitement
   nop
   local Test1_1=$
; corps du traitement
   nop
   nop
   nop
   decf   Cmpt1,f
   btfss   STATUS,Z
   goto   Test1_1
   ; sortie du traitement
   nop
V+=1
   endw   


Plus d'erreur, voici le .lst généré :

Code : Tout sélectionner

MPASM  5.51                TESTMACROTEST3.ASM   6-19-2018  15:22:06         PAGE 10


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

  0000                00083         variable V =    0
0008   3007           00084         movlw   .7
0009   00A2           00085         movwf   Cmpt1
                      00086         while V != 3
                      00087 ; début de traitement
000A   0000           00088         nop
  000B                00089         local Test1_1=$
                      00091 ; corps du traitement
000B   0000           00092         nop
000C   0000           00093         nop
000D   0000           00097         nop
0011   03A2           00103         decf    Cmpt1,f
0012   1D03           00104         btfss   STATUS,Z
0013   280B           00105         goto    Test1_1
                      00107         ; sortie du traitement
0014   0000           00108         nop
  00000001            00109 V+=1
                      00087 ; début de traitement
0015   0000           00088         nop
  0016                00089         local Test1_1=$
                     00091 ; corps du traitement
0016   0000           00092         nop
0017   0000           00093         nop
0018   0000           00097         nop
001C   03A2           00103        decf    Cmpt1,f
001D   1D03           00104        btfss   STATUS,Z
001E   2816           00105        goto    Test1_1
                      00107         ; sortie du traitement
001F   0000           00108         nop
  00000002            00109 V+=1
                      00087 ; début de traitement
0020   0000           00088         nop
  0021                00089         local Test1_1=$
                      00091 ; corps du traitement
0021   0000           00092         nop
0022   0000           00093         nop
0023   0000           00097         nop
0027   03A2           00103         decf    Cmpt1,f
0028   1D03           00104         btfss   STATUS,Z
0029   2821           00105         goto    Test1_1
                      00107         ; sortie du traitement
002A   0000           00108         nop
  00000003            00109 V+=1
                      00110         endw   


On peut observer que les goto génèrent le code attendu. Bonne intuition.

Cependant, il est loin d'être rare que l'on ne soit pas amené à sauter à l’occurrence suivante de la boucle sans traiter ses dernières instructions par exemple :

Code : Tout sélectionner

   variable V =   0
   movlw   .7
   movwf   Cmpt1
   while V != 3
; début de traitement
   nop
   local Test1_1=$
; corps du traitement
   nop
   nop
   goto   Test1_2
   nop
Test1_2
   decf   Cmpt1,f
   btfss   STATUS,Z
   goto   Test1_1
   ; sortie du traitement
   nop
V+=1
   endw   


Inutile même de lancer un assemblage, il est clair que Test1_2 sera définie plusieurs fois
Essayons la manipe précédente en remplaçant l'étiquette Test1_2 par local Test1_2 = $. On obtient une erreur :

Error[113] E:\DOCUMENTS DE JJ\MES PROJETS MPLAB\TEST-MACROSTEST\BYTE\V3\TESTMACROTEST3.ASM 94 : Symbol not previously defined (Test1_2)


En fait c'est assez normal, quand on imagine la boucle while développée, son corps est recopié 3 fois successivement, dans la première copie, l'étiquette Test1_2 n'a pas été rencontrée d'où l'erreur
Essayons de tromper l'assembleur en lui faisant générer une première version du corps de boucle qui ne contiendra que l'étiquette

Code : Tout sélectionner

   variable V = 0xffffffff   
   movlw   .7
   movwf   Cmpt1
   while V != .3 || V==0xffffffff
; début de traitement
   nop
   local Test1_1=$
; corps du traitement
   if V!= 0xffffffff
   nop
   nop
      goto Test1_2
   nop
   nop
   nop
   endif
   local Test1_2 = $
   nop
   decf   Cmpt1,f
   btfss   STATUS,Z
   goto   Test1_1
   ; sortie du traitement
   nop
V+=1
   endw   


Une seule remarque sur ce code, remarquez l'initialisation de V à 0xFFFFFFFF, en effet, V est une variable 32 bits, je ne sais pas où c'est mentionné dans l'aide. J'ai essayé 0xFF et 0x FFFF qui, bien sûr, incrémentés ne donnent pas 0 sur 32 bits et du coup, pour atteindre 3, on dépasse de beaucoup le nombre de 256, maximum de répétition d'une boucle while.
Examinons le .lst généré :

Code : Tout sélectionner

MPASM  5.51                TESTMACROTEST3.ASM   6-19-2018  16:51:35         PAGE 10


LOC  OBJECT CODE     LINE SOURCE TEXT
  VALUE

  FFFF                00083         variable V = 0xffffffff
0008   3007           00084         movlw   .7
0009   00A2           00085         movwf   Cmpt1
                      00086         while V != .3 || V==0xffffffff
                      00087 ; début de traitement
000A   0000           00088         nop
  000B                00089         local Test1_1=$
                      00090 ; corps du traitement
                      00091         if V!= 0xffffffff
                      00092         nop
                      00093         nop
                      00094                 goto Test1_2
                      00095         nop
                      00096         nop
                      00097         nop
                      00098         endif
  000B                00099         local Test1_2 = $
000B   0000           00100         nop
000C   03A2           00101         decf    Cmpt1,f
000D   1D03           00102         btfss   STATUS,Z
000E   280B           00103         goto    Test1_1
                      00104         ; sortie du traitement
000F   0000           00105         nop
  00000000            00106 V+=1
                      00087 ; début de traitement
0010   0000           00088         nop
  0011                00089         local Test1_1=$
                      00090 ; corps du traitement
                      00091         if V!= 0xffffffff
0011   0000           00092         nop
0012   0000           00093         nop
0013   280B           00094                 goto Test1_2
0014   0000           00095         nop
0015   0000           00096         nop
0016   0000           00097         nop
                      00098         endif
  0017                00099         local Test1_2 = $
0017   0000           00100         nop
0018   03A2           00101         decf    Cmpt1,f
0019   1D03           00102         btfss   STATUS,Z
001A   2811           00103         goto    Test1_1
                      00104         ; sortie du traitement
001B   0000           00105         nop
  00000001            00106 V+=1
                      00087 ; début de traitement
001C   0000           00088         nop
  001D                00089         local Test1_1=$
                      00090 ; corps du traitement
                      00091         if V!= 0xffffffff
001D   0000           00092         nop
001E   0000           00093         nop
001F   2817           00094                 goto Test1_2
0020   0000           00095         nop
0021   0000           00096         nop
0022   0000           00097         nop
                      00098         endif
  0023                00099         local Test1_2 = $
0023   0000           00100         nop
0024   03A2           00101         decf    Cmpt1,f
0025   1D03           00102         btfss   STATUS,Z
0026   281D           00103         goto    Test1_1
                      00104         ; sortie du traitement
0027   0000           00105         nop
  00000002            00106 V+=1
                      00087 ; début de traitement
0028   0000           00088         nop
  0029                00089         local Test1_1=$
                      00090 ; corps du traitement
                      00091         if V!= 0xffffffff
0029   0000           00092         nop
002A   0000           00093         nop
002B   2823           00094                 goto Test1_2
002C   0000           00095         nop
002D   0000           00096         nop
002E   0000           00097         nop
                      00098         endif
  002F                00099         local Test1_2 = $
002F   0000           00100         nop
0030   03A2           00101         decf    Cmpt1,f
0031   1D03           00102         btfss   STATUS,Z
0032   2829           00103         goto    Test1_1
                      00104         ; sortie du traitement
0033   0000           00105         nop
  00000003            00106 V+=1
                      00107         endw   


première remarque, en 0013 on trouve 280B ; le premier goto Test1_2 renvoie en arrière, première occurrence de l'étiquette Test1_1 rencontrée, on aurait préféré trouver 2817, c'est en fait ce qu'on avait cru écrire. Dans cet exemple précis, cela n'a pas d'importance puisque les instructions sont les mêmes aux deux adresses, cependant, cela nous a obligé de conserver les instructions de décrémentation du compteur Cmpt1, il y a donc lieu de lui donner une valeur initiale de 8 au lieu de 7.

On constate que ce type de traitement tient beaucoup de l'équilibriste. Une solution beaucoup plus simple est de se passer d'étiquette grâce à l'opérateur $, toutes mes excuses à ceux qui ne l'aiment pas (dont je suis).

Code : Tout sélectionner

   variable V = 0
   movlw   .7
   movwf   Cmpt1
   while V != .3
; début de traitement
   nop
   local Test1_1=$
; corps du traitement
   nop
   nop
      goto $+4   ; Test1_2
   nop
   nop
   nop
   nop
   decf   Cmpt1,f
   btfss   STATUS,Z
   goto   Test1_1
   ; sortie du traitement
   nop
V+=1
   endw


Encore faut-il qu'on soit en mesure de calculer le déplacement à ajouter au $ et qu'il ne dépende pas de V, donc de l’occurrence de la boucle while !

Cordialement.
Cordialement

JJE

C'est pas parcequ'on n'a rien à dire qu'il faut fermer sa G....e

La boucle while dans MPASM
F6FCO
Avatar de l’utilisateur
Expert
Expert
Messages : 1413
Âge : 70
Enregistré en : décembre 2017
Localisation : Furtif je suis.
Contact :

#2 Message par F6FCO » ven. 22 juin 2018 09:49

Merci pour ton exposé JJE, j'ai parcouru et je vais relire tout çà avec intéret :wink:
Une porte nand prend 2 bits en entrée... la cochonne !!! :langue:


Retourner vers « Langage ASM »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 44 invités