Revenir au plan du site

Scrolling facile avec l'ASIC


Si vous ne l'avez pas encore lu, je vous invite à jeter un oeil à la série sur les scrollings CPC car bien qu'utilisant les facilités de l'ASIC, c'est un mélange d'utilisation classique du CRTC et de fonctions ASIC que nous allons utiliser. Les facilités de l'ASIC ne dispensent PAS de calculer correctement les changements de lignes.

Nous réutiliserons le [même fichier graphique]

Le registre de scrolling de l'ASIC


Certains l'appellent SSR, d'autres SSCR, peu importe, on retiendra son adresse dans la page ASIC : #6804

Soft Scroll Register (registre de scroll)
7 6 5 4 3 2 1 0
Si activé, continue d'afficher le border pendant 2 octets Décalage vertical vers le haut(de 0 à 7) Décalage horizontal vers la droite (de 0 à 15)*

*Si vous utilisez un décalage inapproprié avec la résolution, vos pixels ne seront pas correctement affichés. Par exemple, en mode 0, n'utilisez que les valeurs 0, 4, 8 et 12

Nous réutilisons le même source que pour le scrolling normal, avec l'ajout des étapes intermédiaires et un delock de l'ASIC, évidemment.

Des étapes intermédiaires? Oui, on va clarifier ça avec un tableau pour comparer les différents scrollings. En mode 0 la comparaison fait déjà mal mais en mode 1, on voit que le scrolling CPC ne permet de se placer que tous les 8 pixels (soit 16 bits de données). Avec l'usage du registre R3, on améliore la précision à l'octet, soit 4 pixels mode 1. Et avec l'ASIC, ben... ...on se promène à la résolution maximale.

Rappel : L'adresse CRTC n'est pas la même que l'adresse écran. Pour rappel, le CRTC compte en mots de 16 bits. Donc quand on incrémente l'adresse CRTC, l'adresse écran augmente de DEUX octets!
Étapes de scrolling
position X en pixel mode 1 scroll CPC scroll CPC et registre 3 scroll ASIC + SSR adresse écran
0 CRTC Adr = #0000 CRTC Adr = #0000   R3 = #8C CRTC Adr = #0000   SSR = 0 #C000
1 CRTC Adr = #0000   SSR = 2 #C000
2 CRTC Adr = #0000   SSR = 4 #C000
3 CRTC Adr = #0000   SSR = 6 #C000
4 CRTC Adr = #0000   R3 = #85 CRTC Adr = #0000   SSR = 8 #C001
5 CRTC Adr = #0000   SSR = 10 #C001
6 CRTC Adr = #0000   SSR = 12 #C001
7 CRTC Adr = #0000   SSR = 14 #C001
8 CRTC Adr = #0001 CRTC Adr = #0001   R3 = #8C CRTC Adr = #0001   SSR = 0 #C002
9 CRTC Adr = #0001   SSR = 2 #C002
10 CRTC Adr = #0001   SSR = 4 #C002
... ... ... ... ...

Et le source d'exemple :)
BUILDSNA : BANKSET 0
SNASET CPC_TYPE,4 ; modèle 6128+ conseillé
ORG #100 : RUN #100
;*** RMR2 tags ***
ASICOFF equ 0
ROM0000 equ 0
ROM4000 equ %01000
ROM8000 equ %10000
ASICON equ %11000
ROM0 equ 0 : ROM1 equ 1 : ROM2 equ 2 : ROM3 equ 3 : ROM4 equ 4 : ROM5 equ 5 : ROM6 equ 6 : ROM7 equ 7
macro RMR2 tags
ld a,{tags}+%10100000
ld b,#7F
out (c),a
mend

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
call UnlockAsic

LaBoucle
call DoScroll
ld yl,12
.softScroll
call WaitVBL : RMR2 ASICON : ld a,yl : or #80 : ld (#6804),a : RMR2 ASICOFF
ld a,yl : or a : jr z,LaBoucle : sub 2 : ld yl,a
jr .softScroll

DoScroll
call WaitVBL
RMR2 ASICON : ld a,#80+14 : ld (#6804),a : RMR2 ASICOFF
; 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

UnlockAsic
ld bc,#BCFF
out (c),c
out (c),0
ld hl,%1001000011101010
.loop
out (c),c
ld a,h:rlca:ld h,l:ld l,a
srl c:res 3,c
and #88
or c
ld c,a
cp #4D
jr nz,.loop
ld a,#CD
out (c),a : out (c),a
ret

WaitVBL
ld b,#F5 : noVBL in a,(c) : rra : jr c,noVBL
VBL in a,(c) : rra : jr nc,VBL : 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'

Cette fois, le scroll est presque trop lent si on le fait au pixel mode 1. Rien ne vous empêche que le faire en équivalent mode 0, c'est déjà très "smooth".

Animation tronquée hein...