CODINGANTIBUG ★ LE TRACÉ DE LIGNES SUR CPC ET Z80 ★

Le tracé de lignes sur CPC et Z80Coding Antibug
Sommaire:

dernière maj : le 13/09/2007

1 - Préface

Dans cet article nous allons étudier le tracé de lignes en fonction du mode graphique utilisé sur le CPC. Si vous ne savez pas comment la mémoire graphique du CPC est organisée et si vous ne savez pas comment afficher un pixel à l'écran, je vous conseille de consulter mon article précédent sur « La mémoire graphique du CPC ». Dans cet article j'ai détaillé l'organisation des octets et comment sont calculées les adresses de bases des lignes.

Pour tous les calculs de multiplication ou de division, je vais faire référence à des routines détaillées dans un article sur les opérations avec le Z80. Je vous conseille de vous reporter à l'article « Les Multiplications et les Divisions avec le Z80 ».

Pour commencer, nous allons voir comment sont tracées les lignes horizontales, les lignes verticales et pour terminer les lignes obliques.

2 - Calcul de l'adresse de base d'une ligne et d'un point

Pour commencer, il faut savoir que les lignes horizontales et les lignes verticales sont les plus rapides à afficher et que le calcul est très limité. En effet, avant de tracer une ligne la première chose à faire est de calculer l'adresse de base de la ligne (en fonction de la coordonnée Y), puis de calculer ensuite l'adresse du premier point en fonction de l'adresse de la ligne ; vous pouvez ensuite afficher l'ensemble des points séquentiellement. Regardons en semble un exemple concret pour un jeu de coordonnées (X1,Y1)(X2,Y2):

2.1 Calcul de l'adresse de base de la ligne

[Adresse de base de la ligne] = [Adresse vidéo] + [Adresse de la série] + [Offset de la ligne] * &800
— [Adresse de la série] = (Y1 \ 8) * &50
— [Offset de la ligne] = (Y1 MOD 8) * &800

[Adresse de base de la ligne] = &C000 + ((Y1 \ 8) * &50 + ((Y1 MOD 8) * &800)

2.2 Calcul de l'adresse du premier point

[Adresse du premier point] = [Adresse de base de la ligne] + [Offset du point] - [Offset du point] = X1 \ [Nombre de pixels par octet]

Info ! Le nombre de pixels par octet dépend bien sûr du mode graphique, 2 pixels pour le mode 0 (16 couleurs), 4 pour le mode 1 (4 couleurs) et 8 pour le mode 2 (2 couleurs). Toutes les fonctions utilisées dans cet exemple se trouvent en annexe.

Ce qui donne en assembleur :


Infos: Vous pouvez remarquer que des constants et une variable ont été utilisées dans le programme. Celles-ci serviront, en fonction du mode que vous allez utiliser, lors de la compilation de vos programmes à adapter le code. Je vous conseille de prendre l'habitude d'utiliser ces constantes car elles serviront dans tous les prochains exemples. Quand à la variable contenant l'adresse vidéo, celle-ci va nous permettre de gérer des données graphiques dans une autre zone mémoire du CPC sans changer les algorithmes.

Bon
… Nous avons l'adresse vidéo, de base, d'un point, il nous reste plus qu'à afficher ce point ! Comme premier exemple, nous allons voir comment afficher un pixel dans les trois modes graphiques que nous propose le CPC.

3 - Affichage d'un pixel

3.1 Généralités et rappels

Si vous avez lu mon article sur « La structure de la mémoire graphique du CPC » vous savez déjà comment afficher un pixel en fonction du mode graphique. En effet, comme vous le savez, dans la mémoire graphique du CPC les données des pixels sont entrelacées. L'utilisation de tables de correspondances est nécessaire pour trouver facilement les couleurs entrelacées des pixels.

Qu'avons-nous besoin pour afficher un pixel ? De l'adresse de base de celui-ci, d'une table de correspondances pour retrouver facilement les données entrelacées des couleurs et d'un masque logique qui va nous permettre de préserver les données du ou des pixels voisins lorsque l'on va modifier notre point.

3.2 Détail des tables de correspondances en fonction du mode graphique :

Voici l'équivalent en assembleur des tables. Vous pouvez y trouver d'autres variables et constantes utilisées dans les futurs programmes.

;------------------------------------------------------------------------------------------
; Déclarations des variables et constantes
;------------------------------------------------------------------------------------------
DEF_GRAPH_VIDEO_ADR DEFW &C000 ; Adresse vidéo variable
DEF_GRAPH_TABLE_PIXEL_2 DEFB 0, 128 ; &00, &80
DEF_GRAPH_TABLE_PIXEL_4 DEFB 0, 8, 128, 136 ; &00, &08, &80, &88
DEF_GRAPH_TABLE_PIXEL_16 DEFB 0, 2, 8, 10, 32, 34, 40, 42,
DEFB 128, 130, 136, 138, 160, 162, 168, 170
CST_GRAPH_VIDEO_MODE EQU 0
CST_GRAPH_PIXELS_PER_BYTE EQU CST_GRAPH_VIDEO_MODE + 1 * CST_GRAPH_VIDEO_MODE + 2

Pour les algorithmes d'affichage des pixels je vous demande de vous reporter au cours sur le mémoire graphique. Dans les exemples suivant nous allons directement étudier les codes correspondants aux affichages dans les différents modes graphiques.

3.3 Affichage d'un pixel en mode 0 (16 couleurs, 2 pixels par octet)

Si l'on regarde la fonction suivante de plus prêt, on peut y distinguer plusieurs étapes. La première consiste à récupérer les masques logiques, l'un associé à la couleur entrelacée, l'autre permet de préserver les donnés du pixel voisin lors de la modification de notre pixel. La seconde étape consiste à appeler la fonction « GRAPH_ADR_OF_PIXEL » pour calculer l'adresse de base du pixel, on va vérifier ensuite si le pixel à afficher est pair ou impair ; dans le cas d'un pixel impair on va décaler d'un bit les masques logiques de manière à se calquer sur le bon pixel. Pour terminer, on récupère le contenu de l'octet de trouvant à l'adresse précédemment calculée et on applique les masques logiques pour afficher le pixel (on applique d'abord le masque permettant de ne garder que les données du pixel voisin puis on applique le second masque qui va modifier la couleur). Voilà, ce n'est pas très compliqué !

Au premier abord, l'utilisation de masques n'est peut être pas très claire mais en prenant le temps d'étudier cette fonction vous aller voir qu'au final ce n'est pas très compliqué ; la méthodologie est la même pour l'affichage d'un pixel en mode 0, 1 et 2.

Sachant que les méthodes suivantes sont similaires, nous n'allons pas les détailler une à une, une fois que vous aurez compris comment fonctionne la première, vous aurez compris les autres.

;*****************************************************
; Affichage d'un pixel en mode 0 (16 couleurs)
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
; En sortie
; néant
; Registres impactés
; aucun
; Remarques
; - Cette fonction n'utilise pas la pile pour les paramètres en entrée
;
GRAPH_PUT_PIXEL_16:

PUSH AF
PUSH DE
PUSH HL

; Calcul de l'adresse de base du point
; BC et D contiennent les valeurs X et Y du point
LD A, D ; Sauvegarde D (Y)


; Récupération de la couleur entrelacée correspondant à la couleur du pixel
LD HL, DEF_GRAPH_TABLE_PIXEL_16
LD D, 0 ; D à 0 pour ne garder que E (la couleur). D contenait Y,
; on en a plus besoin
ADD HL, DE ; Ajout du déclage en fonction du n° de la couleur
LD E, (HL) ; Le masque associé à la couleur entrelacée correspondant
; à la couleur E se trouve en (HL)
LD D, 85 ; Valeur par défaut du masque logique qui va permettre de préserver
; le pixel voisin, en Mode 0 = 85 <=> %01010101


; Appel de la fonction qui calcul l'adresse de base du point
;
; En entrée
; BC <=> X
; A <=> Y
; En sortie
; HL <=> Adresse graphique du point
; Remarques
; Les registres d'entrée sont préservés
CALL GRAPH_ADR_OF_PIXEL

; Vérification si le pixel est pair ou impair
LD A, C ; Test du bit 0 de C. BC contient le position X du pixel
AND 1 ; Dans le cas où le pixel est un pixel impair ( X AND 1 = 1 ),
; on décale de 1 pixel
; le masque logique vers le haut et la couleur entrelacée vers le bas
; Si le pixel a allumé est pair => A = 0
JP z, _GRAPH_PUT_PIXEL_16_1


SRL E ; Décalage vers le bas du masque associé à la couleur entrelacée
; du pixel
SLA D ; Décalage vers le haut du masque logique permettant de préserver
; le pixel voisin

_GRAPH_PUT_PIXEL_16_1:

; Affichage du pixel
LD A, (HL) ; Récupération de l'octet associé au pixel
AND D ; Préservation des données du pixel voisin
OR E ; Ajout des données du nouveau pixel
LD (HL), A ; Affichage à l'écran

_GRAPH_PUT_PIXEL_16_END

POP HL ; Restauration de HL
POP DE ; Restauration de DE
POP AF ; Restauration de AF
RET

3.4 Affichage d'un pixel en mode 1 (4 couleurs, 4 pixels par octet)

;*****************************************************
; Affichage d'un pixel en mode 1 (4 couleurs)
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
; En sortie
; néant
; Registres impactés
; aucun
; Remarques
; - Cette fonction n'utilise pas la pile pour les paramètres en entrée
; - E peut prendre les valeurs de 0 à 3
;
GRAPH_PUT_PIXEL_4:

PUSH AF
PUSH DE
PUSH HL

; Calcul de l'adresse de base du point
; BC et D contiennent les valeurs X et Y du point
LD A, D ; Sauvegarde D (Y)


; Récupération de la couleur entrelacée correspondant à la couleur du pixel
LD HL, DEF_GRAPH_TABLE_PIXEL_4
LD D, 0 ; D à 0 pour ne garder que E (la couleur). D contenait Y,
; on en a plus besoin
ADD HL, DE ; Ajout du décalage en fonction du n° de la couleur
LD E, (HL) ; Le masque associé à la couleur entrelacée correspondant
; à la couleur E se trouve en (HL)

; Appel de la fonction qui calcul l'adresse de base du point
;
; En entrée
; BC <=> X
; A <=> Y
; En sortie
; HL <=> Adresse graphique du point
; Remarques
; Les registres d'entrée sont préservés
CALL GRAPH_ADR_OF_PIXEL

; Vérification si le pixel est pair ou impair
LD A, C ; Test du bit 0 de C. BC contient le position X du pixel
AND 3 ; X AND 3 = n° du pixel courant, A contient donc le nombre de bits à
; décaler.

; Décalages des masques vers le bas en fonction du n° du pixel concerné
;
; Paramètres de la fonction MATH_SRL_8
; En entrée
; E <=> Entier de 8 bits
; A <=> Nombre de bits à décaler
; En sortie
; E <=> Résultat du décalage des n bits
;
; A et E sont déjà chargés avec leur valeur respective

CALL MATH_SRL_8 ; Décalage du masque de la couleur entrelacée, associée à la
; couleur du pixel
; En sortie E contient le masque de la valeur entrelacée associé à la
; couleur du pixel
LD D, E ; Sauvegarde de E

; A est déjà chargé avec le nombre de décalages
LD E, 136 ; Valeur par défaut du masque logique qui va permettre de préserver
; le pixel voisin, en Mode A = 136 <=> %10001000
CALL MATH_SRL_8 ; Décalage du masque négatif qui permet de préserver le pixel voisin

; Inversion du masque logique négatif de manière à préserver les données
; du pixel voisin
LD A, E
CPL
LD E, D ; Restauration de E qui doit contenir le masque entrelacé lié à la
; couleur du pixel
LD D, A ; D va contenir le masque logique permettant la préservation du pixel
; voisin

; Affichage du pixel
LD A, (HL) ; Récupération de l'octet associé au pixel
AND D ; Préservation des données du pixel voisin
OR E ; Ajout des données du nouveau pixel
LD (HL), A ; Affichage à l'écran

_GRAPH_PUT_PIXEL_4_END

POP HL ; Restauration de HL
POP DE ; Restauration de DE
POP AF ; Restauration de AF
RET

3.5 Affichage d'un pixel en mode 2 (2 couleurs, 8 pixels par octet)

;*****************************************************
; Affichage d'un pixel en mode 2 (2 couleurs)
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
; En sortie
; néant
; Registres impactés
; aucun
; Remarques
; - Cette fonction n'utilise pas la pile pour les paramètres en entrée
; - E peut prendre les valeurs de 0 à 1
;
GRAPH_PUT_PIXEL_2:

PUSH AF
PUSH DE
PUSH HL

; Calcul de l'adresse de base du point
; BC et D contiennent les valeurs X et Y du point
LD A, D ; Sauvegarde D (Y)


; Récupération de la couleur entrelacée correspondant à la couleur du pixel
LD HL, DEF_GRAPH_TABLE_PIXEL_2
LD D, 0 ; D à 0 pour ne garder que E (la couleur). D contenait Y,
; on en a plus besoin
ADD HL, DE ; Ajout du décalage en fonction du n° de la couleur
LD E, (HL) ; Le masque associé à la couleur entrelacée correspondant à la
; couleur E se trouve en (HL)
LD D, 128 ; Valeur par défaut du masque logique qui va permettre de préserver
; le pixel voisin, en Mode 2 = 128 <=> %10001000

; Appel de la fonction qui calcul l'adresse de base du point
;
; En entrée
; BC <=> X
; A <=> Y
; En sortie
; HL <=> Adresse graphique du point
; Remarques
; Les registres d'entrée sont préservés
CALL GRAPH_ADR_OF_PIXEL

; Vérification si le pixel est pair ou impair
LD A, C ; Test du bit 0 de C. BC contient le position X du pixel
AND 7 ; Dans le cas où le pixel est un pixel impair ( X AND 1 = 1 ),
; on décale de 1 pixel le masque logique vers le haut et la couleur
; entrelacée vers le bas. Si le pixel a allumé est pair => A = 0

; Décalages des masques vers le bas en fonction du n° du pixel concerné
;
; Paramètres de la fonction MATH_SRL_8
; En entrée
; E <=> Entier de 8 bits
; A <=> Nombre de bits à décaler
; En sortie
; E <=> Résultat du décalage des n bits
;
; A et E sont déjà chargés avec leur valeur respective

CALL MATH_SRL_8 ; Décalage du masque de la couleur entrelacée, associée à la couleur
; du pixel. En sortie E contient le masque de la couleur
LD D, E ; Sauvegarde de E

; A est déjà chargé avec le nombre de décalages
LD E, 128 ; X AND 7 = n° du pixel courant, A contient donc le nombre
; de bits à décaler.
CALL MATH_SRL_8 ; Décalage du masque négatif qui permet de préserver le pixel voisin


; Inversion du masque logique négatif de manière à préserver les données
; du pixel voisin
LD A, E
CPL
LD E, D ; Restauration de E qui doit contenir le masque entrelacé lié
; à la couleur du pixel
LD D, A ; D va contenir le masque logique permettant la préservation
; du pixel voisin

; Affichage du pixel
LD A, (HL) ; Récupération de l'octet associé au pixel
AND D ; Préservation des données du pixel voisin
OR E ; Ajout des données du nouveau pixel
LD (HL), A ; Affichage à l'écran

_GRAPH_PUT_PIXEL_2_END

POP HL ; Restauration de HL
POP DE ; Restauration de DE
POP AF ; Restauration de AF
RET

3.6 Affichage d'un pixel indépendamment du mode graphique

Je vous laisse deviner …

Et oui voici une fonction que vous allez pouvoir appeler directement sans vous souciez du mode graphique courant. Au début de celle-ci on regarde quel mode est utilisé puis on appelle telle ou telle méthode.

;******************************************************
; Affichage d'un pixel indépendamment du mode graphique
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
; En sortie
; néant
; Registres impactés
; aucun
; Remarques
; - Cette fonction n'utilise pas la pile pour les paramètres en entrée
;
GRAPH_PUT_PIXEL:

PUSH AF ; Sauvegarde de AF

; Affichage d'un pixel en fonction du mode graphique courant
LD A, CST_GRAPH_VIDEO_MODE
CP 2
JP z, _GRAPH_PUT_PIXEL_2
CP 1
JP z, _GRAPH_PUT_PIXEL_4

; Affichage des pixels
;
; En entrée les fonctions possèdent les même paramètres
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits

_GRAPH_PUT_PIXEL_16

; Affichage d'un pixel 16 couleurs
CALL GRAPH_PUT_PIXEL_16
POP AF ; Restauration de AF
RET

_GRAPH_PUT_PIXEL_4

; Affichage d'un pixel 4 couleurs
CALL GRAPH_PUT_PIXEL_4
POP AF ; Restauration de AF
RET

_GRAPH_PUT_PIXEL_2

; Affichage d'un pixel 2 couleurs
CALL GRAPH_PUT_PIXEL_2
POP AF ; Restauration de AF
RET

_GRAPH_PUT_PIXEL_END

4 - Le tracé d'une ligne horizontale

4.1 Généralités

L'avantage du tracé des lignes horizontales est que l'on n'a pas besoin de recalculer l'adresse de base des lignes à chaque fois que l'on veut afficher un point. En effet sachant qu'une ligne horizontale est toujours située sur la même ordonnée (y) et que l'adresse d'une ligne est liée à y, un seul calcul sera nécessaire dans les fonctions d'affichage.

Dans un premier temps, nous allons étudier à quels problèmes nous allons être confronté lorsque nous allons afficher nos pixels. Dans un second temps nous allons mettre un algorithme en place puis pour terminer nous allons voir comment faire fonctionner cet algorithme avec des exemples concrets quelque soit le mode graphique utilisé.

4.2 L'algorithme de tracé horizontal

Réfléchissons ! Quelles étapes allons-nous pouvoir rencontrer pour afficher notre ligne ?

1 : Calculer le nombre de points à traiter 2 : Calculer l'adresse du premier point 3 : Calculer les masques logiques de notre premier point en fonction de sa position 4 : Affichage de notre point 5 : Traitement du pixel suivant …

Jusqu'ici c'est très simple ! Souvenez-vous, les données de pixels sont entrelacées ; dans notre cas les pixels sont consécutifs. Globalement ce qui peut prendre du temps c'est le calcul de l'adresse de basse du point et les calculs des masques logiques. L'adresse de base n'est calculée qu'une seule fois car nous allons travailler sur la même ligne, donc ce qui nous reste à régler c'est le calcul des masque logiques pour chacun des pixels que nous allons afficher ! Pour éviter de recalculer les masques à chaque fois, nous allons tout simplement décaler les deux masques qui ont été calculés pour l'affichage du premier pixel.

Regardons maintenant comment les données des pixels sont ordonnées en fonction du mode graphique utilisé et comment nous allons décaler les masques logiques …

En mode 0 (16 couleurs, 2 pixels par octet) :

Affichons une ligne horizontale de la position X1 = 0 à la position X2 = 5 avec la couleur 7.

Masques logiques initiaux associés au premier pixel (0) :

- masque des données entrelacées de la couleur (7) : %00101010
- masque de préservation du pixel voisin : %01010101

Valeurs des masques pendant l'affichage des pixels suivants :

PixelOctetCouleur entrelacéeMasque de préservation
00%00101010%01010101
10%00010101%10101010
21%00101010%01010101
31%00010101%10101010
42%00101010%01010101
52%00010101%10101010

Si vous regardez bien ce tableau vous pouvez constatez que le masque des données de la couleur entrelacée est décalé de 1 bit vers la droite à chaque octet traité, 2 valeurs possibles car 2 pixels à afficher logique ! Même si vous ne trouvez pas cet exemple essentiel nous allons regarder le cas du mode 1 (4 couleurs, 4 pixels par octet).

En mode 1 (4 couleurs, 4 pixels par octet) :

Affichons maintenant une ligne horizontale de la position X1 = 0 à la position X2 = 3 avec la couleur 3.

Masques logiques initiaux associés au premier pixel (0) :

- masque des données entrelacées de la couleur (7) : %00101010
- masque de préservation du pixel voisin : %01010101

Valeurs des masques pendant l'affichage des pixels suivants :

PixelOctetCouleur entrelacéeMasque de préservation
10%01000100%10111011
20%00100010%11011101
30%00010001%11101110
41%10001000%01110111
51%01000100%10111011
61%00100010%11011101
71%00010001%11101110
82%10001000%01110111
92%01000100%10111011
102%00100010%11011101
112%00010001%11101110

Comme dans l'exemple précédent, le masque logique associé à la couleur est décalé vers la droite de 1 bit pour chaque pixel allumé ; au passage, le masque de préservation des données voisines aussi. Tout çà juste pour vous dire que notre algorithme doit prendre en compte la position du premier pixel pour calculer les masques logiques et les décalages suivants.

Imaginons maintenant que notre ligne horizontale commence à la position 1 et pas à la position 0, pour traiter un octet complet, c.à.d. les 2 derniers pixels de l'octet, nous devrions décaler encore de 2 positions les masques logiques. Et bien voilà !

Regardons maintenant notre algorithme :

Affichage d'une ligne de X1 à X2 à la ligne Y avec la couleur c

On a :

  • X1 et X2, les positions initiale et finale
  • Y, le numéro de la ligne à afficher
  • c, la couleur de la ligne à tracer
  • N, le nombre total de pixels restant à traiter
  • n, le nombre de pixels restant à traiter dans l'octet (fonction du mode graphique)
  • HL, l'adresse de premier pixel
  • m1, masque logique de la couleur entrelacée (dépend mode graphique)
  • m2, masque logique de préservation des données voisines (dépend mode graphique)
  • couleurs, table des associations des couleurs entrelacées (dépend du mode graphique)
  • couleur_max, numéro de la couleur max (dépend du mode graphique)

Voilà pour l'algorithme. Cet algorithme n'est pas compliqué mais comme vous le savez les registres du Z80 étant peu nombreux il va falloir le coder notre routine le plus proprement possible.

Pour aborder facilement la routine, il faut savoir que celle-ci est décomposée en plusieurs parties bien distinctes, le calcul du nombre de points à traiter, le calcul de l'adresse du premier pixel (déjà archi vue !), le calcul des masques initiaux (fonction de la position du premier pixel), affichage du point à la position courante, calcul des masques logiques pour le point suivant, affichage du point à la position courante, puis …, puis …, puis on répète !

Regardons ensemble le contenu de la procédure d'affichage d'une ligne en 16 couleurs…

4.3 Affichage d'une ligne horizontale en mode 0 (16 couleurs, 2 pixels par octet)

;********************************************************
; Affichage d'une ligne horizontale en mode 0 (16 couleurs)
;
; En entrée
; BC <=> X1
; HL <=> X2
; D <=> Y
; A <=> Couleur de la ligne
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
;
GRAPH_LINE_H_16:

PUSH AF ; Sauvegarde des registres
PUSH BC ;
PUSH DE ; AF,BC,DE,HL,IX,IY
PUSH HL ;
PUSH IX ;
PUSH IY ;

; Calcul de Dx (nombre de points à traiter)
LD E, A ; La couleur dans E
RLA ; On efface Carry
SBC HL, BC ; HL = X2 - X1
PUSH HL ; Sauvegarde du nombre de points restant à traiter

; Adresse du premier pixel
;
; En entrée
; BC <=> X1
; A <=> Y
; En sortie
; HL <=> Adresse du point
;
LD A, D ; Y (D) dans A
; BC contient déjà X1
CALL GRAPH_ADR_OF_PIXEL

PUSH HL
POP IX
POP HL

; Préparation des masques logiques en fonction du n° de la couleur
LD A, D ; Sauvegarde de Y dans A
LD D, 0 ; On efface D
LD IY, DEF_GRAPH_TABLE_PIXEL_16 ; Référence à la table des masques 16 couleurs
ADD IY, DE
LD E, (IY) ; Masque logique associé à la couleur entrelacée dans B
LD D, 85 ; Masque logique permettant de préserver le pixel voisin dans D
; (voir affichage d'un pixel en mode 0)

; Décalage des masques en fonction du nombre de points déjà traités
LD B, 2
LD A, C
AND 1
OR A
JP z, _GRAPH_LINE_H_16_1

DEC B
SRL E
SLA D

_GRAPH_LINE_H_16_1

; Affichage du pixel courant
LD A, (IX)
AND D ; Préservation des données du pixel voisin
OR E ; Affichage du nouveau pixel
LD (IX), A

LD A, L ; On teste si tous les points on été traités
OR H ;
JP z, _GRAPH_LINE_H_16_END
DEC HL ; On décrémente le nombre de points restant à traiter
DJNZ _GRAPH_LINE_H_16_2

LD B, 2
INC IX ; Point suivant
LD E, (IY) ; Masque logique associé à la couleur entrelacée dans B
LD D, 85 ; Masque logique permettant de préserver le pixel voisin dans D
; (voir affichage d'un pixel en mode 0)
JP _GRAPH_LINE_H_16_1

_GRAPH_LINE_H_16_2

SRL E
SLA D
JP _GRAPH_LINE_H_16_1

_GRAPH_LINE_H_16_END

POP IY ; Restauration des registres
POP IX ;
POP HL ; AF,BC,DE,HL,IX,IY
POP DE ;
POP BC ;
POP AF ;
RET

4.4 Affichage d'une ligne horizontale en mode 1 (4 couleurs, 4 pixels par octet)

;********************************************************
; Affichage d'une ligne horizontale en mode 1 (4 couleurs)
;
; En entrée
; BC <=> X1
; HL <=> X2
; D <=> Y
; A <=> Couleur de la ligne
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
;
;
GRAPH_LINE_H_4:

PUSH AF ; Sauvegarde des registres
PUSH BC ;
PUSH DE ; AF,BC,DE,HL,IX, IY
PUSH HL ;
PUSH IX ;
PUSH IY ;


; Calcul de Dx (nombre de points à traiter)
LD E, A ; La couleur dans E
RLA ; On efface Carry
SBC HL, BC ; HL = X2 - X1
PUSH HL ; Sauvegarde du nombre de points restant à traiter


; Adresse du premier pixel
;
; En entrée
; BC <=> X1
; A <=> Y
; En sortie
; HL <=> Adresse du point
;
; BC est déjà chargé avec sa valeur
;
LD A, D ; Y dans D
;
CALL GRAPH_ADR_OF_PIXEL
PUSH HL ; On stocke HL dans IX pour accéder à la mémoire écran
POP IX ;
POP HL ; Restauration du nombre de points à traiter dans HL


; Préparation des masques logiques en fonction du n° de la couleur
LD D, 0 ; On efface D
LD IY, DEF_GRAPH_TABLE_PIXEL_4 ; Référence à la table des masques 16 couleurs
ADD IY, DE


; Vérification à partir de quel pixel doit commencer le tracé
LD A, C ; C contient la partie base de X1
AND 3 ; On ne préserve que les 3 premiers bits qui correspondent
; au n° du point
LD C, A ; Calcul du nombre de pixel restant à traiter, inclu le premier pixel
LD A, 4 ;
SUB C ; [Nombre de pixele à traiter] = 4 - [n° du pixel]
LD B, A ;
LD A, C ; Nombre de déclages a effectuer pour calculer les masques logiques
; associés au premier pixel


; Décalages des masques vers le bas en fonction du n° du pixel concerné
;
; Paramètres de la fonction MATH_SRL_8
; En entrée
; E <=> Entier de 8 bits
; A <=> Nombre de bits à décaler
; En sortie
; E <=> Résultat du décalage des n bits
;
; A et E sont chargés avec leur valeur respective
LD E, (IY) ; Masque logique associé à la couleur entrelacée dans B

CALL MATH_SRL_8 ; Décalage du masque de la couleur entrelacée, associée à la couleur
; du pixel
; En sortie E contient le masque de la valeur entrelacée associé à la
; couleur du pixel
LD C, E ; Sauvegarde du masque entrelacé E

; A est déjà chargé avec le nombre de décalages
LD E, 136 ; Valeur par défaut du masque logique qui va permettre de préserver
; le pixel voisin, en Mode 1 = 136 <=> %10001000
CALL MATH_SRL_8 ; Décalage du masque négatif qui permet de préserver le pixel voisin

; Inversion du masque logique négatif de manière à préserver les données du pixel
; voisin
LD D, E ; Sauvegarde du masque décalé qui permet de préserver les pixels voisin
LD A, E ; Inversion du masque pour la préservations des pixels voisins
CPL ;
LD E, C ; Restauration de E qui doit contenir le masque entrelacé lié à la
; couleur du pixel
LD C, A ; C va contenir le masque logique inversé qui permet la préservation
; les pixels voisins

_GRAPH_LINE_H_4_1

; Affichage du pixel courant
LD A, (IX)
AND C ; Préservation des données du pixel voisin
OR E ; Affichage du nouveau pixel
LD (IX), A

LD A, L ; On teste si tous les points on été traités
OR H ;
JP z, _GRAPH_LINE_H_4_END
DEC HL ; On décrémente le nombre de points restant à traiter
DJNZ _GRAPH_LINE_H_4_2

LD B, 4
INC IX ; Point suivant
LD E, (IY) ; Masque logique associé à la couleur entrelacée dans B
LD D, 136 ; Valeur par défaut du masque logique qui va permettre de préserver
; le pixel voisin, en Mode 1 = 136 <=> %10001000
LD C, 119 ; Le masque logique inversé

JP _GRAPH_LINE_H_4_1

_GRAPH_LINE_H_4_2

SRL E
SRL D

LD A, D
CPL
LD C, A
JP _GRAPH_LINE_H_4_1

_GRAPH_LINE_H_4_END

POP IY ; Restauration des registres
POP IX ;
POP HL ; AF,BC,DE,HL,IX,IY
POP DE ;
POP BC ;
POP AF ;
RET

Regardons maintenant en détail toutes les parties de cette routine :

1 : Calcul du nombre de points à traiter :

; Calcul de Dx (nombre de points à traiter)
LD E, A ; La couleur dans E
RLA ; On efface Carry
SBC HL, BC ; HL = X2 - X1
PUSH HL ; Sauvegarde du nombre de points restant à traiter

En entrée, le registre A contient la couleur, vous pourriez me dire pourquoi ne pas directement la couleur dans le registre E sachant que de toute façon c'est E qui contient le couleur ? Et bien tout simplement pour garder une homogénéité entre les appels de méthodes ; toutes les méthodes de tracé horizontal comportent les même paramètres en entrée car elles sont utilisées pour l'affichage de cadres … enfin bref !

RLA permet d'effacer Carry pour la soustraction suivante.
HL – BC = le nombre de points à traiter.

2 : Calcul de l'adresse du premier pixel :

; Adresse du premier pixel
;
; En entrée
; BC <=> X1
; A <=> Y
; En sortie
; HL <=> Adresse du point
;
LD A, D ; Y (D) dans A
; BC contient déjà X1
CALL GRAPH_ADR_OF_PIXEL
PUSH HL
POP IX
POP HL

Comme vous pouvez le voir l'utilisation de la procédure GRAPH_ADR_OF_PIXEL est requise, les paramètres de cette procédure sont indiqués en entrée, jusqu'ici rien de compliqué ! La procédure va nous renvoyer l'adresse du point dans HL, on va l'échanger avec IX via un PUSH/POP car HL va nous servir plus loin pour calculer le nombre de point restant.

3 : Calcul des masques logiques initiaux :

; Préparation des masques logiques en fonction du n° de la couleur
LD A, D ; Sauvegarde de Y dans A
LD D, 0 ; On efface D
LD IY, DEF_GRAPH_TABLE_PIXEL_16 ; Référence à la table des masques 16
; couleurs
ADD IY, DE
LD E, (IY) ; Masque logique associé à la couleur entrelacée dans B
LD D, 85 ; Masque logique permettant de préserver le pixel voisin
; dans D
; (voir affichage d'un pixel en mode 0)

Maintenant nous allons calculer les masques logiques pour l'affichage de notre premier point. D contient y, nous le sauvons via A pour la suite sachant que nous allons avoir besoin de DE pour obtenir l'adresse de la table des données entrelacées des couleurs. L'adresse de la table est stockée dans IY, on ajouter ensuite le décalage en fonction de la couleur contenue dans E sachant que les données de la table sont triées de la couleur 0 à la couleur 15. IY va donc pointer vers les données entrelacées de la couleur de notre ligne ; IY va nous servir pendant le calcul des autres points. Pour finir on transfert la couleur entrelacée à l'adresse (IY) dans E et l'on place dans D le masque logique qui permet de préserver les données du pixel voisin.

4 : Calcul des masques logiques du premier point :

; Décalage des masques en fonction du nombre de points déjà traités
LD B, 2
LD A, C
AND 1
OR A
JP z, _GRAPH_LINE_H_16_1

DEC B
SRL E
SLA D

_GRAPH_LINE_H_16_1

Rappelez-vous qu'en mode 0, 16 couleurs on a 2 pixels par octet. Ici B va contenir le nombre de pixels par octet (2 en 16 couleurs, 4 en 4 couleurs et 8 en 2 couleurs). On décrémente B de 1 en fonction du n° du premier pixel qui est affiché ; les valeurs par défaut des masques sont toujours celles du premier pixel de l'octet, il faut donc décaler ces masque en fonction du n° du pixel courant dans l'octet. Si le premier pixel est le premier d'une série, (A AND 1) = 0, B n'est pas décrémenté et les masques ne sont pas décalés, on saute donc à _GRAPH_LINE_H_16_1.

5 : Affichage du pixel courant :

; Affichage du pixel courant
LD A, (IX)
AND D ; Préservation des données du pixel voisin
OR E ; Affichage du nouveau pixel
LD (IX), A

L'affichage d'un pixel n'est pas compliqué, IX contient l'adresse du pixel à afficher, on charge donc A avec la valeur de l'octet à l'adresse (IX), on applique ensuite le masque de préservation des données du pixel voisin, (A AND D) ; on applique la valeur entrelacée de la couleur de notre nouveau point, (A OR E). Pour terminer, on remplace ensuite la valeur de notre nouvel pour afficher notre point.

6 : Calcul du nombre de points restant :

LD A, L ; On teste si tous les points on été traités
OR H ;
JP z, _GRAPH_LINE_H_16_END
DEC HL ; On décrémente le nombre de points restant à traiter
DJNZ _GRAPH_LINE_H_16_2

Rappelez-vous que HL contient le nombre total de points restant à traiter. HL est décrémenté à chaque fois qu'un point est affiché, on va donc vérifier que tous les points ont été traités, si tel est le cas on sort de la boucle principale via un saut à _GRAPH_LINE_H_16_END, si il nous reste des points à traiter, on va décrémenter B via DJNZ, B contient le nombre de points restant à traiter par octet. Si B = 0 c'est que tous les points de l'octet courant ont été traités.

7 : Vérification que tous les points de l'octet courant ont été traités :

LD B, 2
INC IX ; Point suivant
LD E, (IY) ; Masque logique associé à la couleur entrelacée dans B
LD D, 85 ; Masque logique permettant de préserver le pixel
; voisin dans D
; (voir affichage d'un pixel en mode 0)
JP _GRAPH_LINE_H_16_1

_GRAPH_LINE_H_16_2

SRL E
SLA D
JP _GRAPH_LINE_H_16_1

_GRAPH_LINE_H_16_END

Dernière partie ! Ouf !

Si tous les points on été traités, on réinitialise B avec le nombre de points par octet LD B, 2. IX est incrémenté de 1 car on passe à l'octet suivant, on réinitialise les masques avec les valeurs par défaut du premier pixel du nouvel octet puis on saute à _GRAPH_LINE_H_16_1 pour aller afficher le nouveau pixel.

Dans le cas où il restait des points à traiter dans l'octet courant, en _GRAPH_LINE_H_16_2, on décale les masques logiques d' 1 bit vers la droite pour traiter le pixel suivant, puis l'on saute en _GRAPH_LINE_H_16_1 pour affiche ce pixel.

Voilà ! J'espère que c'est un peu plus clair pour vous.
Les exemples suivant sont basés sur la même structure de codage, la seule différence est que l'on va utiliser la procédure MATH_SRL_8, dans le calcul des masques du premier pixel, pour pouvoir décaler les masques de plusieurs bits à la fois.


Cette première partie est terminée. Le mois prochain nous traiterons le tracé vertical et oblique, @ Bientôt …

4.5 Affichage d'une ligne horizontale en mode 2 (2 couleurs, 8 pixels par octet)

;********************************************************
; Affichage d'une ligne horizontale en mode 2 (2 couleurs)
;
; En entrée
; BC <=> X1
; HL <=> X2
; D <=> Y
; A <=> Couleur de la ligne
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
;

GRAPH_LINE_H_2:

PUSH AF ; Sauvegarde des registres
PUSH BC ;
PUSH DE ; AF,BC,DE,HL,IX, IY
PUSH HL ;
PUSH IX ;
PUSH IY ;


; Calcul de Dx (nombre de points à traiter)
LD E, A ; La couleur dans E
RLA ; On efface Carry
SBC HL, BC ; HL = X2 - X1
PUSH HL ; Sauvegarde du nombre de points restant à traiter


; Adresse du premier pixel
;
; En entrée
; BC <=> X1
; A <=> Y
; En sortie
; HL <=> Adresse du point
;
; BC est déjà chargé avec sa valeur
;
LD A, D ; Y dans D
;
CALL GRAPH_ADR_OF_PIXEL
PUSH HL ; On stocke HL dans IX pour accéder à la mémoire écran
POP IX ;
POP HL ; Restauration du nombre de points à traiter dans HL


; Préparation des masques logiques en fonction du n° de la couleur
LD D, 0 ; On efface D
LD IY, DEF_GRAPH_TABLE_PIXEL_2 ; Référence à la table des masques 16 couleurs
ADD IY, DE


; Vérification à partir de quel pixel doit commencer le tracé
LD A, C ; C contient la partie base de X1
AND 7 ; On ne préserve que les 7 premiers bits qui correspondent
; au n° du point
LD C, A ; Calcul du nombre de pixel restant à traiter, inclu le premier pixel
LD A, 8 ;
SUB C ; [Nombre de pixele à traiter] = 8 - [n° du pixel]
LD B, A ;
LD A, C ; Nombre de déclages a effectuer pour calculer les masques logiques
; associés au premier pixel


; Décalages des masques vers le bas en fonction du n° du pixel concerné
;
; Paramètres de la fonction MATH_SRL_8
; En entrée
; E <=> Entier de 8 bits
; A <=> Nombre de bits à décaler
; En sortie
; E <=> Résultat du décalage des n bits
;
; A et E sont chargés avec leur valeur respective
LD E, (IY) ; Masque logique associé à la couleur entrelacée dans B

CALL MATH_SRL_8 ; Décalage du masque de la couleur entrelacée, associée à la couleur
; du pixel
; En sortie E contient le masque de la valeur entrelacée associé à la
; couleur du pixel
LD C, E ; Sauvegarde du masque entrelacé E

; A est déjà chargé avec le nombre de décalages
LD E, 128 ; Valeur par défaut du masque logique qui va permettre de préserver
; le pixel voisin, en Mode 2 = 128 <=> %10000000
CALL MATH_SRL_8 ; Décalage du masque négatif qui permet de préserver le pixel voisin

; Inversion du masque logique négatif de manière à préserver les données du pixel
; voisin
LD D, E ; Sauvegarde du masque décalé qui permet de préserver les pixels voisin
LD A, E ; Inversion du masque pour la préservations des pixels voisins
CPL ;
LD E, C ; Restauration de E qui doit contenir le masque entrelacé lié à la
; couleur du pixel
LD C, A ; C va contenir le masque logique inversé qui permet la préservation
; les pixels voisins

_GRAPH_LINE_H_2_1

; Affichage du pixel courant
LD A, (IX)
AND C ; Préservation des données du pixel voisin
OR E ; Affichage du nouveau pixel
LD (IX), A

LD A, L ; On teste si tous les points on été traités
OR H ;
JP z, _GRAPH_LINE_H_2_END
DEC HL ; On décrémente le nombre de points restant à traiter
DJNZ _GRAPH_LINE_H_2_2

LD B, 8
INC IX ; Point suivant
LD E, (IY) ; Masque logique associé à la couleur entrelacée dans B
LD D, 128 ; Valeur par défaut du masque logique qui va permettre de préserver
; le pixel voisin, en Mode 1 = 128 <=> %10000000
LD C, 127 ; Le masque logique inversé

JP _GRAPH_LINE_H_2_1

_GRAPH_LINE_H_2_2

SRL E
SRL D

LD A, D
CPL
LD C, A
JP _GRAPH_LINE_H_2_1

_GRAPH_LINE_H_2_END

POP IY ; Restauration des registres
POP IX ;
POP HL ; AF,BC,DE,HL,IX,IY
POP DE ;
POP BC ;
POP AF ;
RET

4.6 Affichage d'une ligne horizontale indépendamment de mode graphique

;*******************************************************************
; Affichage d'une ligne horizontale quelque soit le mode graphique
;
; En entrée
; BC <=> X1
; HL <=> X2
; D <=> Y
; A <=> Couleur de la ligne
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
; - Les modes graphiques supportés sont les modes 0, 1 et 2
;

GRAPH_LINE_H:

PUSH AF ; Sauvegarde de AF pour le retour

; Vérification du mode graphique en cours
LD A, CST_GRAPH_VIDEO_MODE
CP 2
JP z, _GRAPH_LINE_H_2
CP 1
JP z, _GRAPH_LINE_H_4
OR A
JP z, _GRAPH_LINE_H_16

; Retour si le mode graphique est <> 0,1 ou 2
POP AF
RET


; Affichage des pixels
;
; En entrée les fonctions possèdent les même paramètres
; BC <=> X1
; HL <=> X2
; D <=> Y
; A <=> Couleur de la ligne

_GRAPH_LINE_H_16

; Affichage de la ligne horizontale 16 couleurs
POP AF
CALL GRAPH_LINE_H_16
RET

_GRAPH_LINE_H_4

; Affichage de la ligne horizontale 4 couleurs
POP AF
CALL GRAPH_LINE_H_4
RET

_GRAPH_LINE_H_2

; Affichage de la ligne horizontale 2 couleurs
POP AF
CALL GRAPH_LINE_H_2
RET

GRAPH_LINE_H_END

5 - Le tracé d'une ligne verticale

5.1 Généralités

L'avantage du tracé des lignes verticales, comme les lignes horizontales, est que l'on n'a pas besoin de recalculer l'adresse de base des lignes à chaque fois que l'on veut afficher un point. En effet sachant qu'une ligne verticale est toujours située sur la même abscisse x et que l'adresse de base d'une ligne est fonction de (x,y), un seul calcul sera nécessaire.

Dans un premier temps, nous allons étudier à quels problèmes nous allons être confronté lorsque nous allons afficher nos pixels. Dans un second temps nous allons mettre un algorithme en place puis pour terminer nous allons coder cet algorithme.

5.2 L'algorithme de tracé verticale

Regardons toutes les étapes pour créer notre algorithme

1 : Calculer l'adresse du premier point
2 : Calculer le nombre de points à traiter
3 : Calculer les masques logiques de notre premier point en fonction de sa position
4 : Affichage de notre point
5 : Calcul de la position du point suivant en fonction de la série de lignes, courante
6 : Traitement du pixel suivant …


Pas compliqué, c'est presque comme le tracé d'une ligne horizontale !
Souvenez-vous, les données des pixels sont entrelacées ; dans notre cas les masques utilisés pour afficher nos pixels sont toujours identiques car les pixels à afficher se trouvent toujours sur la même abscisse. Comme l'affichage d'une ligne horizontale, le calcul le plus compliqué est le calcul de l'adresse de basse du point. L'adresse de base n'est calculée qu'une seule fois au départ, donc ce qui nous reste à régler c'est le calcul des masque logiques. Souvenez-vous, si vous avez lu mon article sur l'organisation de la mémoire graphique, vous savez que les lignes sont regroupées par séries de 8 lignes. En mémoire, chaque ligne d'une série est distante de l'autre d'un offset de &800, pour passer d'une série à une autre, on incrémente l'adresse de base de &50.

Regardons maintenant comment les lignes et les données des pixels sont ordonnées en fonction du mode graphique utilisé et comment sont représentés les masques logiques …

Si vous regardez bien, pour passer de la ligne 0 à la ligne 8 on ajoute &50 à l'adresse de base de la ligne, cela permet de passer d'une série de lignes à une autre. Vous pouvez remarquez que la distance entre deux lignes fait bien &800.

Tout cela pour vous dire que notre algorithme devra prendre en compte le passage d'une ligne à l'autre et d'une série à une autre. Notre algorithme devra d'abord calculer le nombre total de points à traiter, le nombre de lignes restant à traiter dans la série courante puis calculer tous les décalages d'offset entre chaque ligne en fonction du numéro de la ligne courante et le passage d'une série de lignes à une autre.

Regardons maintenant quelles valeurs les masques logiques pourront prendre en fonction du mode graphique et de la position du pixel à afficher.

Prenons comme premier exemple l'affichage d'un pixel bleu en mode 0, 16 couleurs (couleur n°1 par défaut), à la position X = 1, Y1 = 0 et Y2 = 4 ; voici comment devrait être affichés les pixels dans la mémoire :

Comme vous pouvez le voir, notre pixel bleu est stocké dans l'octet 0 de la mémoire graphique. La table ci-dessous reprend les valeurs des masques logiques des couleurs pour les pixels pairs, dont les données sont entrelacées. Dans notre cas la valeur du masque logique pour coder la couleur bleue devra être décalée d'un bit vers la droite, sa valeur sera %00000001. Comme vous vous en douter, ce masque sera identique pour tous les pixels à afficher sachant que X ne va pas varier. (Les masques de la table sont les masques par défaut du pixel 0).

Table des masques logiques pour le mode 0 (16 couleurs)

Comme second exemple nous allons traiter l'affichage d'un pixel bleu-ciel en mode 1, 4 couleurs (couleur n°2 par défaut), à la position X = 2, Y1 = 0 et Y2 = 4 ; voici comment devrait être affichés les pixels dans la mémoire :

Notre pixel bleu est toujours stocké dans l'octet 0 de la mémoire graphique. La table ci-dessous reprend les valeurs des masques logiques des quatre couleurs utilisables en mode 1. Le masque de la couleur 0 pour le pixel 0, le masque de la couleur 1 pour le pixel 0, le masque de la couleur 2 pour le pixel 0, etc. (Les masques de la table sont les masques par défaut du pixel 0)

Pour notre cas la valeur du masque logique pour coder la couleur bleue-ciel devra être décalée de deux bits vers la droite car le pixel concerné est le pixel 2, sa valeur sera %00100000. Ce masque sera lui aussi identique pour tous les pixels à afficher sachant que X ne va pas varier.

Table des masques logiques pour le mode 1 (4 couleurs)

Dans notre dernier exemple nous allons traiter l'affichage d'un pixel jaune en mode 2, 2 couleurs (couleur n°1 par défaut), à la position X = 6, Y1 = 0 et Y2 = 4 ; voici comment devrait être affichés les pixels dans la mémoire :

Table des masques logiques pour le mode 2 (2 couleurs)

Dans notre dernier exemple notre pixel est toujours stocké dans l'octet 0 de la mémoire graphique. La table propose les valeurs des masques logiques des deux couleurs utilisées en mode 2. Le masque de la couleur 1 pour le pixel 6 est égal au masque de la couleur 1 mais décalé de 6 bits vers la droite, ce qui donne %00000010.

Maintenant que vous avez compris comment trouver les masques logiques utilisés pour coder les couleurs en fonction des numéros des pixels, nous allons voir comment trouver les masques qui permettent de préserver les données des pixels voisins ; nous en avons déjà parlé plusieurs fois mais nous allons regardez un exemple concret pour chaque mode vidéo. (Voir l'affichage d'un pixel dans les différents modes graphiques).

En mode 0, 16 couleurs :
En mode 4, 4 couleurs :
En mode 2, 2 couleurs :

Je suis certain que vous avez tout pigé !

Regardons l'algorithme complet :

Affichage d'une ligne verticale de Y1 à Y2 à la position X avec la couleur c

On a :

  • Y1 et Y2, les positions initiale et finale
  • X, le numéro de la colonne à afficher
  • c, la couleur de la ligne à tracer
  • N, le nombre total de pixels restant à traiter
  • n, le nombre de lignes restant à traiter dans la série de lignes
  • HL, l'adresse de premier pixel
  • m1, masque logique de la couleur entrelacée (dépend mode graphique)
  • m2, masque logique de préservation des données voisines (dépend mode graphique)
  • couleurs, table des associations des couleurs entrelacées (dépend du mode graphique)
  • couleur_max, numéro de la couleur max (dépend du mode graphique)

Regardons maintenant en détail l'affichage d'une ligne verticale en mode 1, 4 couleurs :

1 : Calculer l'adresse du premier point

; Adresse du premier pixel

; Adresse du premier pixel
;
; En entrée
; BC <=> X
; A <=> Y1
; En sortie
; HL <=> Adresse du point
;
PUSH DE ; On préserve Y1 et Y2
LD E, A
LD A, D ; Y1 dans A
CALL GRAPH_ADR_OF_PIXEL
LD A, C ; La partie basse de X dans A
POP BC ; Restauration de Y1 et Y2 dans BC

Nous n'avons plus besoin de détailler ce calcul !

2 : Calculer les masques logiques de notre premier point en fonction de sa position

; Préparation des masques logiques en fonction du n° de la couleur
LD D, 0
LD IX, DEF_GRAPH_TABLE_PIXEL_4 ; Référence à la table des masques
; 4 couleurs
ADD IX, DE
LD E, (IX) ; Masque logique associé à la couleur entrelacée dans B

Ici IX contient l'adresse de base de la table contenant les valeurs entrelacées des données des couleurs. DE contient le numéro de la couleur à afficher, on ajoute donc DE à IX de manière à tomber sur le masque de la couleur courante. Rappelons que cette table de valeurs contient les masques des couleurs pour le premier pixel d'une série, il faut donc décaler ces valeurs de n bits vers le bas (vers la droite) en fonction de la position du pixel que vous voulez afficher ; exemple pour un pixel à la position 1, on décalerait les masques des couleurs de un bit vers le bas, pour un pixel à la position 2 deux bits, etc…

; X se trouve actuellement dans A, on ne préserve que les ; 2 premiers bits de manière à savoir de combien de bits ; doivent être déclalés pour obtenir les masques logiques AND 3


La valeur de X se trouve dans A, le fait de ne préserver que les trois derniers bits permet d'obtenir le numéro du pixel à afficher et donc de savoir de combien de bits il va falloir décaler le masque logique associé à la couleur. Pour le décalage de bits nous utilisons la fonction MATH_SRL_8 qui permet d'effectuer des décalages sur des nombre codés sur 8 bits.

; Décalages des masques vers le bas en fonction du n° du pixel concerné
;
; Paramètres de la fonction MATH_SRL_8
; En entrée
; E <=> Entier de 8 bits
; A <=> Nombre de bits à décaler
; En sortie
; E <=> Résultat du décalage des n bits
;
; A et E sont déjà chargés avec leur valeur respective
CALL MATH_SRL_8 ; Décalage du masque de la couleur entrelacée, associée
; à la couleur du pixel
; En sortie E contient le masque de la valeur entrelacée
; associé à la couleur du pixel
LD D, E ; Sauvegarde de E
; A est déjà chargé avec le nombre de décalages
LD E, 136 ; Valeur par défaut du masque logique qui va permettre
; de préserver le pixel voisin
; en Mode 1 = 136 <=> %10001000
CALL MATH_SRL_8 ; Décalage du masque négatif qui permet de préserver
; le pixel voisin


Après avoir décalé nos masques, il nous reste qu'à inverser les bits du masque qui permet la préservation des données du pixel voisin. Rappelons que le masque permettant la préservation des données des pixels voisins correspond aux bits à 1 de ces mêmes pixels.

; Inversion du masque logique négatif de manière à préserver ; les données du pixel voisin LD A, E CPL LD E, D ; Restauration de E qui doit contenir le masque entrelacé ; lié à la couleur du pixel LD D, A ; D va contenir le masque logique permettant la ; préservation du pixel voisin

3 : Calculer le nombre de points à traiter

; Calcul du nombre de points à traiter
;
; En entrée
; B <=> Y1
; C <=> Y2
;
LD A, C
SUB B
LD C, A ; Le nombre de points à traiter dans C
; Calcul du nombre de lignes restant à traiter dans la série courante
; (Une série = 8 lignes)
LD A, B ; B = Y1
AND 7 ; On ne garde que les 3 derniers bits
LD B, A ;
LD A, 8 ; Le nombre de lignes restantes à traiter dans la série
; courante
SUB B ; = 8 - le nombre de lignes déjà traitées
LD B, A ; Le nombre de lignes restant à traiter dans B

Il n'y a pas grand-chose à dire sur cette partie de code. Pour calculer le nombre de points à traiter il suffit d'effectuer l'opération Y2 – Y1, sachant que l'on affiche systématiquement le premier pixel.

4 : Affichage de notre point

LD A, (HL)
AND D ; Préservation des données du pixel voisin
OR E ; Affichage du nouveau pixel
LD (HL), A

Sachant que HL contient l'adresse vidéo de votre écran (sauf si vous avez redéfini l'adresse graphique), nous récupérons l'octet à l'adresse (HL) et nous appliquons nos masques logiques ; D contient le masque de préservation, E le masque associé aux données entrelacées de la couleur courante.

5 : Calcul de la position du point suivant en fonction de la série de lignes, courante

; Test pour voir si tous les points ont été traités
LD A, C
OR A
JP z, _GRAPH_LINE_V_4_END

C contient dy, un OU logique nous permet de savoir si C = 0.

; Vérification si l'on a atteint une fin de série de lignes
; (série toutes les 8 lignes)
DJNZ _GRAPH_LINE_V_4_3


B contient le nombre de ligne restant à traiter dans la série de lignes, courante.

LD SP, &3FB0 ; &3FB0 = &4000 - &50 = Espace d'adressage d'une série
; complète de lignes - Offset pour la série de lignes
; suivantes
SBC HL, SP ; => HL = HL - &4000 + &50
;
LD B, 8 ; On va traiter une nouvelle série de 8 lignes

Lorsque toutes les lignes de la série de lignes courante ont été traitées, nous repositionnons l'adresse graphique contenue dans HL en fonction de la série de lignes, suivante.

_GRAPH_LINE_V_4_3

LD SP, &800 ; Passage à la ligne suivante (HL = HL + &800)
ADD HL, SP ;
DEC C ; Décrémentation de C qui contient le nombre de points à
; traiter
JP _GRAPH_LINE_V_4_2

_GRAPH_LINE_V_4_END

Pour terminer, lorsque nous voulons passe à la ligne suivante, nous ajoutons à l'adresse graphique de base, l'offset &800. DEC C permet de décrémenter le nombre de points à traiter.

Rappels:

; Valeur par défaut pour l'incrémentation de l'adresse mémoire contenue dans HL
; &800 <=> Permet de passer à la ligne suivante
; &50 <=> Permet de passer à la série de lignes suivante
; &4000 <=> Permet d'ajuster HL en fonction d'une série complète de lignes
; = [nombre de lignes dans une série] * &800
; &3FB0 <=> = Espace d'adressage d'une série complète de lignes – Offset
; pour la série de lignes suivantes
; = &4000 - &50
; => HL = HL - &4000 + &50

5.3 Affichage d'une ligne verticale en mode 0 (16 couleurs, 2 pixels par octet)

;********************************************************
; Affichage d'une ligne verticale en mode 0 (16 couleurs)
;
; En entrée
; D <=> Y1
; E <=> Y2
; BC <=> X
; A <=> Couleur de la ligne
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
;
; GRAPH_LINE_V_16:
PUSH AF ; Sauvegarde des registres
PUSH BC ;
PUSH DE ; AF,BC,DE,HL,IX
PUSH HL ;
PUSH IX ;
; Adresse du premier pixel
;
; En entrée
; BC <=> X
; A <=> Y1
; En sortie
; HL <=> Adresse du point
; PUSH DE
; On préserve Y1 et Y2
LD E, A
LD A, D ; Y1 dans A
CALL GRAPH_ADR_OF_PIXEL
LD A, C ; La partie basse de X dans A
POP BC ; Restauration de Y1 et Y2 dans BC
; Préparation des masques logiques en fonction du n° de la couleur
LD D, 0
LD IX, DEF_GRAPH_TABLE_PIXEL_16 ; Référence à la table des masques 16 couleurs
ADD IX, DE
LD E, (IX) ; Masque logique associé à la couleur entrelacée dans B
LD D, 85 ; Masque logique permettant de préserver le pixel voisin
; dans D (voir affichage d'un pixel en mode 0)
; Vérification si le premier pixel est pair ou impair
; Dans le cas où le pixel est impair, on décale le masque associé
; à la couleur entrelacée, d'un bit vers le bas
; et l'on décale le masque logique permettant de préserver le pixel voisin
; d'un bit vers le haut
AND 1
OR A
JP z, _GRAPH_LINE_V_16_1
SRL E
SLA D
_GRAPH_LINE_V_16_1: ; Calcul du nombre de points à traiter
;
; En entrée
; B <=> Y1
; C <=> Y2
; LD A, C
SUB B
LD C, A ; Le nombre de points à traiter dans C
; Calcul du nombre de lignes restant à traiter dans la série courante
; (Une série = 8 lignes)
LD A, B ; B = Y1 AND 7
; On ne garde que les 3 derniers bits
LD B, A ;
LD A, 8 ; Le nombre de lignes restantes à traiter dans la série courante
SUB B ; = 8 - le nombre de lignes déjà traitées
LD B, A ; Le nombre de lignes restant à traiter dans B
; Valeur par défaut pour l'incrémentation de l'adresse mémoire contenue dans HL
; &800 <=> Permet de passer à la ligne suivante
; &50 <=> Permet de passer à la série de lignes suivante
; &4000 <=> Permet d'ajuster HL en fonction d'une série complète de lignes
; = [nombre de lignes dans une série] * &800 ; &3FB0 <=> = Espace d'adressage d'une série complète de lignes – Offset
; pour la série de lignes suivantes ; = &4000 - &50
; => HL = HL - &4000 + &50
;
LD IX, 0 ; Sauvegarde de l'adresse de la pile
ADD IX, SP ;
_GRAPH_LINE_V_16_2 ; Affichage du pixel
LD A, (HL)
AND D ; Préservation des données du pixel voisin
OR E ; Affichage du nouveau pixel
LD (HL), A ; Test pour voir si tous les points ont été traités
LD A, C
OR A
JP z, _GRAPH_LINE_V_16_END ; Vérification si l'on a atteint une fin de série de lignes
; (série toutes les 8 lignes)
DJNZ _GRAPH_LINE_V_16_3
LD SP, &3FB0 ; &3FB0 = &4000 - &50 = Espace d'adressage d'une série complète
; de lignes - Offset pour la série de lignes suivantes
SBC HL, SP ; => HL = HL - &4000 + &50
;
LD B, 8 ; On va traiter une nouvelle série de 8 lignes
_GRAPH_LINE_V_16_3
LD SP, &800 ; Passage à la ligne suivante (HL = HL + &800)
ADD HL, SP ;
DEC C ; Décrémentation de C qui contient le nombre de points à traiter
JP _GRAPH_LINE_V_16_2
_GRAPH_LINE_V_16_END LD SP, IX ; Restauration de l'adresse de la pile
POP IX ; Restauration des registres
POP HL ;
POP DE ; AF,BC,DE,HL,IX
POP BC ;
POP AF ;
RET

5.4 Affichage d'une ligne verticale en mode 1 (4 couleurs, 4 pixels par octet)

;********************************************************
; Affichage d'une ligne verticale en mode 1 (4 couleurs)
;
; En entrée
; D <=> Y1
; E <=> Y2
; BC <=> X
; A <=> Couleur de la ligne
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
;
;

GRAPH_LINE_V_4:

PUSH AF ; Sauvegarde des registres
PUSH BC ;
PUSH DE ; AF,BC,DE,HL,IX
PUSH HL ;
PUSH IX ;


; Adresse du premier pixel
;
; En entrée
; BC <=> X
; A <=> Y1
; En sortie
; HL <=> Adresse du point
;
PUSH DE ; On préserve Y1 et Y2
LD E, A
LD A, D ; Y1 dans A

CALL GRAPH_ADR_OF_PIXEL
LD A, C ; La partie basse de X dans A
POP BC ; Restauration de Y1 et Y2 dans BC

; Préparation des masques logiques en fonction du n° de la couleur
LD D, 0
LD IX, DEF_GRAPH_TABLE_PIXEL_4 ; Référence à la table des masques 4 couleurs
ADD IX, DE
LD E, (IX) ; Masque logique associé à la couleur entrelacée dans B


; X se trouve actuellement dans A, on ne préserve que les 2 premiers bits
; de manière à savoir de combien de bits
; doivent être déclalés pour obtenir les masques logiques
AND 3


; Décalages des masques vers le bas en fonction du n° du pixel concerné
;
; Paramètres de la fonction MATH_SRL_8
; En entrée
; E <=> Entier de 8 bits
; A <=> Nombre de bits à décaler
; En sortie
; E <=> Résultat du décalage des n bits
;
; A et E sont déjà chargés avec leur valeur respective

CALL MATH_SRL_8 ; Décalage du masque de la couleur entrelacée, associée
; à la couleur du pixel
; En sortie E contient le masque de la valeur entrelacée
; associé à la couleur du pixel
LD D, E ; Sauvegarde de E

; A est déjà chargé avec le nombre de décalages
LD E, 136 ; Valeur par défaut du masque logique qui va permettre de préserver
; le pixel voisin, en Mode 1 = 136 <=> %10001000
CALL MATH_SRL_8 ; Décalage du masque négatif qui permet de préserver le pixel voisin


; Inversion du masque logique négatif de manière à préserver les données
; du pixel voisin
LD A, E
CPL
LD E, D ; Restauration de E qui doit contenir le masque entrelacé
; lié à la couleur du pixel
LD D, A ; D va contenir le masque logique permettant la préservation
; du pixel voisin


_GRAPH_LINE_V_4_1:

; Calcul du nombre de points à traiter
;
; En entrée
; B <=> Y1
; C <=> Y2
;
LD A, C
SUB B
LD C, A ; Le nombre de points à traiter dans C

; Calcul du nombre de lignes restant à traiter dans la série courante
; (Une série = 8 lignes)
LD A, B ; B = Y1
AND 7 ; On ne garde que les 3 derniers bits
LD B, A ;
LD A, 8 ; Le nombre de lignes restantes à traiter dans la série courante
SUB B ; = 8 - le nombre de lignes déjà traitées
LD B, A ; Le nombre de lignes restant à traiter dans B

; Valeur par défaut pour l'incrémentation de l'adresse mémoire contenue dans HL
; &800 <=> Permet de passer à la ligne suivante
; &50 <=> Permet de passer à la série de lignes suivante
; &4000 <=> Permet d'ajuster HL en fonction d'une série complète de lignes
; = [nombre de lignes dans une série] * &800
; &3FB0 <=> = Espace d'adressage d'une série complète de lignes – Offset
; pour la série de lignes suivantes
; = &4000 - &50
; => HL = HL - &4000 + &50
;
LD IX, 0 ; Sauvegarde de l'adresse de la pile
ADD IX, SP ;


_GRAPH_LINE_V_4_2

; Affichage du pixel
LD A, (HL)
AND D ; Préservation des données du pixel voisin
OR E ; Affichage du nouveau pixel
LD (HL), A

; Test pour voir si tous les points ont été traités
LD A, C
OR A
JP z, _GRAPH_LINE_V_4_END

; Vérification si l'on a atteint une fin de série de lignes
; (série toutes les 8 lignes)
DJNZ _GRAPH_LINE_V_4_3

LD SP, &3FB0 ; &3FB0 = &4000 - &50 = Espace d'adressage d'une série complète
; de lignes - Offset pour la série de lignes suivantes
SBC HL, SP ; => HL = HL - &4000 + &50
;
LD B, 8 ; On va traiter une nouvelle série de 8 lignes

_GRAPH_LINE_V_4_3

LD SP, &800 ; Passage à la ligne suivante (HL = HL + &800)
ADD HL, SP ;
DEC C ; Décrémentation de C qui contient le nombre de points à traiter
JP _GRAPH_LINE_V_4_2

_GRAPH_LINE_V_4_END

LD SP, IX ; Restauration de l'adresse de la pile

POP IX ; Restauration des registres
POP HL ;
POP DE ; AF,BC,DE,HL,IX
POP BC ;
POP AF ;
RET

5.5 Affichage d'une ligne verticale en mode 2 (2 couleurs, 8 pixels par octet)

;********************************************************
; Affichage d'une ligne verticale en mode 2 (2 couleurs)
;
; En entr&eacute;e
; D &lt;=> Y1
; E &lt;=> Y2
; BC &lt;=> X
; A &lt;=> Couleur de la ligne
; En sortie
; n&eacute;ant
; Registres affect&eacute;s
; aucun
; Remarques
;
;

GRAPH_LINE_V_2:

PUSH AF ; Sauvegarde des registres
PUSH BC ;
PUSH DE ; AF,BC,DE,HL,IX
PUSH HL ;
PUSH IX ;


; Adresse du premier pixel
;
; En entr&eacute;e
; BC &lt;=> X
; A &lt;=> Y1
; En sortie
; HL &lt;=> Adresse du point
;
PUSH DE ; On pr&eacute;serve Y1 et Y2
LD E, A ; La couleur dans E
LD A, D ; Y1 dans A

CALL GRAPH_ADR_OF_PIXEL
LD A, C ; La partie basse de X dans A
POP BC ; Restauration de Y1 et Y2 dans BC

; Pr&eacute;paration des masques logiques en fonction du n&deg; de la couleur
LD D, 0
LD IX, DEF_GRAPH_TABLE_PIXEL_2 ; R&eacute;f&eacute;rence &agrave; la table des masques 4 couleurs
ADD IX, DE
LD E, (IX) ; Masque logique associ&eacute; &agrave; la couleur entrelac&eacute;e dans B


; X se trouve actuellement dans A, on ne pr&eacute;serve que les 3 premiers bits de mani&egrave;re
; &agrave; savoir de combien de bits
; doivent &ecirc;tre d&eacute;clal&eacute;s les masques logiques
AND 7


; D&eacute;calages des masques vers le bas en fonction du n&deg; du pixel concern&eacute;
;
; Param&egrave;tres de la fonction MATH_SRL_8
; En entr&eacute;e
; E &lt;=> Entier de 8 bits
; A &lt;=> Nombre de bits &agrave; d&eacute;caler
; En sortie
; E &lt;=> R&eacute;sultat du d&eacute;calage des n bits
;
; A et E sont d&eacute;j&agrave; charg&eacute;s avec leur valeur respective

CALL MATH_SRL_8 ; D&eacute;calage du masque de la couleur entrelac&eacute;e,
; associ&eacute;e &agrave; la couleur du pixel
; En sortie E contient le masque de la valeur entrelac&eacute;e
; associ&eacute; &agrave; la couleur du pixel
LD D, E ; Sauvegarde de E

; A est d&eacute;j&agrave; charg&eacute; avec le nombre de d&eacute;calages
LD E, 128 ; X AND 7 = n&deg; du pixel courant, A contient donc le nombre de bits
; &agrave; d&eacute;caler.
; en Mode 2 le masque = 128 &lt;=> %10001000
CALL MATH_SRL_8 ; D&eacute;calage du masque n&eacute;gatif qui permet de pr&eacute;server le pixel voisin


; Inversion du masque logique n&eacute;gatif de mani&egrave;re &agrave; pr&eacute;server les donn&eacute;es
; du pixel voisin
LD A, E
CPL
LD E, D ; Restauration de E qui doit contenir le masque entrelac&eacute; li&eacute;
; &agrave; la couleur du pixel
LD D, A ; D va contenir le masque logique permettant la pr&eacute;servation
; du pixel voisin


_GRAPH_LINE_V_2_1:

; Calcul du nombre de points &agrave; traiter
;
; En entr&eacute;e
; B &lt;=> Y1
; C &lt;=> Y2
;
LD A, C
SUB B
LD C, A ; Le nombre de points &agrave; traiter dans C

; Calcul du nombre de lignes restant &agrave; traiter dans la s&eacute;rie courante
; (Une s&eacute;rie = 8 lignes)
LD A, B ; B = Y1
AND 7 ; On ne garde que les 3 derniers bits
LD B, A ;
LD A, 8 ; Le nombre de lignes restantes &agrave; traiter dans la s&eacute;rie courante
SUB B ; = 8 - le nombre de lignes d&eacute;j&agrave; trait&eacute;es
LD B, A ; Le nombre de lignes restant &agrave; traiter dans B

; Valeur par d&eacute;faut pour l'incr&eacute;mentation de l'adresse m&eacute;moire contenue dans HL
; &amp;800 &lt;=> Permet de passer &agrave; la ligne suivante
; &amp;50 &lt;=> Permet de passer &agrave; la s&eacute;rie de lignes suivante
; &amp;4000 &lt;=> Permet d'ajuster HL en fonction d'une s&eacute;rie compl&egrave;te de lignes
; = [nombre de lignes dans une s&eacute;rie] * &amp;800
; &amp;3FB0 &lt;=> = Espace d'adressage d'une s&eacute;rie compl&egrave;te de lignes û Offset
; pour la s&eacute;rie de lignes suivantes
; = &amp;4000 - &amp;50
; => HL = HL - &amp;4000 + &amp;50
;
LD IX, 0 ; Sauvegarde de l'adresse de la pile
ADD IX, SP ;


_GRAPH_LINE_V_2_2

; Affichage du pixel
LD A, (HL)
AND D ; Pr&eacute;servation des donn&eacute;es du pixel voisin
OR E ; Affichage du nouveau pixel
LD (HL), A

; Test pour voir si tous les points ont &eacute;t&eacute; trait&eacute;s
LD A, C
OR A
JP z, _GRAPH_LINE_V_2_END

; V&eacute;rification si l'on a atteint une fin de s&eacute;rie de lignes
; (s&eacute;rie toutes les 8 lignes)
DJNZ _GRAPH_LINE_V_2_3

LD SP, &amp;3FB0 ; &amp;3FB0 = &amp;4000 - &amp;50 = Espace d'adressage d'une s&eacute;rie compl&egrave;te
; de lignes - Offset pour la s&eacute;rie de lignes suivantes
SBC HL, SP ; => HL = HL - &amp;4000 + &amp;50
;
LD B, 8 ; On va traiter une nouvelle s&eacute;rie de 8 lignes

_GRAPH_LINE_V_2_3

LD SP, &amp;800 ; Passage &agrave; la ligne suivante (HL = HL + &amp;800)
ADD HL, SP ;
DEC C ; D&eacute;cr&eacute;mentation de C qui contient le nombre de points &agrave; traiter
JP _GRAPH_LINE_V_2_2

_GRAPH_LINE_V_2_END

LD SP, IX ; Restauration de l'adresse de la pile

POP IX ; Restauration des registres
POP HL ;
POP DE ; AF,BC,DE,HL,IX
POP BC ;
POP AF ;
RET

5.6 Affichage d'une ligne verticale indépendamment de mode graphique

;*****************************************************************
; Affichage d'une ligne verticale quelque soit le mode graphique
;
; En entrée
; D <=> Y1
; E <=> Y2
; BC <=> X
; A <=> Couleur de la ligne
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
; - Les modes graphiques supportés sont les 0,1 et 2
;

GRAPH_LINE_V:

PUSH AF ; Sauvegarde de AF pour le retour

; Vérification du mode graphique en cours
LD A, CST_GRAPH_VIDEO_MODE
CP 2
JP z, _GRAPH_LINE_V_2
CP 1
JP z, _GRAPH_LINE_V_4
OR A
JP z, _GRAPH_LINE_V_16

; Retour si le mode graphique est <> 0,1 ou 2
POP AF
RET


; Affichage des pixels
;
; En entrée les fonctions possèdent les même paramètres
; D <=> Y1
; E <=> Y2
; BC <=> X
; A <=> Couleur de la ligne

_GRAPH_LINE_V_16

; Affichage de la ligne horizontale 16 couleurs
POP AF
CALL GRAPH_LINE_V_16
RET

_GRAPH_LINE_V_4

; Affichage de la ligne horizontale 4 couleurs
POP AF
CALL GRAPH_LINE_V_4
RET

_GRAPH_LINE_V_2

; Affichage de la ligne horizontale 2 couleurs
POP AF
CALL GRAPH_LINE_V_2
RET

GRAPH_LINE_V_END

Rien à signaller !

6 - Le tracé d'une ligne oblique

6.1 L'algorithme

Cet algorithme est bien connu des développeurs, il a été inventé par Bresenham.
Voici ce que donnerait l'algorithme en Basic:

CALL Pixel (X1, Y1, Couleur) ; Premier pixel

IF X1 < X2 THEN xincr = 1 ELSE xincr = -1
IF Y1 < Y2 THEN xincr = 1 ELSE yincr = -1

dx = ABS(X1 - X2)
dy = ABS(Y1 - Y2)

IF dy > dx THEN
Cumul = dy \ 2

FOR i = 1 TO dy
Y1 = Y1 + yincr
Cumul = cumul + dx
IF cumul >= dy THEN
Cumul = cumul - dy
X1 = X1 + xincr
END
CALL Pixel (X1, Y1, Couleur) ; Pixels suivants
NEXT i
END
ELSE

Cumul = dx \ 2

FOR i = 1 TO dx
X1 = X1 + xincr
Cumul = cumul + dy
IF cumul >= dx THEN
Cumul = cumul - dx
Y1 = Y1 + yincr
END
CALL Pixel (X1, Y1, Couleur) ; Pixels suivants
NEXT i

END


Regardons maintenant comment simplifier cet algorithme.

1 - Première simplification :

;Les variables xincr et yincr permettent respectivement d'incrémenter X, Y si X1 et Y1 sont positifs ou dans le cas contraire, les décrémenter. Si nous nous arrangeons pour que X1 et Y1 soient toujours inférieurs à X2 et Y2, xincr et yincr seront toujours égaux à 1.

2 – Seconde simplification :

Dans un second temps nous calculons les valeurs absolues de dx et dy. Dans le cas où X1 et Y1 sont toujours inférieurs à X2 et Y2, le calcul de dx et dy se réduit à :

dx = X2 – X1dy = Y2 – Y1

L'algorithme devient donc :

CALL Pixel (X1, Y1, Couleur) ; Premier pixel

IF X2 < X1 THEN Echange X2 avec X1
IF Y2 < Y1 THEN Echange Y2 avec Y1

dx = X2 – X1
dy = Y2 – Y1

IF dy > dx THEN
Cumul = dy \ 2

FOR i = 1 TO dy
Y1 = Y1 + 1
Cumul = cumul + dx
IF cumul >= dy THEN
Cumul = cumul - dy
X1 = X1 + 1
END
CALL Pixel (X1, Y1, Couleur) ; Pixels suivants
NEXT i
END
ELSE

Cumul = dx \ 2

FOR i = 1 TO dx
X1 = X1 + 1
Cumul = cumul + dy
IF cumul >= dx THEN
Cumul = cumul - dx
Y1 = Y1 + 1
END
CALL Pixel (X1, Y1, Couleur) ; Pixels suivants
NEXT i

END

Ces simplifications ne sont pas très nombreuses mais permettent de simplifier le codage de la fonction en assembleur. Vous avez l'algorithme final, il nous reste plus qu'à le coder ! Pour éviter tout blabla… j'ai commenté le code à partir de l'algorithme pour qu'il soit plus compréhensible.

6.2 Affichage d'une ligne oblique en mode 0 (16 couleurs, 2 pixels par octet)

;**********************************************************************
; Affichage d'une ligne en mode 0 (16 couleurs, 2 pixels par octet)
;
; En entrée
; BC <=> X1
; HL <=> X2
; D <=> Y1
; E <=> Y2
; A <=> Couleur de la ligne (de 0 à 15)
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
; Zone d'affichage x1 = 0, x2 = 159, y1 = 0, y2 = 199
;

GRAPH_LINE_16:

PUSH AF ; Sauvegarde des registres
PUSH BC ;
PUSH HL ;
PUSH DE ;
PUSH IX ;
PUSH IY ;

; Création de la pile de travail
PUSH AF ; (SP) <=> Y1
; (SP + 1) <=> Couleur du point

; Calcul de la position de la pile de travail
PUSH HL
LD HL, 0
ADD HL, SP
INC HL
INC HL
PUSH HL
POP IY ; IY Contient l'adresse de basse de la pile de travail
POP HL


; Echange des valeurs si X1 > à X2 ou Y1 > Y2
;
; IF X1 > X2 THEN X1 <=> X2
; IF Y1 > Y2 THEN Y1 <=> Y2
;

;Y
LD A, D ; Comparaison Y1 avec Y2
CP E ; (D = Y1, E = Y2)
JP c, _GRAPH_LINE_16_1
LD D, E ; Echange Y1 avec Y2
LD E, A ;

_GRAPH_LINE_16_1

;X
OR A ; On efface Carry
PUSH HL
SBC HL, BC ; Si inférieur à 0 Carry = 1
JP nc, _GRAPH_LINE_16_2
LD H, B
LD L, C
POP BC
JP _GRAPH_LINE_16_3

_GRAPH_LINE_16_2

POP HL

_GRAPH_LINE_16_3

; -----------------------------------------------
; Affichage du premier pixel
;
; Paramètres en entrée de la procédure GRAPH_PIXEL
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
;
; CALL Pixel (X1, Y1, Couleur) (BC, D, E)
;

PUSH DE
LD E, (IY + 1) ; Chargement de E avec la couleur sauvegarder à (SP + 3)

CALL GRAPH_PUT_PIXEL_16 ; Affichage du point en 16 couleurs
POP DE

; Stockage de X1 et de Y1
PUSH BC ; Récupération de X1 dans IX
POP IX ;
LD (IY), D ; Récupération de Y1 dans (IY)


; -----------------------------------------------
; Calcul de dx et de dy
;
; dx = X2 - X1
; dy = Y2 - Y1
;
; HL <=> dx
; BC <=> dy

; dx
OR A ; On efface Carry
SBC HL, BC

; dy
LD A, E
SUB D
LD B, 0
LD C, A

; IF dy > dx THEN
OR A ; On efface Carry
PUSH HL
SBC HL, BC
POP DE ; DE <=> dx
JP nc, _GRAPH_LINE_16_6


; -----------------------------------------------
; Tracé de la ligne (dy > dx)
;
; Rappel de l'affectation des registres
;
; HL <=> Cumul
; DE <=> dx
; BC <=> dy
; IX <=> X1
; A <=> Compteur dy
; (IY) <=> Y1

; Cumul = dy \ 2
; SRL -> RRA
LD H, B
LD A, C
SRL H
RRA
LD L, A ; HL <=> Cumul

; FOR i = dy TO 1
LD A, C

_GRAPH_LINE_16_4

; Y1 = Y1 + 1
INC (IY)
; Cumul = cumul + dx
ADD HL, DE
; IF cumul >= dy THEN
PUSH HL
SBC HL, BC
POP HL
JP c, _GRAPH_LINE_16_5
; Cumul = cumul - dy
SBC HL, BC
; X1 = X1 + 1
INC IX
; END
_GRAPH_LINE_16_5

; -----------------------------------------------
; Affichage du pixel courant
;
; Paramètres en entrée de la procédure GRAPH_PIXEL
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
;
; CALL Pixel (X1, Y1, Couleur) (BC, D, E)
;

PUSH BC
PUSH DE
PUSH IX
POP BC
LD D, (IY) ; Chargement de D avec Y1 à (SP)
LD E, (IY + 1) ; Chargement de E avec la couleur sauvegarder à (SP + 1)

CALL GRAPH_PUT_PIXEL_16 ; Affichage du point en 16 couleurs
POP DE
POP BC

; NEXT i
DEC A
JP nz, _GRAPH_LINE_16_4
JP GRAPH_LINE_16_END


_GRAPH_LINE_16_6

; -----------------------------------------------
; Tracé de la ligne (dy <= dx)
;
; Rappel de l'affectation des registres
;
; HL <=> Cumul
; DE <=> dx
; BC <=> dy
; IX <=> X1
; (IY) <=> Y1

; Cumul = dx \ 2
; SRL -> RRA
LD H, D
LD A, E
SRL H
RRA
LD L, A ; HL <=> Cumul

; FOR i = dx TO 1
LD A, E

_GRAPH_LINE_16_7

; X1 = X1 + 1
INC IX
; Cumul = cumul + dy
ADD HL, BC
; IF cumul >= dx THEN
PUSH HL
SBC HL, BC
POP HL
JP c, _GRAPH_LINE_16_8
; Cumul = cumul - dx
SBC HL, DE
; Y1 = Y1 + 1
INC (IY)
; END
_GRAPH_LINE_16_8

; -----------------------------------------------
; Affichage du pixel courant
;
; Paramètres en entrée de la procédure GRAPH_PIXEL
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
;
; CALL Pixel (X1, Y1, Couleur) (BC, D, E)
;

PUSH BC
PUSH DE
PUSH IX
POP BC
LD D, (IY) ; Chargement de D avec Y1 à (SP)
LD E, (IY + 1) ; Chargement de E avec la couleur sauvegarder à (SP + 1)

CALL GRAPH_PUT_PIXEL_16 ; Affichage du point en 16 couleurs
POP DE
POP BC

; NEXT i
DEC A
JP nz, _GRAPH_LINE_16_7

GRAPH_LINE_16_END

POP AF ; Destruction de la pile de travail

POP IY ; Restauration des registres
POP IX ;
POP DE ;
POP HL ;
POP BC ;
POP AF ;
RET

Si vous avez bien étudié sont fonctionnement vous comprendrez aisément le tracé de lignes 2 et 4 couleurs. Je vais vous présentez le codage de la fonction pour le tracé d'une ligne à quatre couleurs, pour le tracé d'une ligne en 2 couleurs c'est exactement la même chose. La seule différence en le tracé 16 couleurs et les tracés en 4 et 2 couleurs est l'utilisation d'une variable sur 16 bits qui permet de comptabiliser le nombre de points sur X et Y qui ont été traités.

6.3 Affichage d'une ligne oblique en mode 1 (4 couleurs, 4 pixels par octet)

;**********************************************************************
; Affichage d'une ligne en mode 1 (4 couleurs, 4 pixels par octet)
;
; En entrée
; BC <=> X1
; HL <=> X2
; D <=> Y1
; E <=> Y2
; A <=> Couleur de la ligne (de 0 à 3)
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
; Zone d'affichage x1 = 0, x2 = 319, y1 = 0, y2 = 199
;

LINE_4_COUNT DW 0

GRAPH_LINE_4:

PUSH AF
PUSH BC
PUSH HL
PUSH DE
PUSH IX
PUSH IY

; Création de la pile de travail
PUSH AF ; (SP) <=> Y1
; (SP + 1) <=> Couleur du point

; Calcul de la position de la pile de travail
PUSH HL
LD HL, 0
ADD HL, SP
INC HL
INC HL
PUSH HL
POP IY ; IY Contient l'adresse de basse de la pile de travail
POP HL


; Test des valeurs en entrée
; Echange des valeurs si X1 > à X2 ou Y1 > Y2
;
; IF X1 > X2 THEN X1 <=> X2
; IF Y1 > Y2 THEN Y1 <=> Y2
;

;Y
LD A, D ; Comparaison Y1 avec Y2
CP E ; (D = Y1, E = Y2)
JP c, _GRAPH_LINE_4_1
LD D, E ; Echange Y1 avec Y2
LD E, A ;

_GRAPH_LINE_4_1

;X
OR A ; On efface Carry
PUSH HL
SBC HL, BC ; Si inférieur à 0 Carry = 1
JP nc, _GRAPH_LINE_4_2
LD H, B
LD L, C
POP BC
JP _GRAPH_LINE_4_3

_GRAPH_LINE_4_2

POP HL

_GRAPH_LINE_4_3

; -----------------------------------------------
; Affichage du premier pixel
;
; Paramètres en entrée de la procédure GRAPH_PIXEL
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
;
; CALL Pixel (X1, Y1, Couleur) (BC, D, E)
;

PUSH DE
LD E, (IY + 1) ; Chargement de E avec la couleur sauvegarder à (SP + 1)

CALL GRAPH_PUT_PIXEL_4 ; Affichage du point en 16 couleurs
POP DE

; Stockage de X1 et de Y1
PUSH BC ; Récupération de X1 dans IX
POP IX ;
LD (IY), D ; Récupération de Y1 dans (IY)


; -----------------------------------------------
; Calcul de dx et de dy
;
; dx = X2 - X1
; dy = Y2 - Y1
;
; HL <=> dx
; BC <=> dy

; dx
OR A ; On efface Carry
SBC HL, BC

; dy
LD A, E
SUB D
LD B, 0
LD C, A

; IF dy > dx THEN
OR A ; On efface Carry
PUSH HL
SBC HL, BC
POP DE ; DE <=> dx
JP nc, _GRAPH_LINE_4_6


; -----------------------------------------------
; Tracé de la ligne (dy > dx)
;
; Rappel de l'affectation des registres
;
; HL <=> Cumul
; DE <=> dx
; BC <=> dy
; IX <=> X1
; A <=> Compteur dy
; (IY)<=> Y1

; Cumul = dy \ 2
; SRL -> RRA
LD H, B
LD A, C
SRL H
RRA
LD L, A ; HL <=> Cumul

; FOR i = dy TO 1
LD (LINE_4_COUNT), BC
LD A, (IY)

_GRAPH_LINE_4_4

; Y1 = Y1 + 1
INC A
; Cumul = cumul + dx
ADD HL, DE
; IF cumul >= dy THEN
PUSH HL
SBC HL, BC
POP HL
JP c, _GRAPH_LINE_4_5
; Cumul = cumul - dy
OR A
SBC HL, BC
; X1 = X1 + 1
INC IX
; END
_GRAPH_LINE_4_5

; -----------------------------------------------
; Affichage du pixel courant
;
; Paramètres en entrée de la procédure GRAPH_PIXEL
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
;
; CALL Pixel (X1, Y1, Couleur) (BC, D, E)
;

PUSH BC
PUSH DE
PUSH IX
POP BC
LD D, A
LD E, (IY + 1) ; Chargement de E avec la couleur sauvegarder à (SP + 1)

CALL GRAPH_PUT_PIXEL_4 ; Affichage du point en 16 couleurs
POP DE

; NEXT i
OR A
PUSH HL
LD BC, 1
LD HL, (LINE_4_COUNT)
SBC HL, BC
LD (LINE_4_COUNT), HL
POP HL
POP BC
JP nz, _GRAPH_LINE_4_4
JP GRAPH_LINE_4_END

_GRAPH_LINE_4_6

; -----------------------------------------------
; Tracé de la ligne (dy <= dx)
;
; Rappel de l'affectation des registres
;
; HL <=> Cumul
; DE <=> dx
; BC <=> dy
; IX <=> X1
; (IY)<=> Y1

; Cumul = dx \ 2
; SRL -> RRA
LD H, D
LD A, E
SRL H
RRA
LD L, A ; HL <=> Cumul

; FOR i = dx TO 1
LD (LINE_4_COUNT), DE
LD A, (IY)

_GRAPH_LINE_4_7

; X1 = X1 + 1
INC IX
; Cumul = cumul + dy
ADD HL, BC
; IF cumul >= dx THEN
PUSH HL
SBC HL, DE
POP HL
JP c, _GRAPH_LINE_4_8
; Cumul = cumul - dx
OR A
SBC HL, DE
; Y1 = Y1 + 1
INC A
; END
_GRAPH_LINE_4_8

; -----------------------------------------------
; Affichage du pixel courant
;
; Paramètres en entrée de la procédure GRAPH_PIXEL
;
; En entrée
; BC <=> X sur 16 bits
; D <=> Y sur 8 bits
; E <=> Couleur du pixel sur 8 bits
;
; CALL Pixel (X1, Y1, Couleur) (BC, D, E)
;

PUSH BC
PUSH DE
PUSH IX
POP BC
LD D, A ; Chargement de D avec Y1
LD E, (IY + 1) ; Chargement de E avec la couleur sauvegarder à (SP + 1)

CALL GRAPH_PUT_PIXEL_4 ; Affichage du point en 16 couleurs
POP DE

; NEXT i
OR A
LD BC, 1
PUSH HL
LD HL, (LINE_4_COUNT)
SBC HL, BC
LD (LINE_4_COUNT), HL
POP HL
POP BC
JP nz, _GRAPH_LINE_4_7

GRAPH_LINE_4_END

POP AF ; Destruction de la pile de travail

POP IY ; Restauration des registres
POP IX ;
POP DE ;
POP HL ;
POP BC ;
POP AF ;
RET

6.4 Affichage d'une ligne oblique quelque soit le mode graphique utilisé

;*********************************************************************
; Affichage d'une ligne quelque soit le mode graphique
;
; En entrée
; BC <=> X1
; HL <=> X2
; D <=> Y1
; E <=> Y2
; A <=> Couleur de la ligne (de 0 à 3)
; En sortie
; néant
; Registres affectés
; aucun
; Remarques
;

GRAPH_LINE:

PUSH AF

; Vérification du mode graphique en cours
LD A, CST_GRAPH_VIDEO_MODE
CP 2
JP z, _GRAPH_LINE_2
CP 1
JP z, _GRAPH_LINE_4
OR A
JP z, _GRAPH_LINE_16

; Retour si le mode graphique est <> 0,1 ou 2
POP AF
RET

_GRAPH_LINE_16

; Affichage de la ligne 16 couleurs
POP AF
CALL GRAPH_LINE_16
RET

_GRAPH_LINE_4

; Affichage de la ligne 4 couleurs
POP AF
CALL GRAPH_LINE_4
RET

_GRAPH_LINE_2

; Affichage de la ligne 2 couleurs
POP AF
CALL GRAPH_LINE_2
RET

GRAPH_LINE_END

Pour conclure, si vous avez bien compris comment fonctionne les fonctions de traçage de lignes obliques, vous aller pouvoir facilement les optimiser en évitant un maximum d'appels à la fonction d'affichage des pixels en la codant directement et en évitant les PUSH et les POP…

Voilà ! J'espère que vous vous êtes bien amusé ?
Dans un prochain article nous étudierons l'affichage et la gestion des Sprites …

7- Annexe

7.1 Opération de décalage de n bits vers la droite d'un entier 8 bits

;***************************************************************
; Routine de décalage vers la droite d'un entier de 8 bits
;
; En entrée
; E <=> Entier de 8 bits
; A <=> Nombre de bits à décaler
; En sortie
; E <=> Résultat du décalage des n bits
; Registres affectés
; F, E
; Remarques
; - Cette fonction n'utilise pas la pile pour le passage de paramètres
;

MATH_SRL_8:

PUSH BC ; Sauvegarde de AF pour le retour
OR A ; Si B = 0 on sort
LD B, A ; Le nombre d'itération est transféré dans B pour le décompte
JP z, _MATH_SRL_8_END

_MATH_SRL_8_1

SRL E
DJNZ _MATH_SRL_8_1

_MATH_SRL_8_END

POP BC
RET

7.2 Opération de décalage de n bits vers la droite d'un entier 16 bits

;***************************************************************
; Routine de décalage vers la droite d'un entier de 16 bits
;
; En entrée
; DE <=> Entier non signé de 16 bits
; A <=> Nombre de bits à décaler
; En sortie
; DE <=> Résultat du décalage des n bits
; Registres affectés
; F, DE
; Remarques
; - Cette fonction n'utilise pas la pile pour le passage de paramètres
;

MATH_SRL_16:

PUSH BC ; Sauvegarde de BC pour le retour
OR A ; Si B = 0 on sort
JP z, _MATH_SRL_16_END
LD B, A ; B va contenir le nombre de décalages
LD C, A ; Sauvegarde de A
LD A, E

_MATH_SRL_16_1

SRL D
RRA
DJNZ _MATH_SRL_16_1
LD E, A

_MATH_SRL_16_END

LD A, C ; Restauration de A
POP BC ; Restauration de BC
RET

7.3 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

7.4 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

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

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

Lien(s):
» Coding » Structure de la mémoire écran de l'Amstrad CPC par ANTIBUG
» Coding » Cours et initiation d'ANTIBUG
» Coding » Les opérations, la pile et les registres spécialisés par ANTIBUG
» Coding » Les multiplications et les divisions entières avec le Z80 par ANTIBUG
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 295 millisecondes et consultée 2621 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.