CODINGANTIBUG ★ LES OPÉRATIONS, LA PILE ET LES REGISTRES SPÉCIALISÉS PAR ANTIBUG ★

Les opérations, la pile et les registres spécialisés par ANTIBUGCoding 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

★ ANNÉE: 2007
★ AUTEUR: ANTIBUG

Page précédente : Les multiplications et les divisions entières avec le Z80 par ANTIBUG

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Coding » Cours et initiation d'ANTIBUG
» Coding » Structure de la mémoire écran de l'Amstrad CPC par ANTIBUG
» Coding » Les multiplications et les divisions entières avec le Z80 par ANTIBUG
» Coding » Le tracé de lignes sur CPC et Z80
Je participe au site:

» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 448 millisecondes et consultée 2236 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.