CODING - Les opérations, la pile et les registres spécialisés par ANTIBUG
 
 
Sommaire:
dernière maj : le 01/06/2007
1 - Préface
    Vous allez peut être me dire quel est le rapport entre les opérations réalisées avec le Z80, la gestion de la pile et les registres spéciaux ? Et bien nous allons étudier dans cet article l’utilisation de la pile pour la création de fonctions avec passage de paramètres. Les registres spécialisés quand à eux, seront utilisés dans les fonctions de manière à préserver le contenu des registres courant qui utilisés dans vos programmes. 

Dans cet article nous allons reprendre des exemples qui ont été étudiés dans l’article précédent « Les multiplications et divisions avec le Z80 », je vous conseille de vous reporter à cet article si vous débutez en assembleur.

Je vous souhaite une bonne lecture …

2 - Rappel de l’utilisation de la pile
2.1 Rappel sur la pile
   La pile est une zone mémoire qui permet de stocker, par exemple, la valeur de registres, les adresses de retour lorsque vous faites appel à des procédures ou fonctions, ou d’éventuelles données temporaires. L’emplacement de cette zone mémoire est stocké dans le registre SP, qui est un registre de 16 bits, et qui sert de pointeur de pile. Lorsque vous concevez un programme la première chose à faire dans ce programme, est de définir l’emplacement de la pile et sa taille. La taille de celle-ci va bien sûr dépendre de son utilisation, à savoir : l’utilisation des instructions PUSH et POP, par exemple, ou du nombre d’appels imbriqués dans des procédures.

2.2 Déclaration de la pile en assembleur
;****************************************
; Exemple de déclaration de la pile
;

ORG &4000       ; Emplacement de programme en mémoire
RUN &4000       ; Lancement automatique du programme, pour info! (sous WinAPE)

START
        LD SP, STACK + STACK_SIZE – 1  ; SP = [Adresse de STACK] + [Taille de la pile] - 1
        .
        .
        .

STACK_SIZE  EQU  40             ; Taille de la pile en octet
STACK       DEFS STACK_SIZE     ; Emplacement de la pile de 40 octets

END

Remarque :

Si vous utilisez WinAPE pour vos développements, je vous conseille de ne modifier la pile qu’à partir du moment où votre programme est achevé. WinAPE gère par défaut la pile à l’adresse &BFEx.

2.3 Exemple d’utilisation de la pile

    Nous allons voir rapidement comment travailler avec la pile. Prenons un exemple, imaginons que l’adresse de la pile soit fixée à l’adresse &3010 et d’une taille de 16 octets.
;***************************************
; Exemple A : Utilisation de la pile
;
; Adresse de la pile fixée en &3010
;

        LD SP, &3010    ; On fixe l’adresse de la pile
                        ; L’adresse de la pile ? &3010

        LD DE, 5                ; On va stocker 5 sur la pile
        PUSH DE         ; La valeur contenu dans DE se trouve maintenant sur la pile
                        ; à l’adresse (SP – 2) => SP = &3008

        LD DE, 3                ; On stocke maintenant 2 sur la pile
        PUSH DE         ; Le contenu de DE se trouve maintenant sur la pile
                        ; à l’adresse (SP – 4) => SP = &3006

        POP BC          ; Récupération de 3 dans BC
                        ; SP a augmenté de 2 car la valeur 3 a été dépilée
                        ; => SP = &3008

        POP BC          ; Récupération de la valeur 5 de la pile
                        ; SP a été incrémenté de 2
                        ; => SP = &3010 (adresse initiale)


« Je pense que vous avez compris facilement comment on utilise la pile ! »

Dans certain cas, dans vos programmes, vous aurez à consulter des données sans toucher à la pile. Le moyen le plus simple est d’accéder directement à l’adresse de ces données via un adressage indexé sans modifier SP, exemple :

;***************************************
; Exemple 2 : Utilisation de la pile
;
; Adresse de la pile fixée en &3010
;

        LD SP, &3010    ; On fixe l’adresse de la pile
                        ; L’adresse de la pile <=> &3010

        LD IX, 0                ; Copie de l’adresse de SP dans le registre d’indexe IX
        ADD IX, SP      ;

        LD DE, 5                ; On va stocker 5 sur la pile
        PUSH DE         ; La valeur contenu dans DE se trouve maintenant sur la pile
                        ; à l’adresse (SP – 2) => SP = &3008

        LD DE, 3                ; On stocke maintenant 2 sur la pile
        PUSH DE         ; Le contenu de DE se trouve maintenant sur la pile
                        ; à l’adresse (SP – 4) => SP = &3006
        
        LD B, (IX – 1)  ; On transfert le contenu de (SP – 1) dans B
        LD C, (IX – 2)  ; On transfert le contenu de (SP – 2) dans C
                        ; => BC = 5

        LD H, (IX – 3)  ; On transfert le contenu de (SP – 3) dans H
        LD L, (IX – 4)  ; On transfert le contenu de (SP – 4) dans L
                        ; => HL = 3

Ce qu’il faut ne faut pas perdre de vu c’est qu’à chaque lecture de la pile via un adressage indéxé la pile reste intacte, au contraire lorsque l’on récupère une valeur empilée via l’instruction POP la pile est dépilée, SP est ré-incrémenté de 2.
3 – Création de fonctions
    Nous allons maintenant voir comment exploiter la pile pour créer des fonctions avec passage de paramètres. Certains préfèreront l’utilisation des registres pour passer directement des paramètres, cependant dans certains cas il est plus facile d’utiliser la pile. 
3.1 Exemple d’utilisation de la pile

Voyons un exemple concret …

Exemple : Création d’une fonction d’addition avec 2 paramètres sur 16 bits, le résultat est renvoyé via le registre de données DE. 

;*************************************************
; Addition de 2 valeurs sur 16 bits
;

        LD HL, 4
        PUSH HL
        LD BC, 10
        PUSH BC
        CALL MATH_ADD_SP_16x16   ; En retour DE va contenir HL + BC
        .
        .
        .

;*************************************************
; Fonction d’addition de 2 entiers sur 16 bits
;
; En entrée
;       [SP – 2] <=> Paramètre 1
;       [SP – 4] <=> Paramètre 2
; En sortie
;       DE <=> [SP – 2] + [SP – 4]
; Registres affectés
;       F, DE

MATH_ADD_SP_16x16 :

        EXX             ; Sauvegarde des registres BC, DE, HL
        POP BC          ; Récupération de l’adresse de retour
        POP DE          ; Récupération du premier paramètre
        POP HL          ; Récupération du second paramètre
        PUSH BC         ; Sauvegarde de l’adresse de retour sur la pile

        ADD HL, DE
        PUSH HL
        EXX             ; Restauration des registres BC, DE, HL
        POP DE          ; Récupération du résultat de l’opération
        RET


    Si vous regardez bien cet exemple qui ne peut pas être plus simple, vous constatez que l’on a utilisé les registres spécialisés avant l’opération. En effet pour préserver la valeurs des registres courant vous pouvez prendre pour habitude d’utiliser les registres spécialisés dans vos fonctions cela évite en plus une gestion plus complexe de la pile. Seulement c’est à vous de faire attention aux imbrications de fonctions !!
3.2 Fonctions avec passage de 2 paramètres de 8 bits

    Voyons maintenant comment créer une fonction avec 2 paramètres de 8 bits. Comme vous vous en doutez certainement nous allons empiler sur la pile un seul registre de 16 bits :

Exemple :

;*************************************************
; Soustraction de 2 valeurs de sur 8 bits
;
;
        LD D, 10
        LD E, 4
        PUSH DE
        CALL MATH_SUB_SP_8x8    ; En retour A va contenir D - E
        .
        .
        .

;*************************************************
; Fonction de soustraction de 2 entiers de 8 bits
;
; En entrée
;       [SP – 1] <=> Paramètre 1
;       [SP – 2] <=> Paramètre 2
; En sortie
;       A <=> [SP – 1] - [SP – 2]
; Registres affectés
;       AF
                        
MATH_SUB_SP_8x8 :

        EXX             ; Sauvegarde des registres BC, DE, HL
        POP HL          ; Récupération de l'adresse de retour
        POP DE          ; Paramètres 1 et 2
        PUSH HL         ; Préservation de l'adresse de retour

        LD A, D         ; 10 dans A
        SUB E           ; On enlève 4 => reste dans A
        EXX             ; Restauration des registres BC, DE, HL
        RET

    Ici, l’utilisation d’une telle fonction n’est pas nécessaire, elle sert juste d’exemple, il en va de même pour l’utilisation des registres spécialisés. Je vous conseille de faire attention à l’utilisation de fonctions dans vos programmes, une démo par exemple, car une utilisation trop fréquente de la pile peut s’avérer très couteuse en cycles processeur. C’est à vous de juger si les paramètres d’une fonction doivent être passés par registre ou par la pile !

Je pense que vous avez compris maintenant le rapport entre les opérations du Z80, la pile et les registres spécialisés. 

Pour conclure … le dernier chapitre reprend les fonctions de multiplication et division de l’article précédent « Les multiplications et divisions entières avec le Z80 », si vous ne l’avez pas lu je vous conseille vivement d’y consacrer un peu de temps. Les passages de paramètres par registres ont été remplacés par une gestion de la pile.
 

Le mois prochain nous allons étudier le tracé de ligne, @très bientôt … 

4 – Bibliothèque de méthodes
4.1 Les multiplications par retenues
4.1.1 Multiplication de deux entiers non signés de 8 bits, résultat sur 16 bits
;***************************************************************
; Routine de multiplication de 2 entiers non signés, de 8 bits
; avec un résultat sur 16 bits
;
; En entrée :
;       [SP – 1] <=> Multiplicande (A)
;       [SP – 2] <=> Multiplicateur (B)
;       [SP – 4] <=> Adresse de retour
; En sortie :
;       DE <=> Produit de A par B
; Registres affectés
;       DE, les registres spécialisés
; Remarques
;       - Si A ou B = 0 => DE = 0 en sortie
;       - [SP – 1] et [SP – 2] sont dépilés
;       - Vous pouvez utiliser n’importe quel registre 16 bits en sortie
;       
;       - Exemple de méthode d’appel
;
;               LD B, 5
;               LD C, 2
;               PUSH BC
;               CALL MATH_MUL_SP_8x8
;               .
;

MATH_MUL_SP_8x8:

        EXX             ; Sauvegarde des registres BC, DE, HL
        EX AF, AF’      ; Sauvegarde de AF
        
        ; Récupération des paramètres
        POP HL          ; Sauvegarde l’adresse de retour
        POP BC          ; Récupération des deux paramètres
        PUSH HL         ; Sauvegarde l’adresse de retour

        ; Initialisation des registres pour le calcul
        LD HL, 0        ; Valeur de retour
        LD A, B         ; Transfert du multiplicande dans A
                        ; Le multiplicateur se trouve dans C

        ; Vérification des valeurs en entrée
        OR A            ; Test de A
                        ; Si A = 0 on sort
        JP z, _MATH_MUL_SP_8x8_END
        LD L, A         ; Sauvegarde de A pour le test de C
        LD A, C         ; C est transféré dans A pour le test
        OR A            ; Test de C via A
        LD A, L         ; On restore A
        LD L, H         ; On efface L via H
                        ; Si A(C) = 0 on sort
        JP z, _MATH_MUL_SP_8x8_END

        ; Début de code lié à la multiplication
        LD D, L         ; D est effacer par L
        LD E, A         ; Le multiplicande va dans E
        LD H, C         ; Le multiplicateur va dans H
        LD B, 8         ; Traitement des 8 bits
        
_MATH_MUL_SP_8x8_1

        ; Multiplication par 2 de HL (décalage d'1 bit vers le haut)
        ADD HL, HL
        JR nc, _MATH_MUL_SP_8x8_2

        ; Remplacement du bit de débordement par le multiplicateur
        ADD HL, DE      

_MATH_MUL_SP_8x8_2

        DJNZ _MATH_MUL_SP_8x8_1

_MATH_MUL_SP_8x8_END

        PUSH HL         ; Sauvegarde du résultat
        EXX             ; Restauration des registres courants
        EX AF, AF’      ; Restauration de AF
        POP DE          ; Récupération du résultat dans DE (à changer éventuellement)
        RET

4.1.2 Multiplication de deux entiers non signés de 16 par 8 bits, résultat sur 16 bits
;***************************************************************
; Routine de multiplication de 2 entiers non signés, de 16 par
; 8 bits, avec un résultat sur 16 bits
;
; En entrée
;       [SP - 2] <=> Multiplicande, transféré dans DE
;       [SP - 4] <=> Multiplicateur, transféré dans A (partie haute de [SP - 4])
;       [SP – 6] <=> Adresse de retour
; En sortie :
;       DE <=> Produit de DE par A (résultat sur 16 bits !)
; Registres affectés
;       DE et les registres spécialisés
; Remarques
;       - Si A ou DE = 0 => DE = 0 en sortie
;       - [SP - 2] et [SP - 4] sont dépilés
;       - Vous pouvez utiliser n’importe quel registre 16 bits en sortie
;
;       - Méthode d’appel de la fonction
;
;               LD DE, 6
;               PUSH DE
;               LD D, 2         ; D contient le multiplicateur
;               PUSH DE
;               CALL MATH_MUL_SP_16x8   
;               .
;

MATH_MUL_SP_16x8:
        
        EXX             ; Sauvegarde des registres BC, DE, HL
        EX AF, AF'      ; Sauvegarde de AF

        ; Récupération des paramètres
        POP HL          ; Récupération de l'adresse de retour
        POP AF          ; Récupération du multiplicateur
                        ; Le multiplicateur va se retrouvé dans A
        POP DE          ; Récupération du multiplicande
        PUSH HL         ; Préservation de l'adresse de retour

        ; Initialisation des registres
        LD HL, 0        ; Valeur de retour

        ; Vérification des valeurs d'entrée
        OR A            ; Si A = 0 on sort
        JP z, _MATH_MUL_SP_16x8_END
        ADC HL, DE      ; Ajout de DE à HL de manière à vérifier si DE = 0
                        ; Si DE = 0 => z = 1
        JP z, _MATH_MUL_SP_16x8_END

        ; Début du code lié à la multiplication
        LD HL, 0        ; Valeur de retour
        LD B, 8         ; Traitement des 8 bits

_MATH_MUL_SP_16x8_1

        ; Multiplication par 2 de HL (décalage d'1 bit vers le haut)
        ADD HL, HL
        ADD A, A
        JR nc, _MATH_MUL_SP_16x8_2

        ; Remplacement du bit de débordement par le multiplicateur
        ADD HL, DE      

_MATH_MUL_SP_16x8_2

        DJNZ _MATH_MUL_SP_16x8_1

_MATH_MUL_SP_16x8_END

        PUSH HL         ; Sauvegarde du résultat
        EXX             ; Restauration des registres courants BC, DE, HL
        EX  AF, AF'     ; Restauration de AF
        POP DE          ; Récupération du résultat dans DE
                        ; (Au tout autre registre 16 bits)
        RET

4.1.3 Multiplication de deux entiers non signés de 16 bits, résultat sur 16 bits
;***************************************************************
; Routine de multiplication de 2 entiers non signés de 16 bits,
; avec un résultat sur 16 bits
;
; En entrée
;       [SP - 2] <=> Multiplicande, transféré dans BC
;       [SP - 4] <=> Multiplicateur, transféré dans DE
;       [SP - 6] <=> Adresse de retour
; En sortie
;       DE <=> Produit de BC par DE (résultat sur 16 bits !)
; Registres affectés
;       DE et les registres spécialisés
; Remarques
;       - Si BC ou DE = 0 => DE = 0 en sortie
;       -[SP - 2] et [SP - 4] sont dépilés
;       - Vous pouvez utiliser n’importe quel registre 16 bits en sortie
;
;       - Modèle d'appel de la fonction
;
;               LD DE, 5
;               PUSH DE
;               LD DE, 3
;               PUSH DE

;               CALL MATH_MUL_SP_16x16
;               .
;

MATH_MUL_SP_16x16 :

        EXX             ; Sauvegarde des registres  BC’, DE’, HL’
        EX AF, AF’      ; Sauvegarde de AF

        ; Récupération des paramètres
        POP HL          ; Récupération de l’adresse de retour
        POP DE          ; Récupération du multiplicateur
        POP BC          ; Récupération du multiplicande
        PUSH HL         ; Sauvegarde l'adresse de retour

        ; Initialisation des registres
        LD HL, 0        ; Valeur par défaut pour le retour

        ; Vérification des valeurs en entrée
        RL L            ; Permet d'effacer Carry
        ADC HL, BC      ; Vérification que BC’ = 0
        JP z, _MATH_MUL_SP_16x16_END
        LD HL, 0
        ADC HL, DE      ; Vérification que DE’ = 0
        JP z, _MATH_MUL_SP_16x16_END

        ; Début du code lié à la multiplication
        LD HL, 0        ; Valeur de retour
        LD A, B
        LD B, 16

_MATH_MUL_SP_16x16_1

        ; Multiplication par 2 de HL’ (décalage d'1 bit vers le haut)
        ADD HL, HL
        SLA C   ; SLA suivi d'un RLA permet de réaffecter les bits de C’
        RLA     ; dans A’ en cas de débordement de C’, donc de traiter
                ; les 16 bits du multiplicateur
        JR nc, _MATH_MUL_SP_16x16_2

        ; Remplacement du bit de débordement par le multiplicateur
        ADD HL, DE      

_MATH_MUL_SP_16x16_2

        DJNZ _MATH_MUL_SP_16x16_1

_MATH_MUL_SP_16x16_END

        PUSH HL         ; Stockage du résultat sur la pile
        EXX             ; Restauration des registres courants
        EX AF, AF’      ; Restauration de AF
        POP DE          ; Récupération du résultat pour le retour via DE
                        ; (Ou tout autre registre sur 16 bit)
        RET
4.2 Les Multiplications par sous-produits
4.2.1 Multiplication de deux entiers non signés de 8 bits, résultat sur 16 bits
;***************************************************************
; Routine de multiplication de 2 entiers non signés de 8 bits
; avec un résultat sur 16 bits
;
; En entrée
;       [SP - 1] <=> Multiplicateur, transféré dans A
;       [SP - 2] <=> Multiplicande, transféré dans C
;       [SP – 4] <=> Adresse de retour
; En sortie
;       DE <=> Produit de C par A
; Registres affectés
;       DE et les registres spécialisés
; Remarques
;       - Si A ou C = 0 => DE = 0 en retour
;       - [SP - 1] et [SP - 2] sont dépilés
;       - Pour optimiser les calculs, vous pouvez vérifier que le
;         multiplicateur est bien inférieur au multiplicande
;         Plus le multiplicateur est petit plus l'opération est rapide
;
;       - Méthode d’appel de la fonction
;
;               LD D, 6
;               LD E, 2
;               PUSH DE
;               CALL MATH_MUL_SP_8x8
;               .
;

MATH_MUL_SP_8x8:

        EXX             ; Sauvegarde des registres BC, DE, HL
        EX AF, AF'      ; Sauvegarde de AF

        POP HL          ; Récupération de l'adresse de retour
        POP BC          ; Récupération des deux paramètres
        PUSH HL         ; Sauvegarde de l'adresse de retour

        ; Initialisation des registres pour le test en entrée
        LD HL, 0        ; Valeur pour le retour
        LD A, B         ; Le multiplicateur dans A

        ; Vérification des valeurs en entrée
        OR A            ; Test de A
                        ; Retour si A = 0
        JP z, _MATH_MUL_SP_8x8_END
        LD L, A         ; Sauvegarde de A pour le test de C (le multiplicande)
        LD A, C         ; Transfert de B dans A pour le test
        OR A            ; Test de C via A
        LD A, L         ; On restore A
        LD L, H         ; On efface L via H
                        ; Retour si A = 0
        JP z, _MATH_MUL_SP_8x8_END

_MATH_MUL_SP_8x8_1

        ; Début du code lié à la multiplication
        LD D, L         ; Le multiplicande est dans DE pour calculer les sous-produits
        LD E, C         ; 

_MATH_MUL_SP_8x8_2

        BIT 0, A        ; Vérification si le bit 0 = 0, si oui
                        ; on ne cumule pas le sous-produit courant
        JP Z, _MATH_MUL_SP_8x8_3
        ADD HL, DE      ; Cumule du sous-produit courant

_MATH_MUL_SP_8x8_3

        EX HL, DE       ; Décalage du sous-produit courant
        ADD HL, HL      ; de 1 bit vers le haut
        EX HL, DE       ;
        SRL A           ; Décalage du multiplicateur de 1 bit
                        ; vers le bas
        OR A            ; Vérification que tous les bits du
                        ; multiplicateur ont été traités
        JP nz, _MATH_MUL_SP_8x8_2

_MATH_MUL_SP_8x8_END

        PUSH HL         ; Sauvegarde du résultat
        EXX             ; Restauration des registres BC, DE, HL
        EX AF, AF'      ; Restauration de AF
        POP DE          ; Récupération du résultat dans DE
                        ; (Ou tout autre registre 16 bits)
        RET

4.2.2 Multiplication de deux entiers non signés de 16 par 8 bits, résultat sur 16 bits
;***************************************************************
; Routine de multiplication de 2 entiers non signés, de 16 par
; 8 bits, avec un résultat sur 16 bits
;
; En entrée
;       [SP - 2] <=> Multiplicande, transféré dans DE
;       [SP - 4] <=> Multiplicateur, transféré dans A (partie haute de [SP – 4]
;       [SP – 6] <=> Adresse de retour
; En sortie
;       DE <=> Produit de DE par A (résultat sur 16 bits !)
; Registres affectés
;       DE et les registres spécialisés
; Remarques
;       - Si le multiplicande ou le diviseur = 0 => DE = 0 en retour
;       - [SP - 2], [SP - 4] et [SP - 6] sont dépilés
;       - Pour optimiser les calculs, vous pouvez vérifier que le
;         multiplicateur est bien inférieur au multiplicande
;
;       - Méthode d’appel de la fonction
;
;               LD DE, 6
;               PUSH DE
;               LD D, 2         ; D contient le multiplicateur
;               PUSH DE
;               CALL MATH_MUL_SP_16x8
;               .
;

MATH_MUL_SP_16x8:

        EXX             ; Sauvegarde des registres BC, DE, HL
        EX AF, AF'      ; Sauvegarde du registre AF

        POP HL          ; Récupération de l'adresse de retour
        POP AF          ; Récupération du multiplicateur 8 bits dans A
        POP DE          ; Récupération du multiplicande sur 16 bits
        PUSH HL         ; Sauvegarde de l'adresse de retour

        LD HL, 0        ; Mise à blanc de HL pour le retour

        ; Vérification des valeurs en entrée
        OR A            ; Si A = 0 on sort
        JP z, _MATH_MUL_SP_16x8_END

        ADC HL, DE      ; Si DE = 0 on sort
        JP z, _MATH_MUL_SP_16x8_END

        ; Début du code lié à la multiplication
        LD HL, 0

_MATH_MUL_SP_16x8_1

        BIT 0, A        ; Vérification si le bit 0 = 0, si oui
                        ; on ne cumule pas le sous-produit courant
        JP z, _MATH_MUL_SP_16x8_3
        ADD HL, DE      ; Cumule du sous-produit courant

_MATH_MUL_SP_16x8_3

        EX HL, DE       ; Décalage du sous-produit courant
        ADD HL, HL      ; de 1 bit vers le haut
        EX HL, DE       ;
        SRL A           ; Décalage du multiplicateur de 1 bit
                        ; vers le bas
        OR A            ; Vérification que tous les bits du
                        ; multiplicateur ont été traités

        JP nz, _MATH_MUL_SP_16x8_1

_MATH_MUL_SP_16x8_END

        PUSH HL         ; Préservation du résultat
        EXX             ; Restauration des registres courants BC, DE, HL
        EX AF, AF'      ; Restauration de AF
        POP DE          ; Récupération du résultat dans DE
                        ; (ou tout autre registre sur 16 bits)
        RET
         
4.3 La division par utilisation de sous-dividendes
4.3.1 Division de deux entiers non signés de 8 bits, résultat sur 8 bits
;***************************************************************
; Routine de division de 2 entiers non signés de 8 bits, avec un
; résultat sur 8 bits pour le quotient et 8 bits pour le reste
;
; En entrée
;       [SP - 2] <=> Les deux paramètres le dividende (transféré dans B)
;                    et le diviseur (transféré dans C)
; En sortie
;       D <=> Quotient
;       E <=> Reste de la division entière
; Registres affectés
;       DE et les registres spécialisés
; Remarques
;       - Si le dividende ou le diviseur = 0 en entrée => D = 0 et E = 0 en retour
;       - D et E peuvent être remplacés par n’importe quels registres 8 bits en retour
;

MATH_DIV_SP_8x8:

        EXX             ; Sauvegarde des registres BC, DE, HL
        EX AF, AF'      ; Sauvegarde de registre AF

        POP HL          ; Récupération des l'adresse de retour
        POP DE          ; Récupération des deux paramètres D et E
        PUSH HL         ; Préservation de l'adresse de retour

        ; Initialisation des registres
        LD B, 8 ; Les 8 bits du dividende sont traités
        XOR A, A
        
_MATH_DIV_SP_8x8_1

        SLA D   ; Décalage du bit le plus haut, du dividende dans Carry
        RLA     ; Récupération de Carry dans le sous-dividende (A)
                ; (création du sous dividende)
        CP E    ; Vérification si le sous-dividende est >= au diviseur.
                ; Si oui le quotient = + 1, sinon on traite le bit suivant, du dividende

        JR c, _MATH_DIV_SP_8x8_2

        INC D   ; Incrémentation du quotient. Sachant que les bits de D
                ; sortent vers le haut (la gauche), les bits du bas vont
                ; servir pour stocker le quotient
        SUB E   ; On soustrait le diviseur du dividende
        
_MATH_DIV_SP_8x8_2

        DJNZ _MATH_DIV_SP_8x8_1 ; Décrémentation de B de manière à
                              ; traiter les 8 bits du dividende

        LD E, A         ; Récupération du reste dans E
                        ; Le quotient se trouve dans D  
        PUSH DE         ; Préservation du résultat dans DE
        EXX             ; Restauration des registres BC, DE, HL
        EX AF, AF'      ; Restauration du registre AF
        POP DE          ; Récupération du quotient et du reste dans DE
                        ; (ou tout autre registre 16 bits)
        RET

4.3.2 Division de deux entiers non signé de 16 par 8 bits, résultat sur 16 bits
;***************************************************************
; Routine de division d'un entier non signé de 16 bits par un
; entier non signé de 8 bits, avec un résultat sur 16 bits
;
; En entrée
;       [SP - 2] <=> Dividende, transféré dans HL
;       [SP - 4] <=> Diviseur, transféré dans B (8 bits de la partie haute de [SP - 4])
;       [SP – 6] <=> Adresse de retour
; En sortie
;       DE <=> Quotient (sur 16 bits)
;       A  <=> Reste de la division entière (8 bits)
; Registres affectés
;       A, DE et les registres spécialisés
; Remarques
;       - [SP - 2], [SP - 4] et [SP – 6] sont dépilés
;       - Si le dividende ou le diviseur = 0 => DE = 0 et A = 0 en retour
;       - DE peut être remplacé par n’importe quel registre 16 bits pour le retour
;

MATH_DIV_SP_16x8:

        EXX             ; Préservation des registre BC, DE, HL
        EX AF, AF'      ; Préservation de AF

        POP DE          ; Récupération de l'adresse de retour
        POP BC          ; Récupération du diviseur dans B
                        ; (partie haute à l'adresse [SP - 3])
        POP HL          ; Récupération du dividende
        PUSH DE         ; Sauvegarde de l'adresse de retour

        ; Test des valeurs en entrée
        LD A, B
        OR A
        JP nz, _MATH_DIV_SP_16x8_1
        LD H, A
        LD L, A
        JP _MATH_DIV_SP_16x8_END

_MATH_DIV_SP_16x8_1
        
        LD C, B         ; Stockage du diviseur dans C
        LD B, 16                ; Les 16 bits de HL (le dividende) vont être traités
        XOR A, A                ; On efface A pour initialiser le sous-dividende

_MATH_DIV_SP_16x8_2

        SLA L   ; Décalage du bit le plus haut, du dividende dans Carry
        RL H
        RLA     ; Récupération de Carry dans le sous-dividende (A)
                ; (création du sous dividende)
        CP C    ; Vérification si le sous-dividende est supérieur ou
                ; égal au diviseur. Si oui le quotient = + 1, sinon on
                ; traite le bit suivant, du dividende
        JR c, _MATH_DIV_SP_16x8_3
        INC HL  ; Incrémentation du quotient (sachant que tous les bits
                ; de HL sont décalé vers le haut (la gauche), les bits
                ; venant du bas vont servir pour stocker le quotient
        SUB C   ; On soustrait le diviseur du dividende
        
_MATH_DIV_SP_16x8_3

        DJNZ _MATH_DIV_SP_16x8_2 ; Décrémentation de B de manière à
                               ; traiter les 16 bits du dividende

_MATH_DIV_SP_16x8_END

        PUSH HL         ; Sauvegarde du quotient sur la pile, le reste se trouve dans A
        EXX             ; Restauration des registres BC, DE, HL
        LD D, A         ; Sauvegarde du reste de l'opération dans A
        EX AF, AF'      ; Restauration de F
        LD A, D         ; A contient le reste de la division entière
        POP DE          ; Récupération du résultat dans DE
                        ; (ou tout autre registre 16 bits)
        RET

4.3.3 Division de deux entiers non signé de 16 bits, résultat sur 16 bits
;***************************************************************
; Routine de division d'un entier non signé de 16 bits par un
; entier non signé de 16 bits, avec un résultat sur 16 bits
;
;En entrée
;       [SP - 2] <=> Dividende, transféré dans BC
;       [SP - 4] <=> Diviseur, transféré dans DE
;En sortie
;       DE <=> Quotient
;       BC <=> Reste de la division entière (sur 16 bits)
;Registres affectés
;       BC, DE et les registres spécialisés
; Remarques
;       - [SP - 2] et [SP - 4] sont dépilés
;       - Les registres DE et BC en sortie peuvent être remplacés par
;         d'autres registres 16 bits
;      - Si le diviseur ou le dividende = 0 => DE = 0 et BC = 0 en retour
;       - DE peut être remplacé par n’importe quel registre 16 bits pour le retour
;

MATH_DIV_SP_16x16:

        EXX             ; Sauvegarde des registres BC, DE, HL
        EX AF, AF'      ; Sauvegarde de AF

        POP HL          ; Récupération de l'adresse de retour
        POP DE          ; Récupération du diviseur
        POP BC          ; Récupération du dividende
        PUSH HL         ; Préservation de l'adresse de retour
        
        ; Vérification des valeurs en entrée
        LD HL, 0        
        ADC HL, DE      ; Si DE = 0 on sort
        JP nz, _MATH_DIV_SP_16x16_1
        XOR A, A        ; On efface A pour le retour
        LD C, A         ; On efface C pour le retour
        JP _MATH_DIV_SP_16x16_END

_MATH_DIV_SP_16x16_1

        LD HL, 0                ; Servira de sous-dividende
        LD A, B         ; Stockage de la partie haute du dividende dans B
        LD B, 16                ; Les 16 bits de HL (le dividende) vont être traités

_MATH_DIV_SP_16x16_2

        SLA C           ; Décalage du bit le plus haut de la partie basse du 
                        ; dividende, dans Carry
        RLA             ; Récupération de Carry dans la partie haute du dividende
                        ; Et décalage de la partie haute du dividende dans Carry
        ADC HL, HL      ; Récupération éventuelle de Carry et création par la
                        ; même occasion du sous-dividende
        SBC HL, DE      ; On enlève le diviseur du sous-dividende, si Carry est
                        ; allumé c'est que le sous-dividende est inférieur
        JR c, _MATH_DIV_SP_16x16_3
        INC C           ; Incrémentation de C de manière à crée le quotient
                        ; (Remplacement des bits du dividende par le quotient)
        DJNZ _MATH_DIV_SP_16x16_2 ; Décrémentation de B de manière à
                                ; traiter les 16 bits du dividende

        JP _MATH_DIV_SP_16x16_END

_MATH_DIV_SP_16x16_3
        
        ADD HL, DE      ; Restauration du sous-dividende car celui-ci est 
                        ; inférieur au diviseur
        DJNZ _MATH_DIV_SP_16x16_2 ; Décrémentation de B de manière à
                                ; traiter les 16 bits du dividende
_MATH_DIV_SP_16x16_END

        LD B, A         ; Partie haute du quotient dans B
                        ; La partie basse se trouve déjà dans C
        PUSH BC         ; Préservation du quotient
        PUSH HL         ; Préservation du reste de la division
        EXX             ; Restauration des registres BC, DE, HL
        EX AF, AF'      ; Restauration de AF
        POP BC          ; Récupération du reste dans BC
        POP DE          ; Récupération du quotient dans DE
        RET
par –( ANTIBUG )- le 01/06/2007
dernière maj : le 01/06/2007
contact : vincentbouffigny.cpc@free.fr
web : http://ovi.org.free.fr - http://projets.infos.free.fr

 
A voir aussi sur CPCrulez ...

» Coding Z80/Amstrad CPC:Cours et Initiation à l'assembleur  ( Hebdogiciel et Amstar CPC )
» Coding Z80/Amstrad CPC:Informations Technique Divers ...
» A100%: Assembleurs et rubriques bidouilles
» A100%: De l'arcade à l'action par Poum
» A100%: Articles des RUBI Bidouilles
» A100%: Articles des LOGON SYSTEM
» A100%: Les cours de programmtion de l'ASIC / Acces aux nouvelles fonctions du CPC+

» Documentation - MAXAM 464/664/6128
» Documentation - Les vecteurs system
» Documentation - Z80 opcodes reference
» Technique - L'assembleur facile avec votre PC
» Laisser un commentaire ou en discuter sur le forum ...

A voir aussi sur CPCrulez , les sujets suivants peuvent vous intéresser...

» CodingBOOK Clefs1 33 Circuit AY3 8912 PSG - Registres
» Coding - Crossdev - CCZ80
» Coding - Crossdev - Mycpctoolkit
» Coding - Crossdev - PhrozenC

» Laisser un commentaire ou  en discuter sur le forum ...