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 ---
Commentez, partagez et proposez des Tutos en langage ASM !
Menu de routines ASM à disposition
Jérémy
Administrateur du site
Administrateur du site
Messages : 2122
Âge : 39
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#1 Message par Jérémy » sam. 7 avr. 2018 09:07

Bonjour à tous,

La section ASM vous propose une caisse à outils contenant une liste de routines faites en langage ASM.

Ces routines sont commentées au maximum, afin que tout le monde puisse étudier la routine et comprendre le cheminement de l'auteur. Elles ont été testées par son auteur en condition réelle.

Si vous trouvez un BUG ou un problème dans une routine, merci de NE PAS POSTER A LA SUITE SVP. Il vous faut ouvrir un nouveau post dans la partie langage "ASM" en citant le lien de la routine. Ainsi vous pourrez débattre avec l'auteur ou d'autres experts sur la facon de le corriger.

Il y a de nombreuses façon de faire une routine, le but ici n'ai pas de faire la routine parfaite... mais juste de simplifier la vie des membres de fantasPIC pratiquant l'Assembleur. ceci afin de ne pas ré-inventer la roue à chaque fois.

  1. Addition (non-signé)
  2. Soustraction (non-signé)
  3. addition soustraction et calcul de l'opposé sur 8 bits signés(signé)
  4. Outil pour se débarrasser de la gestion des pages de code V.1
  5. Outil pour se débarrasser de la gestion des pages de code V.2
  6. A venir....
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Menu de routines ASM à disposition
F6FCO
Avatar de l’utilisateur
Confirmé
Confirmé
Messages : 507
Âge : 64
Enregistré en : décembre 2017
Localisation : Furtif je suis.
Contact :

#2 Message par F6FCO » mer. 11 avr. 2018 19:23

Bonjour les gens,
Pour mettre dans la caisse à outils voici des routines d'additions sur 16 et 32bits pour nos petits PIC 8bits.
Toutes les explications sont contenues dans les commentaires. J'ai fais le programme sur un 16F88 mais les routines sont utilisables sur n'importe quel autre Pic 8bits utilisant les mêmes instructions.

On peut visualiser le résultat des opérations (valeur1 et valeur2) dans la fenêtre File Register du menu View.

il suffit de renseigner les variables valeur1 et valeur2 et de faire un call vers la routine. Voici les routines :

Addition 16 bits (non-signé) :

Code : Tout sélectionner

;**********************************************************************                                                              
;    NOM:        Caisse à outils                                        
;    Date:       05/04/2018                                           
;    Auteur:     F6FCO  JC Buisson                                       
;     xtal:       4Mhz                                                 
;    
;    Routines d'addition 16 et 32bits
;                                                                        
;**********************************************************************
    CBLOCK 0x020  
        valeur1:2     ; déclarée en 16 bits
        valeur2:2    ; déclarée en 16bits
    ENDC                                                                                  
;********************************************************************
;                   Addition sur 16bits                                *
;     Il faut préalablement déclarer des variables sur 16 bits         *
;             valeur1:2 et valeur2:2                                    *
;                                                                    *
; Placer le poids faible de la première valeur dans valeur1            *
; et le poids fort dans valeur1+1                                    *
; Placer le poids faible de la valeur à additionner dans valeur2    *
; et le poids fort dans valeur2+1                                    *
;                                                                      *   
; Appeler la procédure addition16 et le résultat de                     *
; valeur1+valeur2 sur 16bits sera dans les 2 octets de valeur2           *
;********************************************************************
addition16
        movf    valeur1,W
        addwf    valeur2
        ; on additionne le carry dans le poids fort
        movf    STATUS,W
        andlw    0x1
        addwf    valeur2+1
        movf    valeur1+1,W
        addwf    valeur2+1
        return    



Addition 32 bits (non-signé) :

Code : Tout sélectionner

;**********************************************************************
;
                                                                     
;    NOM:        Caisse à outils                                        
;    Date:       05/04/2018                                           
;    Auteur:     F6FCO  JC Buisson                                       
;     xtal:       4Mhz                                                 
;    
;    Routines d'addition et soustraction 16 et 32bits
;                                                                     
;**********************************************************************
    CBLOCK 0x020  
        valeur1:4     ; déclarée en 32bits
        valeur2:4    ; déclarée en 32bits
    ENDC                                                                                  
;********************************************************************
;                   Addition sur 32bits                                *
;     Il faut préalablement déclarer des variables sur 16 bits         *
;             valeur1:4 et valeur2:4                                    *
;                                                                    *
; Placer le poids faible de la première valeur dans valeur1            *
; et les poids forts dans valeur1+1, valeur1+2, valeur1+3.            *
; Placer le poids faible de la valeur à additionner dans valeur2    *
; et les poids forts dans valeur2+1, valeur2+2, valeur2+3            *
;                                                                      *   
; Appeler la procédure addition32 et le résultat de                     *
; valeur1+valeur2 sur 32bits sera dans les 4 octets de valeur2           *
;********************************************************************
addition32
        ; addition poids faibles
        movf    valeur1,W
        addwf    valeur2
        movf    STATUS,W     ; on additionne le carry 
        andlw    0x1
        addwf    valeur2+1
        ; addition poids+1
        movf    valeur1+1,W
        addwf    valeur2+1
        movf    STATUS,W     
        andlw    0x1
        addwf    valeur2+2
        ; addition poids+2
        movf    valeur1+2,W
        addwf    valeur2+2
        movf    STATUS,W      
        andlw    0x1
        addwf    valeur2+3
        ; addition poids+2
        movf    valeur1+3,W
        addwf    valeur2+3
        return    

Une porte nand prend 2 bits en entrée... cochonne va !!!

Menu de routines ASM à disposition
F6FCO
Avatar de l’utilisateur
Confirmé
Confirmé
Messages : 507
Âge : 64
Enregistré en : décembre 2017
Localisation : Furtif je suis.
Contact :

#3 Message par F6FCO » mer. 11 avr. 2018 22:49

Bonjour les gens,
Pour mettre dans la caisse à outils voici des routines de soustractions sur 16 et 32bits pour nos petits PIC 8bits.
Toutes les explications sont contenues dans les commentaires. J'ai fais le programme sur un 16F88 mais les routines sont utilisables sur n'importe quel autre Pic 8bits utilisant les mêmes instructions.

On peut visualiser le résultat des opérations (valeur1 et valeur2) dans la fenêtre File Register du menu View.

il suffit de renseigner les variables valeur1 et valeur2 et de faire un call vers la routine. Voici les routines :

Soustraction 16 bits (non-signé) :

Code : Tout sélectionner

;********************************************************************
;
                   Soustraction sur 16bits                            *
;
     Il faut préalablement déclarer des variables sur 16 bits         *
;
             valeur1:2 et valeur2:2                                    *
;
                                                                    *
;
 Placer le poids fort de la première valeur dans valeur1            *
;
 et le poids faible dans valeur1+1                                    *
;
 Placer le poids fort de la valeur à soustraire dans valeur2        *
;
 et le poids faible dans valeur2+1                                   *   
; Appeler la procédure soustraction16 et le résultat de             *
;
 valeur1-valeur2 sur 16bits sera dans les 2 octets de valeur2           *
;********************************************************************
   
soustraction16
    
; ------------------------------------- on traite valeur2
    movf    valeur2
,w        ; inversion du poids fort
    xorlw    0xff
    movwf    valeur2
    movf    valeur2
+1,w        ; complément à 2 du poids faible
    xorlw    0xff
    addlw    0x01
    movwf    valeur2
+
    movf    STATUS
,w        ; on isole le carry
    andlw    0x01
    addwf    valeur2
,f        ; et on l'ajoute au poids fort  
    ;----------------------------------- on additionne les deux poids faibles    
    movf    valeur1+1,w
    addwf    valeur2+1,f   
    movf    STATUS,w        ; on isole le carry
    andlw    0x01
    addwf    valeur2,f        ; et on l'
ajoute au poids fort    
    
;--------------------------------- on additionne maintenant les deux poids forts
    movf    valeur1
,w
    addwf    valeur2
,f
    
; s'il y a carry il sera perdu car on reste en 16bits   
    return



Soustraction 32 bits (non-signé) :

Voici le resultat de mon travail sur la soustraction en 32bits.

Code : Tout sélectionner


    
;********************************************************************
;
                   Soustraction sur 32bits                            *
;
     Il faut prélablement déclarer les variables sur 32bits            * 
;             valeur1:4    et valeur2:4                                *
;
                                                                    *
;
 Placer le poids fort de la première valeur dans valeur1            *
;
 et les poids plus faibles dans valeur1+1, valeur+2, valeur+3        *
;
 Placer le poids fort de la valeur à soustraire dans valeur2        *
;
 et les poids faibles dans valeur2+1, valeur2+2, valeur2+3            *   
; Appeler la procédure soustraction16 et le résultat de             *
;
 valeur1-valeur2 sur 32bits sera dans les 4 octets de valeur2         *
;********************************************************************
soustraction32
    
; ------------------------------------- inversion valeur2
    movf    valeur2
+3,w        ; inversions de tous les octets
    xorlw    0xff
    movwf    valeur2
+3
    movf    valeur2
+2,w         
    xorlw    0xff
    movwf    valeur2
+2
    movf    valeur2
+1,w        
    xorlw    0xff
    movwf    valeur2
+1
    movf    valeur2
,w        
    xorlw    0xff
    movwf    valeur2
    
;------------------------- complément à 2 et gestion des dépassements sur valeur2
    movlw    0x01            
    addwf    valeur2
+3,f
    movf    STATUS
,w        ; on isole le carry
    andlw    0x01
    addwf    valeur2
+2,f        ; et on l'ajoute au poids supérieur
    movf    STATUS,w
    andlw    0x01
    addwf    valeur2+1,f        ; et ainsi de suite...
    movf    STATUS,w
    andlw    0x01
    addwf    valeur2,f
    ; s'
il y a un carry de généré on l'ignore, on reste sur 32bits
    ; à partir de là le complément à 2 de valeur2 est fait
    ; on passe à l'
addition des deux valeurs
    
;----------------------------------- additions de valeur1 et valeur2    
    movf    valeur1
+3,w
    addwf    valeur2
+3,f
    movf    STATUS
,w        ; on isole le carry
    andlw    0x01
    addwf    valeur1
+2,f        ; et on l'ajoute au poids sup
    movf    valeur1+2,w
    addwf    valeur2+2,f
    movf    STATUS,w        ; on isole le carry
    andlw    0x01
    addwf    valeur1+1,f        ; et on l'
ajoute au poids sup
    movf    valeur1
+1,w
    addwf    valeur2
+1,f
    movf    STATUS
,w        ; on isole le carry
    andlw    0x01
    addwf    valeur1
,f        ; et on l'ajoute au poids fort
    movf    valeur1,w
    addwf    valeur2,f
    ; s'
il y a carry il sera perdu car on reste en 32bits
    return



Pour ceux que çà intéresse de comprendre la routine, j'ai utilisé la technique de l'addition avec le complément à 2
Voici les séquences de calcul de la routine sur un exemple précis (0x001f-0x00f1):
Désolé pour l'indentation, le forum ne gère pas les tabulations comme mon traitement de texte.

Code : Tout sélectionner


Soit la soustraction sur 32 bits    001f
-00f1=0xffffff2e
Le résultat sera dans valeur2

    00000000 00000000 00000001 11111111            0x001f    valeur1        
-    00000000 00000000 11111111 00000001            0x00f1    valeur2    


inversion des octets de valeur2          
      11111111 11111111 00000000 11111110            0xff0e    valeur2                                    


complément à deux de valeur2      
    11111111 11111111 00000000 11111111              0xff0f    valeur2                                
    

addition de valeur1
+3 et valeur2+3
      00000000 00000000 00000001 11111111               
+    11111111 11111111 00000000 11111111                   
    ___________________________________
                                                c 11111110               0xe  
+carry dans valeur2+3                 

addition du carry dans valeur1
+2  (carry=1)
      00000000 00000000 00000010 11111111                0x2f          valeur1                    
+    00000000 00000000 00000000 11111111                   
    ___________________________________
                                                c 11111110                         
                                     
addition de valeur1
+2 et valeur2+2    
      00000000 00000000 00000010 11111111              
+    00000000 00000000 00000000 11111111              
    ___________________________________
                                 c 00000010 11111110              0x2e  
+ carry    dans valeur2+2 et valeur2+3                    
                     
addition du carry dans valeur1
+1  (carry=1)    
      00000000 00000001 00000010 11111111              0x12f          valeur1                                
+    11111111 11111111 00000000 11111111              0xf0f            valeur2
    ___________________________________
                                 c 00000010 11111110                      
                      
addition de valeur1
+1 et valeur2+1
      00000000 00000001 00000001 11111111                 0x01f          valeur1
+    11111111 11111111 00000000 11111111                 0xf0f            valeur2    
    ___________________________________
                     11111111 00000010 11111110                0xf2e  dans valeur2
+1, valeur2+2 et valeur2+3
             
addition du carry dans valeur1  
(carry=0)
      00000000 00000001 00000010 11111111                  0x12f          valeur1 reste inchangée car c=0                                
+    11111111 11111111 00000000 11111111              
    ___________________________________
                   11111111 00000010 11111110                  
             
addition de valeur1 et valeur2
      00000000 00000001 00000010 11111111                0x012f          valeur1
+    11111111 11111111 00000000 11111111                0xff0f        valeur2    
    ___________________________________
      11111111 11111111 00000010 11111110                0xff2e        dans valeur2
Une porte nand prend 2 bits en entrée... cochonne va !!!

Menu de routines ASM à disposition
JJE
Amateur
Amateur
Messages : 142
Âge : 78
Enregistré en : novembre 2017
Localisation : Picardie

#4 Message par JJE » sam. 14 avr. 2018 17:07

Bonjour à tous,
une petite participation à la boîte à outils.
Le programme ci-dessous permet de tester trois routines d'arithmétique 8 bits signés (-128 à +127).
Pour sa mise en oeuvre dans MPLAB,
    créer un nouveau projet,
    ajouter ce fichier dans les sources
    choisir Debugger/Select Tool/Mplab SIM
    ouvrir une fenêtre Watch
    y mettre WREG, STATUS, op1, op2 et result
    lancer en pas à pas en suivant les commentaires
Cordialement


Code : Tout sélectionner

;**********************************************************************
;
   Test de routines arithmétique 8 bits signés                       *  
;                                                                     *
;**********************************************************************
;
                                                                     *
;
   Historique  
;                                                                     *
;
    Date:     13/04/2018                                             *
;
    Version:  1.0                                                    *
;
 ;    Date:     12/05/2018                                             *
;
    Version:  1.1   
;    Correction d'une anomalie dans sub_8bits_signé                                                 *
;                                                                     *
;**********************************************************************

;**********************************************************************
;                                                                     *
;    NOM:      Test8bitsSignés                                        *
;    Date:     12/05/2018                                             *
;    Version:  1.1                                                    *
;    Circuit:  sans objet                                             *
;    Auteur:   JJE                                                    *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Fichier requis: aucun                                            *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes: 
;    Ce petit programme permet de tester les routines 8bits signés     *
;    sous le simulateur de MPLAB
;                                                                     *
;**********************************************************************


;    LIST          p=PIC12F675         ; Définition du processeur
;    #INCLUDE     <p12F675.inc>         ; Définitions des constantes

STATUS    EQU    .3
C        EQU    0
Z        EQU    2

;    __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _HS_OSC


;*********************************************************************
;                   DECLARATIONS DE VARIABLES                        *
;*********************************************************************

    CBLOCK 0x020                   ; Début de la zone des variables  
    
; sauvegardes pour l'
IT
    w_temp 
: 1                    ; W
    status_temp 
: 1                ; STATUS

; variables utiles aux sous-progtammes d'aritmétique 8bits signé    
; ces 3 variables doivent être dans la même banque    
    op1    : 1
    op2    : 1
    result    : 1

    ENDC                        ; Fin de la zone                        

;**********************************************************************
;                      DEMARRAGE SUR RESET                            *
;**********************************************************************

    org     0x000                 ; Adresse de départ après reset
      goto    init                ; 
      
;**********************************************************************
;                     ROUTINE INTERRUPTION                            *
;**********************************************************************

            ;sauvegarder registres    
            ;---------------------
    ORG     0x004                ; adresse d'
interruption
    movwf    w_temp              
; 1 sauver registre W
    swapf    STATUS
,w            ; 2 swap status avec résultat dans w
    movwf    status_temp            
; 3 sauver status swappé
    
restorereg
    swapf    status_temp
,w        ; 2 swap ancien status, résultat dans w
    movwf   STATUS                
; 3 restaurer status
    swapf   w_temp
,f            ; 4 Inversion L et H de l'ancien W
                                   ; sans modifier Z
    swapf   w_temp,w              ; 5 Réinversion de L et H dans W
                                ; W restauré sans modifier status
    retfie                      ; 7 return from interrupt
    

init
      movlw    .1
      movwf    op1
      movlw    -.1
      movwf    op2
init_1      
      call    opposé_8bits_signé
      ; ici, vous devez constater que op2 vaut 1 et que Z et C sont nuls
      call    add_8bits_signé    
      btfsc    STATUS,C
      goto    Erreur
      ; ici, vous devez constater que op1 et op2 n'
ont pas changé
      
; et que result vaut .2 et que Z et C sont nuls
      call    sub_8bits_signé    
      
; ici, vous devez constater que op1 et op2 n'ont pas changé
      ; et que result vaut .2 et que Z et C sont nuls
      btfsc    STATUS,C
      goto    Erreur
      ; ici, modifiez op1 et op2 dans la fenêtre Watch à convenance
      goto    init_1
      
Erreur
    ; ici, en général, on ne sait pas trop quoi faire
    goto    $
;**********************************************************************
;                            Sous-programmes                           *
;**********************************************************************

sub_8bits_signé
; réalise la soustraction de deux entiers 8 bits signés
; entrée :
;     op1 opérande 1 
;     op2 opérande 2
; sortie :
;     op1 inchangé
;    op2 remplacé par son opposé
;     result contient op1 - op2
;     STATUS,C armé si débordement
;     STATUS,Z armé si résultat nul
; remarque :
;    utilise un niveau de pile
;     la banque mémoire contenant op1, op2 et result 
;     doit être sélectionnée
;     chaîne sur add_8bits_signé pour gagner un octet de code
    call    opposé_8bits_signé
    btfsc    STATUS,C
    goto        sub_8bits_signé_1
    call        add_8bits_signé
    return
sub_8bits_signé_1
    ; ici on calcule op1-(-128) ce qui n'
est possible que si
    
; op1<0
    btfsc        op1
,7
    goto        sub_8bits_signé_2
    bsf        STATUS
,C
    return
sub_8bits_signé_2    
    movf        op1
,w
    addwf    op2
,w
    movwf    result
    bcf    STATUS
,C
    return
    


;**********************************************************************

add_8bits_signé
; réalise l'addition de deux entiers 8 bits signés
; entrée :
;     op1 opérande 1 
;     op2 opérande 2
; sortie :
;     op1, op2 inchangés
;     result contient op1 + op2
;     STATUS,C armé si débordement
;     STATUS,Z armé si résultat nul
; remarque :
;     la banque mémoire contenant op1, op2 et result 
;     doit être sélectionnée
    movf    op1,w
    xorwf    op2,w        ; ou exlusif avec op2
    movwf    result        ; pour manipuler le bit 7 du résultat
    btfsc    result,7    ; on ne s'
intéresse qu'au bit de signe
    goto    add_8bits_signé_1
    ; ici, op1 et op2 sont de même signe
    movf    op1,w
    addwf    op2,w
    movwf    result
    bcf        STATUS, C    ; a priori pas de débordement
    movf    op1,w
    xorwf    result,w    ; ou exlusif avec result
    andlw    0x80
    btfss    STATUS, Z
    ; le bit de signe du résultat diffère de celui des opérandes
    ; il y a débordement
    bsf        STATUS, C    ; on indique le débordement
    movf    result, f    ; pour positionner STATUS,Z
    return
    
add_8bits_signé_1
    ; ici op1 et op2 sont de signe différent
    ; il ne peut pas y avoir de débordement,
    ; on les ajoute comme des insignés
    movf    op1,w
    addwf    op2,w    ; positionne STATUS,Z 
    movwf    result
    ; mais on marque le non débordement
    bcf        STATUS, C
    return

;**********************************************************************

opposé_8bits_signé
; calcule l'
opposé d'un entier 8 bits signés
; entrée :
    ; op2 l'
octet à traiter    
; sortie : 
;    op2 contient -op3
;     STATUS, C est armé si dépassement de capacité
;     se produit si la valeur de l'octet traité en entrée est -128 (0x80)
;     on se débarasse de ce cas gènant 
; remarque :
;     la banque mémoire contenant op2 doit être sélectionnée
    movlw    0x80
    subwf    op2, w
    btfsc    STATUS,Z
    ; C est armé en même temps que Z
    return
    bcf        STATUS,C    ; ici, on n'
aura pas de débordement
    comf    op2
, f
    incf    op2
, f
    return
    
    END             
; directive fin de programme

Cordialement

JJE

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

Menu de routines ASM à disposition
JJE
Amateur
Amateur
Messages : 142
Âge : 78
Enregistré en : novembre 2017
Localisation : Picardie

#5 Message par JJE » lun. 25 juin 2018 06:58

Se débarrasser de la gestion des pages de code.

Bonjour à tous,
Je vous propose, ci-dessous, une technique pour se débarrasser du problème de gestion des pages de code.
Je suis conscient du fait que le problème ne se pose que pour les membres développant de gros programmes mais la technique peut intéresser d'autres membres même ceux qui comme moi n'ont jamais été gênés par la taille mémoire d'un petit 12F675.
L'intérêt majeur de la mise en oeuvre de cette technique est que le déplacement du sous-programme d'une page à une autre ne pose plus aucun soucis, il suffit de préciser l'adresse d'implantation du sous-programme à l'assembleur, inutile de rechercher les appels qui lui sont fait et de modifier le changement éventuel pour chaque appel.
Pour les anciens, une idée analogue avait été mise en oeuvre sur des MO5 petites machines (à base de 6805) développées pour les collèges début des années 1980, Elles disposaient d'une ROM de 4*16k mots et il avait été développé un langage pour l'enseignement le LSE. On imagine que ce soft (d'un niveau supérieur au Basic de l'époque, en particulier pour ses procédures nommées, mais arrêtons là, je vais me faire arracher les yeux, il y avait une vraie bagare entre les tenants de l'un et de l'autre des langages) qui comprenait un éditeur de texte, un compilateur, un décompilateur, un interpréteur était à l'étroit dans ses 4*16k et que ses auteurs devaient bien gérer les pages de code.

Le principe est simple, on écrit en fond de mémoire (mais ce pourrait être n'importe où ailleurs) de chaque page un relais qui gère le changement de page (il faut bien qu'il soit fait quelque part), appel le sous-programme et remet PCLATH en l'état.
J'ai fait deux versions
Dans la première, tout est écrit dans le même .ASM, les commentaires devraient suffire à comprendre.
Dans la deuxième, j'ai isolé la partie utile à la technique dans une macro qui en facilite le réemploi, voir dans la caisse à outils.
Quelques explications suivent les listings de ces programmes.

Première version

Code : Tout sélectionner



;**********************************************************************
;
           Programme de test de la gestion de relais                           *
;
                     d'appel de sous-programme
;                                                                     *
;**********************************************************************
;                                                                     *
;    NOM: Test relais                                         *
;    Date: 23/06/2018 début de projet                                 *                         
;    Version: 1                                                       *
;    Circuit:  Tout Mid-range au moins                                                    *
;    Auteur        JJE
;                                                                     *
;**********************************************************************
;                                                                     *
;    Fichier requis:                                     *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes: Ce petit programme permet de tester les appels de 
;     sous-programmes par relais indépendant de la page de code d'

;     part l'appel            
;     sous le simulateur de MPLAB lancez en pas à pas et suivez 
;     l'
avancement.
;
     Il peut être utile d'ouvrir une fenêtre Watch sur PCLATH
;                                                                     *
;                                                                     *
;**********************************************************************


;    LIST      p=16F876             ; Définition de processeur
;    #include <p16F876.inc>         ; Définitions des constantes
;
;    __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON     ; & _HS_OSC
;

;*********************************************************************
;                              ASSIGNATIONS                          *
;*********************************************************************
PCLATH    EQU 0xA

;*********************************************************************
;                             DEFINE                                 *
;*********************************************************************

; dernière adresse de mémoire programme

;#DEFINE __MAXFLASH    0x03FF    ; pour un 12F675
;#DEFINE __MAXFLASH    0x0FFF    ; pour un 16F87/88 ou 16F873/874
#DEFINE __MAXFLASH    0x1FFF    ; pour un 16F876/877

; où installer le code du sous-programme
#DEFINE        SSP_Code    0x100    

; adresse de fin de la mémoire programme en page 0 plus 1
    variable RelaisSSP = (__MAXFLASH & 0x7FF)    +1
    
    if    (__MAXFLASH >= 0x1800)
        TailleRelais EQU 6
    else
        if    (__MAXFLASH >= 0x800)
            TailleRelais EQU 4
        else
            TailleRelais EQU 2
        endif
    endif
    
;*********************************************************************
;                   DECLARATIONS DE VARIABLES                        *
;*********************************************************************

    CBLOCK 0x020                   ; début de la zone variables
    ENDC                        ; Fin de la zone                        

;**********************************************************************
;                      DEMARRAGE SUR RESET                            *
;**********************************************************************

    org 0x000                     ; Adresse de départ après reset
      goto    init                ; Adresse 0: initialiser

    
;*********************************************************************
;                       INITIALISATIONS                              *
;*********************************************************************
    
    errorlevel -306
    
init
    ; appelle SSP depuis la page 0
    call    SSP    
    if    (__MAXFLASH >= 0x800)
        pagesel    init2
        call    init2
    endif
    if    (__MAXFLASH >= 0x1000)
        pagesel    init3
        call    init3
    endif
    if    (__MAXFLASH >= 0x1800)
        pagesel    init4
        call    init4
    endif
    pagesel init
    goto init

    
    if    (__MAXFLASH >= 0x800)
        org 0x800
init2
        ; appelle SSP depuis la page 1
        call    SSP    
        return
    endif
    
    if    (__MAXFLASH >= 0x1000)
        org 0x1000
init3
        ; appelle SSP depuis la page 2
        call    SSP    
        return
    endif
    if    (__MAXFLASH >= 0x1800)
        org 0x1800
init4
        ; appelle SSP depuis la page 3
        call    SSP    
        return
    endif
    
    org SSP_Code
    nop
    nop
    nop
    return
    

RelaisSSP -= TailleRelais    

SSP EQU    RelaisSSP


    ORG    RelaisSSP
    ; si on arrive ici, sauf sur erreur de programme, 
    ; on est sûr que PCLATH<4, 3> = b'
00'
    if (SSP_Code & 0x800) == 0x800
        ; SSP_Code est en page 0 ou 2
        ; il faut armer PCLATH,3
        bsf    PCLATH, 3
    endif
    if (SSP_Code & 0x1000) == 0x1000
        ; SSP_Code est en page 1 ou 3
        ; il faut armer PCLATH,4
        bsf    PCLATH, 4
    endif
    call    SSP_Code
    if (SSP_Code & 0x800) == 0x800
        bcf    PCLATH, 3
    endif
    if (SSP_Code & 0x1000) == 0x1000
        bcf    PCLATH, 4
    endif
    return
    
    if    (__MAXFLASH >= 0x800)
        ORG    RelaisSSP + 0x800
        ; si on arrive ici, sauf sur erreur de programme, 
        ; on est sûr que PCLATH<4, 3> = b'
01'
        if (SSP_Code & 0x800) != 0x800
            ; SSP_Code n'
est pas en page 0 ou 2
            
; il faut armer PCLATH,3
            bcf    PCLATH
, 3
        endif
        if 
(SSP_Code & 0x1000) == 0x1000
            
; SSP_Code est en page 1 ou 3
            
; il faut armer PCLATH,4
            bsf    PCLATH
, 4
        endif
        call    SSP_Code
        if 
(SSP_Code & 0x800) != 0x800
            bsf    PCLATH
, 3
        endif
        if 
(SSP_Code & 0x1000) == 0x1000
            bcf    PCLATH
, 4
        endif
        return
    endif
    
    if    
(__MAXFLASH >= 0x1000)
        ORG    RelaisSSP + 0x1000
        
; si on arrive ici, sauf sur erreur de programme, 
        
; on est sûr que PCLATH<4, 3> = b'10'
        if (SSP_Code & 0x800) == 0x800
            
; SSP_Code est en page 0 ou 2
            
; il faut armer PCLATH,3
            bsf    PCLATH
, 3
        endif
        if 
(SSP_Code & 0x1000) != 0x1000
            
; SSP_Code n'est pas en page 1 ou 3
            ; il faut armer PCLATH,4
            bcf    PCLATH, 4
        endif
        call     SSP_Code
        if (SSP_Code & 0x800) == 0x800
            bcf    PCLATH, 3
        endif
        if (SSP_Code & 0x1000) != 0x1000
            bsf    PCLATH, 4
        endif
        return
    endif
    
    if    (__MAXFLASH >= 0x1000)
        ORG    RelaisSSP + 0x1800
        ; si on arrive ici, sauf sur erreur de programme, 
        ; on est sûr que PCLATH<4, 3> = b'
11'
        if (SSP_Code & 0x800) != 0x800
            ; SSP_Code n'
est pas en page 0 ou 2
            
; il faut désarmer PCLATH,3
            bcf    PCLATH
, 3
        endif
        if 
(SSP_Code & 0x1000) != 0x1000
            
; SSP_Code n'est pas en page 1 ou 3
            ; il faut désarmer PCLATH,4
            bcf    PCLATH, 4
        endif
        call    SSP_Code
        if (SSP_Code & 0x800) != 0x800
            bsf    PCLATH, 3
        endif :-) 
        if (SSP_Code & 0x1000) != 0x1000
            bsf    PCLATH, 4
        endif
        return
    endif
    
    end


Quelques commentaires

Code : Tout sélectionner

;    LIST      p=16F876             ; Définition de processeur
;    #include <p16F876.inc>         ; Définitions des constantes
.../...
PCLATH    EQU 0xA


comme ce programme n'est pas destiné à être installé dans un pic, point n'est besoin de LIST ni d'include,
par contre, on va travailler avec PCLATH et il faut bien dire à l'assembleur que c'est l'octet d'adresse 0x0A :-)

Code : Tout sélectionner

; dernière adresse de mémoire programme

;#DEFINE __MAXFLASH    0x03FF    ; pour un 12F675
;#DEFINE __MAXFLASH    0x0FFF    ; pour un 16F87/88 ou 16F873/874
#DEFINE __MAXFLASH    0x1FFF    ; pour un 16F876/877


Il y a bien une constante __MAXRAM qui donne l'adresse la plus grande adressable en mémoire de donnée définie dans chaque fichier p*.inc toujours inclus en début d'un code source. Mais je n'ai pas trouvé d'équivalent pour la mémoire programme, j'ai donc laissé à l'utilisateur le soin de donner cette information précieuse en particulier car on peut en déduire le nombre de pages de code, bits 12 et 11 de cette constante
; où installer le code du sous-programme
#DEFINE SSP_Code 0x100
C'est par de DEFINE que l'utilisateur précisera à l'assembleur l'adresse où il veut installer son sous-programme

En fait, ce sont les deux seules lignes que l'utilisateur aura à renseigner

Code : Tout sélectionner

; adresse de fin de la mémoire programme en page 0 plus 1
    variable RelaisSSP = (__MAXFLASH & 0x7FF)    +1


Comme j'ai décidé d'installer mes relais en fond de mémoire, je calcule ici, l'adresse de fond de mémoire de la page 0

Code : Tout sélectionner

; adresse de fin de la mémoire programme en page 0 plus 1
    variable RelaisSSP = (__MAXFLASH & 0x7FF)    +1
   
    if    (__MAXFLASH >= 0x1800)
        TailleRelais EQU 6
    else
        if    (__MAXFLASH >= 0x800)
            TailleRelais EQU 4
        else
            TailleRelais EQU 2
        endif
    endif


La taille des relais dépend bien sûr du nombre de page cette séquence la calcule

Code : Tout sélectionner

init
    ; appelle SSP depuis la page 0
    call    SSP   
    if    (__MAXFLASH >= 0x800)
        pagesel    init2
        call    init2
    endif
    if    (__MAXFLASH >= 0x1000)
        pagesel    init3
        call    init3
    endif
    if    (__MAXFLASH >= 0x1800)
        pagesel    init4
        call    init4
    endif
    pagesel init
    goto init


C'est une simple boucle qui appelle le sous-programme SSP pour chaque page. bien sûr il dépend du nombre de pages.et les appels aux init* servent à se placer dans la bonne page.

Code : Tout sélectionner

    org SSP_Code
    nop
    nop
    nop
    return


Là, c'est le sous-programme à charge de l'utilisateur. Remarquez qu'il est installé là il a été spécifié en début de programme. Remarquez aussi qu'il est anonyme. En fait l'utilisateur n’appellera jamais, bien qu'il puisse le faire, l'adresse SSP_Code, ce sont les relais qui le feront.

Code : Tout sélectionner

RelaisSSP -= TailleRelais   

SSP EQU    RelaisSSP


Il faut bien qu'on sache où on va écrire les relais. Comme, au plus, ils demandent TailleRelais octets de mémoire programme, et qu'on a décidé de les mettre avant la fin de mémoire, on calcule l'adresse d'installation comme dit ci-dessus
et on s'en souvient dans la constante SSP, c'est cette adresse que l'utilisateur appellera quand il voudra appeler son sous-programme. à lui de lui donner un nom plus évocateur.
La fin du code est l'installation des relais eux-même. On voit bien dans la directive ORG qu'on se place au bon endroit dans chaque page, on voit bien aussi qu'on ne touche qu'aux bits de PCLATH utiles (contrairement à la macro pagesel fournie avec MPLAB et qu'on les remets en l'état où ils étaient en entrant . et on voit bien aussi l'appel du sous-programme.
Cordialement

JJE

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

Menu de routines ASM à disposition
JJE
Amateur
Amateur
Messages : 142
Âge : 78
Enregistré en : novembre 2017
Localisation : Picardie

#6 Message par JJE » mar. 26 juin 2018 05:31

Outil pour se débarrasser de la gestion des pages de code


Le sujet se débarrasser de la gestion des page de code décrit une technique . Il est recommandé de le lire avant d’aborder celui-ci.
Celui-ci décrit un outil pour faciliter la mise en œuvre de cette technique.
Il contient un fichier à inclure contenant deux macros et un fichier .asm qui exploite ces macros pour installer deux sous-programmes à une adresse spécifiée par l’utilisateur et les appelle de toutes les pages de code du processeur spécifié par Configure/Select Device

Le fichier à inclure : « Macro RelaisSSP.inc »

Code : Tout sélectionner


m_Relais_Def    macro    ad
, taille
;#DEFINE __MAXFLASH    0x03FF    ; pour un 12F675
;#DEFINE __MAXFLASH    0x0FFF    ; pour un 16F87/88 ou 16F873/874
#DEFINE __MAXFLASH    ad    ; pour un 16F876/877

; adresse de fin de la mémoire programme en page 0 plus 1
    variable RelaisSSP 
= (__MAXFLASH & 0x7FF)    +1
    
    if    
(__MAXFLASH >= 0x1800)
taille EQU .6
    else
        if    
(__MAXFLASH >= 0x800)
taille EQU .4
        else
taille EQU .2
        endif
    endm

m_RelaisSSP macro ad_SSP
,  X
    
RelaisSSP 
-= TailleRelais
    
X EQU    RelaisSSP

    ORG    RelaisSSP
    
; si on arrive ici, sauf sur erreur de programme, 
    
; on est sûr que PCLATH<4, 3> = b'00'
    if (ad_SSP & 0x800) == 0x800
        
; ad_SSP est en page 0 ou 2
        
; il faut armer PCLATH,3
        bsf    PCLATH
, 3
    endif
    if 
(ad_SSP & 0x1000) == 0x1000
        
; ad_SSP est en page 1 ou 3
        
; il faut armer PCLATH,4
        bsf    PCLATH
, 4
    endif
    call    ad_SSP
    if 
(ad_SSP & 0x800) == 0x800
        bcf    PCLATH
, 3
    endif
    if 
(ad_SSP & 0x1000) == 0x1000
        bcf    PCLATH
, 4
    endif
    return
    
    if    
(__MAXFLASH >= 0x800)
        ORG    RelaisSSP + 0x800
        
; si on arrive ici, sauf sur erreur de programme, 
        
; on est sûr que PCLATH<4, 3> = b'01'
        if (ad_SSP & 0x800) != 0x800
            
; ad_SSP n'est pas en page 0 ou 2
            ; il faut armer PCLATH,3
            bcf    PCLATH, 3
        endif
        if (ad_SSP & 0x1000) == 0x1000
            ; ad_SSP est en page 1 ou 3
            ; il faut armer PCLATH,4
            bsf    PCLATH, 4
        endif
        call    ad_SSP
        if (ad_SSP & 0x800) != 0x800
            bsf    PCLATH, 3
        endif
        if (ad_SSP & 0x1000) == 0x1000
            bcf    PCLATH, 4
        endif
        return
    endif
    
    if    (__MAXFLASH >= 0x1000)
        ORG    RelaisSSP + 0x1000
        ; si on arrive ici, sauf sur erreur de programme, 
        ; on est sûr que PCLATH<4, 3> = b'
10'
        if (ad_SSP & 0x800) == 0x800
            ; ad_SSP est en page 0 ou 2
            ; il faut armer PCLATH,3
            bsf    PCLATH, 3
        endif
        if (ad_SSP & 0x1000) != 0x1000
            ; ad_SSP n'
est pas en page 1 ou 3
            
; il faut armer PCLATH,4
            bcf    PCLATH
, 4
        endif
        call     ad_SSP
        if 
(ad_SSP & 0x800) == 0x800
            bcf    PCLATH
, 3
        endif
        if 
(ad_SSP & 0x1000) != 0x1000
            bsf    PCLATH
, 4
        endif
        return
    endif
    
    if    
(__MAXFLASH >= 0x1000)
        ORG    RelaisSSP + 0x1800
        
; si on arrive ici, sauf sur erreur de programme, 
        
; on est sûr que PCLATH<4, 3> = b'11'
        if (ad_SSP & 0x800) != 0x800
            
; ad_SSP n'est pas en page 0 ou 2
            ; il faut désarmer PCLATH,3
            bcf    PCLATH, 3
        endif
        if (ad_SSP & 0x1000) != 0x1000
            ; ad_SSP n'
est pas en page 1 ou 3
            
; il faut désarmer PCLATH,4
            bcf    PCLATH
, 4
        endif
        call    ad_SSP
        if 
(ad_SSP & 0x800) != 0x800
            bsf    PCLATH
, 3
        endif
        if 
(ad_SSP & 0x1000) != 0x1000
            bsf    PCLATH
, 4
        endif
        return
    endif
    endm    




La première macro m_Relais_Def définit les constantes utiles à cette manipe, elle a deux paramètres

__MAXFLASH. Donne l’adresse maximale de la mémoire programme, elle est renseignée par la valeur du premier paramètre effectif donnée par l’utilisateur. Je n’ai pas trouvé dans la doc de moyen de procéder autrement comme on peut le faire pour la taille de la mémoire de donnée connue par __MAXRAM.
RelaisSSP est une variable d’assemblage initialisée à la plus grande adresse en page 0 de la mémoire programme +1. Les relais seront installés juste au-dessus
La macro définit la constante dont le nom est passé en deuxième paramètre par la taille des relais qui dépend du nombre de pages du pic utilisé.

La deuxième macro installe les relais.
Elle a deux paramètres. Le premier donne l’adresse du sous-programme relayé, le deuxième retourne l’adresse de ce relais en page 0, c'est cette adresse qu'il faudra invoquer pour appeler le sous-programme. Il sera astucieux de lui donner le nom du sous-programme traité.


Le programme principal :

Code : Tout sélectionner

;**********************************************************************
;
           Programme de test de la gestion de relais                           *
;
                     d'appel de sous-programme
;         utilisant la macro du fichier Macro RelaisSSP.inc 
;                                                                     *
;**********************************************************************
;                                                                     *
;    NOM: Test relais
;    Date: 24/06/2018
;    Version: 1                                                       *
;    Circuit:  Tout Mid-range au moins
;    Auteur        JJE
;                                                                     *
;**********************************************************************
;                                                                     *
;    Fichier requis: Macro RelaisSSP.inc
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes: Ce petit programme permet de tester les appels de 
;     sous-programmes par relais indépendant de la page de code d'

;     part l'appel            
;     sous le simulateur de MPLAB lancez en pas à pas et suivez 
;     l'
avancement dans le listing de désassemblage.
;
     Il peut être utile d'ouvrir une fenêtre Watch sur PCLATH
;                                                                     *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************


;    LIST      p=16F876             ; Définition de processeur
;    #include <p16F876.inc>         ; Définitions des constantes
;
;    __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON     ; & _HS_OSC
;

;*********************************************************************
;                              ASSIGNATIONS                          *
;*********************************************************************
PCLATH    EQU 0xA

;*********************************************************************
;                             Macros                                 *
;*********************************************************************

    include    Macro RelaisSSP.inc    
    
;*********************************************************************
;                             DEFINE                                 *
;*********************************************************************

; dernière adresse de mémoire programme

    m_Relais_Def 0x1FFF, TailleRelais

; où installer le code du sous-programme
#DEFINE        SSP1_Code    0x1100    
#DEFINE        SSP2_Code    0x900    


;*********************************************************************
;                   DECLARATIONS DE VARIABLES                        *
;*********************************************************************

    CBLOCK 0x020                   ; début de la zone variables
    ENDC                        ; Fin de la zone                        

;**********************************************************************
;                      DEMARRAGE SUR RESET                            *
;**********************************************************************

    org 0x000                     ; Adresse de départ après reset
      goto    init                ; Adresse 0: initialiser

    
;*********************************************************************
;                       INITIALISATIONS                              *
;*********************************************************************
    
    errorlevel -306
    
init
    ; appelle SSP1 puis SSP2 depuis la page 0
    call    SSP1    
    call    SSP2    
    if    (__MAXFLASH >= 0x800)
        pagesel    init2
        call    init2
    endif
    if    (__MAXFLASH >= 0x1000)
        pagesel    init3
        call    init3
    endif
    if    (__MAXFLASH >= 0x1800)
        pagesel    init4
        call    init4
    endif
    pagesel init
    goto init

    
    if    (__MAXFLASH >= 0x800)
        org 0x800
init2
    ; appelle SSP1 puis SSP2 depuis la page 1
    call    SSP1    
    call    SSP2    
        return
    endif
    
    if    (__MAXFLASH >= 0x1000)
        org 0x1000
init3
    ; appelle SSP1 puis SSP2 depuis la page 2
    call    SSP1    
    call    SSP2    
        return
    endif
    if    (__MAXFLASH >= 0x1800)
        org 0x1800
init4
    ; appelle SSP1 puis SSP2 depuis la page 3
    call    SSP1    
    call    SSP2    
        return
    endif
    
    ORG    SSP1_Code
    nop
    nop
    nop
    return
    
    ORG    SSP2_Code
    nop
    nop
    nop
    return

    m_RelaisSSP SSP1_Code,  SSP1
    m_RelaisSSP SSP2_Code,  SSP2
    
    end


Par rapport au programme original qui pouvait faire la même chose mais en étant obligé de gérer les pages de code
on a ajouté, au début de programme

Code : Tout sélectionner

;*********************************************************************
;
                             Macros                                 *
;*********************************************************************

    include    Macro RelaisSSP.inc    
    
;*********************************************************************
;
                             DEFINE                                 *
;*********************************************************************

;
 dernière adresse de mémoire programme

    m_Relais_Def 0x1FFF
, TailleRelais

; où installer le code du sous-programme
#DEFINE        SSP1_Code    0x1100    
#DEFINE        SSP2_Code    0x900    




inclusion du fichier de macros
invocation de m_Relais_Def
définition des adresses où installer les sous-programmes

On a remplacé les définitions de sous-programme :

Code : Tout sélectionner

;SSP1
    ORG    SSP1_Code
    nop
    nop
    nop
    return

;SSP2    
    ORG    SSP2_Code
    nop
    nop
    nop
    return


La définition des étiquettes SSP1 et SSP2 sera effectuée plus loin.

On a invoqué les macros qui installent les relais :

Code : Tout sélectionner


    m_RelaisSSP SSP1_Code
,  SSP1
    m_RelaisSSP SSP2_Code
,  SSP2


C'est ici que sont définies les étiquettes SSP1 et SSP2. En fait, ça veut dire : pour exécuter SSP1_Code, branchez sur SSP1 qui fera les changement de page nécessaires et branchera sur SSP1_Code ; idem pour SSP2.

Remarquez que ce n'est pas cher payer la possibilité d'appeler ces sous-programmes de n'importe où et de les déplacer par une simple modification de l'initialisation d'une variable.
Cordialement

JJE

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


Retourner vers « Langage ASM »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité