ASMtrad CPC

Apprenez l'assembleur Z80

Double buffering.

Le double buffering c'est simplement utiliser deux écrans au lieu d'un.
Prendant que l'on travaille et affiche sur le premeir, c'est le deuxième que l'on montre.
Et inversement, si on travaille sur le deuxième on montrera le premier

DBUFFER1
DBUFFER2

L'intéret est simple: Ne pas se prendre le balayage ou ne pas avoir à se synchroniser pour afficher vos sprites au bon moment.
Bref, vous ne montrerez l'écran sur lequel vous affichez que lorsque celui-ci sera terminé.

Petit rappel:
La RAM centrale est la seule à pouvoir être adressée par le CRTC comme VRAM (RAM Vidéo).
Cette RAM centrale est composée de 4 banks de 16 Ko:

DBUFFER3

L'écran standard se trouve entre #C000 et #FFFF.
Pour travailler sur deux écrans, nous allons donc devoir changer la bank de celui-ci.
Voyons donc un peu comment cela fonctionne.

Changer la bank de l'écran.

Changer l'adresse de l'écran c'est ce qu'on appelle changer l'offset.
L'offset c'est l'adresse de début de l'écran.

Pour changer cet offset, nous passeront par le CRTC qui je le rappel gère justement l'envois de l'écran au moniteur.
C'est lui qui lui donne ses dimensions et son organisation.

Pour changer l'offset nous utiliserons les registres R12 et R13 du CRTC.
Notez que ceci n'a rien à voir avec les registres du Z80. Un registre point de vue CRTC c'est pour résumer un point d'entrée.
Par exemple le registre R1 dit quand le border doit être affiché, R2 donne la position de la HBL...

Voyons donc ces fameux R12 et R13 qui nous permettent de changer l'offset:

DBUFFER4

Pour adresser le CRTC il faut dans un premier temps choisir le registre.
Pour cela nous utiliserons le port #BC qui justement correspond à la sélection de registre.

                    LD      BC,#BC0C            ;#0C correspond à 12 en décimal
                    OUT     (C),C               ;on valide

Une fois le registre sélectionné, nous pouvons lui envoyer une valeur.
Pour cela il faudra cette fois passer par le port #BD

                    LD      BC,#BD00+%00010000  ;personnellement pour ce registre je préfère le binaire qui est plus clair
                    OUT     (C),C               ;on valide

Si vous regardez bien ma valeur binaire envoyée, vous comprendrez que j'ai donné comme offset l'adresse #4000.

Notez que pour le CRTC, il faut toujours d'une part sélectionner le registre puis envoyer la valeur.

Notez que l'adresse de départ de l'écran (l'OFFSET) est pris en compte en fin d'écran (vous pouvez donc le donner quand vous voulez entre le début de l'écran et avant la fin de celui-ci).
Attention cependant à éviter de le donner dans les 8 premières lignes de l'écran car le CRTC 1 le prendra aussitôt en compte dans ce cas précis (mais c'est hors sujet).

Mais surtout: le CRTC ne prend en compte que la RAM centrale dans sa config standard.
Vous aurez beau modifier l'ordre des banks, pour le CRTC c'est comme si vous n'aviez rien fait.
Les banks sont pour lui toujours linéaires avec les banks 0 , 1 , 2 et pour finir 3.

Revenons au double buffering

Pour le principe c'est assez simple. Mais c'est assez contraignant.
En effet puisqu'on affiche à deux endroits différents il nous faut deux routines d'affichage différentes:

-Une routine pour afficher entre #4000/#7FFF.
-Une routine pour afficher entre #C000/#FFFF

C'est en fait assez pénible et pas franchement facile à gérer.

Heureusement pour nous une astuce va nous permettre de passer outre cette contrainte en affichant toujours au même endroit.

Double buffering via changement de configuration de la RAM:

Tout est dans le titre: pour s'affranchir de devoir utiliser deux routines d'affichage différentes, nous allons tout simplement modifier l'ordre dans lesquelles les banks de ram centrale sont pour le Z80.

Avant d'expliquer la technique il faut ABSOLUMENT retenir une chose:

QUELQUE SOIT LA CONFIGURATION DE LA RAM, LE CRTC NE CONSIDÈRE QUE LA RAM CENTRALE LINÉAIRE !!! POUR LE CRTC LA RAM RESTE TOUJOURS LA MÊME !!!

Ainsi, comme dit plus haut, changer l'ordre des banks n'a aucune importance pour le CRTC. L'offset sera toujours relatif à la RAM centrale dans l'ordre logique.

Pour commencer, regardons ce que permet le Gate Array:

GA-RAM-BANKs

Comme on peut le voir ici, le GA nous permet de choisir une configuration de la RAM. (Rappel: le CRTC s'en fout, pour lui ça ne change rien).

"ppp" correspond à la page de 64Ko de RAM.
"ppp"=%000 et c'est la première page, soit, la configuration de base au démarrage.
"ppp"=%001 et se sont les 64Ko de RAM supplémentaires sur un 6128.

Sur un cpc 6128 de base vous n'en avez pas plus (sur un 464 bien entendu ppp=%001 ne donnera rien puisque vous n'avez que 64Ko.).

Ainsi pour avoir la configuration "normale" on fera:

                    LD  BC,#7F00+%11000000  ;On choisit bien la page 0
                    OUT (C),C               ;on valide

Notez que %11000000 donne en hexa #C0, on pourrait donc tout aussi bien écrire #7FC0 directement.

Ce qui va nous intéresser particulièrement ici c'est le dernier cas: %11000011 autrement dit le mode #C3.

Le Mode #C3:

Le mode #C3 précise deux choses:
- "La bank 3 de la page ppp qui est connectée en #C000/#FFFF." - "la Bank #C000/#FFFF de la RAM centrale est connectée en #4000/#FFFF."

Pour ce qui est de la bank 3 de la page ppp qui est connectée en #C000/#FFFF.
Considérons chaque page de 64Ko de la façon suivante:

Page de 64Ko
RAM

Puisque ppp=0, la page sélectionnée correspond donc au 64 premiers Ko de RAM (soit la RAM centrale) et qu'on nous dit que la bank 3 de la page sera connectée en #C000/#FFFF.
En gros pour le coup ça ne changera rien en #C000 puisque c'est la même bank que la normale qui sera connectée en #C000.

Revenons à la phrase: "la Bank #C000/#FFFF de la RAM centrale est connectée en #4000/#FFFF."

L'intéret de la chose, c'est de voir ce qui se passe entre #4000 et #7FFF.
En mode #C0 (RAM standard): en #4000 nous aurons donc bien la bank 1.
Mais dès que nous passerons en mode #C3, en #4000 c'est la bank 3 qui sera connectée !!!

Ainsi et c'est là que réside toute l'astuce: si notre routine d'affichage est faite pour fonctionner en #4000:
-En mode #C0, nous afficherons bien sur la bank 1 normalement en #4000/#7FFF.
-En mode #C3, nous afficherons bien sur la bank 3 normalement en #C000/#FFFF.

Bref voyons concrètement par un schéma ce que va nous faire ce mode #C3:

mode #C3

Et voila résolu notre problème de routine d'affichage puisqu'une seule routine qui affiche en #4000/#7FFF suffira :)

Comme déjà dit, ces changements de la RAM via le GA n'influencent pas (et tant mieux) ce que le CRTC lui, voit.

Voici deux schémas pour voir concrètement ce qu'on va pouvoir faire:

Le cas numéro 1: l'écran est en #C000 on affiche en #4000 (de toute façon maintenant on affichera toujours en #4000).:
frame1

Le cas numéro 2: l'écran est en #4000 mais c'est la bank 3 qui y est connectée.
On écrit donc en #4000 mais finalement dans la bank 3(#C000/#FFF):
frame2

Ce qui compte pour le moniteur c'est l'écran envoyé par le CRTC. Ici on alterne bien entre #4000 et #C000.
Pour nous et pour notre routine, passer du mode standard #C0 au mode #C3 nous permet d'afficher toujours en #4000 bien qu'en mode #C0 il s'agisse de la bank 1 et en mode #C3 de la bank 3.

Astuces:

Changer les valeurs à envoyer au GA et au CRTC c'est facile. Cependant, cela nous oblige à savoir dans quelles configurations ils étaient pour le mettre dans l'autre...

Que nenni !!! Une petite opération logique va nous rendre la chose bien plus facile !!!
Voyons pour le GA: Nous allons donc alterner entre deux valeurs: #C0 et #C3.
Comment pouvons nous passer de l'une à l'autre sans avoir à tester la valeur ???
Passons en binaire:
#C0=%11000000
#C3=%11000011

La différence se fait donc sur les bits 0 et 1.
Il faut donc que quand ces deux bits sont à 0 ils passent à 1 et inversement. Sans bien évidement toucher aux autres bits.

Regardons nos opérations logiques:
Operations logiques

La solution est toute trouvée: le XOR !!!

                    #C0 = %11000000
                    XOR = %00000011
                          %11000011 = #C3

                    #C3 = %11000011
                    XOR = %00000011
                          %11000000 = #C0

Le même principe fonctionne pour notre valeur d'offset à envoyer au registre 12 du CRTC:

                    #30 = %00110000 - Écran en #C000
                    #10 = %00010000 - Écran en #4000

                    #30 = %00110000
                    XOR = %00100000
                        = %00010000 = #10

                    #10 = %00010000
                    XOR = %00100000
                        = %00110000 = #30

On peut donc facilement passer d'une valeur à l'autre sans tester quoi que se soit !!!