Revenir au plan du site

Affiner le scrolling horizontal avec le registre 3 du CRTC


Le registre 3 du CRTC permet de programmer la durée du signal de synchronisation vertical et horizontal. Quelques différences apparaissent entre les CRTC : Certains peuvent programmer la hauteur de la synchro verticale, d'autres non. Quelques différences croisées entre les autres modèles.

VBL = signal de synchronisation verticale
HBL = signal de synchronisation horizontale
Registre 3
CRTC 7 6 5 4 3 2 1 0
0 Hauteur de la synchro verticale (0: VBL de 16 lignes) Largeur de la synchro horizontale (0: pas de HBL*)
1 Bits ignorés, VBL fixe de 16 lignes Largeur de la synchro horizontale (0: pas de HBL*)
2 Bits ignorés, VBL fixe de 16 lignes Largeur de la synchro horizontale (0: HBL de 16 nops)
3 et 4 Hauteur de la synchro verticale (0: VBL de 16 lignes) Largeur de la synchro horizontale (0: HBL de 16 nops)

*pas de HBL => pas d'interruption! Car le Gate Array compte les HBL pour générer les interruptions.
D'autres effets secondaires à prévoir sur Plus.

Changer la largeur de la HBL pour décaler l'écran


Attention, l'utilisation du registre 3 fonctionne sur un écran d'origine, la plupart des télévisions, même cathodiques retravaillent le signal et ce genre d'astuce est filtrée.
Ce n'est pas la catastrophe non plus, le scrolling va simplement descendre à 25Hz.

On va alterner la valeur du registre 3 entre #85 et #8C. Plus la HBL est courte, plus l'écran se décalera vers la droite.
BUILDSNA : BANKSET 0
ORG #100 : RUN #100

ld sp,#100
ld bc,#7F00+%10001100+%01 : out (c),c ; MODE 1
ld bc,#7F10 : out (c),c : ld a,#58 : out (c),a
ld bc,#7F00 : out (c),c : ld a,#58 : out (c),a
ld bc,#7F01 : out (c),c : ld a,#47 : out (c),a
ld bc,#7F02 : out (c),c : ld a,#43 : out (c),a
ld bc,#7F03 : out (c),c : ld a,#4B : out (c),a

Boucle
call DoScroll
ld b,#F5
.VBL in a,(c) : rra : jr nc,.VBL
ld bc,#BC00+3 : out (c),c : ld bc,#BD00+#8C : out (c),c
jr Boucle

DoScroll
ld b,#F5
.NOVBL in a,(c) : rra : jr c,.NOVBL ; pour éviter de faire le scroll alors qu'on est ENCORE dans la VBL précédente
.VBL in a,(c) : rra : jr nc,.VBL

ld bc,#BC00+3 : out (c),c : ld bc,#BD00+#85 : out (c),c

; incrémenter l'adresse dans la ligne de bloc avec gestion de débordement
ld hl,(adresseBloc) : inc hl : res 2,h : ld (adresseBloc),hl

; envoyer au CRTC
ld bc,#BC00+12 : out (c),c : ld a,h : or #30 : inc b : out (c),a
dec b : inc c : out (c),c : inc b : out (c),l

; tracer le sprite avant que le balayage arrive :)
ld xl,100
ld hl,(spriteCourant)
ld de,(adresseSpriteEcran)
.envoie100lignes
ldi : ld a,(hl) : ld (de),a : inc hl : dec e ; incrémenter les données mais revenir à l'adresse initiale écran
ld a,d : add 8 : ld d,a ; ajouter #800 à DE
jr nc,.okLigne ; pas de retenue, on est toujours dans le même bloc de lignes
ld a,80 : add e : ld e,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant
ld a,#C0 : adc d : ld d,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000)
res 3,d ; au cas où on reboucle dans la ligne de bloc (trait bleu), on ajuste dans tous les cas
.okLigne
dec xl : jr nz,.envoie100lignes
; gérer le déroulé des sprites
ld a,(spriteNumero) : inc a : cp 120 : jr nz,.enregistreAdresseSprite
xor a : ld hl,bandesSprites ; réarmer les compteurs
.enregistreAdresseSprite ld (spriteCourant),hl : ld (spriteNumero),a

ex hl,de ; on va utiliser HL plutôt que DE pour effacer, les adressages sont plus nombreux
ld xl,50 ; compteur à 50, on va effacer en zig-zag :)
ld bc,%1010111101011111 ; on précharge une trame sur les encres 2 et 3
Raz100
ld (hl),b : inc l : ld (hl),b : ld a,h : add 8 : ld h,a ; ligne paire, on sait que la ligne suivante est dans le bloc
ld (hl),c : dec l : ld (hl),c : ld a,h : add 8 : ld h,a : jr nc,.okRaz
ld a,80 : add l : ld l,a
ld a,#C0 : adc h : ld h,a
res 3,h
.okRaz
dec xl : jr nz,Raz100

ld hl,(adresseSpriteEcran) : inc hl : inc hl : res 3,h ; gérer le débordement à #C800
ld (adresseSpriteEcran),hl
ret

adresseBloc defw #0000 ; notre écran démarre sur le premier octet de la ligne de bloc
adresseSpriteEcran defw #C000+80 ; avant le premier scroll, cette adresse correspond à la ligne suivante
spriteNumero defb 0
spriteCourant defw bandesSprites
bandesSprites incbin 'BobWinnerFrance.bin'

Notre scrolling devient beaucoup plus agréable à regarder, malgré les deux colonnes qui clignottent sur les côtés (en effet, comme on bouge tout l'écran, le border change de place).


Il est possible d'éviter cet effet secondaire en effaçant une colonne d'un octet, du côté où est placé l'écran, nous n'étudierons pas ce cas d'autant plus qu'il nécessite un double buffer et que l'idée de cette petite série d'articles est de présenter les techniques avec des exemples le plus court possible!.